闭环升级漏洞:当你的专精型智能体陷入循环路由
一个用于市场数据研究的多智能体系统在无人察觉的情况下,在四周内悄悄烧掉了 47,000 美元的推理成本。原本的每周账单仅为 127 美元。原因既不是流量激增,也不是模型升级——而是两个智能体在十一天里来回传递同一个对话,每个智能体都确信对方才是处理该请求的正确位置。没有任何报错。没有任何警报触发。一个机器人的“队列已转移”指标和另一个机器人的“任务已接收”指标都在同步增长,两边的仪表盘看起来都很健康。
这就是闭环升级漏洞 (closed-loop escalation bug)。它是两个热心的同事互相坚持“不,你来处理”的多智能体版本,只不过他们谁都不会感到厌烦并走开。你在设计时画的架构图中,每个专业智能体都拥有一块清晰的问题领域。而运行时实际执行的架构却包含了一个房间里没人能看到的路由循环。
这是一种在发布前评估中无法捕获的故障模式,因为从单个智能体的角度来看,其质量表现非常出色。你的客服智能体能正确回答客服问题。你的计费智能体能正确回答计费问题。漏洞存在于它们之间的 衔接处——而这个衔接处不属于任何一个团队。
循环是如何形成的
起初的设置很平凡。你有一个客服智能体和一个计费智能体。客服智能体的路由提示词写着:如果是计费问题,移交给计费部门。计费智能体的路由提示词写着:如果是服务问题,移交给客服部门。每个提示词都由不同的子团队编写,经过独立评审,并在同一个监督者 (supervisor) 之下发布。
接着,一个真实用户提出了一个确实处于衔接点上的请求——“我从未收到的服务被扣了费,我希望恢复我的访问权限。”客服智能体读到了“扣费”并路由给计费。计费智能体读到了“恢复访问权限”并路由回去。由于监督者没有路由图的全局视野,它忠实地传递了每一条消息。对话弹跳了四十次,直到触发单次对话的 Token 预算或达到轮数限制,用户最后得到一个通用的兜底回复,说“让我为你连接人工客服”——而此时系统在这个单一请求上消耗的计算资源已经超过了人工客服一周的成本。
伯克利的研究人员系统地标注了七个流行多智能体框架中的 150 个生产轨迹,并在其 MAST 分类法中将此类问题归为“智能体间失调” (inter-agent misalignment):即智能体基于谁负责什么的错误假设进行操作、忽略同伴信号,或未能验证是否有人正在取得进展。这三个顶层的故障类别——规范与系统设计故障、智能体间失调,以及任务验证与终止——共同导致了同一个结果:一个在不产生答案的情况下消耗资源的循环。
这种模式之所以如此容易发布,其结构性原因是路由逻辑是 局部 的。每个智能体仅根据其面前的信息决定将任务移交给何处。分布式系统工程师在这个特定的问题领域上花费了几十年的时间。生成树 (Spanning-tree)、BGP、IS-IS——第 2 层和第 3 层协议栈中的每种路由协议之所以存在,部分原因在于 局部路由决策可能会组合成全局循环,而停止这种循环的方法不是编写更好的局部启发式方法。通过工具调用和纯文本路由提示词进行移交的智能体框架,本质上是在构建一个路由架构,却缺乏路由社区在 20 世纪 80 年代就已经成为标准配置的循环检测原语。
为什么单智能体评估看不见它
大多数团队评估智能体的方式与评估其他模型输出的方式相同:输入提示词,对响应打分,然后重复。每个专业智能体根据自己的基准进行评分——计费智能体是否回答计费问题,客服智能体是否回答服务问题。两边都通过了。而真正能捕获此漏洞的评估切片——真正跨越两个领域的对抗性意图——正是没人编写的那部分,因为它处于两个团队评估套件之间的鸿沟中。
更糟糕的是,在循环对话期间,两边的现有仪表盘通常 都 显示为绿色。客服团队的仪表盘显示“智能体未提供帮助,已转接计费”——干净的移交,根据其定义是成功的。计费团队的仪表盘显示“队列错误,已转接客服”——根据其定义也是干净的。没有团队负责衔接处。没有任何团队的指标能反映出同一个对话 ID 在同一分钟内,连续 20 次在两个仪表盘上同时作为“转出”事件出现。
最近一系列关于智能体应用中无监督循环检测的研究,量化了这种现象在标准观测手段下是多么地不可见。在来自 LangGraph 股票市场应用的 1,575 个轨迹中,仅靠结构化调用栈分析发现循环的 F1 分数为 0.08,仅靠语义冗余检测的 F1 分数为 0.28。只有将两者结合的混合方案才能达到 0.72 的 F1 分数和 0.86 的召回率。换句话说:如果你的平台只是在观察“智能体是否返回了结果”,你几乎无法捕获流量中的任何循环。你需要同时观察 调用图的形状 和 消息的语义冗余。
必须落地的规范
将多智能体交付(handoffs)视为路由协议——而非领域抽象——在你第一次避免事故时,这种投入就值回票价了。必须存在的原语并不奇特;它们是生产级路由协议在很久以前就已解决的承重部分。
全局交付账本(A global hand-off ledger)。 对话的每一次交付事件都会记录到每一条对话的账本中,管理者(或路由端中间件)在做出每一次路由决策时都会读取该账本。规则很简单:对话不能在没有明确、经管理者确认的理由的情况下,重新进入一个它刚离开的智能体。账本存在于任何单一智能体的上下文窗口之外,因为不能指望任何智能体能在长对话中可靠地记住自己的路由历史。
明确的“我不同意你的路由”信号。 当智能体 B 收到来自智能体 A 的交付并判定该对话属于 A 时,它应该能够直说——发出一个结构化的“拒绝并解释”事件——而不是静默地重新路由回去 。管理者会看到这种分歧并决定如何处理,就像 L3 路由协议承载路由拒绝信号,而不是让端点静默地相互 NAT 数据包一样。LangChain 发布的交付指南将此框架化为刻意的目标声明:每个智能体声明它可以交付给哪些智能体,由框架强制执行这些路径,而不是让交付从自由文本生成中推断出来。
独立于 Token 预算的交付预算。 大多数团队会根据 Token 消耗来限制对话。这很必要,但并不充分:当 Token 上限在循环对话中触发时,你可能已经烧掉了五十次正常对话的预算。一个较小的整数上限——根据你的拓扑结构,每次对话允许 3 到 5 次交付——触发得更早,并在源头提供清晰的信号。OpenAI 的 Agents SDK 将这种有界循环原语作为其交付抽象的一部分暴露出来;编写智能体的团队应该刻意选择这个边界,而不是继承框架的默认值。
对抗性边界评估切片(An adversarial-seam eval slice)。 发现此类漏洞的评估(eval)不是“每个智能体是否回答了其领域内的问题”,而是“构建意图真正横跨两个领域的提示词,通过实时多智能体系统运行它们,并断言对话在有限的交付次数内达到终止状态”。验收标准是终止,而非正确性——尽管两者都应该被衡量。这个切片必须由负责边界的人员拥有,因为各智能体团队会继续在各自的孤岛中进行优化。
让问题浮现的可观测性
即使有了协议层面的原语,你仍然需要观察生产环境中发生了什么。有三个信号计算成本低且易于报警:
每条对话的交付深度。 绘制每条对话累积交付次数的直方图。健康的分布应该是左偏的——大多数对话在零次或一次交付后终止——并带有细长的尾部。双峰分布或尾部突然抬升是循环对话的特征。可以针对“p99 交付深度超过 5”设置告警。
智能体间流转热力图。 构建一个方阵,行是源智能体,列是目标智能体,单元格是过去一小时内从行到列的交付次数。对角线应该是浅色的(智能体很少交付给自己),非对角线应该是稀疏且不对称的。如果你看到一对对称的明亮单元格——A→B 和 B→A 大致相等且数值很大——那么你正面临一个闭环。这是第一次事故发生后通常需要补上的仪表盘,一旦它存在,后续的每一次拓扑更改在上线前都有了视觉化健全性检查的方法。
针对每一对智能体的重新进入计数器。 对于每一对有序的智能体 (X, Y),统计在 N 轮内,执行了 X→Y 交付的对话随后又执行 Y→X 交付的频率。对于健康的流量,这个数值应该趋于零。任何高于零的数值都是潜在循环的候选者,值得针对每一对进行报警,因为故障是成对发生的:是两个特定智能体之间的契约断裂了,而不是整个系统。
Maxim AI 关于多智能体可靠性的指南用协议术语描述了这一点:将你的协作建模为有界深度的有向无环图 (DAG),并对每次交付进行插桩(instrument),以便在循环和无界链条复合为成本或延迟事故之前检测到它们。DAG 框架之所以重要,是因为它强制要求对“这是交付还是重新进入?”这个问题给出明确回答——而自由文本路由提示词无法回答这个问题。
