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:、ActionAction 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:、ErrorRetry

标签 作用说明 格式要求
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知识更新得很快,旧的知识也很容易被淘汰,保持学习就对了。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐