理解 LangChain 智能体:create_react_agent 与 create_tool_calling_agent

作者:奇舞精选日期:2025/11/7

本文译者为 360 奇舞团前端开发工程师
原文标题:理解 LangChain 智能体:create_react_agentcreate_tool_calling_agent原文作者:Anil Goyal 原文地址:medium.com/@anil.goyal…

当我们使用 LangChain 构建 AI 智能体时,首先要做的是选择正确的智能体架构。 目前常用的2种架构是create_react_agentcreate_tool_calling_agent。两者都可以让AI使用外部工具,但由于它们的运作方式不同,因此适合的场景也有区别。

本文将探讨create_react_agentcreate_tool_calling_agent有哪些区别,如何向大语言模型发送提示词,期望从模型获得哪种响应格式。它们的底层工作原理是什么,分别适合在哪种场景下使用。

什么是Agent?

在深入细节之前,让我们先了解一下什么是 Agent。Agent系统的工作流程如下:

  1. 推理—对问题和任务进行思考与分析;
  2. 行动—调用工具或外部服务处理问题;
  3. 观察—查看获取的结果;
  4. 迭代—不断重复上述过程,直到达到预期的目标。

不同类型智能体之间的关键区别在于:它们与 大语言模型 的交互方式不同,也就是它们在执行推理工具选择过程时,与模型之间的通信方式存在差异。

核心区别:提示词

无论是 create_react_agent 还是 create_tool_calling_agent,它们都会让模型自主决定使用哪些工具**、**何时使用。而两者之间最关键的区别在于:它们如何向 LLM 发送提示词,以及期望 LLM 返回的响应格式。

可以理解为它们是在用两种不同的“语言”与模型沟通:

  • ReAct Agent: “请一步一步地思考,并用文字告诉我你的推理过程。”
  • Tool Calling Agent: “这是函数定义,请直接用结构化数据调用它们。”

于是,LLM 会根据所接受的提示方式来回应,从而形成完全不同的交互模式。

一、create_react_agent:基于文本推理

什么是 ReAct?

ReAct 是 “Reasoning + Acting”(推理 + 行动)的缩写。它是一种让智能体通过“文本化思考循环”来展示自身思维过程的范式。这种循环的结构通常包括以下几个步骤:

  1. Thought(思考): 智能体思考下一步该做什么,分析问题或任务。
  2. Action(行动): 智能体决定使用哪个工具、以及如何使用它。
  3. Observation(观察): 智能体查看执行后的结果,并理解输出内容。
  4. Repeat(重复): 这一循环不断重复,直到任务完成为止。

以下是 ReAct agent实际上会发送给模型的内容:

1#(1)ReAct agent向大语言模型发送如下内容:
2
3“你可以使用这些工具:[add, multiply]
4问题:先计算 5+3,然后将结果乘以 2
5思考:”
6
7#(2)模型回复:
8
9“我需要先把 53 相加,然后将结果乘以 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思考:我需要先把 53 相加,然后将结果乘以 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思考:我需要先把 53 相加,然后将结果乘以 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我需要先把两个数字相加,然后再将结果乘以 24
5Action: ["add", {"a": 5, "b": 3}]
6Observation: {"result": 8}
7
8Thought: 既然我已经得到了和,我将把它乘以 29
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》 是转载文章,点击查看原文


相关推荐


windows npm打包无问题,但linux npm打包后部分样式缺失
悢七2025/11/4

原因 前端package.json中指定的是依赖版本范围,而linux中使用npm install安装的版本与windows不同。 例如"@ant-design/icons": “^4.0.0” 插入符号^意味着它可以安装最新的兼容版本。如果希望它安装特定版本,可以在版本前面删除^。 详见package.json文档和符号学 插入符号将让它安装一个不改变第一个数字的更高版本。例如,你的package.json为@ant-design/icons指定了^4.0.0,但它安装了4.6.2。由


【SCI二区IEEE复现】基于混合有限集模型预测控制(FCS-MPC)的模块化多电平换流器(MMC)整流电路仿真模型(Simulink仿真实现)
荔枝科研社2025/10/31

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭:行百里者,半于九十。 📋📋📋本文内容如下:🎁🎁🎁  ⛳️赠与读者 👨‍💻做科研,涉及到一个深在的思想系统,需要科研者逻辑缜密,踏实认真,但是不能只是努力,很多时候借力比努力更重要,然后还要有仰望星空的创新点和启发点。建议读者按目录次序逐一浏览,免得骤然跌入幽暗的迷宫找不到来时的路,它


2025年前端菜鸟自救指南:从零搭建专业开发环境
良山有风来2025/10/29

你是不是经常遇到这种情况? 新入职一家公司,面对一堆看不懂的配置文件一脸懵逼。同事说“先npm install一下”,你却在终端里卡了半天。好不容易跑起来项目,想改个代码又不知道从哪下手。 别担心,这几乎是每个前端开发者都会经历的阶段。还记得我刚入行时,光是配置个Webpack就折腾了一整天,最后还是在同事帮助下才搞定。 但现在不一样了。经过这几年的实战积累,我总结出了一套超级简单的前端环境搭建方法。今天就把这套方法论完整分享给你,让你在2025年能够快速上手任何前端项目。 为什么你需要专业的开


两张大图一次性讲清楚k8s调度器工作原理
有态度的下等马2025/10/26

面试常被追问k8s调度器工作原理,一图胜10086句言,收藏 == 学废。😣😣 kube-scheduler负责将k8s pod调度到worker节点上。 当你部署pod时,在manifest文件pod规格上会指定cpu、memory、亲和性affinity、污点taints、优先级、持久盘等。 调度器的主要工作是识别create request然后选择满足要求的最佳节点。 分步解释: Pod Create Request: 外部系统(kubectl、cicd)发出了创建一个新pod的


LeetCode第1710题 - 卡车上的最大单元数
小南家的青蛙2025/10/23

题目 解答 class Solution { public int maximumUnits(int[][] boxTypes, int truckSize) { Arrays.sort(boxTypes, new Comparator<int[]>() { @Override public int compare(int[] o1, int[] o2) { return o2[1] - o1[1]; } });


MySQL的整体架构及功能详解
程序新视界2025/10/22

在前面的系列文章中,我们讲解了MySQL基础功能相关的知识,在这篇文章中,重点讲讲MySQL的整体架构,以便在后续的学习中更好的了解所讲的功能属于MySQL的哪一部分,以及前后相关的工作流程。 MySQL整体架构图 这里我们以MySQL官方提供的整体架构图为基准,确保知识的权威性和准确性。 通过上图,我们可以看到,MySQL架构设计总共分为四层,分别是客户端层,服务层,存储引擎层与系统文件层。 下面,我们就来看看各层的详细功能及特性。 客户端层 客户端层是MySQL架构中的最顶层,即架构图中的


SpringBoot “分身术”:同时监听多个端口
风象南2025/10/21

前言 在日常开发中,我们通常构建的 Spring Boot 应用都是"单面"的——一个端口,一套服务逻辑。但在某些实际场景中,我们可能需要一个应用能够"一心二用":同时提供两套完全不同的服务,分别在不同的端口上运行。 比如: 一个端口面向外部用户,提供 API 服务 另一个端口面向内部管理,提供监控和运维功能 或者在一个应用中同时集成管理后台和用户前台 场景示例 假设我们要开发一个电商平台,需要同时满足: 用户端服务(端口8082) 商品浏览 购物车管理 订单处理 管理端服务(端口808


LeRobot 机器人学习(Robot Learning)入门教程(一)
具身智能与人形机器人2025/10/19

系列文章目录 目录 系列文章目录 前言 一、前言 二、引言 2.1 LeRobotDataset 2.1.1 数据集类的设计 2.2 代码示例:批处理(流式)数据集 2.2.1 批处理(流式)数据集 2.3 代码示例:收集数据 2.3.1 记录数据集 前言         机器人学习正处于一个转折点,这得益于机器学习的快速进步以及大规模机器人数据日益普及。这种从经典的基于模型的方法向数据驱动、基于学习的范式转变,正在为自主系统释放前所未有的能力。本教程全面梳理现代机


如何检查本地是否存在 Docker 镜像 ?
鸠摩智首席音效师2025/10/18

当我们深入研究 Docker 的功能时,发现 Docker 不仅仅是一项技术,这是一个充满镜像、容器和数据卷的宇宙。今天我们戴上侦探帽,调查一个看似简单却至关重要的案件:识别本地是否存在某个 Docker 镜像。这可能看起来微不足道,但通常是维持高效工作的关键步骤,特别是在复杂的 Docker 环境中。 什么是 Docker 镜像 ? 首先,让我们简单地定义一下什么是 Docker 镜像。在 Docker 生态系统中,镜像是轻量级的、独立的、可执行的包含运行一个软件所需的一切的软件包,包括代


.net8.0_webapi 生成二维码
焚 城2025/10/17

文章目录 一、思路二、实现1、Program.cs2、二维码辅助类QrCodeHelper.cs 三、效果保存后: 一、思路 环境: 1、内容生成二维码图片 2、保存到wwwroot为png格式 3、返回存储路径保存到数据库 4、前端读取显示 二、实现 1、Program.cs //配置静态文件路径 app.UseStaticFiles(new StaticFileOptions { FileProvider = new PhysicalFileProvider(

首页编辑器站点地图

Copyright © 2025 聚合阅读

License: CC BY-SA 4.0