21 - Agent 智能体


本章课程目标:

  • 理解 Agent(智能体) 到底是什么、适合解决什么问题,以及它与 Tool、Function Calling、RAGMCP 的关系。
  • 掌握 Agent 的核心工作方式:围绕目标持续推理、决定是否调用工具、接收结果、继续决策,直到满足结束条件
  • 理解 LangChain 中 Agent 的两条学习主线:V0.3 / classic 的 Agent + AgentExecutor,以及 V1.x 的 create_agent + LangGraph 运行时
  • 跑通并理解本章全部案例:AgentSmartSelectV0.3.pyAgentSmartSelectV1.0.pyAgentReact.pyAgent2Agent.pyMcpClientAgent.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 再进一步展开,它在更完整的架构图里还可能包含记忆、规划、反思等能力。所以下图更适合理解为“扩展后的能力拼图”,而不是和上面四项定义做一一对应。

Agent 扩展架构示意:中心为 Agent,周邻 Memory(短/长期)、Planning(反思、自评、思维链)、Tools(日历、计算、搜索等)与 Action,强调多模块协同而非最小四元组一一对应(中文)

Agent 扩展架构示意:中心为 Agent,周邻 Memory(短/长期)、Planning(反思、自评、思维链)、Tools(日历、计算、搜索等)与 Action,强调多模块协同而非最小四元组一一对应(英文)

1.2 Agent 最常见的工作方式:ReAct

**ReAct = Reason + Act。**中文可以看作:先推理,再行动。

这是 Agent 最经典的一种运行循环:

  1. Thought / Reason(思考):当前要做什么,先想一步。
  2. Action(行动):如果需要外部能力,就调用某个工具。
  3. Observation(观察):拿到工具返回结果。
  4. 继续循环或结束:如果还没完成,就继续下一轮;如果信息足够,就给出最终答案。

所以 ReAct 的本质就是:先推理,再行动;根据行动结果,再继续推理。

这点和普通“只回答一次”的 LLM 调用差异非常大。普通对话通常是:用户提问、模型直接回答。而 Agent 更像:用户提问、模型判断要不要查工具、调工具、看结果、再判断要不要继续、最终回答。

下图正好对应这条循环:

ReAct 模式:思考(Thought)→ 行动(Action)→ 观察(Observation)→ 根据结果继续循环或给出最终答案的闭环示意

这里还要补一个现实中的重要认知:现代 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

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 去跑。

下图正好适合理解这一点:

AgentExecutor 工作流示意:左侧为消息流(Input、模型回复、History);中间为 Agent 链(Prompt、LLM、输出解析)决定下一步;右侧为可调用的 Tool 1…n,执行结果回传并形成循环直至结束

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

AgentSmartSelectV0.3.py

这个案例适合用来理解 classic Agent 的完整链路,因为它把这些部分都摆出来了:

  1. 定义 get_weather 工具
  2. 定义 ChatPromptTemplate
  3. 在 Prompt 里保留 agent_scratchpad
  4. create_tool_calling_agent 得到 Agent
  5. AgentExecutor 驱动执行

当用户问:请问今天北京和上海的天气怎么样,哪个城市更热?

这个案例里的 Agent 并不是“一次回答完”,而是更像这样:

  1. 先判断需要查天气
  2. 调一次 get_weather(Beijing)
  3. 再调一次 get_weather(Shanghai)
  4. 根据两次工具结果做比较
  5. 最后输出总结

所以它真正演示的不是“天气查询”,而是:一个 classic Agent 如何做多步工具调用,并把多次结果汇总成最终回答。


4、Agent 工作原理(V1.0)

这一节对应当前官方主线,也就是你项目里更现代的 Agent 入口。

4.1 create_agent 的意义

create_agent 的最大价值不是“少写几行代码”,而是:把 Agent 的常见配置收口到一个统一入口里。

你通常会把这些东西交给它:模型,工具,系统提示,有时再加结构化输出、状态、中间件等。这样你可以更专注于业务目标,而不是一开始就陷进大量底层组装细节里。

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 决定“这些状态属于哪一条会话”。

Agent 短期记忆:thread_id 区分会话线程,checkpointer 按线程保存 messages 和 state,支撑多轮延续

实际调用时,thread_id 通常通过运行配置传入,例如:

1
config = {"configurable": {"thread_id": "user-001"}}

版本说明: 在 LangChain 1.x 语境里,thread_id 主要服务于 checkpointing 和多轮状态隔离;如果要传用户资料、租户信息、权限上下文等静态运行时信息,还需要关注 create_agentcontext 等上下文机制,不要把所有业务信息都塞进 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

AgentSmartSelectV1.0.py

这个案例和 V0.3 做的是同一类业务:都是围绕“北京和上海谁更热”来调用天气工具。

但它的教学重点已经变了,不再强调 Prompt + Executor 的手工组装,而是在强调:

  • create_agent(...) 的统一创建方式
  • response_format 带来的结构化输出
  • V1.x Agent 的更简洁用法

所以读这个案例时,建议把关注点放在两件事上:

  1. 为什么代码明显更短了
  2. 为什么最后可以直接拿到 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 增加运行边界。它可以在模型调用、工具调用、状态更新等阶段插入控制逻辑。

Agent Middleware 概念:在模型调用、工具调用和运行过程之间插入守护、改写、审核与日志逻辑

常见用途包括:

  • 动态提示词:根据用户、租户、权限或场景调整 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

AgentReact.py

这个案例可以用来建立“Agent 会自己连续做多步决策”的直觉。

它定义了两个工具:

  • search_products
  • check_inventory

用户的问题不是简单的“查某个 ID 是否有库存”,而是:查找当前最受欢迎的无线耳机并检查是否有库存。

这个问题天然要求两步:

  1. 先搜索产品,找出哪个最热门
  2. 再根据搜索结果,决定去查哪个产品的库存

这里最关键的地方不是工具本身,而是:第二步依赖第一步的结果。
如果流程完全固定,普通工作流也能完成这件事;本案例使用 Agent,是为了观察模型如何根据第一步返回内容,自己决定第二步该查哪个产品、该调用哪个工具。

这个案例还有一个很值得保留的学习点:它会展示 result["messages"],让你看到:AIMessagetool_callsToolMessage、最终 AIMessage

所以这个案例不仅适合学 ReAct,也适合学:现代 Agent 在消息层面到底长什么样。


5.3 A2A 实操

【案例源码】案例与源码-2-LangChain框架/12-agent/Agent2Agent.py

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

McpClientAgent.py

这一节把第 20 章 MCP 和本章 Agent 接上了。前面几个案例里的工具,基本都是当前进程里直接写的 @tool。而这个案例演示的是另一件更接近真实项目的事:工具不一定定义在本地代码里,也可以来自外部 MCP 服务。

它的大致链路是:

  1. 读取 mcp.json
  2. MultiServerMCPClient 连接 MCP 服务
  3. 获取 MCP 暴露出来的工具列表
  4. 把这些工具交给 LangChain Agent
  5. 让 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 在真实项目里怎么配合

一个更接近真实项目的完整链路通常像这样:

  1. 用户提出一个目标
  2. Agent 先判断该怎么做
  3. 如果缺知识,就先走 RAG
  4. 如果缺动作能力,就通过 Function Calling 去调 Tool
  5. 这些 Tool 可能是本地写的,也可能来自 MCP
  6. Agent 再根据返回结果继续判断,直到最终完成任务(需设好迭代上限与超时,避免死循环)

所以关系可以简写成:

  • Agent = 决策层
  • Tool = 能力层
  • Function Calling = 调用机制
  • RAG = 上下文增强
  • MCP = 外部能力接入协议

章节思考题:

  1. 一个任务是否需要 Agent,你会看哪些信号?

    参考思路: 看任务是否步骤不固定、需要多次决策、需要选择工具、需要根据中间结果调整路线。如果只是固定输入到固定输出,链或工作流通常更简单。

  2. Agent、Tool、RAG、MCP 放在一起时,各自的位置是什么?

    参考思路: Agent 负责决策和推进任务,Tool 提供可执行能力,RAG 提供外部知识上下文,MCP 提供标准化接入方式。它们不是互相替代,而是在不同层协作。

  3. 为什么 Agent 系统要设置迭代上限、超时和失败处理?

    参考思路: Agent 会根据中间结果继续决策,如果没有边界,可能循环调用、成本失控或执行危险动作。工程上需要有停止条件、错误兜底和日志追踪。

  4. 旧的 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.pyAgentSmartSelectV1.0.pyAgentReact.pyAgent2Agent.py,对照文档理解 Tool、Agent、AgentExecutor 的配合。若要把外部能力接入 Agent,再回看 第 20 章 MCP 模型上下文协议 中的 McpClientAgent.py。链式固定流程与 Agent 的取舍,可对照 第 15 章 LCEL 与链式调用 和本文 1.4 Agent 的使用场景