本文译者为 360 奇舞团前端开发工程师
原文标题:理解 LangChain 智能体:create_react_agent与create_tool_calling_agent原文作者:Anil Goyal 原文地址:medium.com/@anil.goyal…
当我们使用 LangChain 构建 AI 智能体时,首先要做的是选择正确的智能体架构。 目前常用的2种架构是create_react_agent和create_tool_calling_agent。两者都可以让AI使用外部工具,但由于它们的运作方式不同,因此适合的场景也有区别。
本文将探讨create_react_agent和create_tool_calling_agent有哪些区别,如何向大语言模型发送提示词,期望从模型获得哪种响应格式。它们的底层工作原理是什么,分别适合在哪种场景下使用。
什么是Agent?
在深入细节之前,让我们先了解一下什么是 Agent。Agent系统的工作流程如下:
- 推理—对问题和任务进行思考与分析;
- 行动—调用工具或外部服务处理问题;
- 观察—查看获取的结果;
- 迭代—不断重复上述过程,直到达到预期的目标。
不同类型智能体之间的关键区别在于:它们与 大语言模型 的交互方式不同,也就是它们在执行推理与工具选择过程时,与模型之间的通信方式存在差异。
核心区别:提示词
无论是 create_react_agent 还是 create_tool_calling_agent,它们都会让模型自主决定使用哪些工具**、**何时使用。而两者之间最关键的区别在于:它们如何向 LLM 发送提示词,以及期望 LLM 返回的响应格式。
可以理解为它们是在用两种不同的“语言”与模型沟通:
- ReAct Agent: “请一步一步地思考,并用文字告诉我你的推理过程。”
- Tool Calling Agent: “这是函数定义,请直接用结构化数据调用它们。”
于是,LLM 会根据所接受的提示方式来回应,从而形成完全不同的交互模式。
一、create_react_agent:基于文本推理
什么是 ReAct?
ReAct 是 “Reasoning + Acting”(推理 + 行动)的缩写。它是一种让智能体通过“文本化思考循环”来展示自身思维过程的范式。这种循环的结构通常包括以下几个步骤:
- Thought(思考): 智能体思考下一步该做什么,分析问题或任务。
- Action(行动): 智能体决定使用哪个工具、以及如何使用它。
- Observation(观察): 智能体查看执行后的结果,并理解输出内容。
- Repeat(重复): 这一循环不断重复,直到任务完成为止。
以下是 ReAct agent实际上会发送给模型的内容:
1#(1)ReAct agent向大语言模型发送如下内容: 2 3“你可以使用这些工具:[add, multiply] 4问题:先计算 5+3,然后将结果乘以 2 5思考:” 6 7#(2)模型回复: 8 9“我需要先把 5 和 3 相加,然后将结果乘以 2 10行动:add 11行动输入(Action Input):{"a": 5, "b": 3}” 12 13#(3)智能体调用 add(5, 3),得到结果8。把这个结果加入提示词中,再将更新后的提示词发送给 模型: 14 15“你可以使用这些工具:[add, multiply] 16问题:先计算 5+3,然后将结果乘以 2 17思考:我需要先把 5 和 3 相加,然后将结果乘以 2 18行动:add 19行动输入:{"a": 5, "b": 3}。 20观察:8 21思考:” 22 23#(4)模型回复:“现在我得到了 8,我需要将它乘以 2。 24 25“行动:multiply 26行动输入:{"a": 8, "b": 2}” 27 28# (5)智能体执行 multiply(8, 2),得到结果 16。然后再次将该结果加入提示词,形成最终的提示词: 29 30“你可以使用这些工具:[add, multiply]。 31问题:先计算 5+3,然后将结果乘以 2 32思考:我需要先把 5 和 3 相加,然后将结果乘以 2 33行动:add。行动输入:{"a": 5, "b": 3} 34观察:8 35思考:现在我得到了 8,我需要将它乘以 2 36行动:multiply 37行动输入:{"a": 8, "b": 2} 38观察:16 39思考:” 40 41#(6)LLM 回复:“完美!我现在得到了最终答案。最终答案:(5+3) × 2 的结果是 16” 42
可以看到,ReAct agent 不是通过一轮对话就回答了问题,也就是说模型并不会一次性计划好所有步骤。相反,agent与模型之间会进行多轮对话,每轮对话结束后都会调用不同的工具。
正是这种迭代式的特性, 使得 ReAct agent非常透明且易于调试 —你可以清楚地看到推理过程是如何逐步展开的!
create_react_agent如何工作
1# 导入 LangChain 中的智能体创建方法 2from langchain.agents import AgentExecutor, create_react_agent 3 4# 导入用于创建自定义提示模板的类 5from langchain_core.prompts import PromptTemplate 6 7# 导入 MultiServer MCP 客户端,用于连接和调用外部工具服务 8from langchain_mcp_adapters.client import MultiServerMCPClient 9 10# 导入 Ollama LLM 语言模型 11from langchain_ollama import OllamaLLM 12 13from langchain import hub 14import asyncio 15import os 16os.environ["USER_AGENT"] = "my-langchain-agent/1.0" 17 18async def main(): 19 20 # 创建 MultiServerMCPClient 客户端,用于管理外部工具(这里是 math server) 21 client = MultiServerMCPClient({ 22 "math": { 23 "command": "python", 24 "args": ["mathserver.py"], 25 "transport": "stdio", 26 } 27 }) 28 29 # 获取外部工具列表 30 tools = await client.get_tools() 31 32 # 创建 Ollama LLM 实例,选择使用 "mistral" 模型 33 llm = OllamaLLM(model="mistral") 34 35 # 定义自定义 ReAct 提示模板 36 template = """尽可能回答以下问题。你可以访问这些工具: 37 38 {tools} 39 40 使用如下格式: 41 42 Question: 你必须回答的问题 43 Thought: 考虑该怎么做 44 Action: 采取行动, 应该是 [{tool_names}] 中之一 45 Action Input: 输入必须是有效的JSON格式, 例如 {{"a": 5, "b": 3}} 46 Observation: 观察结果 47 ... (这一 Thought/Action/Action Input/Observation 可以重复N次) 48 Thought: 现在我知道了最终答案 49 Final Answer: 获得最终答案 50 51 IMPORTANT: 输入始终要采用JSON格式。针对数学运算,使用 {{"a": number1, "b": number2}}. 52 53 开始! 54 Question: {input} 55 Thought:{agent_scratchpad}""" 56 57 prompt = PromptTemplate.from_template(template) 58 agent = create_react_agent(llm=llm, tools=tools, prompt=prompt) 59 agent_executor = AgentExecutor( 60 agent=agent, 61 tools=tools, 62 verbose=True, 63 handle_parsing_errors=True 64 ) 65 66 result = await agent_executor.ainvoke({"input": "What's 5 + 3, then multiply by 2"}) 67 print("\nResult:") 68 print(result["output"]) 69 70if __name__ == "__main__": 71 asyncio.run(main()) 72
当运行代码时,控制台会打印类似如下输出:
1Entering new AgentExecutor chain... 2 3我需要先把两个数字相加,然后再将结果乘以 2。 4 5Action: ["add", {"a": 5, "b": 3}] 6Observation: {"result": 8} 7 8Thought: 既然我已经得到了和,我将把它乘以 2。 9 10Action: ["multiply", {"a": 8, "b": 2}] 11Observation: {"result": 16} 12 13Thought: 现在我知道最终答案了。 14 15Final Answer: 结果是 16 16
ReAct Agents的关键特征
- 基于文本的通信:使用自然语言进行推理和交流。
- 透明的推理:可以清楚地看到智能体的思考过程。
- 模型无关:可以与任何文本生成模型配合使用。
- 易于调试: 决策过程容易追踪,便于查找问题。
- 详细输出:显示所有推理步骤,从思考到行动再到观察。
- 字符串参数:工具参数通常以字符串形式传递。
二、create_tool_calling_agent:基于函数调用
工具调用(也称为函数调用)利用了现代大型语言模型的原生能力,可以直接调用函数。与基于文本的推理不同,模型知道如何使用结构化数据调用工具。
工具调用提示策略(Tool Calling Prompting Strategy)
工具调用agent的效率更高,因为它可以在一次与模型的交互中进行多次工具调用,相比于 ReAct agent,以更少的交互完成整个流程。
以下是一个工具调用agent向模型发送的内容示例:
1# 工具调用消息 2messages = [ 3 { 4 "role": "system", 5 "content": "你可以调用数学工具。" 6 }, 7 { 8 "role": "user", 9 "content": "什么是 5 + 3?" 10 } 11 ] 12 13 # 提供给模型的Tool格式 14tools = [ 15 { 16 "type": "function", 17 "function": { 18 "name": "add", 19 "description": "把两个数字相加", 20 "parameters": { 21 "type": "object", 22 "properties": { 23 "a": {"type": "integer"}, 24 "b": {"type": "integer"} 25 }, 26 "required": ["a", "b"] 27 } 28 } 29 } 30 ] 31 32 # 模型用结构化的FUNCTION CALL响应: 33 { 34 "tool_calls": [ 35 { 36 "id": "call_123", 37 "type": "function", 38 "function": { 39 "name": "add", 40 "arguments": '{"a": 5, "b": 3}' 41 } 42 } 43 ] 44 } 45
create_tool_calling_agent如何工作
1from langchain.agents import AgentExecutor, create_tool_calling_agent 2from langchain_groq import ChatGroq 3from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder 4from langchain_mcp_adapters.client import MultiServerMCPClient 5import asyncio 6import os 7 8os.environ["USER_AGENT"] = "my-langchain-agent/1.0" 9os.environ["GROQ_API_KEY"] = "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" 10 11async def main(): 12 13 client = MultiServerMCPClient({ 14 "math": { 15 "command": "python", 16 "args": ["mathserver.py"], 17 "transport": "stdio", 18 } 19 }) 20 21 # 获取tools 22 tools = await client.get_tools() 23 llm = ChatGroq( 24 model="llama3-8b-8192", 25 temperature=0 26 ) 27 28 # 为tool calling agent创建正确的提示词模板 29 prompt = ChatPromptTemplate.from_messages([ 30 ("system", "你是一个有用的助手,可以访问搜索tools。对于有关 DASA 的问题,请使用 DASA_search 工具;对于其他查询,请使用通用的 search 工具。"), 31 ("human", "{input}"), 32 MessagesPlaceholder("agent_scratchpad"), 33 ]) 34 35 36 agent = create_tool_calling_agent(llm=llm, tools=tools, prompt=prompt) 37 38 agent_executor = AgentExecutor( 39 agent=agent, 40 tools=tools, 41 verbose=True, 42 handle_parsing_errors=True 43) 44 45 # 现在我们可以使用agent回答问题了。 46 result = await agent_executor.ainvoke({"input": "What's 5 + 3, then multiply by 2"}) 47 print("\nResult:") 48 print(result["output"]) 49 50if __name__ == "__main__": 51 asyncio.run(main()) 52
当运行代码时,控制台会打印类似如下输出:
1> Entering new AgentExecutor chain... 2 3Invoking: 对 [`{'a': 5, 'b': 3}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.a.md) 执行相加操作 4 5Invoking: 对 [`{'a': 8, 'b': 2}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.a.md) 执行相乘操作 6 7(5 + 3) × 2 的结果是 16. 8 9 > Finished chain. 10
Tool Calling Agents的关键特征
- **基于函数的通信:**使用结构化的函数调用方式进行通信。
- **隐式推理:**决策过程在模型内部完成,不需要显式地展示推理步骤。
- **依赖模型:**需要模型本身支持原生的工具调用功能。
- **输出简洁:**输出中不会显示模型的推理过程,只返回最终结果或结构化调用。
- **高效执行:**执行速度更快,使用的 token 更少。
- 结构化参数: 始终以正确的 JSON 或字典格式传递参数。
上述例子中使用的MCP server如下:
1""" 2使用 FastMCP 的Math Server 3 4这是一个简单的 MCP 服务器,用于提供基本的数学运算功能。 5""" 6 7from fastmcp import FastMCP 8import math 9 10# 创建 MCP server 实例 11 mcp = FastMCP("Math Server") 12 13@mcp.tool() 14def add(a: float, b: float) -> float: 15 """将两个数字相加""" 16 return a + b 17 18@mcp.tool() 19def subtract(a: float, b: float) -> float: 20 """计算两个数字的差值.""" 21 return a - b 22 23@mcp.tool() 24def multiply(a: float, b: float) -> float: 25 """将两个数字相乘""" 26 return a * b 27 28@mcp.tool() 29def divide(a: float, b: float) -> float: 30 """用第二个数字除以第一个数字""" 31 if b == 0: 32raise ValueError("不能用0做除数") 33 return a / b 34 35if __name__ == "__main__": 36 # 运行server 37 mcp.run() 38
三、注意事项:
如果你查看上面的 Python 代码,会发现我在 ReAct agent 中使用了 Mistral 模型,而在 Tool Calling Agent 中使用了 ChatGroq 模型。
原因如下:
- Mistral 擅长自然语言推理和基于文本的思维模式,因此非常适合用于 ReAct agent。
- 相反,ChatGroq 具备原生的函数调用(function calling)支持,并且能够理解 JSON schema,因此非常适合于 Tool Calling Agent。
《理解 LangChain 智能体:create_react_agent 与 create_tool_calling_agent》 是转载文章,点击查看原文。