跳到主要内容

输出耦合陷阱:为什么多智能体系统在接口边界处会发生静默失败

· 阅读需 11 分钟
Tian Pan
Software Engineer

你的多智能体(multi-agent)流水线运行结束了。没有抛出任何异常。编排器报告成功。然而,答案却是错的,而且错得离谱 —— 执行器跳过了两个步骤,总结器将三个部分合并成了一个风马牛不相及的结论,输出看起来像是完全来自另一个任务。没有堆栈跟踪可以遵循,没有错误代码可以搜索。只有一个悄无声息的错误结果。

这就是输出耦合陷阱(output coupling trap)。这不是模型质量问题,而是接口工程(interface engineering)问题,也是多智能体系统在生产环境中发生隐形故障的首要原因。

陷阱:无人记录的隐式契约

在多智能体系统中,智能体 A 产生的输出由智能体 B 消费。问题在于,“产生”和“消费”通常仅在提示词(prompt)中以自然语言定义,在运行时执行,且没有任何强制机制。

智能体 A 的提示词写着:“以带编号的列表形式返回你的分析结果,并在末尾附上置信度分数。”智能体 B 的提示词写着:“解析前一个智能体的编号列表,并提取置信度 > 0.8 的项。”这一直运行良好,直到有人更新了智能体 A 的提示词,让其返回 JSON;或者模型开始返回项目符号而不是数字;又或者模型供应商的一次更新改变了底层模型的格式化倾向。智能体 B 不会抛出解析错误,它会对其接收到的任何内容进行“幻觉式”解释并继续运行。

一项针对七个流行智能体框架中 1,600 多个带注释的执行轨迹的研究发现,模式偏移(schema drift)—— 即智能体的输出与下游智能体期望的格式不匹配 —— 是多智能体系统故障中占比最大的一类。更广泛的故障模式还会叠加:每个误读格式的下游智能体都会引入自己的错误,随后的智能体则会将这些错误视为基准事实(ground truth)。在无结构的网络中,这种放大效应可导致错误率达到单智能体基准的 17 倍。

这种情况之所以难以捕捉,是因为大语言模型(LLM)极其擅长理解格式错误的输入。当一个本该接收 JSON 的智能体收到了 YAML 时,它并不会拒绝处理,而是会将其模式匹配(pattern-match)为某种看似合理的东西并继续。这种故障模式不是异常(exception),而是一个言之凿凿的错误答案。

模式偏移是如何传播的

传播机制一旦看清就很简单。假设一个包含五个智能体的流水线:规划者(planner)、研究者(researcher)、分析师(analyst)、作者(writer)、审核者(reviewer)。

规划者输出任务拆解。它决定将格式从编号列表切换为以 tasks 作为数组键的 JSON 对象。研究者的提示词写着“处理规划者提供的每个编号任务” —— 现在它收到了 JSON,它会将其模式匹配为类似任务的内容,并根据自己对意图的最佳推测继续操作。分析师收到研究者的输出,由于任务范围被误读,内容已微妙地偏离主题。作者收到分析师的输出,生成的文章逻辑自洽但内容错误。审核者检查内部一致性,没发现明显的破绽。

在整个过程中,没有一个智能体报告错误。系统显示“完成”。输出结果却毫无价值。

这就是为什么模式偏移故障特别危险:它们不会出现在你的错误日志中。它们出现在你的质量指标中,通常是在用户已经遇到问题之后。从生产环境故障到定位根因的反馈循环是以“天”而不是“分钟”来衡量的。

同样的研究发现,这类故障中的大多数可以追溯到模糊或未明确的智能体接口 —— 不是模型能力问题,也不是提示词质量问题,而是移交边界处缺失的契约(contracts)。

接口优先设计:先定义契约,后定义行为

解决方法借鉴了 API 设计:先定义接口,再实现它。

在传统的微服务中,你不会允许服务 A 调用服务 B 时使用未记录的载荷并指望 B 能处理它。你会编写 OpenAPI 规范。你会据此生成客户端类型。你的 CI/CD 流水线会验证一致性。架构更改需要提升版本号。破坏性变更(breaking changes)需要迁移路径。

多智能体系统也需要同样的纪律,应用于每个智能体的输入和输出。

具体而言,这意味着:

**为每一次移交定义类型化模式(Typed schemas)。**使用 JSON Schema 或 Pydantic 模型来定义每个智能体的产出和消耗,而不是在提示词中使用散文式的描述。模式存在于代码中,而非提示词文本中。

**在每个边界进行验证。**在一个智能体的输出到达下一个智能体之前,对照预期模式进行验证。验证失败时,立即报错(fail fast)并提供有用的错误信息 —— 不要将格式错误的数据传递给下游并任其传播。边界处的硬失败是可恢复的,而三步之后的隐形故障则不可控。

**为智能体输出建立语义化版本控制(Semantic versioning)。**当智能体的输出格式发生变化时,将其视为 API 变更。破坏性变更 —— 如重命名字段、更改类型、删除必填字段 —— 需要主版本号升级。新增可选字段属于次要变更。针对行为优化,应通过补丁更新提示词,而非修改接口。这听起来增加了开销,直到你不得不去调试一个因为某人“仅仅优化了”智能体输出指令的措辞而导致的级联故障。

**让智能体也能获取模式。**将下游智能体的输入模式包含在上游智能体的提示词上下文中,而不仅仅是作为人类的文档。这为模型提供了一个具体的、机器可读的规范,告诉它需要产出什么,而不是依赖自然语言指令来精确指定格式。

实践中的样子

这是一个规划器-执行器(planner-executor)对在隐式耦合和显式耦合之间的区别。

隐式(陷阱):

规划器提示词:"将任务分解为步骤。返回一个编号列表。"
执行器提示词:"执行规划器输出中的每一个步骤。"

显式(接口):

class PlannerOutput(BaseModel):
steps: List[PlanStep]
context: str
estimated_complexity: Literal["low", "medium", "high"]

class PlanStep(BaseModel):
id: str
action: str
dependencies: List[str]
expected_output_type: str

执行器的提示词将 PlannerOutput 的 schema 作为 JSON Schema 包含在内。编排层在将输出传递给执行器之前,会根据此 schema 验证规划器的输出。如果验证失败,系统会重试规划器,并附带一条错误消息,准确描述哪个字段缺失或格式错误。

这种模式还可以在提供商级别强制执行结构化输出。当给定 JSON Schema 时,OpenAI 的结构化输出(Structured Outputs)API 可以保证模型的响应符合该 schema。这完全消除了一类故障:模型产生的输出不会破坏下游智能体的解析器,因为 API 在生成时就强制执行了 schema 合规性。如果可以使用此功能,请务必使用它。

对于复杂的流水线,如果结构化输出 API 无法涵盖所有情况,或者当你跨提供商工作时,编排层中的 schema 验证就是你的兜底保障。

可观测性:捕捉漏网之鱼

即使有了验证机制,你仍需要对边界处发生的情况保持可见性。技术上通过 schema 验证的 LLM 输出仍可能携带语义偏移(semantic drift)——值虽然是正确的类型,但内容是错误的。

带有相关性 ID(correlation IDs)的跨智能体交接分布式追踪是最低要求。每一个跨越智能体边界的消息都应该携带追踪 ID、来源智能体、有效载荷的 schema 版本以及时间戳。当出现问题时,你可以通过智能体图谱向后追踪,找到偏差开始的地方。

除了追踪之外,将 schema 合规性作为持续指标进行监测的团队——通过智能体对、载荷版本、模型版本来跟踪验证失败率——能在偏移级联之前捕捉到它。特定交接点验证失败率的突然飙升是一个信号,提醒你在其演变成生产事故之前进行调查。

分布式系统中的熔断模式(circuit breaker pattern)在这里同样适用。当特定的智能体到智能体路径产生高频率的 schema 验证失败时,应果断切断,而不是继续通过流水线转发错误数据。在连续三次验证失败后开启的熔断器,可以防止瞬时的模型行为变化影响到下游的十个智能体。

测试接口,而不仅仅是行为

大多数多智能体测试套件都在测试系统端到端是否产生了良好的答案。很少有直接测试接口的。

多智能体系统的接口测试应包括:

  • 格式注入:向每个智能体提供格式错误的输入,并验证其是否能快速失败,而不是产生听起来很有道理的垃圾内容
  • Schema 版本不匹配:向期望当前版本的智能体提供旧版本的 schema,并验证错误信息是否有效
  • 字段边界情况:测试必填字段缺失、可选字段类型错误、额外的意外字段
  • 级联故障追踪:在某个智能体处故意引入错误,并追踪它是传播了还是在验证边界被捕捉到了

这更接近于传统微服务中的契约测试(contract testing),而不是大多数团队使用的端到端评估方法。它更快、更具确定性,并且能捕捉到端到端测试经常漏掉的一类故障。

MAST 研究分类法将 schema 偏移识别为主要的失败模式,这正是源于这种系统的测试——注入特定的故障模式并观察传播情况。定期运行故障注入的团队通常会发现,他们的智能体间接口比端到端测试通过率所显示的要脆弱得多。

从提示词工程向契约工程的转变

这里需要的思维模型转变是真实存在的:多智能体系统是分布式系统,适用的工程学科是分布式系统工程,而不仅仅是提示词工程。

在分布式系统中,你不会基于“共同理解”去信任服务能够正确通信。你会定义契约、验证合规性、监测边界,并针对接口处的失败进行设计。多智能体系统中的“服务”是 LLM 这一事实并不会改变基本要求——反而使其变得更加紧迫,因为 LLM 总会产生一些东西,即使产生的内容是错误的。

接口优先设计——定义 schema、验证输出、对契约进行版本化——是将随着规模增长而保持可靠的多智能体系统,与那些随着模型行为变化而需要不断人工干预的系统区分开来的关键。预先定义这些契约的成本是几个小时的 schema 设计和验证代码编写。而在生产事故后才发现需要它们的成本则要高得多。

在向流水线添加下一个智能体之前,请先问:这个智能体会产生什么?该契约在哪里被强制执行?如果答案是“在提示词里”,那么你正在为流水线增加技术债。如果答案是“在边界处带有验证的 schema 中”,那么你正在构建真正可维护的东西。

References:Let's stay in touch and Follow me for more thoughts and updates