
把一个任务拆给多个 Agent 之后,最常见的故障长这样:任务没有报错,也没有超时,就是一直没结束。或者:结束了,但中间某一步被人来回推了三次,最后一次谁都没做。
这类问题的共同点是——不是某个 Agent 变笨了,而是编排层的规则缺了东西。
单 Agent 的故障排查有一个天然锚点:所有决策都在一条 trace 上,责任主体是同一个。多 Agent 之后这个锚点没了:出错的边界落在"谁交给谁"这一步上,而这一步通常没有任何人负责。
下面四种失败模式,我认为是拆多 Agent 之后必然要面对的。
最典型的形态是来回踢:A 判断这属于 B 的职责,B 判断信息不足应该由 A 补充,A 又觉得 B 可以先做——两轮之后,任务卡在两个人中间。
根因有两个,都是设计缺省。
一是不存在"升级"这个概念。 编排规则里只有"交给谁",没有"如果对方也不接,交给谁"。所以踢回来那一刻,系统只能再踢一次。
二是没有轮次账本。 没有地方记录"这件事已经被转手过几次",也就无法在第二轮做出不同决策。
修法很直接:给任务加一个转手计数,超过阈值(比如 2 次)强制走"升级"分支——升级到人,或者升级到"由最初接收方负责收尾"。关键不是阈值定多少,而是这条分支必须存在。
这是最容易被忽略的一种。
单 Agent 里,给一次模型调用设 30 秒超时、重试一次,最坏 60 秒。多 Agent 之后每一层各自设超时:A 等 B 60 秒,B 等 C 60 秒,C 等模型 30 秒还重试两次。
结果是:上层超时几乎永远不会触发,因为它总是大于下层的总和;而整条链的最坏耗时是各层超时的乘积量级,不是加和。用户那边表现为"偶尔有个请求要等十几分钟"。
正确做法是传 deadline,不传 timeout。
这一条改动成本很低,却是多 Agent 里性价比最高的约束。它还顺带解决了另两个问题:重试预算和降级时机。
任务失败了,日志上能看出是哪个子任务挂的,但没有"谁来负责把它收尾"。
举个例子:三步流程,第二步的 Agent 判定"需要人工介入"就返回了。编排层收到这个信号之后做什么?规则里没写的话,常见结果是:编排层把它当成"已完成",第三步照常执行——用着一个不完整的中间结果。
修法是在编排层引入任务所有者(owner):每个子任务有一个唯一负责方,无论成功、失败还是"需要人工",都由 owner 给出终态。owner 可以把活派出去,但不能把责任派出去。
这话听起来像管理术语,落到代码上很具体:子任务的返回类型必须包含明确的终态枚举,而不是"成功 / 抛异常"两种;编排层对未识别的终态必须报错,而不是当成成功。
单 Agent 的补偿只涉及自己的步骤。多 Agent 之后,副作用之间会有关联。
典型场景:子任务 X 创建了一条记录,子任务 Y 基于这条记录发了通知。要回滚 X,就必须先撤回 Y 的通知——但 Y 并不知道 X 正在回滚。
所以副作用的登记要跨 Agent 做:谁创建了被依赖的对象、谁依赖了它,这两条关系要在编排层可见。补偿时按依赖逆序执行,而不是各自管各自的。
这里和状态持久化是同一件事的延伸:幂等键要跨 Agent 唯一。否则两个 Agent 各自生成的键互不识别,同一件事会被做两次,"去重"就失效了。
上面四个问题能不能被及时发现,取决于 trace 里有没有记这几样东西:
少了任何一项,上面四种故障就只能靠人肉读日志猜。
我不建议做"自由协商式"的多 Agent——让几个 Agent 自己讨论、自己决定谁来干。
它的问题不在效果,在可验证性:自由协商产生的执行路径无法预测,也就无法为它设计上面那四条约束(轮次账本、deadline 传播、owner、补偿顺序)。你会发现每次故障都是新形态,永远归纳不出规则。
更实用的结构是:固定流程 + 局部自主。整体流程写死在编排层(谁在什么条件下交给谁),只在单个节点内部保留 Agent 的自主性。这样路径可枚举,故障可归纳。
多 Agent 的价值在于分工,代价是故障会落在交界的缝里。上面四条约束做的是同一件事:把"缝"变成有规则的地方——谁负责、还剩多少时间、转了几手、撤销时牵连谁。
这些规则不写,多 Agent 就只是把单体的复杂度摊到更多进程上,而且更难查。
同系列:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。