Agent 八股
什么是 Agent?与大模型有什么本质不同?
我理解 Agent 本质上是一个能自主完成目标的 AI 系统,跟 LLM 最核心的区别在于「自主性」和「行动力」。
LLM 有很多局限性,只能被动地回答问题,上下文窗口有限,无法与外界交互完成复杂任务;
而 Agent 有如下特点:
一是 Agent 有自主规划能力,给它一个复杂目标它能自己拆解成多步;
二是它能行动,通过工具调用跟外部世界真实交互;
三是它有闭环,通过记忆访存和工具交互结果以指导下一步,而不是一次性生成完就结束。
另外:模型本身只是「大脑」,工具的真正执行是你的代码,模型只负责决策。
Agentj:感知 -> 规划 -> 行动 -> 再感知
第一件:工具调用(Tool Use)
第二件:记忆机制
第三件:多步推理和自我纠错
为什么 Agent 现在才爆发?
第一个条件是大模型的能力跨过了「能用」的门槛。早期的语言模型理解能力有限,你让它做任务拆解、判断下一步该调哪个工具,它根本做不好。但从 GPT-4、Claude 3 这一代开始,模型的推理能力、指令遵循能力有了质的飞跃,它真的能「读懂」复杂指令并做出合理的多步决策了。
第二个条件是工具调用的标准化。OpenAI 在 2023 年推出了 Function Calling 机制,让模型能以结构化的 JSON 格式输出工具调用请求,这个标准很快被各家模型厂商跟进。有了统一的工具调用协议,开发者才能方便地给模型接上各种外部能力,不然每接一个工具都要自己写一套解析逻辑,工程成本太高。
第三个条件是配套生态的完善。LangChain、LlamaIndex 这些框架把 Agent 的开发门槛大幅降低了,向量数据库解决了长期记忆的存储问题,各种 API 服务让可调用的工具越来越丰富。
三个条件凑齐,Agent 从论文概念变成了工程实践,这才有了现在的爆发。
Agent 生态的最新趋势
MCP
第一个是 Anthropic 在 2024 年底提出的 MCP(Model Context Protocol,模型上下文协议)。你可以把 MCP 理解成 Agent 工具世界的「USB-C 接口」。
MCP 的做法是定义一套标准的 JSON-RPC 协议,工具提供方只要按这个标准暴露自己的能力(变成一个 MCP Server),任何支持 MCP 的 Agent(通过内置的 MCP Client)都能直接发现和调用这些工具,不需要额外写适配代码。
MCP 的架构分三层:最外层是 Host(就是用户直接交互的 AI 应用,比如 Claude Desktop、Cursor 这些),中间是 Client(负责和 MCP Server 建立连接、管理通信),最里层是 Server(真正暴露工具能力的服务)。
A2A
第二个是 Google 在 2025 年 4 月推出的 A2A(Agent2Agent,Agent 间通信协议)。如果说 MCP 解决的是「Agent 怎么调用工具」的问题,A2A 解决的就是「Agent 怎么和另一个 Agent 协作」的问题。
A2A 的核心设计是一个叫 Agent Card 的概念,每个 Agent 都有一张「名片」,上面写着它能做什么、正在做什么、需要什么输入,其他 Agent 读了这张名片就知道该怎么跟它协作。
Agent 的基本架构由哪些核心组件构成?
我理解 Agent 的基本架构有四个核心组件:LLM、工具、记忆、规划模块。
LLM 是整个系统的大脑,负责理解任务和做决策;工具让 Agent 能跟外部世界交互,搜索、执行代码、调 API 都靠它;记忆让 Agent 在任务执行过程中保持状态,不会「失忆」;规划模块负责把复杂目标拆解成可执行的步骤。
这四个组合在一起,才让 Agent 具备了自主完成任务的能力。
LLM 核心
- System Prompt(系统提示词)。
System Prompt 就已经定义好了它的角色、行为边界、输出格式要求等等
工程考量
推理能力/推理优化(大模型>小模型)
任务权衡:用推理能力强的大模型做核心决策(比如任务规划、关键判断),用更快更便宜的小模型做简单任务(比如意图分类、格式提取),根据不同环节的需求来搭配。
工具调用稳定性
上下文窗口大小
工具系统
工具定义里没有一行执行逻辑,只有 schema「名字、描述、参数说明」
工具描述的质量直接影响 Agent 的表现
记忆系统
- 短期记忆
最基础的是短期记忆,就是当前这轮对话的上下文,装在 context window 里。
- 长期记忆
通常用向量数据库来实现,把重要信息 embedding 之后存起来,下次用的时候做语义检索拿回来。
这里借用认知科学对人类长期记忆的分类来理解 Agent 长期记忆的组织方式(注意这只是便于理解的类比,Agent 系统里的实现通常都是向量检索 + metadata 过滤,不一定真的分这么细):
语义记忆(Semantic Memory)存的是事实性知识,比如「用户是做金融行业的」「某个 API 的调用频率限制是每分钟 60 次」;
情景记忆(Episodic Memory)存的是具体的经历,比如「上次用户问退款问题时我们查了订单系统,发现他的订单已过退款期」;
程序性记忆(Procedural Memory),存的是「怎么做事」的经验,比如「处理退款问题的标准流程是先查订单状态再核实支付方式」。程序性记忆特别有意思,它不是存某个具体的事实,而是把 Agent 做事的方法论沉淀下来,让它下次碰到类似任务时能直接套用高效的处理流程,而不是每次都从头摸索。
注意点
如果什么都往向量数据库里塞,检索出来的噪音会很多,反而干扰模型的决策;如果存得太少,又失去了长期记忆的意义。目前比较好的做法是在存入之前做一轮重要性评估,只把真正有价值的信息持久化。另外还有一个容易忽略的机制叫记忆衰减(Memory Decay)。
规划模块
技术手段
CoT(Chain of Thought,思维链),它的核心思想是让模型「把思考过程写出来」,而不是直接输出最终答案。你可以在 prompt 里加一句「Let's think step by step」,模型就会把推理的中间步骤一步步展开。
ToT(Tree of Thoughts,思维树),它不是走一条线性的推理链,而是在每个推理节点上展开多个可能的分支,然后评估每个分支的质量,选出最优的路径继续往下走。
主流模式
第一种是「先规划后执行」,也就是 Plan-and-Execute 模式,先让 LLM 输出一个完整的步骤列表,然后按顺序逐步执行。好处是整体结构清晰,你能在执行前就看到完整计划,方便人工审核;缺点是如果中间某一步的结果和预期不一样,原来的计划可能就不合适了,需要重新调整。
第二种是「边执行边规划」,也就是 ReAct 模式,每走一步就根据当前结果重新思考下一步该做什么,不提前制定完整计划。好处是灵活性极高,能根据实际情况随时调整;缺点是容易「走偏」,因为每一步都是局部最优决策,有时候会忽略整体目标。在实际工程里,很多团队会把两种模式结合起来,先做一个粗略的计划确定大方向,执行过程中再根据反馈动态微调。
Workflow,Agent,Tools 这三个的概念和区别介绍一下?
我理解这三个概念是粒度从小到大的三层结构。
Tools 是最小的能力单元,就是封装好的可调用函数,比如搜索、执行代码、发邮件,它只负责「执行」,本身没有任何决策能力。
Agent 是一个完整的决策系统,内部用 LLM 做大脑,自己判断什么时候调哪个 Tool、要不要继续、什么时候结束,是主动的。
Workflow 是更上层的编排框架,把 Agent、LLM、Tools 组织成一条确定性流程,每个节点做什么、按什么顺序流转都是开发者事先写死的。
三者最核心的区别就一句话:Tools 不做决策只执行,Agent 自己做决策,Workflow 是开发者替所有节点把决策提前写好。
Workflow
把整个执行流程的「骨架」写在代码里,LLM、Agent、Tools 都只是这个流程里的「节点」,每个节点负责完成自己那一步,但整体走哪条路、下一步去哪里,全由开发者的代码决定,不是任何节点自己说了算。
谁在做「下一步去哪」这个决策?Agent 是 LLM 自己决定,Workflow 是开发者在代码里写死。
写死不代表没有自主决策性
Workflow 最大的优点是可预测、可控、好调试。你在代码里看到什么,它就做什么,不会有任何「惊喜」。生产环境里出了问题,你可以打断点逐步追,精确定位是哪个节点出了故障。这种确定性在线上系统里非常珍贵。
三者如何组合?
目前生产环境里最主流的模式是 「Agentic Workflow」 :用 Workflow 固定主流程的骨架,在需要灵活判断的节点嵌入 Agent,其余固定节点直接用 LLM 或 Tools。 骨架是确定的,让你能控制整体行为、便于调试;关键节点是灵活的,让你能应对各种复杂情况。
Anthropic 在他们的 Agent 工程实践中总结了几种常见的 Workflow 编排模式,值得了解一下。
第一种叫「Prompt Chaining」(提示链),就是把一个大任务拆成多个小步骤,前一步的输出作为后一步的输入,像流水线一样串起来。
第二种叫「Routing」(路由),先用一个 LLM 做分类判断,然后根据分类结果把请求分发到不同的处理分支,客服系统的例子就是典型的路由模式。
第三种叫「Parallelization」(并行化),把可以同时进行的子任务并行执行,最后汇总结果,这在需要多维度分析的场景下特别有用,比如同时从多个数据源检索信息。
第四种叫「Orchestrator-Workers」(编排者-工人),一个中央编排者负责分配任务,多个 Worker 各自完成子任务,适合任务可以分解但子任务之间相互独立的场景。
还有一种非常实用但经常被忽略的模式叫「Evaluator-Optimizer」(评估者-优化者)。
它的核心思路是:一个 LLM 负责生成输出,另一个 LLM(或者同一个模型换一个角色)负责评估这个输出的质量,如果评估不通过就把反馈给回生成者,让它改进后重新输出,如此循环直到评估通过或者达到最大重试次数。
这个模式特别适合对输出质量要求很高的场景,比如生成营销文案、撰写法律条款、编写代码等等。它的本质其实就是把「人类审稿-修改」的过程自动化了,用 LLM 来充当那个「审稿人」。不过要注意的是,评估标准必须在代码里定义清楚(比如用一个打分函数来判断是否通过),不能让评估者自由发挥,否则评估本身的质量也不可控。
了解哪些其他的 Agent 设计范式?Agent 和 Workflow 的区别是什么?
我理解 Agent 和 Workflow 最核心的区别是「谁来决定下一步」。Workflow 是我提前把流程写死的,每一步怎么走都是固定的,确定性高、好控制;Agent 是让 LLM 自己决定下一步做什么,灵活但不可控。
常见的设计范式除了纯 Agent 之外,还有 ReAct、Plan-and-Execute、Reflection 这几种。
我在实际工程里用得最多的反而是把两者混用,固定流程的部分用 Workflow,需要灵活决策的节点嵌入 Agent 能力,这样既保住了整体可控,又有局部的灵活性。
三种设计范式
- ReAct( Reasoning + Acting)
它的名字直接说明了它的核心机制:把推理(Reasoning)和行动(Acting)交替进行。具体来说,ReAct 的每一轮循环由三个步骤组成,形成一个完整的 Thought -> Action -> Observation 循环。
Thought 阶段,LLM 先把当前的情况分析一遍,把推理过程写出来,比如「用户想查竞品信息,我应该先用搜索工具查一下竞品 A 的最新动态」;Action 阶段,LLM 根据思考的结论决定调用哪个工具、传什么参数;Observation 阶段,工具返回的结果被反馈给 LLM,它读取这个结果,然后进入下一轮 Thought,重新分析当前局面、决定接下来怎么做。
为什么要把这三步显式地分开?因为如果让模型直接输出行动,它经常会「冲动决策」,比如还没搞清楚用户到底要什么就急着调工具。加了 Thought 环节之后,模型会先把问题理清楚,推理过程写出来了,决策质量自然就稳定多了。而且 Thought 的内容是可见的,出了问题你可以直接看它是在哪一步想歪了,调试起来方便很多。这个循环会不断重复,直到 LLM 在某轮 Thought 中判断「信息已经够了,可以给出最终答案」,整个 Agent 才停下来。
不过 ReAct 也有一个明显的短板:它是「走一步看一步」的模式,每一步都是局部最优决策,处理特别复杂的、需要全局规划的任务时,容易在中间迷失方向。比如一个需要十几步才能完成的研究任务,ReAct 可能做到第五步就忘了最初的目标是什么,或者反复在几个工具之间打转。
- Plan-and-Execute
它把规划和执行彻底分开,先让一个 LLM 专门做规划,输出一个完整的步骤列表,然后由另一个 LLM(或同一个模型以不同角色)逐步执行。
规划和执行解耦之后,好处是复杂任务的整体结构非常清晰,你甚至可以在执行前让人工审核一下计划是否合理。
这里有一个非常关键的机制需要特别说一下:动态重规划。很多人对 Plan-and-Execute 的理解停留在「先做一个计划,然后死板地执行」,这其实是不对的。
成熟的 Plan-and-Execute 实现里,每执行完一步都会把结果反馈给规划器,规划器会判断:当前的执行结果和预期一致吗?后续的计划还适用吗?需不需要调整?如果发现某一步的结果和预期严重偏离,规划器会修改后续的步骤,甚至插入新的步骤来应对。
这种「计划是活的、会根据执行结果动态调整」的能力,让 Plan-and-Execute 既保持了全局视野,又不会因为死板而失效。缺点是多了规划和重规划的 LLM 调用,延迟和成本都会增加,而且如果初始规划本身的方向就做错了,后面不管怎么调整执行细节都很难挽回。
- Reflection(反思)
在前两种范式的基础上加了一层「质量保障」。
它的做法是在 Agent 完成一步或者完成整个任务之后,再让一个 LLM(可以是同一个模型也可以是专门的评估模型)来判断做得好不好、结果是否符合预期。如果评估不通过,就重试或者换一种策略。这个机制能显著提升输出质量,尤其是在代码生成、文案写作这类「质量要求高但一次做对很难」的场景下效果特别明显。
Reflection 有一个非常值得关注的变体叫 Reflexion。它和基础 Reflection 的区别在于,Reflexion 不只是简单地说「这个结果不好,重做一遍」,而是会生成一段具体的「反思总结」,记录下这次失败的原因和改进建议,然后把这段总结作为额外的上下文传给下一次尝试。
你可以把它理解成「写错题本」,不是简单地重做一遍,而是先分析错在哪了、下次该注意什么,然后带着这些经验教训再做一次。
这个机制的效果是有数据支撑的:在 HumanEval 代码生成基准测试上,GPT-4 直接做的准确率大约是 80%,加上 Reflexion 之后提升到了 91%,这个提升幅度是非常可观的。不过代价也很直接,每加一轮反思就多一次甚至多次 LLM 调用,token 消耗和延迟都会增加,你需要在「质量提升」和「成本增加」之间做取舍。
Agent 推理模式有哪些?ReAct 是啥?具体是怎么实现的?
Agent 的推理模式我用过几种。最基础的是直接输出答案,没有中间推理;CoT 是让 LLM 先把推理过程写出来再给答案,准确率更高;还有就是 ToT,思维树,先分散思维,然后选择最优路径推进。
第一,ReAct 是在 CoT 基础上加了「行动」,让 LLM 交替输出思考和工具调用,每次行动后再根据结果继续思考,形成一个循环。本质是「思考 -> 行动 -> 观察」的循环,推理过程显式化,又能动态调用外部工具,解决了 CoT 只能纯文字推理的局限
第二,这个循环是由代码框架驱动的,模型每次只输出 Thought + Action,你的代码负责解析、执行工具、把 Observation 填回历史,再把完整历史传给模型进入下一轮。
ReAct 有两个实战局限:循环漂移和错误传播
循环漂移简单来说就是陷入不可预测的死循环之中
错误传播就是 ReAct 的每一步决策都建立在前面所有步骤的结果之上,如果中间某一步拿到了错误的信息,或者工具返回了一个有误的结果,后面所有的推理都会被这个错误带跑。
Plan-and-Execute 是怎么通过「先规划再执行」来解决 ReAct 的漂移问题的,先规划可以让模型有全局意识,缓解在具体细节上被误导和陷入循环
实际项目中两者经常混合使用(规划用大模型、执行用小模型)
CoT
CoT,全称 Chain of Thought(思维链)
第一种叫 Zero-shot CoT,做法非常简单,直接在 prompt 末尾加上「让我们一步步思考」这句话就行了,LLM 会自己展开推理过程,不需要你提供任何示例。这种方式的优势是零成本、即插即用,缺点是 LLM 的推理格式和深度完全靠它自己发挥,不太稳定,有时候会写得很详细,有时候又跳步。
第二种叫 Few-shot CoT,你需要在 prompt 里给几个带有完整推理过程的例子,让 LLM 照着这个格式来模仿。比如你先写一道数学题,把每一步怎么算、最后得出什么结论都写清楚,LLM 看到这个模板之后就会按照同样的格式展开推理。Few-shot 的效果更稳定,特别适合输出格式要求比较固定的场景,代价是需要你提前准备高质量的示例,而且示例本身也会占用 token。
ReAct、Plan-and-Execute、Reflection 三种范式有什么核心区别?实际项目中该如何选型?
我理解这三者是 Agent 开发里最主流的三种设计范式,核心区别在于「决策和执行的关系」。
ReAct 是边想边干,走一步看一步,单步迭代实时调整,灵活度最高;
Plan-and-Execute 是先想全再干,先定完整计划再分步执行,适合长流程复杂任务,不容易跑偏;
Reflection 不是独立的完整流程,而是给前两者加的「检查修正 buff」,用来提升输出质量。
实际选型就看三个维度:任务复杂度、流程确定性、输出质量要求,新手入门首选 ReAct,复杂任务用 Plan-and-Execute,高要求场景再加 Reflection。
高级范式
- 动态 Replan
它解决的是 Plan-and-Execute 的一个核心痛点:计划定死了,中途遇到意外怎么办?
比如你规划了五步来写竞品分析报告,执行到第三步发现某个竞品已经被收购了,原来的分析框架需要调整,但计划已经定好了,后面的步骤还是按老计划跑,输出的报告就会有问题。
动态 Replan 的做法是在每个步骤执行完之后,把当前结果和剩余计划一起交给规划模块,让它判断「原来的计划还合理吗,需不需要调整」。如果需要,就生成一份新的剩余步骤计划,替换掉原来的。
这样既保留了 Plan-and-Execute「先规划再执行」的结构优势,又不会因为计划太僵硬而在意外情况下翻车。代价是每步都多了一次「重新评估计划」的 LLM 调用,token 消耗会增加。
- Reflexion
它把 Reflection 的「自我反思」推到了更深的层次。普通的 Reflection 是「做完了检查一遍、发现问题就重做」,有点像考试做完检查一遍。
Reflexion 在这个基础上多做了一件关键的事:它不仅检查输出对不对,还会把每次失败的原因总结成一段「经验教训」,存进记忆里,下次再遇到类似任务时,这段教训会作为上下文传给 LLM,让它避免重蹈覆辙。
这个机制有点像你做错了一道数学题,不只是改答案,还会在错题本上写「这类题容易漏掉符号变化,下次要特别注意」,下次遇到同类题时翻一下错题本再动笔。
选型指南
讲完了三者和进阶机制,选型的逻辑其实很清晰。
任务不复杂、流程不固定、需要实时调整的,直接用 ReAct,够用就好,别搞复杂的。任务很长、容易跑偏、需要整体结构清晰的,上 Plan-and-Execute,先把计划定清楚再执行。如果执行过程中经常遇到意外需要调整计划,就加上动态 Replan。输出要求高、不能出错的,在前两者基础上叠加 Reflection 做自我检查。如果还需要跨任务积累经验、避免重复犯错,就用 Reflexion 把失败教训沉淀下来。
实际项目中还有一种非常常见的混合用法:规划阶段用 Plan-and-Execute 的思路定好全局计划,每一步的执行用 ReAct 的循环来处理(因为单步执行可能也需要多轮工具调用),最后对整体输出做一次 Reflection 检查质量。这种三层嵌套的架构听起来复杂,但其实在 LangGraph 这类框架里实现起来很自然,很多生产级的 Agent 系统都是这么搭的。
最容易踩的坑是学了这些范式就全堆在一起,又要规划、又要反思、又要 Replan、又要积累经验,结果系统又复杂又慢,还容易出奇怪的 bug。工程开发永远是「够用就好」,先把最基础的 ReAct 玩明白,再根据实际需求往上加,别为了炫技搞过度工程化。
复杂任务怎么做的任务拆分?为什么要拆分?效果如何提升?
我理解任务拆分的原因是 LLM 一次性处理太复杂的任务很容易出错,把大任务拆成小步骤,每步聚焦一件事,准确率会明显提升。
拆分方式主要有两种:一种是静态拆分,提前把步骤写死;另一种是动态拆分,让 LLM 自己根据目标规划步骤,更灵活但也更难控制。
拆完之后步骤之间可能有依赖关系,我的经验是把能并行的步骤并发跑,端到端延迟可以降很多,有时能降 40% 到 60%。
任务拆分
为什么要拆分?
- context window 大小有限制,能同时处理的信息量有上限
如何拆分?
静态拆分是你提前把任务流程设计好,固定成一个确定的 Workflow,每一步是什么、按什么顺序执行,全部事先写死。好处是行为完全可预测,出了问题知道是哪一步的问题,好排查;坏处是灵活性低,遇到你没设计进流程的情况就容易卡住。
动态拆分则是把「任务拆解」这件事本身也交给 LLM 来做。你给它一个目标,让它先输出一个执行计划,再按计划一步步执行,这是 Plan-and-Execute 模式的核心思想。
能并行就并行,DAG 图。
自适应拆分:LLM 一次做不好,需要再拆细一些。或者反过来,某一步其实很简单,拆得太细反而浪费了调用次数。
Replan 机制
Replan 机制就是在每个步骤执行完之后,把当前步骤的结果和剩余的计划一起交给规划模块,让它判断「基于当前的新信息,后面的计划还合理吗」。如果合理就继续执行,如果不合理就生成一份新的剩余步骤计划。这个机制保证了计划始终和实际情况同步,不会出现「死守一份过时计划」的尴尬。
代价是每步都多了一次「评估计划」的 LLM 调用,token 消耗会增加。实践中的折中做法是:不是每步都触发 Replan,而是设置触发条件,比如当某步的输出和预期差异很大时,或者当步骤执行失败时,才启动 Replan。这样既能应对意外,又不会无谓地增加消耗。
验收标准
第一个是「完备性」,也就是所有步骤加在一起,能不能覆盖原始任务的全部要求,有没有遗漏。比如用户说「帮我写一份竞品分析报告,包含市场份额、产品功能对比和定价策略三个维度」,你拆出来的步骤里必须每个维度都有对应的步骤在负责,少了任何一个都算拆分不完备。检查方法很直接:把所有步骤的描述拼在一起,和原始任务描述做逐项对照,看有没有某个要求在任何步骤里都没被提到。
第二个是「独立性」,也就是每个步骤的职责边界是不是清晰,有没有两个步骤在做同一件事,或者某个步骤的输出和另一个步骤的输出有重叠。
第三个是「可验证性」,也就是每个步骤执行完之后,能不能用一个简单的标准判断它做对了没有。这一点在实际项目中特别容易被忽视,但它直接决定了你能不能做自动重试和质量把控。比如你拆了一个步骤叫「搜索竞品 A 的定价信息」,如果没有完成标准,执行完之后你只能人工看一眼判断做得好不好。但如果你在拆分时就定义了「输出中必须包含价格数字和计费模式(按量/包月/免费增值)」,执行完之后自动检查输出是否包含这两个要素就行了,缺了就自动触发重试。
请你介绍一下 AI Agent 的记忆机制,并说明在实际开发中应该如何设计记忆模块?
Agent 需要记忆才能在多步任务中保持状态、跨任务积累知识。
记忆机制分四层:
感知记忆(当前输入的原始内容)
短期记忆(context window 里的对话历史)
长期记忆(存在外部数据库、语义检索召回)
实体记忆(结构化提取的关键事实)。
实际设计时要解决三个核心问题:存什么、怎么存、什么时候取出来用,根据信息类型选合适的存储方式,再搭配主动检索和按需检索两种策略使用。
四个记忆机制
- 第一层:感知记忆(Sensory Memory)
这是最短暂的一层,就是「当前这次调用的原始输入」,用户发来的这条消息、上传的截图、传入的文档。它的生命周期只有一次调用,处理完就消失,不会主动保留。类比到人的话,就是你刚听到的一句话,如果没有主动去记,几秒后就忘了。感知记忆就是这个「刚进来还没处理」的原始感知,它存在的意义是给模型提供一个「入口」来接收外部信息。
- 第二层:短期记忆(Short-term Memory)
这是 context window 里的 messages 列表,维持着当前任务执行过程中的完整状态,包括用户说了什么、模型输出了什么、工具调用返回了什么。只要任务还在进行,这些信息就都在;任务结束(对话关闭),这块记忆就清空了。你可以把它想象成你的「工作台」,桌上摆着的都是正在处理的东西。工作台有大小限制(token 上限),放满了就得清一清。工作台的特点是「随时可见」,不需要去翻箱倒柜地「找」,直接读就行。
- 第三层:长期记忆(Long-term Memory)
这是跨任务保留的信息,存在外部数据库里,通常是向量数据库、关系数据库或 Key-Value 存储。任务结束了,信息不会消失,下次需要时去检索拿回来用。你可以把它理解成你的「档案室」,东西放进去不会丢,但要用的时候需要主动去翻。长期记忆的关键技术是向量数据库,它支持「语义检索」:你不需要知道存的时候用了什么关键词,只要意思相近就能检索到相关内容。这比精确匹配灵活得多,比如你存的是「用户不喜欢冗长的注释」,用「代码风格偏好」去查也能找到它。
长期记忆其实不是铁板一块,它还可以细分成三种子类型,每种存的东西和用途都不一样。
第一种是「情节记忆」(Episodic Memory),存的是具体的事件经历。比如「上周二用户让我写了一个 Python 爬虫,中间遇到了反爬问题,最后用 Selenium 解决了」,这是一段完整的任务经历,包含了时间、场景、过程和结果。情节记忆的价值在于,当 Agent 遇到类似的新任务时,可以检索出历史上的相似经历,参考上次是怎么解决的,避免重复踩坑。
第二种是「语义记忆」(Semantic Memory),存的是从多次经历中提炼出来的通用知识和规律。比如经历了好几次反爬问题之后,Agent 沉淀出一条规律:「当目标网站有 JavaScript 动态渲染时,requests 库抓不到内容,应该优先考虑 Selenium 或 Playwright」。这不再是某一次具体的事件记录,而是跨多次经验总结出来的抽象知识。语义记忆的信息密度更高,检索时也更容易命中,因为它直接存储的就是结论而不是过程。
第三种是「程序记忆」(Procedural Memory),存的是怎么做某件事的操作流程。比如「部署一个 Flask 应用的标准步骤:创建虚拟环境 -> 安装依赖 -> 配置 gunicorn -> 设置 nginx 反向代理 -> 启动服务」,这是一套可以直接复用的操作 SOP。程序记忆在处理重复性任务时特别有用,Agent 不需要每次都从头推理,直接调出对应的 SOP 执行就行,既快又稳。
三种子类型各有侧重,实际项目中通常会混合使用。情节记忆提供具体的参考案例,语义记忆提供抽象的知识规律,程序记忆提供可复用的操作流程,三者配合起来才能让 Agent 的长期记忆真正好用。
- 第四层:实体记忆(Entity Memory)
这层比长期记忆更精炼,它不是存原文,而是把对话中出现的关键实体和事实主动提取出来,存成结构化字段。比如「用户偏好 Python」「客户预算是 5 万」「项目截止日是 3 月底」,这些是从对话里提炼出来的「结论」,而不是原始对话本身。类比到人的话,就像医生的病历卡,不是把问诊录音存起来,而是结构化地记录「主诉:头痛三天;诊断:偏头痛;用药:布洛芬」。信息密度高,查询快,而且不受原始表述方式影响。
Agent 的长短期记忆系统怎么做的?记忆是怎么存的?粒度是多少?怎么用的?
我理解记忆系统分两层。
短期记忆就是 context window 里的对话历史,存当前任务的中间状态,任务结束就清掉;长期记忆用向量数据库存,把信息 embedding 后写入,用的时候做语义检索拿回来注入 prompt。
粒度上我通常按「一次完整交互」或「一个关键事件」为单位存,太细碎检索噪音大,太粗糙又丢失细节,这个需要根据业务实际调整。
长短期记忆
- 短期记忆
先说短期记忆,它就是你每次调 LLM 时传进去的 messages 列表。你可以把它想象成 LLM 当前的「工作台」,桌面上摆着当前任务的所有相关内容:用户的指令、LLM 自己的思考过程、工具调用的结果、每一步的中间状态。LLM 靠这张桌面知道「我在做什么、做到哪了、前面几步发现了什么」。
- 结构化工作记忆
结构化工作记忆的思路是,给这个「工作台」划出几个固定区域,比如一个区域专门放「当前任务目标」,一个区域放「已确认的中间结论」,一个区域放「待验证的假设」。每一步执行完之后,Agent 不只是把新消息追加到列表末尾,而是主动更新对应区域的内容,把过时的中间结论替换掉,把已验证的假设移到确认区。
这样做的好处是,即使对话很长,Agent 的工作台始终是结构清晰的,不会被一堆杂乱的历史消息淹没,LLM 每次读到的都是当前最准确的任务状态。
- 长期记忆
长期记忆的核心工具是向量数据库(Vector Database)加上 Embedding(向量化),对初学者来说这两个词可能很陌生,先解释清楚。
- 记忆衰减
这里还有一个容易忽略的问题:记忆衰减。人的记忆会随着时间淡化,Agent 的长期记忆其实也应该有类似的机制。
想象一下,用户半年前说「我最近在学 Go」,但最近三个月的所有对话都是关于 Python 的,如果 Agent 不做衰减,下次检索到那条旧记忆还按「用户在学 Go」来处理,就会很违和。
常见的做法是给每条记忆加一个「新鲜度权重」,检索排序时同时考虑语义相似度和时间新鲜度,越久远的记忆权重越低。另一种做法是定期让 LLM 审查长期记忆库,把过时的、矛盾的记忆标记为失效或者合并更新,保持记忆库的「健康状态」。
什么是 Multi-Agent?
多智能体系统(Multi-Agent)就是多个 Agent 协作完成任务,每个 Agent 各有分工,有的负责搜索、有的负责写代码、有的负责做评审。
我理解单个 Agent 主要受两个限制:一是 context 窗口大小,复杂任务信息量一多就撑爆了;二是单点能力,什么都让一个 Agent 做,每件事都是泛才。
Multi-Agent 通过专业分工和并行执行,能处理更复杂、更长流程的任务,同时,如果复杂任务使用并行执行优化,多个 Worker 同时跑,整体效率有实质提升。
Multi-agent
Multi-Agent 之间的协作方式主要有三种模式。
第一种是顺序流水线(Sequential Pipeline),Agent A 做完把结果交给 Agent B,B 做完交给 Agent C,就像工厂流水线一样,每个环节依次处理。
第二种是并行扇出(Fan-out),一个调度者把多个独立子任务同时分发给不同的 Worker Agent,它们各自并行执行,最后由调度者收集汇总。
第三种是辩论/评审模式(Debate/Review),多个 Agent 对同一个问题各自给出方案,然后由一个裁判 Agent 或者它们互相评审来筛选最优解,这种模式在需要高质量决策的场景特别有用,比如代码评审、方案选型。
说说 Single-Agent 和 Multi-Agent 的设计方案?
Single-Agent 适合任务流程清晰、复杂度适中的场景,实现简单、好维护;Multi-Agent 适合需要专业分工、任务量大(context 不足以支持任务)或者需要并行执行的复杂场景。
Multi-Agent 架构上主要有两种拓扑:中心化的 Orchestrator 模式,由一个主 Agent 统一调度各个 Worker;去中心化的 Peer-to-Peer 模式,Agent 之间直接通信。
我在工程里用中心化用得更多,因为好控制、好调试,出问题链路清晰。
Multi-Agent 中心化方案
Multi-Agent 的中心化方案,核心是一个叫 Orchestrator 的特殊角色。「Orchestrator」直译是「交响乐指挥」,在 Multi-Agent 系统里,它的中文可以理解成「总调度员」或「项目经理」。它是整个系统里最特殊的那个 Agent,因为它不做任何具体工作,它只负责三件事:读懂用户的大目标、把它拆成一个个子任务;判断每个子任务该交给哪个 Worker Agent 去做;收集每个 Worker 的产出,把它们拼成最终答案。
Orchestrator 其实有几种变体,适合不同复杂度的场景。
最基础的是静态路由(Static Router),任务拆分和分配规则是预先定义好的,比如「遇到代码任务交给 Coder Agent,遇到搜索任务交给 Researcher Agent」,逻辑简单可预测。
进阶一点的是动态规划(Dynamic Planner),Orchestrator 本身是一个 LLM,它会根据用户输入动态生成任务计划,决定需要几个步骤、每步交给谁,计划本身也可以在执行过程中调整。
最复杂的是自适应编排(Adaptive Orchestration),Orchestrator 不仅动态规划,还会根据 Worker 的执行结果实时调整后续计划,比如 Researcher 搜回来的信息不够,Orchestrator 会追加一轮搜索任务,而不是硬着头皮往下走。
实际项目里,大多数场景用动态规划就够了,自适应编排虽然更强大但调试复杂度也高很多。
去中心化方案:为什么「听起来更灵活」却很少在工程上用
去中心化的思路是没有总调度,多个 Agent 通过共享的消息队列或状态空间自行协商、直接通信。听起来很美好,像一个能自我组织的团队,不需要领导,大家自动配合,还更灵活。
但实际工程里会遇到什么问题?用一个具体场景来说明。
假设三个 Agent 在处理同一个任务:Agent A 在搜索信息,Agent B 也在搜索类似的信息,Agent C 负责汇总结果,但没有人统筹调度。这时候几个问题会同时出现:首先,没有人告诉 A 和 B 「你们各搜什么范围」,很可能两个人搜了大量重叠的内容,做了重复工作;其次,C 需要等 A 和 B 都搜完才能汇总,但没有人告诉 C「A 和 B 什么时候算搜完了」,C 不知道该等多久,也不知道有没有漏掉某个 Agent 的结果;再者,如果 A 中途出错了,没有中央调度者收到错误通知,B 和 C 可能还在正常运行,最后汇总出来的是一份不完整的结果,但系统甚至不知道这里出了问题。
总结下来,去中心化系统里这几类问题会频繁出现:任务分配没有协调、执行顺序没有保证、失败没有感知、没有人来确认「任务整体完成了」。类比一个没有项目经理的团队:每个人都很能干,但没有人协调时间节点和接口,最后交出来的可能是互不兼容的结果,而且没有人知道整体进度到底怎么样了。
这就是为什么去中心化方案更多停留在学术研究里探索,研究的是「AI 系统能不能实现自主协调」这个更宏观的问题。而生产环境里,几乎所有正经项目都选 Orchestrator 模式,因为可控、可追踪、出了问题能排查,这才是工程上真正需要的。
Agent 记忆压缩通常有哪些方法?
记忆压缩常见有四种方法:摘要压缩、滑动窗口、重要性过滤、结构化抽取。
摘要压缩是把长对话总结成简短摘要;滑动窗口是只保留最近 N 轮对话;重要性过滤是打分筛选,只留重要内容;结构化抽取是把关键信息抽成结构化数据存起来。
我在实际项目里最常用的是摘要压缩和滑动窗口,而且经常组合用,滑动窗口丢弃前先做一次摘要,尽量不丢重要信息。
滑动窗口
滑动窗口是最符合直觉的做法,就像手机聊天记录默认只显示最近 200 条:超出就从最老的开始删,只保留最近 N 轮对话。
好处是实现极其简单,不需要任何额外的 LLM 调用,也没有额外开销。坏处是「硬截断」,对话内容按时间一刀切,三周前确认的关键决策和昨天随口说的一句话,在这个方案里是被同等对待的,超出窗口就都消失了。
可以用一个词概括它的特性:「金鱼记忆」。它只记得最近发生的事,越往前越模糊,再久一点就什么都没了。对于短对话、或者历史信息不重要的场景,这个方案足够用,成本最低。
摘要压缩
摘要压缩是对滑动窗口「硬截断」的改进。核心思路是:不直接丢弃即将超出窗口的历史,而是先让 LLM 把这段历史总结成一段精华摘要,用摘要替换原始对话,再继续往前。
代价是摘要会丢失细节。LLM 在总结时,会按照自己判断的「重要性」来决定保留什么、省略什么。有些细节当时看起来不重要、被摘要略过了,后来却刚好需要,这时候就找不回来了。
这个方案单独用时,通常的做法是「旧的压缩成摘要,近的保持完整」,最近几轮对话往往和当前任务关系最密切,保持原文;更早的历史相关性低,压缩成摘要。
进阶一点的做法是层级式摘要(Hierarchical Summarization)。不是对所有旧历史做一次性摘要,而是分层处理:最近 10 轮保持原文,10 到 50 轮的历史压缩成一份「中期摘要」,50 轮之前的历史进一步压缩成更精炼的「长期摘要」。
每一层的信息密度不同,越久远的越精炼,但核心决策和关键结论始终被保留。这有点像公司的会议纪要体系:今天的会议有详细的逐条记录,上个月的会议只留要点摘要,去年的只留关键决策备忘。
层级式摘要的好处是,Agent 既能精确回忆近期细节,也能粗略回忆远期要点,比一刀切的摘要颗粒度更合理。
在实际工程里,这两种方法通常一起用,而不是单独用其中一种。滑动窗口负责控制对话历史的总长度上限,摘要压缩负责在历史被丢弃之前做一次提炼,把关键信息留下来。这样既有长度控制,又不是直接硬截断,是目前最常见的工程方案
重要性过滤,按价值筛选,不按时间筛选
滑动窗口和摘要压缩有一个共同的思路:都是在「时间维度」处理历史,按照发生的先后顺序来决定保留什么。但时间不等于重要性。三周前的一句关键决策,可能远比昨天的几句闲聊更有价值,但在滑动窗口里它会先被丢掉。
重要性过滤换了一个角度,按内容的实际价值来决定去留:给每条对话记录打一个重要性分数,低于阈值的淘汰,高分的保留。
打分的方式有两种。
一种是规则打分:包含「决定」「确认」「需求」等关键词的记录加分,被后续对话引用次数多的加分,纯闲聊降分。规则快、没有额外开销,但比较粗糙,边界情况容易判断失误。
另一种是让 LLM 来打分:逐条判断每条记录的重要程度。准确率更高,但每条记录都需要一次 LLM 调用,开销大,通常在批量清理历史时做,而不是实时处理每条消息。
其他方法:
- 观察遮蔽
还有一种更激进的重要性过滤思路叫观察遮蔽(Observation Masking)。它的做法不是删除低分内容,而是在构造 prompt 时选择性地「隐藏」某些历史条目。
比如当前任务是写代码,Agent 会把之前关于需求讨论的对话标记为「与当前步骤无关」,构造 prompt 时直接跳过这些条目,只把和代码相关的历史传进去。任务进入测试阶段时,再把测试相关的历史「显示」出来,代码实现的细节对话则被遮蔽。
这样做的好处是信息没有被真正删除,只是在不同阶段动态选择「当前最需要看到什么」,既节省了 token,又避免了不可逆的信息丢失。
- 主动压缩
另一个值得了解的概念是主动压缩(Proactive Compression)。前面说的所有方法都是被动触发的,等 context 快满了才开始压缩。主动压缩的思路是,Agent 在每一步执行完之后,主动判断哪些中间过程可以压缩。
比如 Agent 调用了一个搜索工具,返回了 2000 token 的原始搜索结果,Agent 在读完之后立刻把搜索结果压缩成 200 token 的要点摘要,替换掉原始内容。这样 context 的增长速度从一开始就被控制住了,而不是等到快满了才临时抱佛脚。
主动压缩特别适合工具调用频繁的 Agent,因为工具返回的原始数据往往很长,但真正有用的信息只占一小部分。
结构化抽取,换一种载体存信息
前三种方法有一个共同的前提假设:历史信息最好以「对话文本」的形式保留。结构化抽取的思路完全不同,它先问一个更本质的问题:我们真的需要保留对话文本本身吗?
很多场景里,真正有价值的不是对话文字,而是对话中传递的事实和状态。比如「用户偏好用 Python」「预算上限是 5 万」「已确认方案 B」「需要兼容移动端」。把这些信息主动提取出来,存成结构化字段,后续注入 prompt 时直接用这些字段,比传一大段对话文本要高效得多,信息密度也高得多。
这种方案的信息损失最小,只要字段定义合理,重要信息全部被精确保留,没有摘要带来的模糊化。代价是开发成本最高:你需要预先定义「什么是重要字段」,这需要对业务场景有深入理解,而且不同类型的任务所需的字段可能完全不同,通用性较低。
感觉和长期记忆的存取有关联?
这四种方法不是互斥的,也不是按优劣排列的,而是从三个不同维度来解决问题的。
滑动窗口和摘要压缩解决的是「历史太长,怎么截」的问题,前者直接截,后者截之前先提炼。重要性过滤解决的是「内容不等价,怎么挑」的问题,打破时间顺序,按价值筛选。结构化抽取解决的是「对话文本本身是不是最佳载体」的问题,换一种更高效的形式来存储信息。
这三个维度可以组合:比如先用重要性过滤筛掉低价值内容,再用摘要压缩处理剩余历史,同时对特定类型的关键信息做结构化抽取。实际系统里,往往是多种方法配合使用的。
Prompt Caching
理解它之前,先知道一个背景:LLM 每次处理请求,都需要把输入的所有 token「过一遍模型」来做计算,这个过程叫 prefill,是延迟和成本的主要来源之一。一个常见的场景是:你有一段固定的 system prompt 加上越来越长的对话历史,每次调用时这段历史都会被重新计算一遍,哪怕它和上一次调用时完全一样。
Prompt Caching 的思路是:如果 prompt 的前缀部分在多次请求之间是一样的,就把这部分的计算结果缓存起来,下次请求如果前缀匹配,直接复用缓存,不重新计算。费用和延迟都大幅降低,某些场景下能降到原来的十分之一。
这和前面的记忆压缩是两个不同层次的优化。记忆压缩在「信息层」工作,决定哪些内容值得被保留在对话历史里;Prompt Caching 在「计算层」工作,对已经决定要带进去的内容减少重复计算的开销。两者解决的不是同一个问题,可以同时使用,是互补关系,不是替代。
在工程实践中,为什么有时候选择「手搓」Agent,而不是直接用成熟框架?
我的感受是框架用起来快,封装好,有很多优点:
- 比如 LangChain,功能很全,上手快,工具注册、ReAct loop、记忆管理都帮你封装好了,开发效率高很多
但有几个实际痛点。
第一是抽象层太多,调试的时候不知道哪步出了问题,得一层层往下扒;
第二是版本升级经常有破坏性变更,线上稳定性难保证;
第三是框架的通用设计往往和具体业务需求有偏差,定制起来反而更费劲。
手搓的代码完全在自己掌控之内,可观测性好、出问题好排查,也更方便做性能优化。所以我现在的策略是核心逻辑手写,只在边缘功能上用框架的工具。
如何赋予 LLM 规划能力?
给 LLM 加规划能力主要靠这几种思路。
CoT 是让 LLM 把推理步骤写出来,线性地一步步推导到答案;
ToT 是让它同时探索多条推理路径,选最优的继续深入;
GoT 是图结构推理,推理节点可以复用和合并,适合更复杂的任务。
工程上我用 CoT 最多,因为实现成本最低,就是改个 prompt;ToT 效果更好但调用次数多,成本大概是 3 到 5 倍;GoT 目前还比较学术,生产环境我没见过有人真正落地用的。
CoT、ToT、GoT 说的都是「怎么让 LLM 把推理过程做得更好」,但在真实的 Agent 项目里,还有一种更贴近工程实践的规划模式,叫做 Plan-and-Execute(先规划再执行)。
这个模式的思路很直白:面对一个复杂任务,先让 LLM 制定一份完整的执行计划,把任务拆成若干步骤,然后一步一步执行,每完成一步就检查一下进度,必要时调整后续计划。你可以把它理解成「先写大纲再动笔」的写作方式,而不是拿到题目就开始一口气往下写。
三者差异
- CoT
CoT 的全称是 Chain of Thought(思维链),核心思路极其简单:在 prompt 里加一句「请一步步思考」,LLM 就会把推理过程逐步写出来,而不是直接蹦出答案。
- ToT
ToT 的全称是 Tree of Thoughts(思维树),针对的正是 CoT「一旦走错就全错」的问题。
核心改变是把「生成一条推理链」变成「同时探索多条推理路径,边探索边剪枝,最终选出最优路径」。用一个生活类比来理解:CoT 像你做题时只想了一个解法,一路做到底;ToT 像你先想了三种可能的解题思路,评估了一下哪种最靠谱,选了最好的那条继续深入,另外两条直接放弃。
ToT 的执行流程可以分三步来理解。
首先是生成多个候选思路,让 LLM 针对同一个问题给出 3 个不同的初步方向,而不是只走一条路。
然后是评估每个思路的可行性,用另一个 LLM 调用(或同一个 LLM 带上评估 prompt)给每个思路打分,判断哪个最有希望。
最后是选优继续深入、剪掉差的,只保留分数高的思路,再展开下一层推理,反复循环直到得出最终答案。
这个「生成 -> 评估 -> 剪枝」的循环,让 LLM 不再是「一条道走到黑」,而是有了探索多条路、选好的走、发现走错了还能回头的能力。代价也很明显:原来 CoT 一次生成就搞定,ToT 需要多次 LLM 调用(多条路径 × 多层深度 × 每层还要评估)。具体多几倍要看路径数和搜索深度:典型设置(每层 3 条路径、搜 2-3 层)下成本通常是 CoT 的 3-5 倍;极端场景(深搜、更多路径、每步都打分)可能到 10 倍以上。
- GoT
ToT 虽然引入了多路径探索,但它是树形结构,不同分支之间完全独立,两条推理路径上的中间结论无法互相借用。GoT 把推理结构换成了图,允许不同路径的中间结果合并、复用,也就是说一个推理节点可以接收来自多个前置节点的输出作为输入。
GoT 的图结构允许「多个中间结论合并输入到下一步」的操作在图里是一等公民,表达起来非常自然。
GoT 能建模的推理模式比 ToT 更丰富,也更接近人类实际处理复杂任务的思考方式。但落地复杂度很高,目前主要还是学术研究场景,生产环境里极少见到真正用起来的。
讲讲 Agent 的反思机制?为什么要用反思?具体怎么实现?
反思机制我的理解是:让 Agent 在完成一个步骤或整个任务后,自我评估输出质量,判断有没有问题,不达标就重试或调整策略。
用反思的原因是 LLM 第一次输出不一定是最优的,加一轮自我检查能显著提升质量,相当于人写完东西自己再看一遍。
代价是多至少一次 LLM 调用,token 消耗和延迟都会增加,所以我在工程里通常只在质量要求高的关键节点启用反思,不是每步都做。
核心循环
反思机制的核心思路来自 Self-Refine 论文(Madaan 等人 2023 年提出),整个流程就是「生成 -> 评估 -> 改进」的循环。
这个循环靠两个 prompt 来驱动。第一个负责评估,让 LLM 扮演「检查者」的角色,专门去找问题:
任务:{task}当前输出:{current_output}请评估以上输出:
1. 有没有事实错误或逻辑问题?
2. 有没有遗漏重要内容?
3. 表达是否清晰准确?
如果输出已经足够好,回复「PASS」;
否则指出具体问题并给出改进建议。这个评估 prompt 的设计有几个值得注意的地方。
首先,它给出了明确的检查维度(事实、逻辑、完整性、表达),而不是让 LLM 自由发挥。这很重要,没有方向的评估往往流于表面,LLM 可能只是说「输出看起来不错」,没有真正找到问题。给出具体维度,它才会有针对性地逐项审查。
其次,「PASS」机制是必须有的,这是给 LLM 一个「足够好就停」的出口。如果没有这个机制,LLM 为了反思而反思,可能对一个已经很好的输出挑不必要的小毛病,反而把原本对的东西改错。
如果评估结果不是 PASS,就把评估意见喂进第二个改进 prompt:
原始任务:{task}
当前输出:{current_output}
评估意见:{reflection}
请根据评估意见改进输出:改进 prompt 有一个关键点:它同时传入了原始任务、原始输出、评估意见这三样东西,缺任何一个都会让改进变得盲目。只有任务没有原始输出,LLM 不知道在什么基础上改;只有原始输出没有评估意见,LLM 不知道改哪里;只有评估意见没有任务,LLM 可能改着改着偏离了原始目标。三者都在,它才能有针对性地修改,而不是把内容全部重写一遍。
两个 prompt 循环调用,直到 LLM 自己回复 PASS,或者超过最大轮次强制退出,整个外层逻辑不过是一个普通的 for 循环。
两个粒度:步骤级 vs 任务级
- 步骤级
步骤级反思是在每个工具调用或推理步骤完成后立即检查。它的好处是错误早发现早纠正,不会让一个小错误在后续步骤里层层放大。
想象一下 Agent 在做多步信息检索:第一步选了一个不精准的搜索关键词,后续所有步骤都在错误的信息上继续,到最后才发现,前面的工作全废了。
步骤级反思能在第一步就发现关键词的问题,马上纠正,后续步骤都建立在正确基础上。适合这种粒度的场景是步骤之间强依赖、前一步错了后面会全错的任务。代价是每一步都多一次 LLM 调用,整体延迟和 token 消耗会大幅增加,一个 10 步的任务可能实际要调用 20 次 LLM。
- 任务级
任务级反思是整个任务执行完之后做一次整体评估。好处是开销更小,整个任务只多一次 LLM 调用;而且从整体视角审视,能发现步骤级看不到的问题,各个步骤单独看都是对的,但整体结论前后矛盾,或者各部分之间衔接不自然,这种问题只有从整体视角才能看出来。
代价是如果任务中途某步出了大问题,到最后才发现,前面的执行都已经浪费了。适合步骤之间相对独立、最终输出的整体质量更重要的场景,比如生成一份报告。
多 Agent 互评
除了单 Agent 的自我反思,还有一种效果通常更好的方式,多 Agent 互评:专门设置一个独立的 Critic Agent,让它来审查执行 Agent 的输出。
单 Agent 自我反思时,评估者和生成者是同一个模型,它在生成输出时形成的一套「内部逻辑」,做评估时也会沿用这套逻辑,对自己输出的错误不够敏感,容易陷入「自洽」。而独立的 Critic Agent 没有这种包袱,它的唯一职责就是「找问题」,视角更客观,更容易发现执行 Agent 自己看不出来的漏洞。
互评的具体流程是:执行 Agent 生成输出,Critic Agent 审查并给出具体批注,执行 Agent 根据批注修改,Critic Agent 再次确认。
进阶:Reflexion 和 LATS,把反思做得更深
前面讲的 Self-Refine 是最基础的反思模式,学术界在此基础上还有更进一步的探索,了解这些能帮你在面试里展现更深的理解。
- Reflexion
第一个是 Reflexion(Shinn 等人 2023 年提出,和 Self-Refine 是同年的工作),这篇论文的核心思路是:不仅让 Agent 反思当前输出的质量,还要让它把「失败经验」存下来,下次遇到类似任务时直接参考,避免重蹈覆辙。这里的"类似"通常通过把经验记忆塞到当前任务的上下文里,让 LLM 自己在生成时参考(而不是靠严格的相似度匹配去检索)。
你可以理解成 Self-Refine 是「写完作文当场改」,Reflexion 是「把这次犯的错记在笔记本上,下次写作文之前先翻一遍笔记」。
Reflexion 引入了一个「经验记忆」的概念,每次反思产生的教训会被存储起来,作为后续任务的参考上下文。这个思路在需要重复执行类似任务的场景里特别有价值,比如一个代码生成 Agent,第一次写出了有 bug 的代码,反思后不仅修好了这次的 bug,还把「这类 bug 的成因和避免方法」记下来,下次生成类似代码时就不太容易犯同样的错。
- LATA
第二个是 LATS(Language Agent Tree Search,Zhou 等人 2024 年提出),它把反思和树搜索结合了起来。前面讲规划能力时提到过 ToT(思维树),LATS 的思路是把蒙特卡洛树搜索(MCTS)和反思结合起来:通过 MCTS 同时探索多条路径,每条路径执行之后都会做评估和反思,反思结果作为经验反馈给后续的路径探索。这样一来,Agent 不仅能同时探索多条路径,还能从已经走过的路径里学到教训,让后续的探索更有针对性。代价当然也更大,既有多路径的成本又有反思的成本,目前主要还是学术研究场景,还没看到成熟的生产级实现。
- 辩论式反思
还有一种思路叫辩论式反思,不是让一个 Agent 自己审查自己,而是让多个 Agent 互相辩论。比如设置一个「正方 Agent」和一个「反方 Agent」,正方提出一个方案,反方专门挑毛病、提反对意见,正方再针对反对意见优化方案。这种对抗式的反思比单方面审查更能暴露深层问题,因为反方的「职责」就是找漏洞,它会比一个只是「检查一下有没有问题」的 Critic Agent 更积极地挖掘问题。工程上偶尔会在高质量要求的场景里用到这个模式,比如重要的商业决策分析、法律文本审查等
如何设计多 Agent 的协作与动态切换机制?
多 agent 协作靠两件事:消息传递和共享状态。
消息传递是 Agent 完成自己的工作后把结果发出去,下一个 Agent 取用;核心在于解耦,发送方不需要知道接收方是谁;适合 Agent 较为独立的业务场景。
共享状态是所有 Agent 共同读写一个状态对象,记录任务进展和中间结果。适合各步骤依赖关系明确的流水线型任务。
同时,Agent 的动态切换有 Orchestrator 和 Handoff 等等方式,但是 Orchestrator 是主流,路由有两种方式:
一种是静态路由,提前写好规则「任务类型 A 就找 Agent X」;
另一种是让 LLM 动态决策,根据当前情况实时判断该把任务交给谁。
我的实践是两种混用,主流程用静态路由保证稳定,边缘情况才交给 LLM 动态判断。
消息传递
你可以把多 Agent 系统想象成一个公司里的多个部门:研究部、开发部、测试部各司其职。部门之间传递信息,有两种方式。
第一种方式,像发邮件。研究部完成了资料整理,就把报告「发」出去,开发部收到邮件后再开始工作。这就是「消息传递」的思路,Agent 完成自己的工作后把结果发送到一个消息队列,下游的 Agent 订阅自己感兴趣的消息,取到了再开始处理。这种方式最大的优点是解耦,研究 Agent 不需要知道谁在等它的结果,只管发;接收方也不需要知道消息是谁发的,只管处理。缺点是需要一个「邮件服务器」,也就是消息中间件来维护这套机制,部署成本稍高一些。
第二种方式,像共享白板。公司里所有部门都盯着同一块白板,上面写着「当前任务是什么、进展到哪一步了、各部门完成了什么」。研究部写上「资料整理完成」,开发部一看,知道可以开始了,于是接手并写上「代码开发中」。这就是「共享状态」的思路,所有 Agent 都读写同一个状态对象。LangGraph 就是用这个思路来设计的,它有一个贯穿所有 Agent 的 State,每个 Agent 执行完就往 State 里写入自己的结果,下一个 Agent 直接从 State 里读取前面的产出。
状态管理设计原则
既然提到了共享状态,这里有必要展开聊一下状态管理的设计,因为这是多 Agent 系统里最容易出 bug 的地方之一。
为什么状态管理这么重要?你想,多个 Agent 都在读写同一个状态对象,如果设计不好,很容易出现一个 Agent 写入的结果被另一个 Agent 意外覆盖,或者读到了一半更新的脏数据。这就像公司那块共享白板,如果没有任何规则,两个人同时往白板上写东西,写完之后谁也看不懂。
工程上设计共享状态时有几个关键点需要考虑。
首先是状态结构要分层,通常会把状态分成「全局状态」和「局部状态」两层。全局状态存放所有 Agent 都需要读取的信息,比如用户的原始请求、当前任务进展、最终输出,这些是共享的。
局部状态存放每个 Agent 自己的中间结果,比如搜索 Agent 找到的候选文档列表、代码 Agent 生成的草稿代码,这些在 Agent 内部使用,不会直接暴露给其他 Agent,避免信息污染。
其次是写入规则要明确。最简单也最可靠的做法是「只追加不覆盖」,每个 Agent 完成工作后把结果追加到状态里,而不是修改已有的字段。LangGraph 的 State 更新机制就是这个思路,你定义好 State 的 schema,每个节点返回的是一个「增量更新」,框架帮你合并到全局状态里,这样就不会出现互相覆盖的问题。
最后是错误状态的处理。如果某个 Agent 执行失败了,它的错误信息也应该写入状态,而不是悄悄吞掉。后续的 Agent 或者 Orchestrator 读到这个错误状态后,才能做出正确的决策,比如跳过这一步、换一个 Agent 重试、或者直接终止任务。
Orchestrator 路由决策
「切换」就是决定下一步把任务交给哪个 Agent,这个决策动作在系统里叫做「路由」。Orchestrator 就是那个负责做路由决策的角色。
路由有两种策略。
- 静态路由
就是提前把规则写死。比如任务描述里包含「搜索」就找 Researcher Agent,当前步骤已经是「代码写完了」就找 Reviewer Agent,找不到匹配规则就回到 Orchestrator 兜底。
这就像工厂流水线,每道工序完成后,下一步去哪个工位是固定的,效率高、可预测、好调试。但它覆盖不了你没预料到的情况,如果任务走了一条你没定义规则的路径,系统就不知道该怎么办了。
- 动态路由
则是把「下一步找谁」的决策权交给 LLM 来做。Orchestrator 把当前任务描述、已经完成了什么、还有哪些 Agent 可以调用,全部告诉 LLM,让它判断「现在应该叫哪个 Agent 来做下一步」。
这种方式的优点是灵活,能处理任何你没预先设计的路径,任务走到一个边缘情况时,LLM 也能做出合理判断。缺点是每次路由都要多一次 LLM 调用,增加了延迟和成本,而且 LLM 偶尔也会路由错,系统行为的可预测性就降低了。