21-Agent智能体
21 - Agent 智能体
本章课程目标:
- 理解 Agent(智能体) 到底是什么、适合解决什么问题,以及它与 Tool、Function Calling、RAG、MCP 的关系。
- 掌握 Agent 的核心工作方式:围绕目标持续推理、决定是否调用工具、接收结果、继续决策,直到满足结束条件。
- 理解 LangChain 中 Agent 的两条学习主线:V0.3 / classic 的 Agent + AgentExecutor,以及 V1.x 的
create_agent+ LangGraph 运行时。 - 跑通并理解本章全部案例:
AgentSmartSelectV0.3.py、AgentSmartSelectV1.0.py、AgentReact.py、Agent2Agent.py、McpClientAgent.py。
学习建议: Agent 这章先抓一句话:Agent 是决策层,不是工具本身。读的时候先看它如何决定下一步,再看 Tool、RAG、MCP、Function Calling 分别给它补了什么能力。代码部分重点比较旧的 AgentExecutor 和新的 create_agent 思路;读完后要能判断一个需求到底该用普通链、工具调用,还是 Agent。
官方文档与资源:详见 工具导航与参考资料索引 - 工具调用、MCP与智能体。
1、Agent 简介
1.1 定义
先给初学者一句最重要的话:Agent 不是某个单独的模型,也不是某个单独的工具,而是一种“围绕目标持续做决策并调用能力”的运行方式。
如果只看最小本质,可以把 Agent 看作:Agent = 模型 + 工具集 + 运行循环 + 当前状态。
这里的四个部分分别代表:
- 模型(Model):负责理解用户目标、分析当前局面、决定下一步。
- 工具集(Tools):负责执行动作,例如查天气、查库存、调用 API、搜索文档、访问数据库。
- 运行循环(Loop):负责让模型不是只回答一次,而是可以“想一步、做一步、看结果、再决定下一步”。
- 状态(State):负责保存本轮对话、工具返回、中间结果,有时也包含短期记忆。
这也是本章首先要修正的一个常见误区:不是所有 Agent 都必须同时具备“长期记忆、复杂规划、多智能体协作”。
对很多入门场景来说,一个最简单的 Agent 只要能:1. 读懂用户目标;2. 知道什么时候调工具;3. 能根据工具结果继续判断;4. 最后给出答案。就已经是 Agent 了。
上面的公式是帮助你先抓住重点的“最小理解版”。如果把 Agent 再进一步展开,它在更完整的架构图里还可能包含记忆、规划、反思等能力。所以下图更适合理解为“扩展后的能力拼图”,而不是和上面四项定义做一一对应。


1.2 Agent 最常见的工作方式:ReAct
**ReAct = Reason + Act。**中文可以看作:先推理,再行动。
这是 Agent 最经典的一种运行循环:
- Thought / Reason(思考):当前要做什么,先想一步。
- Action(行动):如果需要外部能力,就调用某个工具。
- Observation(观察):拿到工具返回结果。
- 继续循环或结束:如果还没完成,就继续下一轮;如果信息足够,就给出最终答案。
所以 ReAct 的本质就是:先推理,再行动;根据行动结果,再继续推理。
这点和普通“只回答一次”的 LLM 调用差异非常大。普通对话通常是:用户提问、模型直接回答。而 Agent 更像:用户提问、模型判断要不要查工具、调工具、看结果、再判断要不要继续、最终回答。
下图正好对应这条循环:

这里还要补一个现实中的重要认知:现代 Tool Calling Agent 不一定会把“Thought”完整显示给你看。
很多时候你在代码里真正看到的是:
AIMessage里出现tool_calls- 工具执行后得到
ToolMessage - 最后再出现一个普通
AIMessage
所以在今天的 LangChain / Tool Calling 语境里,ReAct 更应该被理解成一种工作机制,而不只是某种固定的 Prompt 模板格式。
Agent 不只有 ReAct 这一种工作方式。
ReAct 只是最经典、最适合入门的一种理解方式,因为它最容易让人看懂“为什么 Agent 不只是一次回答”。但在真实项目里,常见的 Agent 形态还包括:
- Plan-and-Execute:先整体规划,再按计划逐步执行。
- Router / Supervisor:先判断该把任务交给哪个工具、哪个子 Agent、哪个流程。
- Workflow + Agent 混合:固定部分用工作流,遇到不确定节点时再让 Agent 决策。
- Multi-Agent / A2A:多个 Agent 分工协作,由一个主 Agent 或协调器统筹。
- Human-in-the-loop:关键步骤需要人工确认,Agent 不是全自动闭环。
所以更准确的结论是:
- ReAct 是 Agent 最经典的一种工作机制
- 不是 Agent 的唯一形态
- 本章先用 ReAct 入门,是因为它最容易把 Agent 的核心价值讲清楚
1.3 Tool 与 Agent 的关系
这一节是整章最容易混淆的地方。
Tool(工具) 是能力封装。
例如: get_weather()、search_products()、check_inventory()、book_flight()。它们都只是“能做一件事”的函数或接口。
Agent 则是决策者。
它负责判断:现在要不要调用工具、调哪个工具、先调哪个、后调哪个、一个工具够不够、工具失败了要不要重试或换路线、什么时候可以停止并给最终答案。
所以两者关系可以概括成:Tool = 能力;Agent = 决策 + 使用这些能力。
| 对象 | 本质定位 | 一句话理解 |
|---|---|---|
| Tool | 能力层 | 我能做什么 |
| Agent | 决策层 | 我什么时候、按什么顺序去用这些能力 |
也正因为如此,不是“有 Tool 就有 Agent”。比如“查一下北京天气”这种一步问题,直接调一个天气工具就够了,完全可以不需要 Agent。
但如果问题变成:“帮我找最热门的无线耳机,再查库存,再告诉我哪款可以买”;“先订机票,再订酒店,再预约打车”;“先查知识库,再看是否需要调外部 API,再整理成报告”。
这时就不是某个单独 Tool 能解决的了,而是需要有人负责多步决策,这时 Agent 才有价值。
1.4 Agent 的使用场景
这一点结合官方关于 workflow vs agent 的区分来理解最清楚。这里的 workflow,中文通常可以理解成:工作流 / 固定流程。指的是一条步骤基本提前确定、执行顺序相对稳定的处理路线,例如先做 A,再做 B,再做 C,中间不太需要模型临场决定“下一步该怎么走”。
先把它和 Agent 粗略区分开会更清楚:workflow 的流程基本写死,重点是“按既定步骤执行”;agent 的流程不完全固定,重点是“根据上下文动态决策”。如果流程路径是固定的,优先考虑工作流 / 链,而不是 Agent。
比如:
- 固定先做文本切分,再做向量化,再写入向量库
- 固定先分类,再摘要,再存库
- 固定按 A → B → C 的顺序执行
这类场景更像 第 15 章 LCEL 与链式调用 或后续 LangGraph 的工作流问题。
如果下一步怎么做不固定,需要模型根据中间结果动态决定,就更适合 Agent。
比如:
- 用户问题不确定,需要模型决定先查库还是先调 API
- 工具很多,模型要自己选哪个
- 可能要调一次工具,也可能要调很多次
- 工具返回后还要继续推理
所以更贴近实际项目的判断标准可以写成:
| 场景 | 更适合什么 |
|---|---|
| 路径固定、步骤明确、顺序可提前写死 | 链 / 工作流 |
| 路径不固定、工具选择依赖上下文、中间结果会影响后续决策 | Agent |
这也是为什么今天很多企业项目其实是:Workflow 负责固定骨架,Agent 负责不确定节点的决策。
从 2025-2026 年的真实项目看,Agent 的典型场景也在从“会调几个工具”扩展到更完整的任务闭环。比如:
- 浏览器自动化 / Computer Use Agent:根据目标理解页面、点击按钮、填写表单、滚动页面,并通过截图或页面状态校验结果。
- 长任务研究代理:围绕复杂问题拆分子任务,多轮搜索、交叉验证资料,最后生成带来源的结构化报告。
- 代码库维护代理:读取代码库、定位相关文件、制定修改计划、编辑代码、运行测试,并根据失败结果继续修复。
- 文件 / 数据分析代理:读取表格、PDF、日志或业务数据,调用代码执行、SQL、统计或可视化工具,输出分析结论和图表。
这些例子仍然符合上面的判断标准:如果流程完全固定,用链或工作流更稳;如果每一步都要根据中间结果继续判断,才更适合交给 Agent。
2、演变过程:从多步组装到一步创建
2.1 V0.3 / classic 路线:显式组装 Agent
在较早的 LangChain Agent 写法中,通常要显式准备这些部分:1. 模型;2. 工具列表;3. Prompt 模板;4. create_tool_calling_agent(...);5. AgentExecutor(...)。
也就是说,Agent 本身只负责“出主意、决定调用什么”,真正驱动循环、执行工具、把结果写回上下文的,通常是 AgentExecutor。
这一套写法的优点是:结构清楚、很适合教学、容易看懂 Agent 和 Executor 是怎么配合的。
它的局限是:代码更长、容易被 Prompt、scratchpad、executor 等概念同时压住、工程上需要手动拼接更多组件。
仓库里的 AgentSmartSelectV0.3.py 就是这条路线的典型案例。
2.2 V1.x 路线:create_agent 一步创建
到了 LangChain 1.x,官方更推荐的入口是:
1 | from langchain.agents import create_agent |
然后直接把模型、工具、系统提示等交进去,得到一个可运行的 Agent。
这种方式的核心变化不是“Agent 不循环了”,而是:很多原来要自己显式组装的部分,被封装进了更统一的运行时。
根据当前官方文档,create_agent 背后使用的是基于 LangGraph 的 graph-based runtime。这里的 graph-based runtime,可以看成:Agent 的执行过程不再只是“一次函数调用”,而是由一个基于状态流转的运行框架来驱动。
可以把它看成这样:
- 当前有哪些消息和中间结果,这是状态
- 下一步是继续让模型推理、去调工具,还是结束输出,这是状态流转
- 整个过程像一张“节点 + 连线”的执行图,所以叫 graph-based
这里不用先深入 LangGraph 细节,先抓住一句话就够了:
create_agent 虽然看起来像一步创建,但底层仍然有一套负责“循环、状态、工具调用”的运行时在支撑它。
这意味着:Agent 仍然在循环,仍然会调工具,仍然会维护消息状态。只是这些动作不再要求你手动拼出一套 Agent + AgentExecutor + scratchpad 才能跑。
2.3 这两条路线的意义
对你这套教程来说,这两条路线都值得保留,因为它们分别承担不同教学价值:
V0.3 / classic 路线
帮助你理解 Agent 内部到底怎么转:Prompt、工具、Executor、循环是怎么配合的。V1.x /
create_agent路线
帮助你掌握当前官方更推荐的写法,更接近真实项目开发。
所以这一章不是在教你背两个 API,而是在教你:经典写法怎么看,当前写法怎么用,二者背后的 Agent 本质其实是同一件事。
下图就可以把这种“从组件输入到 Agent 创建”的感觉建立起来:
![三步组装智能体示意:① 定义工具(如 `tools = [get_weather]`)② 构建系统提示 ③ 调用 `create_agent(model, tools, system_prompt)` 将 Tools / Prompt / Model 收口为可运行 Agent](/images/21/21-2-1-1.jpeg)
2.4 V0.3 与 V1.x 的对比速览
| 维度 | V0.3 / classic | V1.x / create_agent |
|---|---|---|
| 核心入口 | create_tool_calling_agent + AgentExecutor |
create_agent |
| 代码组织 | 手动拼更多组件 | 统一入口更简洁 |
| 学习价值 | 更容易看清内部结构 | 更接近当前官方主线 |
| 运行方式 | Agent 决策,Executor 驱动循环 | graph runtime 驱动循环 |
| 更适合 | 理解原理、维护旧案例 | 新项目、快速搭建 |
还有一个实践补充:
**当前官方 1.x 文档更强调以 messages 状态作为 Agent 的统一输入。**但本教程仓库中为了教学连续性,仍保留了部分 {"input": "..."} 风格示例。读代码时先抓住入口含义:它们都是在给 Agent 一个“新的用户请求”,只是不同版本、不同适配层的调用方式略有差异。
3、Agent 工作原理(V0.3)
这一节聚焦本教程里的 classic 路线,因为它最适合拆开理解 Agent 的内部工作机制。
3.1 保留 V0.3 的原因
虽然今天新项目更常直接用 create_agent,但 classic 路线依然有学习价值。它能让你看清楚:Agent 自己负责什么,AgentExecutor 负责什么,为什么 Prompt 里要有 agent_scratchpad,工具结果是怎么“再喂回去”给模型继续推理的。
3.2 Agent 与 AgentExecutor 的职责分工
在 V0.3 / classic 路线下,职责可以直接拆成:
- Agent:负责分析输入、决定下一步动作
- AgentExecutor:负责执行动作、拿结果、继续驱动循环
也就是说:**Agent 更像大脑,AgentExecutor 更像执行器和循环调度器。**这也是为什么单独有 Agent 通常还不够,还要再交给 Executor 去跑。
下图正好适合理解这一点:

3.3 agent_scratchpad 重要性
你在 classic 路线里经常会看到 Prompt 里有这样一个占位:
1 | ("placeholder", "{agent_scratchpad}") |
其中 ChatPromptTemplate、占位符与消息结构,与 第 13 章 提示词与消息模板 一脉相承;这里多出来的 {agent_scratchpad} 专供多轮工具循环使用。
这不是装饰,它的作用非常关键。它相当于 Agent 的“草稿区 / 中间步骤区”,用来承接:模型上一轮决定调用什么工具;工具返回了什么;下一轮模型基于这些信息继续推理。
如果没有这块区域,模型就很难在多步循环里“记住刚刚自己做过什么”。
所以在 classic 路线里,agent_scratchpad 不是一个边角知识点,而是 ReAct 循环能成立的重要拼图。
3.4 结合案例理解
【案例源码】案例与源码-2-LangChain框架/12-agent/AgentSmartSelectV0.3.py
这个案例适合用来理解 classic Agent 的完整链路,因为它把这些部分都摆出来了:
- 定义
get_weather工具 - 定义
ChatPromptTemplate - 在 Prompt 里保留
agent_scratchpad - 用
create_tool_calling_agent得到 Agent - 用
AgentExecutor驱动执行
当用户问:请问今天北京和上海的天气怎么样,哪个城市更热?
这个案例里的 Agent 并不是“一次回答完”,而是更像这样:
- 先判断需要查天气
- 调一次
get_weather(Beijing) - 再调一次
get_weather(Shanghai) - 根据两次工具结果做比较
- 最后输出总结
所以它真正演示的不是“天气查询”,而是:一个 classic Agent 如何做多步工具调用,并把多次结果汇总成最终回答。
4、Agent 工作原理(V1.0)
这一节对应当前官方主线,也就是你项目里更现代的 Agent 入口。
4.1 create_agent 的意义
create_agent 的最大价值不是“少写几行代码”,而是:把 Agent 的常见配置收口到一个统一入口里。
你通常会把这些东西交给它:模型,工具,系统提示,有时再加结构化输出、状态、中间件等。这样你可以更专注于业务目标,而不是一开始就陷进大量底层组装细节里。

4.2 V1.x 的核心输入
在入门阶段,先看 create_agent 常见的 6 个参数:
| 参数 | 是否常见 | 作用 |
|---|---|---|
model |
必备 | 让谁来做推理与决策 |
tools |
很常见 | 给 Agent 哪些可调用能力 |
system_prompt |
很常见 | 约束 Agent 的角色、风格和工作规则 |
response_format |
很常见 | 让最终结果更适合结构化输出 |
checkpointer |
工程化能力 | 保存运行状态,可支撑短期记忆 |
middleware |
工程化能力 | 在模型调用、工具调用等阶段插入自定义控制逻辑 |
放到项目开发里,可以这样对应:
model:模型能力怎么选tools:Agent 可以用哪些外部能力system_prompt:行为规则怎么约束response_format:输出要不要便于程序直接接收checkpointer:跨多轮调用时,状态和短期记忆怎么保留middleware:要不要加入守护、拦截、动态控制
其中前四个最适合先入门;后两个更偏工程化能力。
4.3 结构化输出在 Agent 中的理解
本教程里的 V1.0 案例保留了一个很有价值的知识点:**Agent 不一定只能返回自然语言,它也可以返回结构化结果。**实际项目里,我们常常不只是想“让模型说一段话”,而是希望它最终给出:JSON、TypedDict、Pydantic 对象、便于程序直接消费的字段结构。
官方文档也把 response_format 作为 create_agent 的重点能力之一。所以你可以把这个能力理解成:Agent 不只是会调用工具,它还可以把最终答案整理成程序更容易接收的格式。
在当前 1.x 文档语境里,response_format 常见有三种理解方式:
- 直接传 schema 类型:例如
TypedDict、Pydantic 模型,框架会按模型能力自动选择更合适的结构化输出策略。 - 显式
ProviderStrategy(schema):当底层模型原生支持结构化输出时,更贴近 provider 原生能力。 - 显式
ToolStrategy(schema):把结构化输出当成一次工具调用式约束,兼容性通常更好。
在入门阶段,可先把握一个基本判断:response_format 不是“把字符串转 JSON”的后处理,而是在 Agent 最终输出阶段,把“结果长什么样”提前约束清楚。
4.4 checkpointer、thread_id 与短期记忆
如果你给 create_agent 传入 checkpointer,底层运行时就可以把 Agent 的状态保存下来。这时 Agent 不再只是“当前这一轮问什么答什么”,而是可以在多轮调用之间保留上下文。
这里可以先把三个词对应起来:
- checkpointer:状态保存器,负责把运行过程中的状态记下来
- thread_id:一次会话或一条对话线程的标识
- 短期记忆:在同一个
thread_id下,多轮消息和状态能够被延续使用
所以可以概括成一句话:checkpointer 决定“状态能不能存下来”,thread_id 决定“这些状态属于哪一条会话”。

实际调用时,thread_id 通常通过运行配置传入,例如:
1 | config = {"configurable": {"thread_id": "user-001"}} |
版本说明: 在 LangChain 1.x 语境里,
thread_id主要服务于 checkpointing 和多轮状态隔离;如果要传用户资料、租户信息、权限上下文等静态运行时信息,还需要关注create_agent的context等上下文机制,不要把所有业务信息都塞进thread_id。
这一点和 第 16 章 记忆与对话历史(含Redis基础) 是连着的。第 16 章更偏“记忆是什么、怎么存历史消息”,而这里更偏“在 create_agent 这条 1.x 主线上,状态和短期记忆是怎么接进 Agent 运行时的”。
4.5 运行过程怎么观察:stream 与 LangSmith
在真实项目里,只会 invoke() 还不够,因为 Agent 往往不是一步完成的。
4.5.1 stream() 的作用
如果 Agent 要经历:模型判断、工具调用、工具返回、再次判断、最终输出。那么直接 invoke() 往往要等到最后才看到结果。而 stream() 的价值就在于:把中间进展实时暴露出来。
这对实际项目非常有用,因为它能帮助你:
- 看到 Agent 到底卡在模型还是工具上
- 看到是否发生了多轮工具调用
- 给前端提供更好的交互体验
- 调试“为什么这次 Agent 没按预期走”
所以这里的区别很直接:invoke() 更像等最终结果,stream() 更像看 Agent 执行过程。
4.5.2 LangSmith 与 Agent 的关系
Agent 的问题,往往不是“有没有报错”这么简单,而是:
- 为什么调了这个工具而不是那个
- 为什么多调了一轮
- 为什么结构化输出没按预期生成
- 为什么这一步耗时特别长
这类问题只看最后一句回答,通常是不够的。也是为什么官方文档会把 LangSmith 和 Agent 经常放在一起讲。可以把 LangSmith 先看作:用于追踪、调试、测试、评估 Agent 运行过程的可观测平台。
这里不用立刻深入平台细节,只要先知道:stream() 让你在代码层面看到过程,LangSmith 让你在可视化层面看到过程,两者都能帮助 Agent 开发。
4.6 结合案例理解
【案例源码】案例与源码-2-LangChain框架/12-agent/AgentSmartSelectV1.0.py
这个案例和 V0.3 做的是同一类业务:都是围绕“北京和上海谁更热”来调用天气工具。
但它的教学重点已经变了,不再强调 Prompt + Executor 的手工组装,而是在强调:
create_agent(...)的统一创建方式response_format带来的结构化输出- V1.x Agent 的更简洁用法
所以读这个案例时,建议把关注点放在两件事上:
- 为什么代码明显更短了
- 为什么最后可以直接拿到
structured_response
这两点正好代表了 V1.x 路线的两个现实价值:更适合新项目快速搭建;更适合把 Agent 输出接进后端业务逻辑。
另外,虽然本教程里的 AgentSmartSelectV1.0.py 重点放在 invoke() 和结构化输出上,但如果放到真实项目里,你通常还会继续关心:
- 要不要用
stream()展示中间进展 - 要不要用
checkpointer保留短期记忆 - 要不要通过
middleware做动态控制和守护
这也是为什么 create_agent 看起来只是一个函数,背后却能一路延展到更完整的 Agent 工程化能力。
4.7 V0.3 与 V1.x 结合案例对比
总体差异已在上文 2.4 节(V0.3 与 V1.x 对比速览) 从 API 与运行时角度概括过;下表仅对照本仓库**同一业务(双城气温比较)**下的两个文件,便于你并排阅读代码。
| 维度 | AgentSmartSelectV0.3.py |
AgentSmartSelectV1.0.py |
|---|---|---|
| 教学重点 | 看懂 Agent + Executor 怎么配合 | 看懂 create_agent 统一入口 |
| 代码风格 | 显式组装 | 一步创建 |
| 中间机制 | agent_scratchpad、Executor 循环更明显 |
运行时被更高层封装 |
| 输出重点 | 最终自然语言回答 | structured_response 更适合程序处理 |
一句总结:V0.3 更适合理解“Agent 是怎么转起来的”,V1.x 更适合理解“今天项目里通常怎么写”。
4.8 Middleware 与人类审核
如果说 tools 是给 Agent 增加能力,middleware 更像是给 Agent 增加运行边界。它可以在模型调用、工具调用、状态更新等阶段插入控制逻辑。

常见用途包括:
- 动态提示词:根据用户、租户、权限或场景调整 system prompt。
- 工具调用守护:高风险工具调用前先检查参数、权限或业务规则。
- 人类审核:删除、支付、发消息、批量修改这类动作,不让 Agent 静默执行。
- 日志与监控:记录关键决策、工具参数、异常和耗时。
所以生产级 Agent 的重点不是“工具越多越好”,而是:能力越强,边界越要清楚。后续 LangGraph 章节会继续展开中断、人工确认和复杂状态控制。
5、实操与案例
前面 3、4 节已经把两条 Agent 主线讲清楚了,这一节把所有案例重新放回到清晰的位置里。
5.1 全部案例先建立一张总览表
| 案例 | 主要学习点 | 工具来自哪里 | 更适合放在什么语境里理解 |
|---|---|---|---|
AgentSmartSelectV0.3.py |
classic Agent + AgentExecutor | 本地 @tool |
理解 Agent 内部工作机制 |
AgentSmartSelectV1.0.py |
create_agent + 结构化输出 |
本地 @tool |
理解当前 1.x 主线 |
AgentReact.py |
ReAct 循环、多步工具调用、消息轨迹 | 本地 @tool |
理解 Agent 的动态决策 |
Agent2Agent.py |
多智能体协作 / A2A | 本地 @tool |
理解多角色分工 |
McpClientAgent.py |
Agent + MCP 工具接入 | MCP 服务 | 理解外部工具接入 |
也就是说,这一章不是在用 5 个案例重复讲一件事,而是在从 5 个不同角度,把 Agent 的完整能力拼出来。
5.2 ReAct 实操
【案例源码】案例与源码-2-LangChain框架/12-agent/AgentReact.py
这个案例可以用来建立“Agent 会自己连续做多步决策”的直觉。
它定义了两个工具:
search_productscheck_inventory
用户的问题不是简单的“查某个 ID 是否有库存”,而是:查找当前最受欢迎的无线耳机并检查是否有库存。
这个问题天然要求两步:
- 先搜索产品,找出哪个最热门
- 再根据搜索结果,决定去查哪个产品的库存
这里最关键的地方不是工具本身,而是:第二步依赖第一步的结果。
如果流程完全固定,普通工作流也能完成这件事;本案例使用 Agent,是为了观察模型如何根据第一步返回内容,自己决定第二步该查哪个产品、该调用哪个工具。
这个案例还有一个很值得保留的学习点:它会展示 result["messages"],让你看到:AIMessage、tool_calls、ToolMessage、最终 AIMessage。
所以这个案例不仅适合学 ReAct,也适合学:现代 Agent 在消息层面到底长什么样。
5.3 A2A 实操
【案例源码】案例与源码-2-LangChain框架/12-agent/Agent2Agent.py
这个案例对应的是广义上的多智能体协作,也就是 A2A(Agent-to-Agent)。这里的 A2A 指“Agent 之间分工协作”的思想,不特指某一个外部通信协议。
它的教学价值非常高,因为它把“一个 Agent 解决所有问题”换成了另一种思路:携程 Agent 只负责机票;美团 Agent 只负责酒店;滴滴 Agent 只负责打车;最上面再有一个总协调逻辑负责调度。
这和真实项目非常贴近。因为很多企业级系统里,往往不是“一个大而全的 Agent”,而是:
- 一个总入口
- 多个领域专长子 Agent
- 各自有边界
- 最后再汇总结果
和 LangChain 官方多智能体资料对照时要注意:官方常见做法是把 subagent 包装成 tool,再交给主 Agent 调用。
而本教程里的这个案例,使用的是:
- 子 Agent 链
RunnableLambda协调- 显式顺序调度
这不是错误,而是另一种更适合教学的表达方式。它的好处是你可以更清楚地看到:子 Agent 如何单一职责;总协调如何串联业务顺序;A2A 不一定非要从“主 Agent 调子 Agent 工具”这一个套路入门。
所以这个案例更适合帮你先抓住一个重点:多智能体协作的关键不是 API 长什么样,而是“分工 + 协调”。
5.4 Agent + MCP 实操
【案例源码】案例与源码-2-LangChain框架/11-mcp/McpClientAgent.py
这一节把第 20 章 MCP 和本章 Agent 接上了。前面几个案例里的工具,基本都是当前进程里直接写的 @tool。而这个案例演示的是另一件更接近真实项目的事:工具不一定定义在本地代码里,也可以来自外部 MCP 服务。
它的大致链路是:
- 读取
mcp.json - 用
MultiServerMCPClient连接 MCP 服务 - 获取 MCP 暴露出来的工具列表
- 把这些工具交给 LangChain Agent
- 让 Agent 在对话中继续像本地 Tool 一样使用它们
所以这个案例真正学的不是“怎么聊天”,而是:Agent 的工具来源可以被标准化外置。
这在实际项目里意义很大,因为很多企业系统都会走这条路线:
- 能力由后端团队封装成 MCP 服务
- Agent 侧只负责接入和使用
- 这样一个工具集可以被多个 AI 应用复用
也正因为如此,本章和 第 20 章 MCP 模型上下文协议 是强关联的:第 20 章解决“工具怎么标准化暴露”,第 21 章解决“Agent 怎么把这些能力真正用起来”。
6、小结:Agent、Tool、Function Calling、RAG、MCP 的区别与联系
这是本章最后必须收口的一节,因为这些概念最容易混。
术语约定: 为和前文保持一致,本章这里写 Function Calling 是因为它在很多官方资料里仍然常见;如果你更习惯 第 17 章 的说法,也可以直接把它理解成 Tool Calling 这层调用机制。
6.1 一张总表先记住
| 概念 | 它解决什么问题 | 一句话理解 |
|---|---|---|
| Tool | 系统有哪些可调用能力 | 能力层 |
| Function Calling | 模型怎么把“调工具”表达出来 | 调用机制 |
| RAG | 模型缺知识时怎么拿上下文 | 上下文增强 |
| MCP | 工具 / 资源 / Prompt 怎么标准化接入 | 连接协议 |
| Agent | 什么时候用什么能力、按什么顺序做 | 决策与编排层 |
6.2 在真实项目里怎么配合
一个更接近真实项目的完整链路通常像这样:
- 用户提出一个目标
- Agent 先判断该怎么做
- 如果缺知识,就先走 RAG
- 如果缺动作能力,就通过 Function Calling 去调 Tool
- 这些 Tool 可能是本地写的,也可能来自 MCP
- Agent 再根据返回结果继续判断,直到最终完成任务(需设好迭代上限与超时,避免死循环)
所以关系可以简写成:
- Agent = 决策层
- Tool = 能力层
- Function Calling = 调用机制
- RAG = 上下文增强
- MCP = 外部能力接入协议
章节思考题:
一个任务是否需要 Agent,你会看哪些信号?
参考思路: 看任务是否步骤不固定、需要多次决策、需要选择工具、需要根据中间结果调整路线。如果只是固定输入到固定输出,链或工作流通常更简单。
Agent、Tool、RAG、MCP 放在一起时,各自的位置是什么?
参考思路: Agent 负责决策和推进任务,Tool 提供可执行能力,RAG 提供外部知识上下文,MCP 提供标准化接入方式。它们不是互相替代,而是在不同层协作。
为什么 Agent 系统要设置迭代上限、超时和失败处理?
参考思路: Agent 会根据中间结果继续决策,如果没有边界,可能循环调用、成本失控或执行危险动作。工程上需要有停止条件、错误兜底和日志追踪。
旧的 AgentExecutor 和新的
create_agent思路,你会怎样看待它们?参考思路: 旧写法有助于读懂历史代码,新写法更贴近当前 LangChain / LangGraph 主线。学习时不必纠结“谁完全替代谁”,要看项目版本、依赖和维护成本。
本章小结:
- Agent 的定位是决策层:它不是多几个 API,也不是多几个 Tool,而是让系统围绕目标判断下一步做什么。Tool 是能力层,Agent 负责协调这些能力。
- 理解 Agent,可以放回 ReAct 循环里看:观察问题、决定动作、调用工具、拿回观察结果、继续决策。这样再去看 classic 路线里的 scratchpad / AgentExecutor,以及 1.x 路线里的
create_agent,就不会只剩 API 记忆。 - LangChain 1.x 的主线要抓住三个工程点:
response_format负责把最终输出结构化,checkpointer负责线程状态持久化,thread_id负责多轮对话和会话隔离。它们共同决定 Agent 能不能从“演示能跑”走向“系统可用”。 - 什么时候不该上 Agent 也要明确:如果步骤固定、路径稳定、可控性要求高,优先用 LCEL 或 Workflow;只有当任务真的需要动态选工具、临场分解步骤、边执行边调整时,Agent 才值得它带来的复杂度。
- 可上线的 Agent,重点在边界而不只是能力:工具白名单、参数校验、人审或二次确认、超时重试、日志与状态持久化,往往比“再多接几个 Tool”更重要。
建议下一步: 先在本地依次运行 AgentSmartSelectV0.3.py、AgentSmartSelectV1.0.py、AgentReact.py 和 Agent2Agent.py,对照文档理解 Tool、Agent、AgentExecutor 的配合。若要把外部能力接入 Agent,再回看 第 20 章 MCP 模型上下文协议 中的 McpClientAgent.py。链式固定流程与 Agent 的取舍,可对照 第 15 章 LCEL 与链式调用 和本文 1.4 Agent 的使用场景。