[控场AI]
· 11 分钟阅读· 5,726 字

多智能体评审团自信出错:实测百万token的教训

多智能体评审团自信出错:实测百万token的教训

多智能体评审小组的自信共识往往是简报偏见的证据,而非真相的证据。

一位开发者用多智能体流水线做代码评审,却发现三个智能体因无法访问登录墙后的标准文档,仅凭搜索摘要推理,得出了与文档原文几乎相反的结论——他本人一次约2000 token的阅读推翻了约120万 token 的结论,形成600:1的不对称。更令人不安的是,同一问题、同一模型、同一证据,仅因简报框架不同,裁决就完全反转,说明评审小组的一致性本质上是关于简报的证据。文章还揭示了更隐蔽的失败模式:死掉的智能体会报告死亡,而"成功但猜测"的智能体返回结构良好的错误结果却不会触发任何警报。作者给出的修复包括为每个评判智能体加 provenance 必填字段、中立化简报、对组合结果从零重新评分、审计过滤器、以及不要用正则给智能体打分。

一次"自信的共识"如何变成灾难

一位开发者用多智能体(multi-agent)流水线做代码评审已经有一段时间了。他的做法是:让几十个智能体各自带着不同视角、结构化输出、对抗式验证轮次,跑出看起来非常严谨的评审结果。

上周,这套流水线给出了一个"自信、全体一致、但完全错误"的答案。由于他保留了完整的对话记录(transcript),所以他能够精确说出这次失误的代价和修复方案。

数据来自一周的运行统计:18 条工作流、158 个智能体、139 MB 对话记录、约 2800 万 token。其中大约三分之一是可以避免的浪费。

rss source: My multi-agent review panel was confidently wrong. I measured why.

失败是怎么发生的

一个由三个智能体组成的评审小组要审查一项技术主张,判断它是否真实、是否值得行动。三个智能体都说"不"。每个都写了详细、具体、论证充分的拒绝理由。

它们的推理都围绕一份公开标准文件展开——那份文件管辖着这个决策。问题在于:三个智能体都打不开这份文件。文档在一个登录墙后面,而智能体正确地拒绝了身份验证请求(这是作者希望看到的行为)。于是它们只能根据标题、搜索摘要,以及"一份叫这个名字的文档大概会说什么"来进行推理。

结果,文档的实际内容和它们猜的几乎相反。

作者自己通过已验证的浏览器会话读了这份文档,只花了一次工具调用。文档的实际文本——在它自己的工作示例中——直接回答了三个智能体构建拒绝理由时所依赖的两个具体反驳点。

那次阅读大约花了 2000 token。它推翻了大约 120 万 token 的结论。

这是一个 600:1 的不对称,也是作者那一周做过的最有价值的一件事。

多智能体流水线(multi-agent pipeline) 指将一项任务拆解给多个独立运行的 LLM 智能体,每个智能体拥有各自的提示词、角色或视角,输出再被汇总、对抗或交叉验证。常见形态包括扇出(fan-out,同一问题分发给多个智能体以获取多样答案)、评审小组(review panel,多个智能体独立裁决同一主张)、以及对抗式验证(adversarial verification,让智能体互相挑错)。

它的核心假设是:独立视角的多数意见能抵消单点错误。但本文揭示的漏洞是——独立性可能只是表面的。如果所有智能体共享同一份有偏见的简报、同一批不可访问的源文件、同一个无法发问的失败通道,那么它们实际上是在同一个错误前提上分叉,共识反而会放大而非纠正错误。这也是为什么作者强调要读自己的提示词、要求分歧字段、以及给输出加 provenance 标注:这些都是为了把"伪独立"重新变回"可核查的独立"。

真正让人不安的部分

作者用真实文档内容重新跑了这个评审小组。这次三个智能体全部反转,说"是"。

结果很好,但有一件事让他不安:两次简报(briefing)都是他自己写的。第一份告诉智能体要充满敌意、假设主张是错的。第二份引用了标准原文,并指出前一个小组读错了。

同一个问题、同一个模型、同样的证据。相反的框架,相反的裁决。

所以第二次运行不是纠正,而是作者得到了自己已经决定的答案,然后三个智能体带着引用把答案还给他。他之所以发现这一点,是因为恰好重读了自己的提示词,注意到在希望智能体重点关注的段落上方写了"把最后一段读两遍"这句话。

他杀掉了那次运行并重写:引用来源时不加评论,传递证据前剥掉 helps 和 hurts 标签,并要求每个智能体填写一个必填字段——说明简报哪里错了。

这个版本也说了"是"。但这次三个智能体中有两个告诉他:他的简报夸大了一个约束条件,并且掩埋了一个本该浮出的反论据。其中一个指出,他递给智能体一个有利论据的同时,省略了同一份文档中一个不利条款。

这才是评审小组存在的意义。 共识是廉价的。价值在于分歧,而只有当留有分歧的空间时,你才能得到它。

框架效应(framing effect) 原本是行为经济学概念:同一组事实,仅因表述方式(强调损失还是收益、假设为真还是为假)不同,就会导致人们做出相反判断。在 LLM 语境下,它表现为提示词中的语气、顺序、标签和隐含期待会系统性影响模型的输出倾向。

本文中作者在两个版本里都亲自撰写了简报:第一版要求智能体"充满敌意、假设主张是错的",第二版引用标准原文并指出前一组读错了。模型、问题、证据都不变,裁决却完全反转。这说明模型的"独立评审"很大程度是在反映提示词中已经埋好的结论——即所谓的 sycophancy(迎合性) 的变体:模型会顺着用户暗示的方向组织论证,并配上看起来扎实的引用。

因此,当评审小组给出全体一致的裁决时,真正被测量的往往不是证据强度,而是简报的偏向。要获得有信息量的分歧,简报必须中立:只给来源、不给评论,剥掉 helps/hurts 这类裁决形状的标签,并强制要求智能体指出简报中可能出错的地方。

你没有在盯防的失败模式

那一周中途,作者触发了用量限制。四个智能体在运行中死亡。

这没有造成任何损失。运行时打印出了失败块。用一行命令对日志做独立检查就能确认:统计每个目录下 started 和 result 类型事件的数量,如果数字不一致,说明有东西死了。响亮的失败是廉价的,因为它们是可见的。

真正昂贵的失败是那个成功的智能体。它正常完成,返回了结构良好的结果,并报告说它无法访问所需文档。然后它还是根据摘要进行了推理,而下游的智能体把它的输出当作已定事实。没有任何东西发出警报,因为在任何 harness 能检测到的意义上,都没有出错。

死掉的智能体会告诉你它死了。猜测的智能体什么都不会告诉你。

provenance(来源追踪 / 证据出处) 指对每条关键主张标注它究竟是怎么得来的,而不是只看结论是否格式正确。在本文的 schema 里用四个值区分:READ(确实读了源文件)、EXECUTED(实际运行了代码或命令)、INFERRED(从摘要、标题或间接线索推断)、BLOCKED(需要但无法访问某份材料)。

它的价值在于把"结果看起来对不对"换成"结果能不能被追溯"。一个正常完成、结构良好、却说不出自己读了什么的智能体,和死掉的智能体完全不同——后者会触发失败块,前者会安静地把猜测传给下游,并被下游当成既定事实。加一个必填的 provenance 字段几乎不增加成本,却能让评审者立刻看到哪些前提是 INFERRED、哪些数字是从别的智能体那里信任采纳而未经验证。作者测试的两个模型都能良好遵守该字段,输出也从"自信"变为"可核查"。

近乎零成本的修复

作者给每个评判智能体的输出 schema 加了一个必填字段:

provenance: 对每个承载关键论点的主张,标注 READ(读了什么)、
            EXECUTED(跑了什么)、INFERRED 或 BLOCKED。
            关键前提为 INFERRED 的裁决必须声明这一点。

他测试的两种模型都能很好地遵守这个字段,成本几乎为零。它把返回结果从"自信"变成"可核查"。

最精彩的例子来自一次运行:一个智能体把登录受限页面标记为 BLOCKED,精确列出它从早期智能体那里信任采纳、没有重新运行的具体数字,并将这些与它自己从源文件验证的事实分开。那个智能体的裁决比三个自信的裁决更有价值,因为作者能看到该在哪里深入追查。

最彻底的那次运行,返回了干净的"什么都没有"

在看到框架效应之后,作者想要一个更硬的测量,于是设置了一个盲测。方法和他给评测套件打分时一样:拿答案已经确定的材料,把答案藏起来,看这个测量工具实际检测到什么。你实测到的检测率,胜过你声称的检测率。

他把六个智能体锁在一个源码树里,把所有包含先前分析的文件移出可达范围,给六个智能体完全相同的提示词,提示词里从不说要找什么。

六个中有三个浮出了底层机制。真正重要的东西是两个独立观察——只有放在一起时才变得有意义。

他第一遍打分说六个都没建立这个联系。那是错的,而且错的原因令人尴尬:他用关键词搜索给它们的输出打分,而不是真的读。当他真正读的时候,发现三个中有两个明确建立了联系。一个写道,它第三个发现中的某一步是"发现 1 恰好需要的前提条件"。另一个写道,同一步"正是发现 1 和上面 (a) 点共同利用的"。

然后它们各自把这个观察归档为一个次要发现的子条款,继续往下走。

所以失败不在检测,甚至不在组合。而在 重新评分(re-scoring)。两个智能体都发现了联系、用平实的语言写了下来,然后让这个组合继承其组成部分的低严重度,而没有问这个组合本身值多少。有趣的结果不是智能体会错过联系,而是它们能找到联系却仍然不据此更新判断。

作者的打分错误是同样的形状:一个检查返回了自信的答案,但理由是错的,只有阅读底层材料才抓住了它。一周之内出现了三次,这大概就是整篇文章的意义。

一个"什么都没找到"的智能体,其实最认真

作者一直回想的那次运行,什么也没返回。

那个智能体做了六个中最细致的工作。它构建了项目,运行了现有的 391 个测试,提取了仓库中每一份参考文档,并把每个候选发现与它们逐一核对。它正确地将自己找到的片段匹配到了已经记录并接受的已知问题。然后它合理地得出结论:没有什么新东西。

它的笔记里有一句话,描述了真实问题所在的确切代码行,并记录它们为安全。

它不是粗心。它在遵循作者"把已知问题列表当作硬过滤器"的指令,而且比那些更接近的智能体更忠实地遵循了这个指令。每个已记录的问题描述一个机制。每个都携带一个例外,用于其自身机制从未触及的情况。组合触及了它。

所以是作者的过滤器错了,不是智能体错了。"这匹配已知的某个东西吗"会丢弃那个逃出已知范围的组合。问题必须是:"这匹配吗,以及这些候选的任何组合是否触及已知项自身声明的例外?"

一般化的版本是:当你给智能体一个过滤器,你同时也在告诉它们该扔掉什么,而一个认真的智能体会扔掉更多。

组合爆炸与非单调性(combinatorial emergence) 是这类流水线里最容易漏掉的一类发现:单个候选问题可能都平凡、无害、被已知列表覆盖,但两个或多个候选叠加后,会触发某条已被记录的规则的例外情形,从而产生一个全新的问题。

本文中那个"什么都没找到"的智能体之所以被判为安全,是因为它被要求"把已知问题列表当作硬过滤器"——每个已知问题都描述一种机制,并携带一个该机制自身从未触及的例外。逐个检查候选时,没有任何一个落在例外里;但组合起来,恰好触及了它。问题出在过滤器,而不是智能体。

一般化的教训是:当你给智能体一个过滤器,你同时也在告诉它该扔掉什么,而一个认真的智能体会扔掉更多。因此需要一道专门的"组合轮"——由单个智能体(而非扇出)审视整个候选列表,问是否存在任何组合加总后等于它们单独都不等于的东西,并对该组合从零重新评分,而不是让它继承各组成部分的低严重度。

作者改了什么

四条规则,按运行顺序:

一、在任何智能体启动之前,自己读管辖文档。 决策实际取决于什么——规范、标准、策略、配置——就都读一遍。把一份事实文件交给每个智能体,这样没人重新推导,也没人瞎猜。如果它在登录墙后面,那是人的工作,而且只需一次工具调用。

二、便宜的检查放在昂贵的检查之前。 作者的流水线先构建完整复现,然后很晚才发现两个候选死在了各需一次查询的问题上。现在,廉价的淘汰性问题首先在所有候选上运行,然后才对任何东西运行昂贵的检查。

三、绝不要给评审小组指向某个答案的简报。 引用来源不加评论。传递证据前剥掉裁决形状的标签。要求一个 disagreements 字段。

四、用经过时间或错误率来限制探索性工作,而不是用完成与否。 一次探查跑了 99 分钟、积累了 465 个错误后才因速率限制死亡,而它追寻的东西早前一次探查已经结构性地排除了。没有什么阻止它,因为除了它是否完成,没有任何东西在盯防。

五、加一道组合轮,并对它发现的东西从零重新评分。 一个智能体,而非扇出,问整个候选列表:这里是否有任何组合加总起来等于它们单独都不等于的东西,那个组合本身值多少——以其自身评定,而非从其部分继承。后半句正是失败的地方。

六、审计你的过滤器。 对每个交给智能体的过滤器,写下它扔掉了什么,然后去垃圾堆里看一眼。

七、不要用正则给智能体打分。 作者用关键词搜索给检测测试打分,得到了反向的头条结果。读输出。

诚实的局限

一周。一条流水线。一个领域。作者测量的是对话记录体积和 token 数量,不是受控实验,而且框架效应的结果是 n=3、单个问题。

他能确信的范围比听起来要窄:当一个智能体小组达成一致,而所有简报都是同一个人写的,那个一致是关于简报的证据。 上面其他一切都是这个事实的推论。

这个问题的深层版本并不新鲜。一个不可能失败的检查不是检查。 我们对 CI 门禁知道这一点——一个由被跳过的步骤满足的必需任务能通过评审好几年,因为没人要求它证明自己可以变红。我们对测试套件也知道这一点。对评审小组同样成立,而且更难看见,因为输出是流畅的、结构化的,还一式三份地到来。

如果你在跑智能体扇出,去读你自己的提示词。找找那句话——你告诉它们你想听什么的那句话。

作者找到了他的。

分享:

相关推荐