Chapter 03
Agent 架构与多智能体:把 LLM 塞进一个循环
前两章备好了零件:会调工具的 LLM(01 章 Function Calling)和会补知识的检索(02 章 RAG)。这一章把它们组装进一个自主循环,得到 Agent——并算清这个循环带来的成本、延迟、失控三笔账。
本章你要建立的心智模型
- Anthropic 对 Agent 与 Workflow 的分界,以及怎么判断该不该上 Agent
- ReAct / Plan-and-Execute / Reflection 各自的循环结构与取舍
- 记忆系统怎么分层(短期/长期、情景/语义/程序性),跨会话怎么做
- 多智能体的真实代价(约 15× token)与 MCP 解决的工程问题
把前两章的零件平铺在桌上:一个会按 token 计费、会调工具、会被检索喂上下文的 LLM。它仍然是一次性的——输入进、输出出,没有「自己再想一步」的能力。Agent 就是给这台机器接上一根反馈线:把它的输出重新喂回输入,让它在一个循环里自己决定下一步做什么,直到任务完成。这一根反馈线带来了全部的威力,也带来了全部的麻烦——本章的每道面试题,深层都在问同一件事:这个循环的代价你算不算得清。
3.1Agent vs Workflow(Anthropic 的分界)
区别不在用没用 LLM,而在「谁来决定下一步」:路径写死在代码里的是 Workflow,模型自己决定的是 Agent。
「Agent」这个词被用滥了——一个调一次 LLM 的脚本也敢叫 Agent。Anthropic 在《Building Effective Agents》(2024-12)里把这团模糊一刀切开:两者都属于 agentic systems,但 workflow 是「LLM 与工具通过预定义代码路径编排」,agent 是「LLM 自主决定流程与工具用法、自己掌控如何完成任务」。这条线决定了一个系统可不可控、好不好调试、贵不贵——面试官问「这是 Agent 吗」,考的就是能不能用这条线归类。
判据落到一个具体问题上:控制流由谁写。如果「检索→总结→翻译」这条路径是工程师在代码里用 if/else 和函数调用钉死的,那它是 workflow——LLM 只是被调用的算子,跑多少步、跑哪几步在运行前就确定了。如果是 LLM 在运行时自己输出「我下一步要调检索」「现在该调计算器」「够了,收尾」,控制流由模型动态生成,那它才是 agent。Anthropic 给出一条反直觉的工程建议:能用 workflow 就别上 agent。多数生产场景任务边界清晰、路径可枚举,预定义路径更可控、更便宜、更好测;agent 的自主性是为「无法预先枚举步骤」的任务保留的。
| 维度 | Workflow(预定义路径) | Agent(自主循环) |
|---|---|---|
| 控制流由谁定 | 工程师在代码里写死 | LLM 运行时动态生成 |
| 可控 / 可测 | 高,路径可枚举、可单测 | 低,每次运行路径都不固定 |
| 成本 / 延迟 | 可预估,调用次数固定 | 不可预估,循环步数不定、token 易膨胀 |
| 适合的任务 | 步骤可预先枚举的(多数生产场景) | 步骤无法预知、需运行时探索的 |
| Anthropic 的默认建议 | 优先用它——更可控更便宜 | 仅当 workflow 确实表达不了任务时才上 |
上 Agent 等于用「可控性、成本可预估性、可测试性」三样换「灵活性」。换之前先问:这个任务的步骤真的无法预先枚举吗?很多被包装成 Agent 的系统,拆开看其实是固定三步——那本该是 workflow,套上 Agent 外壳只是徒增 token 与不可控。
一个客服系统:先分类用户意图,再按意图路由到「查订单 / 退款 / 转人工」三条固定处理链。这是 Agent 还是 Workflow?面试官追问「为什么很多生产场景反而更适合 Workflow」,怎么答?
展开答案(先停 10 秒再点)
这是 Workflow(具体说是 routing 模式):意图分类后走哪条链,是代码里 if/else 钉死的,LLM 只负责「分类」这一个算子,没有「自己决定下一步」。
很多生产场景更适合 Workflow,因为:①任务边界清晰、步骤能枚举——客服的处理路径就那么几条;②可控性是生产硬需求,Workflow 每条路径可单测、行为可预测,Agent 每次运行路径都可能不同、难回归;③成本可预估,Workflow 调用次数固定,Agent 的循环步数不定、token 会膨胀。判断该不该上 Agent 的标准:任务的步骤能不能预先枚举?能枚举就用 Workflow;只有当「下一步做什么」必须在运行时根据中间结果才能决定、且路径组合爆炸到没法写死时,自主循环才划算。
3.2增强型 LLM 与工具循环(最小积木)
增强型 LLM = LLM + 检索 + 工具 + 记忆;Agent 就是把这块积木套进一个「调用→观察→再调用」的循环。
裸 LLM 无状态、知识有截止日期、不能与外界交互——它只会生成文本。要让它去「做事」,得先给它三样增强:检索(补它不知道的知识,02 章)、工具(让它能调 API、查数据库、跑代码,01 章 Function Calling)、记忆(让它跨轮次记住状态)。Anthropic 把这个组合叫增强型 LLM(augmented LLM),并明确它是所有 agentic system 的最小积木——无论 workflow 还是 agent,底座都是它。先理解这块积木,上层的 ReAct、Plan、多 Agent 才有地方挂。
积木本身还不是 Agent——它只是一台「能力更强的一次性机器」。把它变成 Agent,靠的是外面那个循环:LLM 输出一个动作(调哪个工具、传什么参数)→ 执行得到观察结果 → 把结果拼回上下文 → LLM 据此再决定下一步。循环的终止条件由 LLM 自己判断(「信息够了,输出最终答案」)或由外部熔断(步数上限、超时)。3.3 的 ReAct 就是这个循环最经典的一种组织方式;3.4 的 Plan-and-Execute 是另一种。它们的差异不在积木,而在「循环怎么转」。
| 增强项 | 裸 LLM 的缺陷 | 对应章节 |
|---|---|---|
| 检索 | 知识有截止日期、私有知识不知道、会幻觉 | 02 章 RAG |
| 工具 | 不能与外界交互、不会算数、读不到实时数据 | 01 章 Function Calling |
| 记忆 | 无状态,跨轮次 / 跨会话不记得 | 本章 3.6 |
面试里有人把「调了 Function Calling 的 LLM」直接叫 Agent——这不准确。调一次工具、拿到结果就返回,那只是「带工具的单次调用」。只有当工具结果回喂、且 LLM 据此决定要不要再调,循环成立,才是 Agent。增强型 LLM 是名词(积木),Agent 是动词(让积木在循环里转起来)。
3.3ReAct:推理-行动-观察
ReAct = Reasoning + Acting:让 LLM 交织地「想一步、做一步、看一眼结果」,把推理和工具调用拧在同一个循环里。
纯推理(Chain-of-Thought)的问题是不接地:模型在脑内一路推下去,没法核对外部事实,错了也不自知,越推越离谱。纯行动(只调工具、不推理)的问题是没规划:不知道为什么调、调完该干嘛。ReAct(Yao 等,2022)把两者缝起来——推理迹用来「诱导、跟踪、更新行动计划,并处理异常」(reason-to-act),行动用来「把外部信息拉进推理」(act-to-reason)。靠接地它胜过纯 CoT,靠规划它胜过纯行动。论文里 ALFWorld 提升 +34%、WebShop +10%。这是目前最主流的 Agent 范式,LangGraph 的默认 agent 就是它。
循环的一轮长这样:Thought(模型想:我现在缺什么、下一步该调谁)→ Action(输出一个工具调用,如 search("张三 2023 论文"))→ Observation(工具返回结果,被拼回上下文)→ 回到 Thought(基于新观察再想)。如此往复,直到模型在某轮 Thought 里判断「信息够了」,输出 Final Answer。关键机制是:每一轮的 observation 都会回喂进上下文,模型下一轮的推理是看着累积的全部观察做的——这让它能纠错(上一步查错了,这步换个 query),也让它能分解多跳问题(先查 A,拿到 A 再查 B)。
# 最小 ReAct 循环骨架 —— 演示思路,省略了 prompt 模板与解析细节
def react(question, tools, llm, max_steps=8):
scratchpad = "" # 累积的 Thought/Action/Observation
for step in range(max_steps): # ← 步数上限:防死循环的第一道闸
# LLM 看着 question + 历史 scratchpad,产出下一步
output = llm(prompt(question, scratchpad, tools))
if "Final Answer:" in output: # ← 模型自己判断该收尾了
return output.split("Final Answer:")[-1].strip()
thought, action, args = parse(output) # 解析出 Thought / 要调的工具 / 参数
observation = tools[action](args) # 真正执行工具,接地到外部世界
# 关键:把这一轮的观察回喂进 scratchpad,下一轮推理能看到
scratchpad += f"Thought: {thought}\nAction: {action}({args})\n"
scratchpad += f"Observation: {observation}\n"
return "达到步数上限,未得出答案" # ← 熔断兜底,不让它无限转
| 范式 | 怎么工作 | 短板 |
|---|---|---|
| 纯 CoT(只推理) | 脑内一路推到底,不碰外部 | 不接地,事实错了不自知 |
| 纯行动(只调工具) | 反复调工具,不显式推理 | 没规划,不知道为什么调、调完干嘛 |
| ReAct(推理+行动交织) | 想一步、做一步、看一眼,观察回喂 | token 膨胀、错误累积、易死循环 |
observation 回喂是双刃:上下文每轮变长,token 随步数线性甚至更快膨胀,长任务会撑爆窗口;模型还会错误累积(一步判断错,后续都基于错的观察推)或死循环(反复调同一个工具、永远不输出 Final Answer)。工程上必须配:步数上限、循环检测(识别重复 Action)、超时熔断、以及兜底的人工接管。
一个 ReAct Agent 处理「比较 A、B、C 三款产品的价格和评分」,它反复调 search("A 价格")、search("A 价格")、search("A 价格")……卡住了。根因是什么?怎么从机制上止损?
展开答案(先停 10 秒再点)
根因通常是:①工具返回的 observation 没被模型有效吸收(结果为空 / 格式模型读不懂 / 被截断),于是它每轮都觉得「还没拿到」又重试;②prompt 没引导它「拿到 A 就去查 B」,缺全局规划,陷在单步。
止损手段(对应「Agent 死循环怎么办」这道高频追问):步数上限(max_steps,硬熔断)、循环检测(检测连续相同的 Action+args 就中断或强制换策略)、超时熔断(总时长/总 token 上限)、人工兜底(触发熔断后转人工或返回「无法完成」而非空转)。更治本的是换范式——这种「步骤可预先规划」的比较任务,Plan-and-Execute(3.4)先列出「查 A、查 B、查 C、对比」再执行,比 ReAct 边走边想更稳、更省 token。
推理模型(extended thinking / test-time reasoning,如 o 系列、GPT-5.x 思考模式、Claude 扩展思考)把多步推理收进了模型内部——输出前先生成一段会计费、也增加延迟的推理 token。这改写了"要不要自己搭 ReAct / Plan 脚手架"这笔账:纯想的问题(数学、规划、代码推导)可以让模型在内部思考,省掉外部循环的多次往返;但凡要接地到外部世界(查库、调 API、读实时数据)的任务,仍然需要 ReAct 式的工具循环——推理模型替代不了"行动"那一半。中高级判断:先分清这道题缺的是"想得更深"还是"够到外部信息"——前者交给推理模型,后者才上 Agent 脚手架;代价分别是推理 token 与循环往返,都不是免费的。
3.4Plan-and-Execute:先规划后执行
先让 LLM 一次性把所有步骤规划好,再逐步执行;执行偏离时才回头 replan——用「规划/执行分离」换更少的 LLM 调用与全局视角。
ReAct 每一步都要调一次 LLM 来「想下一步」——任务越长,调用越多,token 与延迟越高,而且它短视:每步只看眼前,缺全局视角,容易在多步任务里走弯路。Plan-and-Execute 把「想」和「做」拆开:开头调一次(或少数几次)LLM 产出完整计划(步骤 1…N),然后按计划执行——执行阶段大多不需要再调昂贵的规划模型。结果是调用更少、更便宜更快,且有一份显式的全局计划可审查、可干预。
结构是「Planner → Executor →(必要时)Re-planner」:Planner 看任务输出步骤列表;Executor 逐条执行(每条是一次工具调用或一个子 ReAct);执行中如果发现现实和计划对不上(某步失败、拿到的结果推翻了前提),触发 replan——把已完成的结果和新情况交回 Planner 重新规划剩余步骤。它不是「计划一次就一条道走到黑」,replan 正是它应对环境变化的机制。
| 维度 | ReAct(边想边做) | Plan-and-Execute(先规划后执行) |
|---|---|---|
| LLM 调用次数 | 每步一次,多 | 规划一次 + 执行少调,少(更便宜更快) |
| 全局视角 | 短视,每步只看眼前 | 有显式全局计划 |
| 适应环境变化 | 强,每步都能根据新观察调整 | 弱,计划僵化;靠 replan 补救 |
| 可审查 / 可干预 | 难,路径运行时才展开 | 易,计划是显式产物,可人工过目 |
| 什么时候选它 | 步骤难预知、强依赖中间结果探索 | 步骤大体可预先规划、想省 token / 要全局最优 |
计划是开头一次性定的——环境一变,计划就僵。如果执行到第 3 步发现第 1 步的前提已不成立,没有 replan 机制就会一条错路走到底。所以 Plan-and-Execute 的工程难点在「什么时候该 replan」:太频繁就退化回 ReAct(失去省 token 的意义),太迟钝就在错误计划上空耗。常见触发条件:某步执行失败、观察结果与计划假设冲突、或执行了 K 步仍未逼近目标。
Plan-and-Execute 执行到一半,发现前提变了(例如计划假设「文件存在」,第 2 步却报文件已被删)。该怎么 replan,又怎么避免 replan 太频繁退化成 ReAct?
展开答案(先停 10 秒再点)
replan 的做法:把「原计划 + 已完成步骤的结果 + 触发 replan 的具体偏差」一起交回 Planner,让它只重规划剩余部分(保留已成功的步骤,不推倒重来),产出新的剩余步骤列表,Executor 继续。
避免退化成 ReAct 的关键是设好 replan 的触发阈值,别每步都回头问 Planner:只在「步骤执行失败、观察与计划假设明确冲突、或连续 K 步未逼近目标」这类硬信号下才 replan。如果发现 replan 频率高到接近「每步一次」,说明这个任务本身步骤难预知——那它本就更适合 ReAct,选错范式了。
3.5Reflection 与五种工作流模式
Reflection:让 Agent 对自己的输出做口头自我批评、把批评存进记忆、在重试时据此改进——本质是「拿额外的 LLM 调用换质量」。
LLM 第一次的输出常常「差一点」——代码跑不过、答案漏了条件。Reflexion(Shinn 等,2023)的做法:让模型用自然语言批评自己刚才哪里错了(口头自我反思),把这段批评存进情景缓冲(episodic buffer),当作一种「语义梯度」——下一次重试时把它读回来,据此改进。这对应 Anthropic 的 evaluator-optimizer 工作流:一个角色生成、一个角色评判,迭代到满足标准。它在「有清晰评判标准、且值得多花几次调用换质量」的任务上有效。
Reflection 之外,Anthropic 在《Building Effective Agents》里把工程上真正常用的组织方式归纳为五种工作流模式——多数生产系统用的是这些,而非完全自主的 agent。把它们当成一张「先于上 Agent 该考虑的备选清单」:
| 模式 | 怎么组织 | 适用 |
|---|---|---|
| Prompt chaining | 固定子任务串成链,前一步输出喂下一步 | 任务能稳定拆成固定子步骤;拿延迟换准确 |
| Routing | 先分类,再把输入分派给专才 / 便宜模型 | 输入类别清晰、各类该用不同处理 |
| Parallelization | sectioning(拆独立子任务并行)/ voting(同任务多跑取投票) | 子任务独立可并行,或要多次采样投票 / 加护栏 |
| Orchestrator-workers | 主控动态拆解子任务、分派给 worker、汇总 | 子任务无法预先枚举、需运行时拆 |
| Evaluator-optimizer | 生成→评判→改进的迭代回路(Reflection 的工程形态) | 有清晰评判标准、值得多花调用迭代 |
两者都「并行多个子任务」,差别在子任务从哪来:parallelization 的子任务是预先定好的(开发者知道要把文档切成 5 段并行处理);orchestrator-workers 的子任务是主控运行时动态拆的(拆几个、拆什么事先不知道)。前者是 workflow,后者已经带 agent 的自主性——这也正是「单 Agent 编排 vs 固定并行」的分界,面试常借这两个模式考你对自主性的理解。
Reflection / evaluator-optimizer 每迭代一轮就多一组生成 + 评判的调用,token 和延迟成倍涨。它只在「评判标准明确、且质量提升值这个钱」时划算——评判标准模糊时,模型的自我批评本身就不可靠,越反思越跑偏。别把 Reflection 当默认开关。
3.6记忆系统(短期 / 长期)
短期记忆 = 上下文窗口里的 scratchpad(模型唯一能直接推理的东西);长期记忆 = 外部存储,按情景 / 语义 / 程序性分层,用时检索回上下文。
LLM 无状态——一次调用只看得见这次塞进上下文的内容。要让 Agent 在多轮对话里记得三步前说过什么、在跨会话里记得用户上周的偏好,就得有记忆系统。核心约束有一条要记牢:模型唯一能直接推理的,只有上下文窗口里的东西。长期记忆存得再多,不检索回上下文,模型就「看不见」。所以记忆系统的真正工作不是「存」,而是「在对的时机把对的东西捞回上下文」。
短期记忆是当前上下文窗口里的对话历史 / scratchpad——它就是 3.3 那个 ReAct 累积的 thought-observation 串。它直接可推理,但容量受窗口限制,且每轮都在烧 token。长期记忆放在外部(向量库 / KV / 数据库),容量无限但必须检索才用得上。长期记忆按认知科学的三分法组织:
| 类型 | 存什么 | 典型载体 |
|---|---|---|
| 情景 episodic | 过往具体交互(上次对话、上次操作) | 向量库 / 会话日志 |
| 语义 semantic | 无时间性的事实、用户偏好 | 向量库(最常见) |
| 程序性 procedural | 「怎么做」的技能 | 模型权重 / 系统提示 / 工具注册表 |
工程落地上,LangGraph 用 checkpointing(持久化到 Postgres / Redis / SQLite)把对话状态存盘,实现「续上一次会话」;LangMem 之类在其上加带命名空间的长期记忆。记忆系统的设计三问:写入时机(每轮都写还是会话结束才摘要写)、检索召回(用什么 query 捞、捞回几条)、压缩摘要(旧历史怎么压缩以免撑爆窗口)。
记忆不是「越多越好」。检索回来的记忆挤占上下文窗口(和当前任务争 token),召回不准还会塞进噪声、误导模型;写入太频繁则放大延迟与存储成本。跨会话记忆尤其要管「该不该记、记多久、谁能读」——把用户敏感信息长期存进向量库,是隐私与合规的雷区。
一个多轮 Agent 聊到第 50 轮,上下文眼看要爆窗口。同时面试官追问「跨会话记忆怎么做」。两个问题怎么答?
展开答案(先停 10 秒再点)
上下文爆了怎么办:①滑动窗口——只保留最近 N 轮原文;②摘要压缩——把更早的历史用 LLM 压成一段摘要顶在前面(拿信息损失换 token);③外置——把早期对话写入长期记忆(向量库),需要时再按相关性检索回来,而不是全量留在窗口里。三者常组合用:近期保原文 + 远期存摘要 + 关键事实进长期记忆。
跨会话记忆怎么做:会话结束时把关键信息(用户偏好=语义记忆、这次发生了什么=情景记忆)写入外部存储;新会话开始时,按当前用户 / 话题检索回相关记忆,拼进系统提示或上下文开头。LangGraph 的 checkpointing 负责「同一会话续上」,命名空间化的长期记忆(如 LangMem)负责「跨会话记得这个用户」。核心仍是那条铁律——长期记忆必须检索回上下文模型才用得上。
记忆只是“管理放进窗口的内容”这件事的一个侧面。把它推到一般情形——每一步该让模型看到什么、看不到什么——就是 §3.9 要讲的上下文工程。
3.7多智能体:何时该上、代价是什么
多个 Agent 分工协作,靠角色分工 + 上下文隔离 + 并行换能力上限;代价是约 15× 的 token 与协调/调试难度——只在任务价值高且能拆成独立并行子任务时划算。
单个 Agent 有两个天花板:上下文窗口装不下超大任务,以及一个角色很难同时擅长「搜索 + 编码 + 审校」。多智能体用分工破这两个天花板——主管(orchestrator)拆任务,多个子代理各管一块、各自带独立上下文并行干。Anthropic 的研究系统给了硬数据:Opus 主管 + 3–5 个 Sonnet 子代理并行,比单 Opus +90.2%。但同一篇报告也给了反面数据:约 80% 的性能差异由 token 用量解释,且多智能体烧约 15× 普通 chat 的 token。所以它不是「更高级所以更好」,而是一笔要算清的账。
多智能体的强项是广度优先:任务能切成多条互相独立、可并行的探索路径(如「同时调研 5 家公司的财报」),每条超出单个上下文窗口。它的死穴是需要大量共享中间上下文或步骤强依赖的任务——Anthropic 直言「LLM 还不擅长实时协调与委派」,子代理之间传递上下文有损耗,一步失败就让整体崩。编排模式有几种:supervisor / hierarchical(主管派活)、network(代理互相调用)、sequential(流水线)、handoff(OpenAI Agents SDK,一个代理显式把控制权连同上下文转交另一个)。
| 维度 | 单 Agent | 多 Agent |
|---|---|---|
| 能力上限 | 受单上下文 + 单角色限制 | 高,分工 + 并行突破上限 |
| token 成本 | 基准 | 约 15× —— 仅高价值任务划算 |
| 协调 / 调试 | 简单,单条轨迹好追 | 难,跨代理通信、错误难定位 |
| 擅长的任务形态 | 串行、上下文需共享 | 广度优先、独立可并行的子任务 |
| 需大量共享上下文 / 步骤强依赖时 | 更合适 | 不适合——协调损耗 + 一步崩全盘 |
约 15× token 只是显性成本。隐性代价更难受:协调开销(代理间传上下文有损、主管要花调用去拆解与汇总)、调试难(一次失败要在多条交织轨迹里定位是哪个代理哪一步出的错)、错误跨代理传播(子代理的错误观察被主管当真,污染全局)。上多智能体前先确认任务能拆成独立并行块——拆不开就别上,单 Agent + 好的工具更省心。
一个任务需要多个 Agent 共享大量中间上下文(每个 Agent 的产出都要喂给下一个、且彼此频繁互相依赖),该上多智能体吗?
展开答案(先停 10 秒再点)
不该。这正是多智能体的死穴场景。Anthropic 明确指出多智能体擅长的是「广度优先、子任务独立可并行」的任务;而「需大量共享上下文或多步互相依赖」的任务不适合——理由:①代理间传递上下文有损耗,频繁共享会持续丢信息;②「LLM 还不擅长实时协调委派」,强依赖链条下一步失败可能让整体崩;③还要白白多付约 15× 的 token。
这种任务更适合单 Agent(所有中间结果都在同一个上下文里,无传递损耗、好调试),或拆成Plan-and-Execute 的串行流水线(显式计划 + 顺序执行)。判据一句话:子任务能不能独立并行? 能并行才考虑多 Agent;要频繁共享上下文,多 Agent 是负优化。追问「Agent 间怎么编排」答 supervisor / network / sequential / handoff;「错误怎么跨 Agent 控制」答每个子代理的输出要校验后再汇总、主管对子代理结果做可信度判断、失败子任务可重派或降级。
3.8MCP:工具接入的标准协议
MCP(Model Context Protocol,Anthropic 2024-11)= 「AI 的 USB-C」:用 JSON-RPC 标准化 Agent 与工具/数据源的接入,让工具写一次、任何 MCP 客户端复用。
没有 MCP 时,每个应用要接每个工具都得写一套专用胶水——M 个应用 × N 个工具 = M×N 套各不相同的对接代码,新增一个就要再写一排。这是工程层的集成爆炸。MCP 把对接抽象成一个标准协议:工具方实现一次 MCP server,应用方实现一次 MCP client,双方就能互通。M×N 套胶水塌缩成 M+N 次实现。这是「USB-C」类比的本意——统一接口,谁插谁都通。
架构是三层:host(用户面对的应用,如 IDE、Claude Desktop)→ client(host 内部为每个 server 维护一条 1:1 连接)→ server(暴露能力的一方)。server 暴露三类 primitives:tools(可执行函数)、resources(上下文数据,如文件 / 数据库记录)、prompts(可复用的提示模板);client 侧也有 primitives:roots(文件系统边界)、sampling(让 server 反向请求 LLM 补全)。传输层两种:stdio(本地进程)和 HTTP/SSE(远程)。
| 维度 | Function Calling | MCP |
|---|---|---|
| 属于哪一层 | 模型层 | 工程 / 集成层 |
| 解决什么 | 模型「想调什么、参数填什么」的输出格式 | 工具「怎么被标准接入、发现、复用」的协议 |
| 形态 | 模型输出的结构化调用意图(JSON) | JSON-RPC 协议 + host/client/server 架构 |
| 复用性 | 每个应用各自定义函数 schema | 一次实现、任何 MCP 客户端复用 |
| 二者关系 | 决定「调谁」(大脑的意图) | 负责「调得通」(接线的标准)——互补不互斥 |
面试常设的陷阱是让你「二选一」——其实它们在不同层、互补。一次工具调用里:Function Calling 让模型产出「我要调 search、参数是 X」这个意图;MCP 负责把这个意图路由到一个标准化的 search server 并拿回结果。没有 FC,模型不知道要调什么;没有 MCP,每个工具的接入都得重写胶水。生产里两者同时在场。
MCP 把外部 server 接进 Agent,等于扩大了攻击面:恶意或被污染的 server 可以返回带 prompt 注入的 resource、或暴露危险 tool。所以 MCP 的安全机制要点:server 的能力授权与用户确认(高危 tool 调用前要批准)、client 用 roots 限定文件系统边界、对 server 返回内容做注入防御、远程 server 要鉴权与传输加密。把任意第三方 MCP server 无脑接进生产 Agent,是典型失败模式。
3.9上下文工程:长程 Agent 的头号失败模式
上下文工程 = 主动管理“到底把什么放进上下文窗口”。长程 Agent 出问题,多半不是模型不行,而是 token 越堆越多把它拖垮——这是 2026 最被强调的工程能力。
§3.3 说过 ReAct 每轮把 observation 回喂、上下文线性膨胀;§3.6 的记忆检索又往里塞。Agent 跑得越久,窗口里堆的无关历史、旧工具输出、过期观察越多。实测一个在干净 prompt 上能拿 98.1 分的模型,把同样的信息散落进多轮 Agent 运行后会掉到 64.1——业界叫它 context rot(上下文腐化)。所以“放进窗口的是什么”本身就是一等工程问题:prompt engineering 之后是 context engineering。
主流框架把上下文管理拆成四个动作,各治一种失败:
| 动作 | 做什么 | 治哪种失败 |
|---|---|---|
| write 写出 | 把该留的事实 / 进展写到窗口外的存储(记忆、草稿) | context poisoning:幻觉状态被反复带进后续 |
| select 选取 | 每一步只把当前真正需要的工具、上下文捞进来 | context confusion:工具 / 信息过载,模型选错 |
| compress 压缩 | 对累积历史做摘要 / 折叠(compaction) | context distraction:旧历史堆积,稀释当前任务 |
| isolate 隔离 | 把独立子任务交给 subagent,各用干净上下文 | context clash:多路信息混在一起互相干扰 |
两条最常被追问的具体技术:
compaction(压缩 / 摘要折叠):历史快撑爆窗口时,用 LLM 把旧历史摘成一段短摘要顶上去。代价是有损(摘错就丢了关键信息)且阻塞(要等这次摘要调用返回)。进阶做法 context-folding 把已完成的子任务“折叠”成结论、只留活跃上下文,实测能用约 10× 更小的活跃上下文逼近 ReAct 基线。
记忆即工具(memory-as-tools):把 §3.6 的长期记忆从“后台自动塞”升级成模型主动调用的工具——把 store / retrieve / update / summarize / discard 五个动作都做成函数,让模型自己决定何时写、何时捞、何时丢。好处是写入和召回都受控、可追溯,不再无脑往窗口里灌。
初级想“prompt 怎么写”,中高级想“这一步该让模型看到什么、看不到什么”。同样的工具和模型,上下文管得好不好,能在长任务上拉开 30 多分的差距(98 → 64 那条)。面试聊 Agent 可靠性时,能主动提 context rot + 四杠杆,是明确的中高级信号。
一个 Agent 任务跑到第 40 步开始“失忆 / 抓不住重点”,但单看模型在短 prompt 上表现很好。最该先怀疑什么?
展开答案(先停 10 秒再点)
先怀疑 context rot,不是模型变笨。长程运行里窗口被几十轮工具输出、旧观察、检索回来的记忆塞满,关键信息要么被挤出窗口、要么落在中部被 Lost-in-the-Middle(§1.3)忽略。对策按四杠杆来:select 每步只取真正需要的工具 / 上下文(别把几十个工具定义全塞)、compress 对旧历史做 compaction、isolate 把独立子任务拆给 subagent 各用干净上下文、write 把该留的事实写进外部记忆而非全堆窗口。根因是上下文管理,换个更大模型解决不了。
3.10Computer Use / GUI agents
Computer Use = 让 Agent 通过截图 + 鼠标键盘动作直接操作图形界面,把“没有 API 的软件”也变成可调用的工具。
Function Calling(§1.6)和 MCP(§3.8)都要求目标系统暴露了接口。但大量真实软件没有 API——老旧的企业系统、只有网页的后台、桌面应用。Computer Use 让模型像人一样“看屏幕、点按钮”,把这部分系统也纳入 Agent 的行动范围。代表能力:Anthropic Computer Use、OpenAI 的计算机操作 Agent 等。
机制上它仍是 ReAct 循环,只是 observation 和 action 换了形态:模型拿到一张截图(多模态输入)→ 输出一个动作(点击坐标 (x, y) / 输入文本 / 滚动 / 按键)→ runtime 执行后回传新截图 → 模型据此再决策。把 §3.3 那张图里的“工具返回文本”换成“返回截图”,闭环不变。
| 接入方式 | 适用 | 代价 |
|---|---|---|
| API / Function Calling / MCP | 目标系统有接口——首选 | 需要对方暴露接口 |
| Computer Use(截图 + 动作) | 没有 API 的网页 / 桌面 / 老系统,兜底手段 | 慢、脆(UI 一变就失效)、安全风险大 |
三个现实代价:①慢——每步要截图 + 多模态推理 + 渲染,比调 API 慢一个量级;②脆——UI 一改版、按钮一挪位,写死的视觉定位就失效;③安全被放大——一个能读屏、能点任何东西的 Agent,正好凑齐 §4.5 的致命三件套(不可信输入 + 私有数据 + 对外通道),被间接注入一句“把数据发出去”后果严重。所以 Computer Use 必须配最小权限、沙箱、高危动作人工确认(HITL)。有 API / MCP 能用时,永远优先用接口,别上 Computer Use。
§面试题检索
先合上正文,把答案在心里过一遍或写下来,再点开对照。直接展开等于把这一章又读了一遍——记不住。标「高频」的是社招中高级几乎必问的。
- [高频] Agent 和 Workflow / 单纯 LLM 调用有什么区别?
展开答案
三者都属 agentic system,区别在「谁决定下一步」:单纯 LLM 调用是一次性输入输出,无循环;Workflow是 LLM 与工具通过预定义代码路径编排,流程在运行前钉死,可控、可测、成本可预估;Agent是 LLM 自主决定流程与工具用法,带规划 + 工具 + 记忆 + 反思的自主循环,灵活但不可控、贵、难调试。很多生产场景混合最优。
追问:为什么很多生产场景反而更适合 Workflow? 因为多数任务步骤可预先枚举,预定义路径更可控(可单测、行为可预测)、更便宜(调用次数固定)、更好回归。Agent 的自主性是为「步骤无法预先枚举」的任务保留的。怎么判断该不该上 Agent? 一句话判据:任务的步骤能不能预先枚举?能枚举用 Workflow;只有「下一步做什么」必须运行时根据中间结果决定、且路径组合爆炸到没法写死时,才上 Agent。
- [高频] Agent 有哪些工作模式?分别适用什么?
展开答案
ReAct(思考-行动-观察交织,每轮观察回喂)——步骤难预知、需边走边探索;Plan-and-Execute(先一次性规划再执行,省 token、有全局视角)——步骤大体可预先规划;Reflection(自我反思、迭代改进)——有清晰评判标准、值得多花调用换质量;Multi-Agent(多角色分工并行)——任务可拆成独立并行子任务且价值高。
追问:Agent 死循环怎么办? 步数上限(max_steps 硬熔断)、循环检测(识别重复 Action 就中断/换策略)、超时熔断(总时长/总 token 上限)、人工兜底(触发熔断后转人工或返回「无法完成」而非空转)。
- [高频] 详细解释 ReAct。
展开答案
ReAct = Reasoning + Acting,把推理和行动拧进一个循环:Thought(想:缺什么、下一步调谁)→ Action(输出工具调用)→ Observation(工具返回,拼回上下文)→ 回到 Thought,直到模型判断信息够了输出 Final Answer。核心机制是每轮 observation 回喂上下文,让模型能接地、纠错、分解多跳问题。靠接地胜过纯 CoT,靠规划胜过纯行动;LangGraph 默认就是这个范式。
追问:ReAct 缺点? token 随步数膨胀、错误累积(一步错后续基于错的推)、可能死循环。vs Plan-and-Execute 怎么取舍? ReAct 每步调一次 LLM、灵活适应变化但贵且短视;Plan-and-Execute 规划一次再执行、省 token 有全局视角但计划僵化。步骤可预先规划选后者,步骤难预知选前者。
- [高频] Agent 的记忆系统怎么设计?
展开答案
短期记忆=对话上下文 / scratchpad,是模型唯一能直接推理的东西,受窗口限制、烧 token;长期记忆=向量库 / 外部存储,容量无限但必须检索回上下文才用得上,按认知科学三分:情景 episodic(过往交互)、语义 semantic(无时间性的事实/偏好,常向量库)、程序性 procedural(技能,在权重/系统提示/工具注册表)。设计三问:写入时机、检索召回、压缩摘要。LangGraph 用 checkpointing 持久化。
追问:跨会话记忆怎么做? 会话结束写关键信息(偏好=语义、发生了什么=情景)入外部存储,新会话按用户/话题检索回来拼进上下文。上下文爆了怎么办? 滑动窗口(留最近 N 轮)+ 摘要压缩(早期历史压成摘要)+ 外置长期记忆(按需检索)。铁律:长期记忆不检索回上下文模型就看不见。
- [高频] MCP 是什么协议?解决什么?和 Function Calling 本质区别?
展开答案
MCP = Model Context Protocol(Anthropic 2024-11),用 JSON-RPC 标准化 Agent 与工具/数据源的接入,让工具可发现、可复用,把 M 应用×N 工具的集成爆炸(M×N 套胶水)收敛成 M+N 次实现(「AI 的 USB-C」)。架构:host(应用)→ client(1:1 连接管理)→ server(能力);server primitives = tools / resources / prompts;传输 = stdio(本地)/ HTTP-SSE(远程)。
本质区别:Function Calling 是模型层「想调什么、参数填什么」的输出格式(决定调谁);MCP 是工程层「工具怎么标准接入」的协议(负责调得通)。二者互补不互斥,生产里同时在场。追问:MCP 安全机制? 高危 tool 调用前用户确认、client 用 roots 限定文件边界、对 server 返回做注入防御、远程 server 鉴权 + 传输加密。追问:MCP 和 A2A 什么关系?(2025–2026 面试一旦问到 MCP 常跟这一刀)A2A(Agent-to-Agent 协议)管的是「Agent ↔ Agent」的互操作——能力发现、任务委托;MCP 管的是「Agent ↔ 工具/数据源」。两者不同层、互补:A2A 对接同伴 Agent,MCP 对接工具。
- 多智能体什么时候值得上?
展开答案
值得上:任务能拆成独立可并行的子任务(广度优先)、需要多角色分工、需要上下文隔离,且任务价值高足以摊薄成本。代价:通信开销、协调难、调试难、约 15× token(Anthropic 数据:约 80% 性能差异由 token 用量解释)。不适合:任务需大量共享中间上下文或步骤强依赖时——代理间传上下文有损、LLM 还不擅长实时协调委派、一步失败可能整体崩。
追问:Agent 间怎么编排? supervisor/hierarchical(主管派活)、network(互相调用)、sequential(流水线)、handoff(显式转移控制权并带上下文,如 OpenAI Agents SDK)。错误怎么跨 Agent 控制? 子代理输出校验后再汇总、主管对子结果做可信度判断、失败子任务可重派或降级。
- [高频] 怎么保证 Agent 行为安全、可控?
展开答案
最小权限(只给完成任务必需的工具/数据访问)、高危操作走 Human-in-the-Loop 审批、Prompt 注入防御(隔离不可信输入、对工具返回内容做净化)、操作可回滚 / 沙箱(在隔离环境执行、可撤销)、行为审计(全程记录调用轨迹便于追责)。
追问:Agent 误删数据怎么防? 高危操作前强制确认、先 dry-run 预演影响再真执行、用权限边界限制可触达范围、对可执行操作设白名单(只允许列表内的动作),删除类操作走软删除 / 可恢复路径。
- Plan-and-Execute 相比 ReAct 的优劣?
展开答案
优:先一次性规划再执行,减少 LLM 调用 / token(执行阶段大多不必再调昂贵规划模型),有显式全局计划、可审查可干预、全局视角避免短视。劣:计划是开头定的,僵化,环境变化时难适应,依赖 replan 补救。
追问:执行到一半前提变了怎么 replan? 把「原计划 + 已完成步骤结果 + 触发偏差」交回 Planner,只重规划剩余部分(保留已成功步骤),Executor 继续。注意设好触发阈值(只在步骤失败、观察与假设冲突、连续 K 步未逼近目标时 replan),否则 replan 太频会退化成 ReAct。
- RAG 和 Agent 什么关系?Agentic RAG 是什么?
展开答案
关系:Agent 把 RAG 当成它的一个工具(检索是 Agent 工具箱里的一项,对应 3.2 增强型 LLM 的「检索」增强)。Agentic RAG:让 Agent 动态决定要不要检索、检索几次、要不要改写 query 重检索,而不是固定「检索一次→生成」。代表变体:Self-RAG(模型自评是否需要检索、检索结果是否相关/有用)、Corrective RAG(CRAG)(评估检索质量,差就触发纠正性动作如改 query / 转网络搜索)。
追问:复杂度更高,什么时候值得? 当查询多样、单次检索常不够(多跳问题、需要判断「这题到底要不要查」)、对答案质量要求高且容忍更高延迟/成本时值得;简单事实问答用固定 RAG 更省。
- [高频] 长程 Agent 跑久了效果变差,但模型本身没问题。怎么回事?怎么治?
展开答案
多半是 context rot:窗口被几十轮工具输出 / 旧观察 / 检索记忆塞满,关键信息被挤出或落在中部被忽略(§1.3)——干净 prompt 98 分的模型,长程散落后能掉到 60 分上下。这是上下文管理问题,不是换大模型能解决的。按上下文工程四杠杆治:select(每步只取需要的工具 / 上下文)、compress(对旧历史做 compaction 摘要 / 折叠)、isolate(独立子任务交 subagent 用干净上下文)、write(关键事实写进外部记忆而非全堆窗口)。
追问:compaction 的代价是什么? 有损(摘要难免丢信息)+ 阻塞(要等摘要这次调用返回);context-folding 这类做法用更小的活跃上下文缓解。
- 什么是 Computer Use?它和 Function Calling / MCP 是什么关系?
展开答案
Computer Use 让 Agent 通过截图 + 鼠标键盘动作操作 GUI,机制仍是 ReAct 循环(observation = 截图,action = 点击 / 输入)。它和 Function Calling / MCP 是互补的兜底:有 API / 接口就用 FC / MCP(快、稳);只有没接口的网页 / 桌面 / 老系统才上 Computer Use。代价是慢、脆(UI 一变就失效)、且把安全风险放大——能读屏能乱点的 Agent 正好凑齐致命三件套(§4.5),必须配最小权限 + 沙箱 + HITL。
给一个你会坚持用 Agent(而非 Workflow)的具体场景
Anthropic 在《Building Effective Agents》里建议多数场景先用 workflow 而不是 agent。请给出一个你会坚持用 Agent 的具体场景,并说明它满足了什么条件——让 workflow 确实表达不了。
提示(卡住再展开)
回到 3.1 的判据:Agent 的自主性只为「步骤无法预先枚举」的任务买单。找一个路径在运行前无法枚举、必须根据中间结果才能决定下一步的任务。比如「开放式代码调试」:报错信息要跑了才知道,下一步查哪个文件、改哪行,完全取决于上一步的观察——没法预先画出固定流程图,每个 bug 的探索路径都不同。检验你的场景是否合格,问三件事:①步骤能预先枚举吗(能 → 该用 workflow)?②下一步是否真的依赖运行时才产生的中间结果?③这个任务的价值是否撑得起不可控 + token 膨胀的代价?三条都站得住,才是 Agent 的正当场景。