LangChain关于Agent的创建和使用示例以及报错
本文探讨了Agent智能体的概念及其在LangChain框架中的实现方式。Agent作为协调大语言模型和工具的系统,具备记忆、任务规划和自主调用工具等能力。文章对比了两种创建模式(Function Call和ReAct模式)及其实现方式,指出旧方法initialize_agent存在提示词固定和参数传递问题,推荐使用新方法AgentExecutor。重点分析了ReAct模式的核心标签体系(Thou
0 对于Agent的理解
Agent(智能体)是一个通过动态协调 大语言模型(LLM) 和工具(Tools) 来完成复杂任务的智能系 统。它让LLM充当"决策大脑",根据用户输入自主选择和执行工具(如搜索、计算、数据库查询等),最终生成精准的响应。

作为Agent智能体, 就不再是一个普通的“大脑”,而是一个智能的整体,即除了上述说的拥有工具以外还具备记忆、规划分解任务能力、自主调用工具能力等。
个人理解的LangChain中的Agent模块即类似上一篇文章:LangChain使用之Tools相比,不使用LangChain中的Agent模块也能达到类似的大模型调用工具的效果,使用了Agent模块能更方便地以更少的代码到达大模型调用工具地效果,功能也更强大,实现方式更简洁。
1 Agent、AgentExecutor的创建
Agent、AgentExecutor的创建有两种模式,两种方式
两种模式:
- 模式 1:Funcation Call模式
- 模式 2:ReAct 模式
区别:
- Function Call 模式会直接调用工具,直接生成工具参数,效率更高,适合工具明确的场景。
- ReAct(Reasoning + Acting)模式基于文本推理的链式思考,具备反思和自我纠错能力适合需要明确推理步骤的场景。例如智能客服、问答系统、任务执行等
两种创建方式:
即每一种模式都有两种创建方式
| 方式 | 创建 Agent | 创建 AgentExecutor | 特点 |
|---|---|---|---|
| 旧方式 | 使用AgentType 指定 | initialize_agent() | 快速上手(3行代码完成配置),但是定制化能力较弱(如提示词固定) |
| 新方式 | create_xxx_agent() | AgentExecutor() | 可自定义提示词(如从远程hub获取或本地自定义),清晰分离Agent逻辑与执行逻辑,需要更多代码 |
2 旧方式initialize_agent(提示词固定)代码示例
核心代码如下:
该示例使用initialize_agent创造了ReAct模式的AgentExecutor,该方式无法使用自定义提示词并且ReAct模式下大模型会进行思考推理,所以没有提示词限制很容易将思考内容混入提取的参数中,所以大模型很容易输出错误的工具参数
# 工具参数模板
class FieldInfo(BaseModel):
number: int = Field(description="一个整数")
# 定义工具函数
def is_even_numbers(number):
is_even = number % 2 == 0
return f"✅ 数字 {number} {'是' if is_even else '不是'} 偶数"
# 定义工具
tool1 = StructuredTool.from_function(
func=is_even_numbers,
name="is_even_numbers",
description="Determine if it is an even number",
args_schema=FieldInfo
)
agent_executor = initialize_agent(
llm=chat_model,
memory=memory,
agent=AgentType.CONVERSATIONAL_REACT_DESCRIPTION,
tools=tools,
)
输出报错pydantic_core._pydantic_core.ValidationError: 1 validation error for FieldInfo number Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='3\nObservation', input_type=str] For further information visit https://errors.pydantic.dev/2.12/v/int_parsing

如果使用initialize_agent来创建Function Call模式的AgentExecutor,也会存在底层参数传递冲突(回调函数被重复传递)
小结:
使用initialize_agent创建AgentExecutor的方式创建ReAct模式会因为无法指定提示词模板,所以大模型很容易因为参数提取不正确而报错,而同样的方式创建Function Call模式的AgentExecutor则会因为底层冲突而报错,所以这种方式不推荐使用,而应该使用AgentExecutor()这种新方式创建AgentExecutor
3 新方式AgentExecutor(可定义提示词)代码示例
3.1 ReAct模式
ReAct 框架的核心是通过 结构化标签 实现「思考 - 行动 - 反馈」的循环,所有标签都是为了让 Agent
和框架能清晰解析彼此的意图(避免歧义)。其涉及的标签可分为「核心必选标签」「终止标签」「辅助标签」三类,且不同 LangChain 版本 / 实现可能略有差异,但核心逻辑一致。
ReAct模式常用标签
1.必选标签(ReAct 框架的基础,缺一不可) Thought:、Action、Action Input
| 标签 | 作用说明 | 格式要求 |
|---|---|---|
| Thought: | 说明当前思考过程(为什么要调用工具、参数怎么来的、下一步要做什么) | 以「Thought:」开头,后面跟自然语言思考(如:“用户问 5 是否为偶数,需要调用 is_even_numbers 工具,参数为 5”) |
| Action: | 指定要调用的工具名称(必须与定义的工具名完全一致) | 以「Action:」开头,后面仅写工具名(无多余字符,如:“Action: is_even_numbers”) |
| Action Input: | 传递给工具的参数(需与工具的参数要求匹配) | 格式分两种:1.React 原生(基础 Tool):纯参数值(如 “Action Input: 5”)2.结构化工具:JSON 格式(如 “Action Input: {“number”: 5}”) |
| Final Answer: | 输出最终答案(无需再调用工具),是 LangChain ReActOutputParser 原生支持的终止标签 | 以「Final Answer:」开头,后面跟自然语言结果(如:“Final Answer: ✅ 数字 7 不是偶数”) |
2.终止标签(标记任务完成,避免无限循环) Final Answer
| 标签 | 作用说明 | 格式要求 |
|---|---|---|
| Final Answer: | 输出最终答案(无需再调用工具),是 LangChain ReActOutputParser 原生支持的终止标签 | 以「Final Answer:」开头,后面跟自然语言结果(如:“Final Answer: ✅ 数字 7 不是偶数”) |
3.辅助标签(可选,视场景扩展)) Observation:、Error、Retry
| 标签 | 作用说明 | 格式要求 |
|---|---|---|
| Observation: | 记录工具返回的结果(框架自动填充,无需模型手动输出) | LangChain 的 agent_scratchpad 会自动拼接「Action→Observation」,供模型后续思考参考 |
| Error: | 标记工具调用失败或参数错误(自定义场景用)) | 如参数无效时,模型输出 “Error: 输入不是整数,无法调用工具” |
| Retry: | 标记需要重试工具调用(自定义场景用) | 如参数错误后,输出 “Retry: 请用户提供有效的整数” |
对于ReAct模式,它的提示词是至关重要的,它需要明确指定三个必选标签,缺一不可,并且需要通过清晰明确的提示词来保证正确的输出,以下示例是使用大模型调用判断一个数是否为偶数的工具的示例
from langchain import hub
from langchain.agents import create_react_agent, AgentExecutor
from langchain.memory import ConversationBufferMemory
import os
import dotenv
from langchain_core.prompts import PromptTemplate
from langchain_core.tools import Tool
from langchain_openai import ChatOpenAI
dotenv.load_dotenv()
os.environ["OPENAI_BASE_URL"] = os.getenv("QWEN_BASE_URL")
os.environ["OPENAI_API_KEY"] = os.getenv("QWEN_API_KEY")
# 对话模型
chat_model = ChatOpenAI(
model="qwen-plus",
temperature=0
)
# 工具函数(保持不变)
def is_even_numbers(number_str):
try:
number = int(number_str.strip())
except ValueError:
return f"❌ 输入 {number_str} 不是有效的整数,请重新输入"
is_even = number % 2 == 0
return f"✅ 数字 {number} {'是' if is_even else '不是'} 偶数"
# 基础工具
tool1 = Tool(
name="is_even_numbers",
description="判断一个整数是否为偶数,仅接收纯整数输入(如 3、4、10),返回判断结果",
func=is_even_numbers
)
# 核心修改1:优化提示词,明确终止条件
template = """
你是一个严格遵循格式要求的助手,仅使用提供的工具解决问题,必须遵守 React 框架的解析规则。
### 核心规则:
1. 第一步:分析用户问题,若需要判断整数是否为偶数,输出「Thought-Action-Action Input」格式调用工具;
2. 第二步:工具返回结果后,**立即输出「Final Answer:」+ 工具返回的内容**(无需其他格式标签,直接结束);
3. 禁止在 Final Answer 后添加任何额外内容,禁止重复调用工具。
### 格式要求:
- 调用工具时必须包含:Thought: + Action: + Action Input:(缺一不可);
- 最终答案必须以「Final Answer:」开头(后面紧跟工具返回结果);
- Action Input 仅写纯整数(无引号、无多余字符)。
### 完整流程示例(必须严格遵循):
用户问:3是偶数吗?
(第一步:调用工具)
Thought: 需要判断3是否为偶数,调用is_even_numbers工具,参数为3
Action: is_even_numbers
Action Input: 3
(工具返回:✅ 数字 3 不是 偶数)
(第二步:输出最终答案)
Final Answer: ✅ 数字 3 不是 偶数
### 可用工具:
{tools}
工具说明:{tool_names} - 仅接收整数参数,用于判断是否为偶数
对话历史:{chat_history}
用户问题:{input}
{agent_scratchpad} # 自动填充工具调用记录和工具返回结果
"""
prompt = PromptTemplate.from_template(template)
# 工具列表
tools = [tool1]
# 记忆组件
memory = ConversationBufferMemory(
memory_key="chat_history",
return_messages=False,
output_key="output"
)
# 创建 Agent
agent = create_react_agent(chat_model, tools, prompt)
# 核心修改2:调整 AgentExecutor 参数,限制迭代次数 + 优化解析错误处理
agent_executor = AgentExecutor(
agent=agent,
memory=memory,
tools=tools,
verbose=True,
handle_parsing_errors="请直接输出工具返回的结果,无需重复调用工具!",
early_stopping_method="force" # 强制早期停止,工具返回后直接结束
)
# 测试对话
print("对话1:", agent_executor.invoke({"input": "3是偶数嘛?"}))
print("对话2:", agent_executor.invoke({"input": "4呢?"}))
输出效果
通过提示词限定在工具返回结果后就使用终止标签 Final Answer返回结果,此时Agent会识别此标签并返回最后终结果
⚠️注意:
若不以Final Answer标签返回结果agent可能无法识别会陷入无限自我思考的过程中
3.2 Function Call模式
相比于ReAct模式, Function Call模式则无需将精力花费在提示词模板上,只需要简单的提示词即可,无需使用标签约束,稳定性更强、效率更高。
代码示例
以下示例使用agent调用两数之和工具,在Function Call 模式下,更推荐使用ChatPromptTemplate,此时无需复杂的提示词也不需要使用各种标签来进行限制输出。
from langchain import hub
from langchain.agents import create_react_agent, AgentExecutor, create_openai_tools_agent, create_tool_calling_agent
from langchain.memory import ConversationBufferMemory
import os
import dotenv
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder, PromptTemplate
from langchain_core.tools import StructuredTool
from langchain_openai import ChatOpenAI
from pydantic import BaseModel, Field
dotenv.load_dotenv()
os.environ["OPENAI_BASE_URL"] = os.getenv("QWEN_BASE_URL")
os.environ["OPENAI_API_KEY"] = os.getenv("QWEN_API_KEY")
# 获取对话模型
chat_model = ChatOpenAI(
model="qwen-plus",
temperature=0
)
# 工具参数模板
class FieldInfo(BaseModel):
number1: int = Field(description="第一个参数")
number2: int = Field(description="第二个参数")
# 定义工具函数
def add_two_numbers(number1, number2):
return number1 + number2
# 定义工具
tool1 = StructuredTool.from_function(
func=add_two_numbers,
name="add_two_numbers",
description="计算两个数字之和",
args_schema=FieldInfo
)
prompt = ChatPromptTemplate.from_messages([
("system", """
你是个数学大师
"""),
MessagesPlaceholder(variable_name="chat_history"),
("human", "{input}"),
MessagesPlaceholder(variable_name="agent_scratchpad"),
])
# 加入工具列表
tools = [tool1]
# 实在例化ConversationBufferMemory对象,修改历史消息的key为chat_history(默认为history)
memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)
# 创建Agent 对象
agent = create_tool_calling_agent(chat_model, tools, prompt)
# 创建 AgentExecutor
agent_executor = AgentExecutor(
agent=agent,
memory=memory,
tools=tools,
verbose=True,
)
# 对话1
print(agent_executor.invoke({"input": "2和3的和是多少?"}))
# 对话2
print(agent_executor.invoke({"input": "4和5呢?"}))
输出效果
相比ReAct模式,Function Call省略了复杂的思考过程,也减少了思考过程中的工具参数的提取错误概率,简洁快速地输出了工具调用结果并返回
4 小结
目前LangChain1.0已经出了一段时间了,initialize_agent的方式已经被淘汰了,并且这种方式缺点很多,稳定性查、使用复杂。可以尝试使用一下AgentExecutor()来进行AgentExecutor创建的方式,目前还没去学习1.0+版本,不知道AgentExecutor()有没有被淘汰,但是学习一下这种api的思想是不错的,LangChain以及各种Ai知识更新得很快,旧的知识也很容易被淘汰,保持学习就对了。
更多推荐

所有评论(0)