这两年跟多agent系统打交道多了,一个感受越来越强烈:单个agent是玩具,多个agent协作才是工程。说句实话,多agent系统是那种“听着很酷、做着很痛”的方向,市面上讲demo、讲概念的文章一大堆,但真正能落到生产环境、能承受线上流量和业务复杂度的方案,少之又少。我最近刚把我们内部一个工单分诊场景从单agent重构为多agent协作架构,整个过程走下来,从架构设计到治理体系,踩坑无数,也沉淀了一套自己用起来比较顺的方法论。这篇就把这些经验完整梳理一遍,给正在做多agent平台、或者正准备把多个agent接入生产系统的团队一个参考——尤其适合那些已经过了“单agent能跑通”阶段,开始被协作、状态、可观测性等问题卡住的同学。
1. 多agent系统为什么难落地:先想清楚这三个问题
1.1 多agent和单agent,本质上是两种物种
很多人以为多agent系统就是把几个agent堆在一起,互相调用就行。这个理解是最大的坑。单agent的本质是一个闭环:输入进来,模型推理,调用工具,输出结果。你只需要关注这个环路的准确性。但多agent系统面对的是一个意图网络——任务进来之后,要拆解成子任务,分发给不同的agent,收集结果,再汇合、再判断,整个过程是动态分叉的。
我常用一个类比解释这种差异:单agent就像一个全能型自由职业者,一个人包揽需求分析、设计、开发、测试;多agent系统则是一个项目组,有人做产品、有人写代码、有人做QA。项目组的难点从来不是单个人强不强,而是信息怎么同步、任务边界怎么划、风险谁来兜底。代码写挂了自由职业者自己修,项目组里得先搞清楚是哪个环节掉的链子。
这个差异直接决定了你在技术选型和架构设计上的思路完全不同。单agent你可以把逻辑都塞进一个prompt里,让它自己规划;多agent则必须面对“任务派发”、“节点间通信”、“状态一致性”、“分布式链路追踪”这些原本属于后端工程的问题。换句话说,多agent系统首先是分布式系统,然后才是AI系统。这个认知不建立起来,后面的路会很难走。
1.2 落地前必须想清楚的三个问题
我见过不少团队,一上来就搞了七八个agent,结果跑不起来。根本原因是在动手前有几个关键问题没想透:
第一个问题,你需要的到底是“多agent”还是“多流程”?这是最容易混淆的。如果一个系统只是同一个模型配了多套prompt模板,根据不同的输入走不同的分支,那它其实是多流程单agent,不是多agent系统。多agent的核心特征是:每个agent有自己的状态、工具、决策权限,并且它们之间存在真正的双向信息交互。判断标准很简单——如果业务上只是“不同场景给不同prompt”,那就老老实实做单agent,别为了架构噱头增加复杂度。
第二个问题,协作是必要的吗?很多时候,任务完全可以用一个精心设计的prompt完成,强行拆成多agent只会引入大量无效的通信开销和不确定性。我之前见过一个知识问答场景,团队拆了“搜索agent”“总结agent”“审核agent”三个角色,跑一轮要调用三次模型,中间还有信息丢失的风险。实际上同一个模型拿到搜索工具,一步就能完成大部分需求。多agent应该用在任务本身存在清晰边界、不同步骤需要不同专业背景或不同工具集的场景,而不是为了用而用。
第三个问题,失败成本有多高?每个agent节点都意味着一次模型调用,而模型调用是有概率失败的——可能输出格式不对、可能超时、可能跑飞进入死循环。节点越多,失败的概率就越大,而且失败会沿着链路传播。如果系统承载的是高频高并发的生产流量,每个环节都需要做重试、降级、兜底。这个成本在设计之初就要算进资源预算里,否则上线后会发现模型调用费用暴涨、响应时间不可控。
2. 架构设计:拓扑选型、消息协议与状态管理
2.1 三类拓扑结构:星型、链型和网格型
多agent系统的架构设计,第一件事是选拓扑结构。我把它归纳为三类:星型、链型、网格型。
星型拓扑,也叫orchestrator-worker模式,是生产环境中用得最多的。一个中心调度者(orchestrator)负责接收用户请求、拆解任务、分配子任务给各个worker agent、再汇总各worker的结果进行最终输出。这种模式的好处是控制权集中,调度逻辑清晰,方便做超时控制、重试和兜底。坏处是orchestrator本身容易变成瓶颈,而且如果拆解逻辑写得不好,中心节点就成了单点故障。
链型拓扑,也叫pipeline模式,适合数据处理流。任务按固定顺序经过一个个agent,每个agent处理完一个阶段就传给下一个。比如“信息抽取agent → 情感分析agent → 摘要生成agent”。这种模式好处是链路简单,每个节点职责单一,方便单独优化;坏处是链路中任何一个节点出错,后面就没法继续,而且信息在传递过程中容易损耗。
网格型拓扑,各agent之间可以自由通信、互相调用。理论上最灵活,符合“多agent自主协作”的理想图景,但实际落地我强烈建议避开——自由通信意味着不可预测性呈指数级上升,根本无法控制Agent A什么时候调用Agent B,状态不一致和死循环的问题会让你崩溃。
我的建议很直接:生产系统超过80%的场景用星型拓扑,剩下不到20%用链型。网格型少碰,除非你的团队有极强的可观测性基建兜底,并且业务本身对不确定性有很高的容忍度。
2.2 消息协议:多agent系统的通信契约
既然多agent系统本质是分布式系统,那agent之间的消息就得有明确的契约。我刚开始做的时候吃过亏——让两个agent直接传原始对话文本,结果上下文越滚越大,token费用暴涨,效果还变差了。
后来我总结了一套比较稳妥的消息结构,每个agent间传递的消息都遵循这个格式:
{ "session_id": "uuid-xxxx", "message_id": "uuid-yyyy", "agent_id": "intent-router", "message_type": "task_assign", "payload": { "task_type": "knowledge_retrieval", "query": "用户提交的原始问题", "context": { "user_id": "u_12345", "department": "售后", "priority": "high" } }, "timestamp": "2024-06-18T10:30:00Z", "trace_id": "trace-uuid-zzzz" }这套结构解决了我最头疼的几个问题:session_id保证了同一个用户请求的所有agent协作属于一个会话;message_type让每个agent知道自己收到的是一个任务派发、一个结果回传还是一次状态查询;payload里只传必要信息,不把整个对话历史塞进去;trace_id是后面做可观测性的基础,没有它,线上出了问题你连查都查不了。
这里有个关键设计原则:agent之间传递的是结构化数据,不是自然语言长文本。很多新手喜欢让agent直接用“人话”互相沟通,看起来智能,实际上非常脆弱——模型输出稍微有点歧义,下游agent就理解错了。结构化payload可以降低这种歧义,同时方便做日志审计和错误排查。
2.3 状态管理:别把上下文当成万能解法
多agent系统中,状态管理是最容易被低估的一环。每个agent在执行任务时都有自己的“记忆”——它看到了什么、做了什么、得出了什么结论。如果所有状态都靠上下文传递,系统很快就会膨胀到不可维护。
我实践下来的做法是:把状态分成两层。第一层是全局状态,放在中心存储(比如Redis或数据库),记录整个会话的进展——当前在哪个阶段、已经完成哪些子任务、收获了哪些关键信息。第二层是局部状态,只存在于单个agent的执行周期内,任务结束就丢弃。
举个例子,工单分诊场景里,全局状态记录的是“用户的问题是什么、当前分诊到哪个部门、紧急程度如何”;局部状态则是“意图识别agent在分析时参考了哪几条历史工单”。这样一来,即使某个agent执行失败需要重试,只需要重置局部状态,不会影响整个会话的进展。
还有一点很关键:任何状态下发到agent之前,都要设置一个大小上限。我一般控制在2k~4k token以内,超出就截断或做摘要,绝不让上下文无限膨胀。这个习惯帮我省下了大量token成本,也让响应速度稳定了很多。
3. 治理体系:多agent系统能不能长期跑的真正分水岭
3.1 可观测性:没有Trace,多agent故障就是“薛定谔的猫”
多agent系统最折磨人的地方在于,它的bug往往是概率性的、非确定性的。同一个请求,上午跑是好的,下午就错了;参数一模一样的两次调用,结果可能完全不同。这种情况如果没有一套完备的可观测性体系,排查问题无异于大海捞针。
我给多agent系统做的可观测性包含三个层次:全链路Trace、结构化日志、运行指标。
全链路Trace是整个体系的基石。每个请求都有一个trace_id,贯穿所有agent调用。这样线上出了问题,我可以直接查到这个请求经历了哪几个agent、每个agent的输入输出是什么、在哪一步耗时最长、在哪一步出现了异常。我通常会把每个agent的调用、每工具的执行都记录成一帧span,挂在同一个trace下,一眼就能看到完整的调用链。
结构化日志是Trace的补充。每个agent执行完,都会输出一条结构化的日志,包含当前agent的id、输入摘要、输出摘要、调用的工具、用时、token消耗、错误信息。这些日志既用于事后排查,也用于后续的离线分析和效果评估。
运行指标则是宏观视角。我至少会盯四个指标:任务成功率(整个多agent流程完整走通的概率)、单次任务平均耗时、模型调用token消耗量、各agent节点的失败率分布。这四个指标能帮助我快速发现系统的劣化趋势——比如某个worker agent的失败率突然从1%涨到10%,那大概率是模型行为漂移或者输入数据分布变了,需要及时干预。
3.2 版本管理与回归测试:让agent工程也告别“玄学开发”
多agent系统的效果,很大程度取决于prompt、模型参数和工具定义的组合。这三样东西任何一个变动,都可能导致系统行为变化。但现实是,很多团队还在用“改了prompt → 线上看看效果 → 不对再改”这种原始方式,这是完全没有工程化的状态。
我推荐的做法是建立一套类似软件工程的版本管理体系。prompt要有版本号,工具定义要有版本号,模型参数配置要有版本号。每一次改动都记录是谁改的、改了啥、为什么改、在哪个环境验证过。上线前必须经过回归测试——准备一组覆盖主要场景的测试用例集,比如100条典型的用户问题,跑一遍多agent流程,比较结果和基准版本的区别。
这里分享一个实操技巧:回归测试不一定要人工判断输出质量,可以先做机械化校验——检查流程是否走通、每个agent是否成功执行、是否有异常重试、token消耗是否在可接受范围。机械化校验过了,再做人工抽检评判输出质量。这样可以大幅降低回归成本,让版本发布更加频繁和安全。
3.3 权限、安全与成本:生产环境的硬约束
多agent系统落到生产环境,就不能只考虑“能不能跑”,还要考虑“跑得安不安全、跑不跑得起”。这里有三件事需要从第一天就规划好。
权限控制方面,每个agent能够调用的工具必须明确区分。比如“数据库查询agent”只能访问数据库,“企业微信发送agent”只能调用企业微信接口。工具调用要有白名单机制,Agent绝不能拥有超出其职责范围的工具访问权限。这一点尤其重要,因为一旦某个agent被prompt injection攻击,权限隔离能限制攻击的影响面。
数据隔离方面,不同租户、不同用户的数据不能在agent之间无差别流动。以工单系统为例,客户A的agent不能读取到客户B的工单信息。这个约束必须在架构层面实现,而不是靠prompt里写“不要泄露其他用户信息”——模型在复杂场景下很容易被诱导,不能寄希望于它的自觉性。
成本控制方面,多agent系统是真正的token消耗大户。一个请求可能触发5次、10次甚至更多次模型调用,成本不容小觑。我的做法是给每个会话设置token预算,超预算自动截断或者降级;同时做模型路由,简单任务用小模型,复杂任务才用大模型;再配合限流,控制并发调用数,避免某个瞬间调用量过大导致费用爆炸。
4. 实操环节:从零搭建一个工单分诊多agent系统
4.1 场景定义与agent角色划分
理论讲再多,不如动手做一遍。我用最近实际落地的“工单分诊”场景完整走一遍流程。这个场景的背景是:企业内部每天有大量用户报修的工单,需要快速识别问题类型、找到对应的处理部门、判断紧急程度,并自动回复用户初步处理进展。
我们对任务做了拆解,设计了四个agent:
- 意图识别agent:接收用户原始描述,提取问题类型、紧急程度、涉及的系统或设备。
- 知识检索agent:根据意图识别结果,在企业知识库中检索解决方案或历史工单。
- 工单处理agent:负责创建工单、分配处理部门、设置优先级。
- 质检审核agent:对前三个agent的输出做最终校验,检查信息完整性、部门分配合理性、回复话术质量。
这里有个设计细节值得说:质检审核agent不是可选的,而是必须的。它是整个系统的安全网。多agent链路中的任何一个节点出错,最终都可能被质检agent发现并拦截。它扮演的是“测试工程师”的角色——生产代码(agent)可能出bug,但要保证交付给用户的不是bug。
4.2 基于星型拓扑的编排流程
这四个agent不是自由协作,而是由中心orchestrator统一调度。整个流程是这样的:
第一步,orchestrator接收用户报修信息,生成session_id和trace_id,把任务派发给意图识别agent。第二步,意图识别agent返回结构化结果,比如问题类型是“网络故障”、紧急程度是“高”。第三步,orchestrator拿着这个结构化结果去调知识检索agent,查询是否有已知解决方案。第四步,知识检索agent返回匹配的解决方案和参考工单。第五步,orchestrator汇总前两步的结果,交给工单处理agent去创建正式工单。第六步,工单处理agent返回工单编号和分配部门。最后,orchestrator把所有信息打包给质检审核agent,审核通过后,才把最终回复展示给用户。
采用星型拓扑而不是链型的原因很简单:链型拓扑里,每个agent只能看到前一个agent的输出,如果一个早期阶段的判断有偏差,错误会一路传导下去,而且中间无法干预。而星型拓扑让orchestrator全程掌握全局信息,可以在任意节点之间做信息回溯,也可以针对某个节点单独重试。
4.3 关键参数与兜底策略
系统能跑通只是第一步,线上稳不稳,靠的是细节参数和兜底策略。
先说模型参数。意图识别agent和知识检索agent的temperature设置在0.1~0.2之间,保证输出稳定,减少“发挥”的成分。质检审核agent的temperature设置在0,完全确定性输出。工单处理agent因为是结构化操作,同样用低temperature,0.1左右。多agent系统里,想象力值钱,但稳定性更值钱——每一个随机的输出,都意味着下游节点要处理多一分不确定性。
超时和重试方面,每个agent调用设置10秒超时,超时后自动重试一次;重试仍失败则触发降级策略。这里要特别说明重试机制的坑:模型调用不是天生幂等的,同一个请求重试两次,可能产生两个不同的结果。所以重试前需要判断operations的类型——如果是查询类操作,重试安全;如果是创建工单这类写操作,必须等第一次调用明确返回失败才重试,否则可能重复提交。
最后是兜底策略,也就是“所有agent都挂了怎么办”。我会在orchestrator层设置最终兜底:如果经过两轮重试仍无法完成全流程,直接把用户的请求接入人工客服通道,并出具一份中间诊断报告。这份兜底策略可以保证即使AI链路彻底不可用,用户的诉求仍然会被受理。对一个生产系统来说,永远要有plan B。
5. 常见问题与排查技巧实录
| 症状 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| agent空转,反复执行相同操作 | 目标不明确或上下文缺失 | 查看Trace中该agent的输入输出,确认是否死循环 | 在orchestrator层设置最大轮次限制,超过自动终止 |
| 上下文污染,后续agent被无关信息干扰 | 上下文传递过多、未做剪枝 | 检查每个节点的输入上下文大小 | 设置上下文上限,只传结构化摘要 |
| 链式传递中信息丢失 | 结构化payload字段不一致 | 对比各节点日志的payload结构 | 统一消息协议,增加payload格式校验 |
| 并发任务互相争抢资源 | 共享状态未加锁或未隔离 | 检查状态存储层是否并发安全 | 引入分布式锁,或按session_id做数据分片 |
| 模型行为漂移,效果突然变差 | prompt被改动、模型更新或输入分布变化 | 对比近期版本回归测试结果 | 建立版本管理,及时回滚 |
5.1 一个典型的死循环排查案例
有一次线上反馈,某个工单请求的响应时间异常,跑了一个多小时没结束。我打开Trace一看,发现质检审核agent在反复调用工单处理agent——“审核不通过,请重新分配部门”,然后工单处理agent重新分配了一个部门,质检又认为不合理,又打回。这个循环整整转了几十轮。
根因是什么?工单处理agent在分配部门时,参考的知识库比较老旧,经常分配到一个已经不存在的“旧部门”;质检agent的知识库里有新部门信息,所以每次都判定不合格。两个agent的知识库不同步,导致互相矛盾。
这个案例让我意识到两个问题:一是agent之间对同一概念的认知必须要一致,最好共享同一个知识源,或者在设计阶段就明确各自的知识边界;二是系统必须要有最大循环次数限制,绝对不能允许无限循环。后来我在orchestrator层加了硬性约束——任何一个子任务最多执行3轮,超过直接转人工。这个改动上线后,再也没有出现过“跑一个多小时不结束”的线上事故。
5.2 排查多agent问题的通用思路
踩了这么多坑之后,我总结了一套多agent问题的通用排查思路,可以套用在大多数场景。
第一步,先看Trace,确认问题发生在哪个节点。多agent系统的故障是沿着链路传播的,表面上的“症状点”往往不是“根因点”。比如用户收到的最终回复是“工单创建失败”,问题可能在工单处理agent,也可能是意图识别agent一开始就把信息提取错了,导致后面全部跟着错。
第二步,对比“输入”和“输出”。对于排查中的那个节点,先看它的输入信息是否完整正确,再看它基于这些输入产出的输出是否合理。如果输入正确、输出错误,那是这个agent自身的问题;如果输入已经错了,那就往上游找。
第三步,检查“重试次数”和“降级路径”。看这个请求在链路中是否触发过重试、是否走过降级分支。很多问题不是正常流程下的逻辑错误,而是异常处理路径没有被充分测试。
这套思路看起来简单,但很实用——它逼着你从“全局视角”去定位问题,而不是盯着某一个agent的输出发呆。
每次落地多agent系统,都是一次对工程能力的全面体检
做完这个工单分诊系统,我最大的体会是:多agent系统真正考验的不是你对大模型的理解,而是你对软件工程基础功的掌握程度。消息协议、状态管理、可观测性、版本控制、权限隔离、成本预算——这些恰恰是传统后端开发里最“无聊”的部分,却是多agent系统能否长期稳定运行的决定性因素。
再分享一个小技巧作为收尾:如果你现在准备从单agent迁移到多agent,别急着把场景做大,先挑一个你业务中流程最清晰、边界最明确的小任务试水。跑通之后再逐步扩展。这个方法让我少走了很多弯路——多agent系统最怕一开始就摊大饼,复杂度和不确定性叠加起来,出了问题你都分不清是架构问题、模型问题还是prompt问题。从小场景建立自己的方法论,再放大到更复杂的业务里,你会感谢当初自己的克制。