1. 从五条动态里拆出来的工程信号10 月 7 日那天,我关注的几个技术社区里集中冒出来五条动态,主题各不相同,但放在一起看,指向的是同一件事:Agent 这套东西,正在从"演示能跑"往"工程能交付"的阶段走。这五条动态分别涉及任务编排、工具调用协议、记忆管理、可观测性、以及多 Agent 协作的边界划分。单看每一条都像是某个团队在解决自己的局部问题,但拼起来就是一张工程栈的草图。我自己做 Agent 相关项目差不多两年,从最早的"一个 prompt 加几个 if-else"到现在要管十几个 Agent 的状态流转,踩过的坑基本能对应上这五条动态里的每一个点。所以这篇文章我不打算逐条复述那五条动态说了什么,而是把它们当成五个切面,聊聊 Agent 工程栈到底是怎么成形的,每一层在解决什么问题,以及如果你现在要动手搭一套,哪些地方可以抄作业、哪些地方必须自己踩一遍。先说清楚这篇文章适合谁看。如果你只是用现成的对话产品做点问答,那这里的内容对你帮助有限。但如果你正在或者准备把 Agent 往生产环境推,需要处理任务拆解、工具调度、上下文管理、故障排查这些事,那这篇应该能帮你少走一些弯路。我会尽量把每个环节的"为什么"讲透,参数和步骤能给具体的就给具体的,给不了具体的会说明判断依据。核心关键词我先摆出来:任务编排、工具调用、记忆管理、可观测性、多 Agent 协作。这五个词基本覆盖了当前 Agent 工程栈的主要分层,后面每个章节会围绕其中一个展开,最后再讲它们之间怎么咬合。2. 任务编排:Agent 工程栈的地基2.1 为什么编排是第一个要解决的问题五条动态里有一条专门讲任务编排,我一点都不意外。Agent 和普通 LLM 调用最大的区别,就是它要"做一串事"而不是"答一句话"。一旦涉及多步骤,第一个冒出来的问题就是:这些步骤谁来定、按什么顺序走、中间失败了怎么办。我最早的做法是把步骤写死在代码里,比如"先查资料、再总结、再生成报告",三个函数串起来。这种做法在流程固定的时候没问题,但一旦用户输入稍微变一下,整个链路就崩了。后来改成让模型自己规划步骤,又遇到新问题:模型规划出来的步骤经常不可执行,或者执行到一半发现前置条件不满足。所以任务编排这一层,本质上要解决的是规划与执行的解耦。规划可以交给模型,但执行必须由确定性的调度器来管。我现在的做法是:模型输出一个结构化的任务图,调度器负责按图执行,每个节点执行完把结果回填,调度器再决定下一个节点走哪个分支。2.2 编排器的三种常见形态从我这边的实践看,编排器大致分三种形态,各有适用场景。第一种是线性链式,就是 A 完了走 B,B 完了走 C。这种最简单,适合步骤固定、分支少的场景,比如"提取信息、校验格式、写入数据库"。优点是调试容易,缺点是灵活性差。第二种是有向无环图(DAG),节点之间可以有多个依赖关系,调度器按拓扑序执行。这种适合步骤之间有并行可能的场景,比如"同时查三个数据源,都回来了再汇总"。实现上可以用现成的图调度库,也可以自己写一个简单的依赖解析。第三种是状态机,每个节点是一个状态,状态之间的转移由条件决定。这种适合需要循环、重试、回退的场景,比如"生成内容、检查质量、不合格就回到生成、合格就输出"。状态机的实现复杂度最高,但表达能力最强。我一般建议从线性链式起步,遇到并行需求再升级到 DAG,只有确实需要循环和回退时才上状态机。过早引入复杂编排,调试成本会吃掉大部分开发时间。2.3 编排中的参数与超时设计编排器里有一类参数特别容易被忽略,就是超时和重试。我见过不少项目,单个工具调用设了超时,但整个任务链路没有总超时,结果一个任务卡在某一步,把整个队列堵死。我的做法是给每个节点设三个时间参数:单次调用超时、节点总超时(含重试)、任务总超时。单次调用超时一般设 30 秒到 2 分钟,取决于工具类型;节点总超时设单次超时的 3 倍左右,给重试留空间;任务总超时根据业务容忍度设,一般不超过 10 分钟。重试策略也要分情况。对于网络抖动这类瞬时故障,指数退避重试 2 到 3 次是合理的。但对于"参数错误"这类确定性失败,重试没有意义,应该直接走失败分支。我踩过的坑是早期对所有失败都无脑重试,结果一个参数错误的任务重试了五次,浪费了大量调用额度。提示:编排器里最好加一个"最大步数"限制,防止模型规划出无限循环的任务图。我一般设 20 步,超过就强制终止并记录日志。3. 工具调用:Agent 的手脚怎么接3.1 工具描述的质量决定调用成功率五条动态里有一条讲工具调用协议,这个点我太有感触了。很多人以为工具调用失败是模型能力问题,其实大部分时候是工具描述写得不好。工具描述包括名称、功能说明、参数说明三部分。名称要短且语义明确,比如search_docs比do_search好,因为前者说明了搜什么。功能说明要写清楚"什么时候用这个工具",而不只是"这个工具做什么"。参数说明要给类型、是否必填、取值范围,最好给一个示例值。我做过一个对比测试:同一个工具,描述写得含糊时调用成功率大概六成,描述写清楚后能到九成以上。差距主要来自模型对"该不该调这个工具"的判断,描述里写清楚适用场景,模型就不会乱调。3.2 工具返回值的结构化处理工具调用还有一个容易翻车的地方是返回值处理。如果工具返回的是一大段自然语言,模型解析起来很容易出错。我的做法是让工具尽量返回结构化数据,比如 JSON,然后在编排层做一次校验和裁剪,只把模型需要的字段传给它。举个例子,查询接口返回 20 个字段,但模型只需要其中 3 个。如果全传过去,一是浪费上下文,二是干扰模型判断。我会在工具和模型之间加一层适配器,负责字段筛选和格式转换。这层适配器看起来是额外工作,但它把工具的不确定性和模型隔离开了,后期换工具时模型侧几乎不用改。3.3 工具调用的错误分类与处理工具调用失败分几类,处理方式完全不同。错误类型典型表现处理方式参数错误缺少必填参数、类型不对不重试,返回错误信息让模型修正权限错误无权限访问资源不重试,记录日志并告警瞬时故障超时、连接中断指数退避重试 2-3 次业务错误资源不存在、状态冲突视情况,一般返回给模型决策限流触发频率限制等待后重试,配合退避这张表是我从实际故障里总结出来的,早期我把所有错误都当瞬时故障处理,结果参数错误也重试,白白浪费调用。后来做了错误分类,重试逻辑才合理起来。注意:工具调用的日志一定要记录完整的入参和出参,但要注意脱敏。我见过因为日志里带了敏感信息导致的问题,排查故障时反而成了隐患。4. 记忆管理:Agent 的上下文怎么管4.1 短期记忆与长期记忆的分工五条动态里讲记忆管理的那条,核心观点是记忆要分层。我完全同意。Agent 的记忆大致分两类:短期记忆是当前任务执行过程中的上下文,长期记忆是跨任务积累的知识。短期记忆的管理相对简单,就是控制上下文长度。但这里有个坑:不是所有历史消息都值得保留。我的做法是按重要性打分,工具调用的原始返回、中间推理过程这些,如果已经提炼成结论了,就可以从上下文里移除,只保留结论。长期记忆就复杂多了。它涉及存什么、怎么存、怎么取三个问题。存什么取决于业务,一般存事实性知识和用户偏好。怎么存可以用向量库,也可以用结构化数据库,看检索需求。怎么取是难点,检索不准的话,长期记忆反而会干扰当前任务。4.2 上下文窗口的分配策略上下文窗口是有限资源,怎么分配直接影响 Agent 表现。我一般按这个比例分:系统提示占 10%,长期记忆检索结果占 20%,短期对话历史占 40%,当前任务相关文档占 30%。这个比例不是固定的,任务类型不同要调整。比如做文档问答时,当前文档的占比要提到 50% 以上,因为答案主要来自文档。做多轮对话时,历史占比要提高,否则 Agent 会忘记前面说过什么。分配策略确定后,还要有裁剪机制。当某一部分超预算时,按什么规则裁剪?我的规则是:系统提示不动,长期记忆按相关度从低到高裁,短期历史按时间从远到近裁,当前文档按段落相关度裁。裁剪前最好做一次摘要,把裁掉的内容压缩成一句话保留,这样信息损失最小。4.3 记忆检索的常见问题记忆检索最容易出的问题是"检索到了但不相关"。向量检索基于语义相似度,但语义相似不等于任务相关。我遇到过检索出一堆语义相近但实际没用的记忆,反而挤占了上下文。解决办法是加一层重排序。先用向量检索召回一批候选,再用一个小的重排序模型按任务相关度排序,取 top-k。重排序模型可以用交叉编码器,也可以用规则打分。我用规则打分的场景比较多,比如给"最近使用过的记忆"加分,给"和当前任务类型匹配的记忆"加分,效果比纯向量检索好不少。还有一个问题是记忆冲突。同一个事实,长期记忆里存了两个版本,检索时都召回了,模型不知道该信哪个。我的做法是给记忆加时间戳和置信度,冲突时优先用时间近、置信度高的。如果两个记忆置信度接近,就把冲突暴露给模型,让它自己判断,同时在日志里记一笔,方便后续人工核查。5. 可观测性:Agent 跑起来之后怎么知道它在干嘛5.1 为什么 Agent 的可观测性和普通服务不一样五条动态里有一条专门讲可观测性,这个点被单独拎出来讲,说明它确实是个痛点。普通服务的可观测性主要看指标、日志、链路追踪三件套。Agent 的可观测性要复杂一层,因为它的行为是不确定的,同样的输入可能走不同的路径。我现在的做法是在三件套基础上加一个"决策轨迹"。每次 Agent 做决策,不管是选择工具、规划步骤还是生成内容,都把决策依据记下来。这样出问题时,我能回放整个决策过程,看到底是哪一步的判断偏了。决策轨迹的记录粒度要把握好。记太细,日志量爆炸;记太粗,排查时信息不够。我的经验是记三个层次:任务级记录整体目标和最终结果,步骤级记录每步的输入输出和选择理由,调用级记录工具调用的完整参数和返回。平时看任务级和步骤级,出问题时下钻到调用级。5.2 关键指标该盯哪些Agent 的指标体系和普通服务有重叠也有差异。我列一下我这边重点盯的指标。指标类别具体指标关注原因成功率任务完成率、步骤成功率反映整体健康度效率平均步数、平均耗时、工具调用次数反映是否走了弯路质量重试率、人工干预率反映输出质量成本token 消耗、工具调用成本反映经济性异常超时率、错误率、循环检测触发次数反映稳定性这些指标里,我特别关注"平均步数"和"重试率"。平均步数突然上升,往往意味着模型规划能力下降或者工具出了问题。重试率上升,可能是工具不稳定,也可能是模型对工具的理解出了偏差。这两个指标是早期预警信号,比等任务失败率上升再排查要主动得多。5.3 日志与追踪的落地细节日志这块,我踩过的最大坑是日志格式不统一。早期各个模块各记各的,排查时要在好几个地方拼信息。后来统一了日志格式,每条日志必须带任务 ID、步骤 ID、时间戳、模块名、日志级别、消息体。这样用任务 ID 一搜,整个链路的日志就串起来了。追踪方面,我用的是 span 的方式,每个步骤一个 span,记录开始时间、结束时间、状态、关键属性。span 之间用父子关系连接,形成调用树。这样一眼就能看出哪一步耗时最长、哪一步失败了。提示:Agent 的日志里最好记录模型的原始输出,哪怕它最终没被采用。我遇到过好几次模型输出了正确内容但被后续逻辑覆盖的情况,没有原始输出根本查不出来。6. 多 Agent 协作:什么时候该拆,什么时候不该拆6.1 多 Agent 的适用边界五条动态里最后一条讲多 Agent 协作,这个话题争议最大。我的观点是:多 Agent 不是越多越好,大部分场景单 Agent 加工具就够了。多 Agent 真正有价值的场景有两类。一类是任务本身可以自然分解成不同角色,比如一个负责规划、一个负责执行、一个负责审核,角色之间有明确的职责边界。另一类是任务需要不同能力,比如一个 Agent 擅长代码、一个擅长文案,需要它们配合完成一个综合任务。如果只是任务步骤多,那用单 Agent 加编排就够了,没必要拆成多个 Agent。拆成多个 Agent 后,Agent 之间的通信成本、状态同步成本、调试成本都会上升。我见过为了"看起来架构先进"而拆多 Agent 的项目,最后维护成本高得离谱。6.2 Agent 之间的通信协议如果确实要用多 Agent,通信协议是第一个要定的事。常见的有三种:共享内存、消息传递、黑板模式。共享内存是多个 Agent 读写同一块状态,实现简单但容易出竞态问题。消息传递是 Agent 之间发消息,解耦好但需要定义消息格式和路由规则。黑板模式是有一个公共区域,Agent 往里写和读,适合松耦合场景。我用消息传递比较多,因为职责边界清晰。消息格式我一般定义成{from, to, type, payload, timestamp},type 区分是请求、响应还是通知。路由规则用编排器统一管,Agent 不直接找对方,都通过编排器转发,这样链路清晰,也方便加日志。6.3 多 Agent 的常见故障模式多 Agent 系统有几类典型故障,我列一下。第一类是死锁,两个 Agent 互相等对方的消息。预防办法是设超时,等不到就报错退出,不要无限等。第二类是消息风暴,Agent 之间来回发消息停不下来。预防办法是设消息数量上限,超过就强制终止。第三类是责任不清,出了问题不知道是哪个 Agent 的锅。预防办法是每个 Agent 的输出都要带明确的来源标识,日志里也要记清楚。第四类是状态不一致,多个 Agent 对同一份状态的认知不同。预防办法是状态变更走统一入口,不要各改各的。这四类故障我在不同项目里都遇到过,最麻烦的是死锁,因为排查时系统看起来是"卡住"而不是"报错",需要看消息轨迹才能定位。7. 五层怎么咬合:一套可参考的工程栈结构7.1 分层结构与依赖关系把前面五层拼起来,Agent 工程栈大致是这样的结构:最底层是工具调用,往上是记忆管理,再往上是任务编排,多 Agent 协作是编排的扩展,可观测性横跨所有层。依赖关系上,编排层依赖工具层和记忆层,多 Agent 层依赖编排层,可观测层被所有层依赖。这个依赖方向很重要,不能反过来。比如工具层不应该依赖编排层,否则工具就没法复用了。我见过把编排逻辑写进工具里的做法,结果工具和特定任务绑死,换个任务就得重写工具。正确的做法是工具保持纯粹,只负责"做一件事",编排逻辑放在编排层。7.2 数据流与控制流数据流和控制流要分开设计。数据流是信息在层之间怎么传,控制流是决策在层之间怎么走。数据流上,我一般用统一的数据结构在层之间传递,包含任务上下文、当前状态、历史记录。每层读取自己需要的部分,写入自己产生的部分。这样层之间耦合低,换一层实现不影响其他层。控制流上,编排层是决策中心,其他层是被调用方。工具层被调用时执行并返回,记忆层被调用时检索或存储,可观测层被动记录。多 Agent 场景下,编排层升级成协调者,负责在多个 Agent 之间路由。7.3 从零搭建的推荐路径如果你现在要从零搭一套,我建议按这个顺序来。第一步,先把工具层做扎实。定义清楚工具的描述规范、返回格式、错误分类。这一步做不好,后面全是坑。第二步,加一个最简单的线性编排器,能串起几个工具就行。先跑通端到端,别急着上复杂编排。第三步,加记忆管理。先做短期记忆的上下文裁剪,跑一段时间有感觉了再加长期记忆。第四步,加可观测性。这一步不能省,而且要尽早加。没有可观测性,后面排查问题全靠猜。第五步,根据实际需求决定要不要上多 Agent。大部分场景到第四步就够了。这个路径的好处是每一步都有可运行的产出,不会出现"搭了半个月还没跑通"的情况。我自己就是这么一步步过来的,中间也走过弯路,比如一开始就想上多 Agent,结果基础没打好,返工了好几次。8. 实操中踩过的坑与排查技巧8.1 编排层的典型问题编排层最常见的问题是步骤规划不合理。模型规划出来的步骤要么太粗,一个步骤里塞了太多事;要么太细,把简单操作拆成好几步。我的调优办法是在系统提示里给几个规划示例,让模型照着示例的粒度来。示例不用多,三五个就够,关键是覆盖不同类型的任务。另一个问题是分支条件写错。编排器里的条件判断如果写得不严谨,会导致走错分支。我的做法是条件判断尽量用结构化数据,不要用自然语言。比如判断"上一步是否成功",用step.status == 'success',不要用模型去理解"上一步看起来成功了"。8.2 记忆层的典型问题记忆层最常见的问题是检索噪音。检索出来的记忆里混了很多不相关的,干扰模型判断。我的解决办法前面提过,加一层重排序。另外还可以给记忆加标签,检索时按标签过滤,减少噪音。还有一个问题是记忆过期。有些记忆存的时候是对的,过一段时间就失效了,但检索时还是会召回。我的做法是给记忆设有效期,过期自动降权或归档。有效期长短看业务,事实性知识可以长一些,状态性信息要短一些。8.3 可观测层的典型问题可观测层的问题是日志太多或太少。太多会淹没关键信息,太少会漏掉排查线索。我的经验是按日志级别分层,正常流程记 INFO,异常记 WARN 和 ERROR,调试信息记 DEBUG 且默认关闭。排查时按需打开 DEBUG。还有一个问题是追踪断链。跨进程或跨服务的调用,如果 trace ID 没传好,链路就断了。我的做法是在任务开始时生成一个全局 trace ID,所有调用都带上,包括工具调用和模型调用。这样不管跨多少层,都能串起来。8.4 常见问题速查表现象可能原因排查方向任务卡住不动死锁、超时未设看消息轨迹、检查超时配置步数异常多规划不合理、循环看决策轨迹、检查循环检测工具调用失败率高描述不清、参数错误看工具日志、检查描述质量输出质量下降上下文污染、记忆冲突看上下文构成、检查记忆检索成本突然上升重试过多、上下文膨胀看重试率、检查上下文长度响应变慢工具慢、模型慢看各步骤耗时、定位瓶颈这张表是我从实际故障里整理出来的,基本覆盖了八成以上的常见问题。排查时按表里的方向走,能省不少时间。提示:排查 Agent 问题时,第一步永远是看决策轨迹,而不是看最终输出。最终输出只是结果,决策轨迹才能告诉你为什么是这个结果。9. 一些个人体会做 Agent 工程这两年,我最大的体会是:Agent 的复杂度不在模型,在工程。模型能力再强,如果编排、工具、记忆、可观测性这些没做好,系统照样跑不起来。反过来,模型能力一般,但工程做扎实了,系统反而稳定可用。另一个体会是不要追求一步到位。我早期总想设计一个完美的架构,结果设计了两周还没写一行代码。后来改成先跑通最小闭环,再逐步迭代,效率高多了。Agent 这东西,很多问题只有跑起来才会暴露,纸上设计是设计不出来的。最后一个体会是可观测性要尽早做。我第一个 Agent 项目没做可观测性,出问题时全靠加日志重新跑,效率极低。后来每个项目都先把可观测性搭起来,虽然前期多花点时间,但后期排查问题的效率提升是数量级的。这套工程栈不是标准答案,只是我这边跑通的一条路径。不同业务场景可能需要调整,比如实时性要求高的场景,编排要更轻量;成本敏感的场景,记忆管理要更激进地裁剪。关键是理解每一层在解决什么问题,然后根据实际情况做取舍。
1. 从五条动态里拆出来的工程信号10 月 7 日那天,我关注的几个技术社区里集中冒出来五条动态,主题各不相同,但放在一起看,指向的是同一件事:Agent 这套东西,正在从"演示能跑"往"工程能交付"的阶段走。这五条动态分别涉及任务编排、工具调用协议、记忆管理、可观测性、以及多 Agent 协作的边界划分。单看每一条都像是某个团队在解决自己的局部问题,但拼起来就是一张工程栈的草图。我自己做 Agent 相关项目差不多两年,从最早的"一个 prompt 加几个 if-else"到现在要管十几个 Agent 的状态流转,踩过的坑基本能对应上这五条动态里的每一个点。所以这篇文章我不打算逐条复述那五条动态说了什么,而是把它们当成五个切面,聊聊 Agent 工程栈到底是怎么成形的,每一层在解决什么问题,以及如果你现在要动手搭一套,哪些地方可以抄作业、哪些地方必须自己踩一遍。先说清楚这篇文章适合谁看。如果你只是用现成的对话产品做点问答,那这里的内容对你帮助有限。但如果你正在或者准备把 Agent 往生产环境推,需要处理任务拆解、工具调度、上下文管理、故障排查这些事,那这篇应该能帮你少走一些弯路。我会尽量把每个环节的"为什么"讲透,参数和步骤能给具体的就给具体的,给不了具体的会说明判断依据。核心关键词我先摆出来:任务编排、工具调用、记忆管理、可观测性、多 Agent 协作。这五个词基本覆盖了当前 Agent 工程栈的主要分层,后面每个章节会围绕其中一个展开,最后再讲它们之间怎么咬合。2. 任务编排:Agent 工程栈的地基2.1 为什么编排是第一个要解决的问题五条动态里有一条专门讲任务编排,我一点都不意外。Agent 和普通 LLM 调用最大的区别,就是它要"做一串事"而不是"答一句话"。一旦涉及多步骤,第一个冒出来的问题就是:这些步骤谁来定、按什么顺序走、中间失败了怎么办。我最早的做法是把步骤写死在代码里,比如"先查资料、再总结、再生成报告",三个函数串起来。这种做法在流程固定的时候没问题,但一旦用户输入稍微变一下,整个链路就崩了。后来改成让模型自己规划步骤,又遇到新问题:模型规划出来的步骤经常不可执行,或者执行到一半发现前置条件不满足。所以任务编排这一层,本质上要解决的是规划与执行的解耦。规划可以交给模型,但执行必须由确定性的调度器来管。我现在的做法是:模型输出一个结构化的任务图,调度器负责按图执行,每个节点执行完把结果回填,调度器再决定下一个节点走哪个分支。2.2 编排器的三种常见形态从我这边的实践看,编排器大致分三种形态,各有适用场景。第一种是线性链式,就是 A 完了走 B,B 完了走 C。这种最简单,适合步骤固定、分支少的场景,比如"提取信息、校验格式、写入数据库"。优点是调试容易,缺点是灵活性差。第二种是有向无环图(DAG),节点之间可以有多个依赖关系,调度器按拓扑序执行。这种适合步骤之间有并行可能的场景,比如"同时查三个数据源,都回来了再汇总"。实现上可以用现成的图调度库,也可以自己写一个简单的依赖解析。第三种是状态机,每个节点是一个状态,状态之间的转移由条件决定。这种适合需要循环、重试、回退的场景,比如"生成内容、检查质量、不合格就回到生成、合格就输出"。状态机的实现复杂度最高,但表达能力最强。我一般建议从线性链式起步,遇到并行需求再升级到 DAG,只有确实需要循环和回退时才上状态机。过早引入复杂编排,调试成本会吃掉大部分开发时间。2.3 编排中的参数与超时设计编排器里有一类参数特别容易被忽略,就是超时和重试。我见过不少项目,单个工具调用设了超时,但整个任务链路没有总超时,结果一个任务卡在某一步,把整个队列堵死。我的做法是给每个节点设三个时间参数:单次调用超时、节点总超时(含重试)、任务总超时。单次调用超时一般设 30 秒到 2 分钟,取决于工具类型;节点总超时设单次超时的 3 倍左右,给重试留空间;任务总超时根据业务容忍度设,一般不超过 10 分钟。重试策略也要分情况。对于网络抖动这类瞬时故障,指数退避重试 2 到 3 次是合理的。但对于"参数错误"这类确定性失败,重试没有意义,应该直接走失败分支。我踩过的坑是早期对所有失败都无脑重试,结果一个参数错误的任务重试了五次,浪费了大量调用额度。提示:编排器里最好加一个"最大步数"限制,防止模型规划出无限循环的任务图。我一般设 20 步,超过就强制终止并记录日志。3. 工具调用:Agent 的手脚怎么接3.1 工具描述的质量决定调用成功率五条动态里有一条讲工具调用协议,这个点我太有感触了。很多人以为工具调用失败是模型能力问题,其实大部分时候是工具描述写得不好。工具描述包括名称、功能说明、参数说明三部分。名称要短且语义明确,比如search_docs比do_search好,因为前者说明了搜什么。功能说明要写清楚"什么时候用这个工具",而不只是"这个工具做什么"。参数说明要给类型、是否必填、取值范围,最好给一个示例值。我做过一个对比测试:同一个工具,描述写得含糊时调用成功率大概六成,描述写清楚后能到九成以上。差距主要来自模型对"该不该调这个工具"的判断,描述里写清楚适用场景,模型就不会乱调。3.2 工具返回值的结构化处理工具调用还有一个容易翻车的地方是返回值处理。如果工具返回的是一大段自然语言,模型解析起来很容易出错。我的做法是让工具尽量返回结构化数据,比如 JSON,然后在编排层做一次校验和裁剪,只把模型需要的字段传给它。举个例子,查询接口返回 20 个字段,但模型只需要其中 3 个。如果全传过去,一是浪费上下文,二是干扰模型判断。我会在工具和模型之间加一层适配器,负责字段筛选和格式转换。这层适配器看起来是额外工作,但它把工具的不确定性和模型隔离开了,后期换工具时模型侧几乎不用改。3.3 工具调用的错误分类与处理工具调用失败分几类,处理方式完全不同。错误类型典型表现处理方式参数错误缺少必填参数、类型不对不重试,返回错误信息让模型修正权限错误无权限访问资源不重试,记录日志并告警瞬时故障超时、连接中断指数退避重试 2-3 次业务错误资源不存在、状态冲突视情况,一般返回给模型决策限流触发频率限制等待后重试,配合退避这张表是我从实际故障里总结出来的,早期我把所有错误都当瞬时故障处理,结果参数错误也重试,白白浪费调用。后来做了错误分类,重试逻辑才合理起来。注意:工具调用的日志一定要记录完整的入参和出参,但要注意脱敏。我见过因为日志里带了敏感信息导致的问题,排查故障时反而成了隐患。4. 记忆管理:Agent 的上下文怎么管4.1 短期记忆与长期记忆的分工五条动态里讲记忆管理的那条,核心观点是记忆要分层。我完全同意。Agent 的记忆大致分两类:短期记忆是当前任务执行过程中的上下文,长期记忆是跨任务积累的知识。短期记忆的管理相对简单,就是控制上下文长度。但这里有个坑:不是所有历史消息都值得保留。我的做法是按重要性打分,工具调用的原始返回、中间推理过程这些,如果已经提炼成结论了,就可以从上下文里移除,只保留结论。长期记忆就复杂多了。它涉及存什么、怎么存、怎么取三个问题。存什么取决于业务,一般存事实性知识和用户偏好。怎么存可以用向量库,也可以用结构化数据库,看检索需求。怎么取是难点,检索不准的话,长期记忆反而会干扰当前任务。4.2 上下文窗口的分配策略上下文窗口是有限资源,怎么分配直接影响 Agent 表现。我一般按这个比例分:系统提示占 10%,长期记忆检索结果占 20%,短期对话历史占 40%,当前任务相关文档占 30%。这个比例不是固定的,任务类型不同要调整。比如做文档问答时,当前文档的占比要提到 50% 以上,因为答案主要来自文档。做多轮对话时,历史占比要提高,否则 Agent 会忘记前面说过什么。分配策略确定后,还要有裁剪机制。当某一部分超预算时,按什么规则裁剪?我的规则是:系统提示不动,长期记忆按相关度从低到高裁,短期历史按时间从远到近裁,当前文档按段落相关度裁。裁剪前最好做一次摘要,把裁掉的内容压缩成一句话保留,这样信息损失最小。4.3 记忆检索的常见问题记忆检索最容易出的问题是"检索到了但不相关"。向量检索基于语义相似度,但语义相似不等于任务相关。我遇到过检索出一堆语义相近但实际没用的记忆,反而挤占了上下文。解决办法是加一层重排序。先用向量检索召回一批候选,再用一个小的重排序模型按任务相关度排序,取 top-k。重排序模型可以用交叉编码器,也可以用规则打分。我用规则打分的场景比较多,比如给"最近使用过的记忆"加分,给"和当前任务类型匹配的记忆"加分,效果比纯向量检索好不少。还有一个问题是记忆冲突。同一个事实,长期记忆里存了两个版本,检索时都召回了,模型不知道该信哪个。我的做法是给记忆加时间戳和置信度,冲突时优先用时间近、置信度高的。如果两个记忆置信度接近,就把冲突暴露给模型,让它自己判断,同时在日志里记一笔,方便后续人工核查。5. 可观测性:Agent 跑起来之后怎么知道它在干嘛5.1 为什么 Agent 的可观测性和普通服务不一样五条动态里有一条专门讲可观测性,这个点被单独拎出来讲,说明它确实是个痛点。普通服务的可观测性主要看指标、日志、链路追踪三件套。Agent 的可观测性要复杂一层,因为它的行为是不确定的,同样的输入可能走不同的路径。我现在的做法是在三件套基础上加一个"决策轨迹"。每次 Agent 做决策,不管是选择工具、规划步骤还是生成内容,都把决策依据记下来。这样出问题时,我能回放整个决策过程,看到底是哪一步的判断偏了。决策轨迹的记录粒度要把握好。记太细,日志量爆炸;记太粗,排查时信息不够。我的经验是记三个层次:任务级记录整体目标和最终结果,步骤级记录每步的输入输出和选择理由,调用级记录工具调用的完整参数和返回。平时看任务级和步骤级,出问题时下钻到调用级。5.2 关键指标该盯哪些Agent 的指标体系和普通服务有重叠也有差异。我列一下我这边重点盯的指标。指标类别具体指标关注原因成功率任务完成率、步骤成功率反映整体健康度效率平均步数、平均耗时、工具调用次数反映是否走了弯路质量重试率、人工干预率反映输出质量成本token 消耗、工具调用成本反映经济性异常超时率、错误率、循环检测触发次数反映稳定性这些指标里,我特别关注"平均步数"和"重试率"。平均步数突然上升,往往意味着模型规划能力下降或者工具出了问题。重试率上升,可能是工具不稳定,也可能是模型对工具的理解出了偏差。这两个指标是早期预警信号,比等任务失败率上升再排查要主动得多。5.3 日志与追踪的落地细节日志这块,我踩过的最大坑是日志格式不统一。早期各个模块各记各的,排查时要在好几个地方拼信息。后来统一了日志格式,每条日志必须带任务 ID、步骤 ID、时间戳、模块名、日志级别、消息体。这样用任务 ID 一搜,整个链路的日志就串起来了。追踪方面,我用的是 span 的方式,每个步骤一个 span,记录开始时间、结束时间、状态、关键属性。span 之间用父子关系连接,形成调用树。这样一眼就能看出哪一步耗时最长、哪一步失败了。提示:Agent 的日志里最好记录模型的原始输出,哪怕它最终没被采用。我遇到过好几次模型输出了正确内容但被后续逻辑覆盖的情况,没有原始输出根本查不出来。6. 多 Agent 协作:什么时候该拆,什么时候不该拆6.1 多 Agent 的适用边界五条动态里最后一条讲多 Agent 协作,这个话题争议最大。我的观点是:多 Agent 不是越多越好,大部分场景单 Agent 加工具就够了。多 Agent 真正有价值的场景有两类。一类是任务本身可以自然分解成不同角色,比如一个负责规划、一个负责执行、一个负责审核,角色之间有明确的职责边界。另一类是任务需要不同能力,比如一个 Agent 擅长代码、一个擅长文案,需要它们配合完成一个综合任务。如果只是任务步骤多,那用单 Agent 加编排就够了,没必要拆成多个 Agent。拆成多个 Agent 后,Agent 之间的通信成本、状态同步成本、调试成本都会上升。我见过为了"看起来架构先进"而拆多 Agent 的项目,最后维护成本高得离谱。6.2 Agent 之间的通信协议如果确实要用多 Agent,通信协议是第一个要定的事。常见的有三种:共享内存、消息传递、黑板模式。共享内存是多个 Agent 读写同一块状态,实现简单但容易出竞态问题。消息传递是 Agent 之间发消息,解耦好但需要定义消息格式和路由规则。黑板模式是有一个公共区域,Agent 往里写和读,适合松耦合场景。我用消息传递比较多,因为职责边界清晰。消息格式我一般定义成{from, to, type, payload, timestamp},type 区分是请求、响应还是通知。路由规则用编排器统一管,Agent 不直接找对方,都通过编排器转发,这样链路清晰,也方便加日志。6.3 多 Agent 的常见故障模式多 Agent 系统有几类典型故障,我列一下。第一类是死锁,两个 Agent 互相等对方的消息。预防办法是设超时,等不到就报错退出,不要无限等。第二类是消息风暴,Agent 之间来回发消息停不下来。预防办法是设消息数量上限,超过就强制终止。第三类是责任不清,出了问题不知道是哪个 Agent 的锅。预防办法是每个 Agent 的输出都要带明确的来源标识,日志里也要记清楚。第四类是状态不一致,多个 Agent 对同一份状态的认知不同。预防办法是状态变更走统一入口,不要各改各的。这四类故障我在不同项目里都遇到过,最麻烦的是死锁,因为排查时系统看起来是"卡住"而不是"报错",需要看消息轨迹才能定位。7. 五层怎么咬合:一套可参考的工程栈结构7.1 分层结构与依赖关系把前面五层拼起来,Agent 工程栈大致是这样的结构:最底层是工具调用,往上是记忆管理,再往上是任务编排,多 Agent 协作是编排的扩展,可观测性横跨所有层。依赖关系上,编排层依赖工具层和记忆层,多 Agent 层依赖编排层,可观测层被所有层依赖。这个依赖方向很重要,不能反过来。比如工具层不应该依赖编排层,否则工具就没法复用了。我见过把编排逻辑写进工具里的做法,结果工具和特定任务绑死,换个任务就得重写工具。正确的做法是工具保持纯粹,只负责"做一件事",编排逻辑放在编排层。7.2 数据流与控制流数据流和控制流要分开设计。数据流是信息在层之间怎么传,控制流是决策在层之间怎么走。数据流上,我一般用统一的数据结构在层之间传递,包含任务上下文、当前状态、历史记录。每层读取自己需要的部分,写入自己产生的部分。这样层之间耦合低,换一层实现不影响其他层。控制流上,编排层是决策中心,其他层是被调用方。工具层被调用时执行并返回,记忆层被调用时检索或存储,可观测层被动记录。多 Agent 场景下,编排层升级成协调者,负责在多个 Agent 之间路由。7.3 从零搭建的推荐路径如果你现在要从零搭一套,我建议按这个顺序来。第一步,先把工具层做扎实。定义清楚工具的描述规范、返回格式、错误分类。这一步做不好,后面全是坑。第二步,加一个最简单的线性编排器,能串起几个工具就行。先跑通端到端,别急着上复杂编排。第三步,加记忆管理。先做短期记忆的上下文裁剪,跑一段时间有感觉了再加长期记忆。第四步,加可观测性。这一步不能省,而且要尽早加。没有可观测性,后面排查问题全靠猜。第五步,根据实际需求决定要不要上多 Agent。大部分场景到第四步就够了。这个路径的好处是每一步都有可运行的产出,不会出现"搭了半个月还没跑通"的情况。我自己就是这么一步步过来的,中间也走过弯路,比如一开始就想上多 Agent,结果基础没打好,返工了好几次。8. 实操中踩过的坑与排查技巧8.1 编排层的典型问题编排层最常见的问题是步骤规划不合理。模型规划出来的步骤要么太粗,一个步骤里塞了太多事;要么太细,把简单操作拆成好几步。我的调优办法是在系统提示里给几个规划示例,让模型照着示例的粒度来。示例不用多,三五个就够,关键是覆盖不同类型的任务。另一个问题是分支条件写错。编排器里的条件判断如果写得不严谨,会导致走错分支。我的做法是条件判断尽量用结构化数据,不要用自然语言。比如判断"上一步是否成功",用step.status == 'success',不要用模型去理解"上一步看起来成功了"。8.2 记忆层的典型问题记忆层最常见的问题是检索噪音。检索出来的记忆里混了很多不相关的,干扰模型判断。我的解决办法前面提过,加一层重排序。另外还可以给记忆加标签,检索时按标签过滤,减少噪音。还有一个问题是记忆过期。有些记忆存的时候是对的,过一段时间就失效了,但检索时还是会召回。我的做法是给记忆设有效期,过期自动降权或归档。有效期长短看业务,事实性知识可以长一些,状态性信息要短一些。8.3 可观测层的典型问题可观测层的问题是日志太多或太少。太多会淹没关键信息,太少会漏掉排查线索。我的经验是按日志级别分层,正常流程记 INFO,异常记 WARN 和 ERROR,调试信息记 DEBUG 且默认关闭。排查时按需打开 DEBUG。还有一个问题是追踪断链。跨进程或跨服务的调用,如果 trace ID 没传好,链路就断了。我的做法是在任务开始时生成一个全局 trace ID,所有调用都带上,包括工具调用和模型调用。这样不管跨多少层,都能串起来。8.4 常见问题速查表现象可能原因排查方向任务卡住不动死锁、超时未设看消息轨迹、检查超时配置步数异常多规划不合理、循环看决策轨迹、检查循环检测工具调用失败率高描述不清、参数错误看工具日志、检查描述质量输出质量下降上下文污染、记忆冲突看上下文构成、检查记忆检索成本突然上升重试过多、上下文膨胀看重试率、检查上下文长度响应变慢工具慢、模型慢看各步骤耗时、定位瓶颈这张表是我从实际故障里整理出来的,基本覆盖了八成以上的常见问题。排查时按表里的方向走,能省不少时间。提示:排查 Agent 问题时,第一步永远是看决策轨迹,而不是看最终输出。最终输出只是结果,决策轨迹才能告诉你为什么是这个结果。9. 一些个人体会做 Agent 工程这两年,我最大的体会是:Agent 的复杂度不在模型,在工程。模型能力再强,如果编排、工具、记忆、可观测性这些没做好,系统照样跑不起来。反过来,模型能力一般,但工程做扎实了,系统反而稳定可用。另一个体会是不要追求一步到位。我早期总想设计一个完美的架构,结果设计了两周还没写一行代码。后来改成先跑通最小闭环,再逐步迭代,效率高多了。Agent 这东西,很多问题只有跑起来才会暴露,纸上设计是设计不出来的。最后一个体会是可观测性要尽早做。我第一个 Agent 项目没做可观测性,出问题时全靠加日志重新跑,效率极低。后来每个项目都先把可观测性搭起来,虽然前期多花点时间,但后期排查问题的效率提升是数量级的。这套工程栈不是标准答案,只是我这边跑通的一条路径。不同业务场景可能需要调整,比如实时性要求高的场景,编排要更轻量;成本敏感的场景,记忆管理要更激进地裁剪。关键是理解每一层在解决什么问题,然后根据实际情况做取舍。