跳到主要内容

一致性鸿沟:为什么并行 LLM 调用会相互矛盾以及如何修复它

· 阅读需 13 分钟
Tian Pan
Software Engineer

想象一个处理用户支持工单的多智能体流水线。智能体 A 读取工单历史并认为用户是一个需要进阶回复的高级用户。智能体 B 在并行的调用中读取同样的工单历史,却认为用户是一个需要分步引导的初学者。两个智能体同时完成并将输出交给组合智能体——而现在,组合智能体必须调和这两个对同一个人的根本不兼容的心理模型。

这并非罕见的极端情况。分析生产环境多智能体故障的研究发现,36.9% 的失败是由智能体间的失调引起的:冲突的输出、移交过程中的上下文丢失,以及独立得出的不兼容结论。一致性鸿沟(consistency gap)——即并行 LLM 调用对共享实体产生相互矛盾的倾向——是智能体系统中被低估最多的失效模式之一。

这种失效模式之所以阴险,在于它的失败方式。与抛出异常的工具调用或超时的网络请求不同,一致性失败通常是无声的。两个智能体都成功了。两者都产生了看起来有效的输出。矛盾只在下游显现,而且往往很难追溯到根本原因。

为什么并行调用会产生分歧

一旦你看清了其中的机制,就会发现它其实很直截了当。语言模型不是数据库。当两个智能体使用重叠的上下文进行独立调用时,每次调用都是一次全新的推理,对另一个智能体正在生成的内容一无所知。模型并不会检查一个“我们目前已经决定了什么”的共享寄存器——它只是根据其上下文窗口中的内容从概率分布中进行采样。

即使输入完全相同,采样温度(temperature)也会引入分歧。在温度为 0 时,具有相同提示词的调用将返回相同的输出,但大多数生产系统出于质量原因会运行在 0 以上的温度。即使上下文稍有不同——不同的工具结果、相同事实的不同排序、不同的对话历史前缀——两个智能体也可能得出局部连贯但全局不兼容的结论。

这个问题会在推理步骤中不断复合。如果多步链条中的每一步都有 10% 的幻觉率,并且每一步都以步骤为条件,那么即使单步看起来没问题,一个 6 步的链条也可能在 99% 的时间里失败。更糟糕的是,当多个智能体都以同一个幻觉前提为条件时,它们会强化彼此的错误而不是纠正它们。集成投票(Ensemble voting)——这种平庸的修复方案——如果所有智能体都共享相同的偏见,那就起不到作用。关于投票方法的研究表明,当智能体的错误是相关的而非独立的时候,多数票投票可能会出现系统性的错误。

模式 1:在并行化之前锁定实体表示

最直接的修复方法是确保所有并行调用在并行工作开始之前,都能接收到每个共享实体的相同规范表示。这就是以实体为键的提示词模板(entity-keyed prompt templates)。

这种模式的工作原理如下:在生成任何并行智能体之前,为将在整个工作流中被引用的每个实体构建一个单一的结构化表示——比如用户档案、正在分析的文档或正在审查的代码库。对其进行确定性的序列化(每次都使用相同的字段顺序、相同的空格、相同的 JSON 结构),并将其注入到每个智能体的提示词中的相同位置。

这样做有两个作用。首先,它消除了最常见的分歧来源:智能体以不同的格式或顺序接收相同的基础数据,这会导致模型对事实的权重分配不同。其次,它创建了一个能够与提示词缓存(prompt caching)完美配合的稳定前缀——每个并行调用都有相同的起始 Token,因此缓存会命中而不是失效。

关键的纪律是,实体表示在并行阶段必须是只读的。需要更新共享状态的智能体应该写入暂存缓冲区,而不是在中途修改实时表示。这与数据库中的乐观锁(optimistic locking)直觉一致:允许并发读取,序列化写入。

模式 2:在并行化之前预热缓存

提示词缓存通常被视为一种成本优化手段,但在多智能体系统中,它也是一种一致性工具。如果并行调用共享一个缓存前缀,它们都是基于完全相同的上下文进行推理的——不是相同上下文的副本,而是相同的缓存计算结果。

问题在于缓存是在第一次使用时创建的。如果十个智能体同时启动且没有预热缓存,所有十个调用都会竞相创建缓存,产生冗余计算,并可能命中略有不同的服务器状态。解决方案是专门的预热调用:在并行工作开始之前,发送一个轻量级的预检请求来创建缓存。一旦缓存存在,后续所有的并行调用都会命中它。

这一做法还强制执行了一种有用的架构纪律。只有当缓存内容出现在提示词开头且在调用之间不发生变化时,缓存才会起作用。任何变量内容——工具结果、对话轮次、特定于智能体的状态——都必须放在最后。这种约束与你追求一致性的初衷是一致的:稳定的、共享的实体上下文放在前面;特定于智能体的指令放在最后。

一个实际的启发是:不要通过编辑系统提示词(system prompt)来跨轮次携带状态。团队经常这样做是为了将日期、模式或每个用户的上下文传递到系统提示词中,但这会导致每次调用都使缓存失效。请改用消息(messages)。这样缓存可以保持预热,状态仍然可以传播。

模式 3:根据证据而非多数原则协调输出

当并行调用确实产生冲突的输出时,你需要一个协调步骤。显而易见的方法——多数投票制(Majority voting)——往往是错误的。

多数投票制的问题在于独立性假设。在一个包含三个智能体的流水线中,如果两个智能体说 X,一个智能体说 Y,多数投票制会选择 X。但如果那两个同意 X 的智能体共享了包含细微错误的上下文,而持不同意见的智能体拥有揭示该缺陷的额外上下文,那么你刚刚就把正确的答案投票出局了。研究表明,当智能体共享上下文时,并行 LLM 调用之间的错误率具有强相关性,而这正是大多数实际流水线的情况。

更好的协调方法:

基于证据的仲裁:不再仅仅统计票数,而是让每个智能体展示支持其结论的具体证据。协调步骤随后评估哪份证据更强,而不是哪个结论更受欢迎。这种方法成本更高,但可靠性显著提升。

结构化矛盾检测:在组合输出之前,运行专门的一致性检查,寻找显式的逻辑冲突。如果智能体 A 说“用户偏好简洁的回答”,而智能体 B 说“用户偏好详细的回答”,应显式标记该冲突,而不是默默地混合输出。强制执行解决步骤。

Saga 风格的补偿:借鉴分布式事务设计。将多智能体工作流分解为可补偿的步骤:每个步骤都有定义的“撤销”操作。如果下游处理检测到矛盾,它可以触发补偿——回滚特定决策,并利用额外的上下文重新请求,以解决冲突。这套机制较重,但对于一致性失败会产生实际下游后果的工作流来说,它是正确的模型。

模式 4:在 Schema 边界显式报错

相当大比例的一致性失败实际上是隐式的格式错误。对生产环境智能体流水线的研究跟踪发现,在未经校验的流水线中,37% 的工具调用存在参数不匹配,且未触发任何错误。工具在缺少参数或参数类型错误的情况下执行并返回了结果——只不过是错误的结果。

这对于一致性至关重要,因为工具调用下游的智能体是基于该工具的输出来构建推理的。如果该输出在隐式状态下格式错误,那么后续每一个对该数据进行推理的调用都将是基于垃圾数据进行推理。智能体之间会保持完美的连贯性,但对于现实情况却是完全错误的。

在多智能体系统中,每一个智能体边界的 Schema 强制执行(Schema enforcement)都是必选项。每一个工具输入在执行前都应根据声明的 Schema 进行验证。每一个智能体输出在传递到下一步之前,也都应根据声明的 Schema 进行验证。硬故障(Hard failures)是可恢复的,而隐式损坏(Silent corruptions)则不然。

这也限制了智能体被允许输出的内容,从而减少了发散的空间。如果两个智能体都被要求返回具有特定字段和类型的结构化对象,那么潜在不兼容的空间将比它们返回自由文本时小得多。

分布式系统的正确之道

底层问题——多个进程在没有显式协调的情况下操作共享状态——正是分布式系统研究在过去三十年里致力于解决的问题。其中一些解决方案可以非常丝滑地移植到多智能体 LLM 系统中。

CRDTs(无冲突复制数据类型)提供了一种模型。其核心洞察是设计这样一种状态表示:无论更新到达的顺序如何,都可以确定性地进行合并。应用于 LLM 智能体时,这意味着将智能体的输出设计为可合并的而非冲突的:智能体不再断言单一结论,而是输出一组加权声明,这些声明可以在无需解决逻辑的情况下进行组合。你用精度换取了可组合性。

Saga 模式解决了“当出错时我们该怎么办”的问题。传统的分布式事务假设你可以获取锁并保证原子性——但在 LLM 工作流中,这两点都不成立,因为每次调用都是一个可能产生任何输出的黑盒推理。Sagas 将工作流分解为带有显式回滚逻辑的可补偿步骤。如果第 3 步产生的输出与第 1 步不兼容,你不需要回滚整个工作流——只需回滚导致冲突的具体决策。

这些并不是开箱即用的解决方案。LLM 智能体拥有传统分布式系统所不具备的失败模式:幻觉、上下文遗忘、指令漂移。但其设计直觉——使状态显式化、使合并确定性、使失败可恢复——是直接适用的。

实践检查清单

对于正在构建针对共享实体进行并行化的多智能体系统的团队:

  • 在并行化之前序列化实体表示,并在并行阶段将其视为只读。写入操作进入暂存缓冲区(Staging buffer)。
  • 在生成并行智能体之前预热缓存。不要让他们竞争创建第一个缓存条目。
  • 在每一个边界进行验证。工具输入和智能体输出都要进行 Schema 检查。宁要硬故障,不要隐式损坏。
  • 设计结构化协调。不要混合冲突的输出——要显式检测冲突并使用专门的步骤进行解决。
  • 为一致性进行监测,而不只是成功率。记录并行调用何时达成冲突的结论,即使下游组合妥善处理了它。日志会告诉你你对协调层的依赖频率。

最后一点是团队最常忽略的。建立一个能平滑冲突并产生可接受输出的协调步骤,然后宣布问题已解决,这很容易。但如果没有洞察冲突发生的频率以及发生在哪些实体上,你就像在盲飞。一旦工作流的规模或复杂性增加,被默默处理的一致性失败往往会累积成更大的正确性问题。

更深层次的问题

并行 LLM 调用引入了一个在顺序流水线中不存在的一致性鸿沟,而弥补这一鸿沟需要刻意的架构选择。这些模式——实体规范化、缓存预热、基于证据的调和、Schema 强制执行——并不复杂,但需要从一开始就构建进去。

更难的转变是认知上的:将每一次并行调用都视为对世界的一个潜在独立且不兼容的观察,而不是假设它们会自然地趋于一致。分布式系统工程师默认具备这种直觉。大多数 LLM 应用构建者则不然,因为早期的原型通常是顺序运行的,而对同一模型使用相同上下文的顺序调用往往是一致的。一致性鸿沟只会在规模化阶段、为了性能而引入并行化时才显现出来,而到那时,架构往往已经定型。

在你可以预见一致性问题之前就为此进行构建。在发生第一次生产事故后再添加这些模式的成本,远高于在设计仍具可塑性时就将其纳入其中的成本。

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