我想看看将同一个问题运行 51 次是否会让答案更可靠。我拿了一个本地 LLM,喂给它一段生产环境的代码,并要求它进行审查。然后我再次运行。一遍又一遍。总共运行了 51 次,并使用多数投票法来挑选“最佳”回答。想法很简单:如果模型在某次运行中出错,那么 51 次生成过程中的“群体智慧”或许能抵消噪声,并浮现出正确的分析。但事实并非如此。实验表明,多数投票并不能选出正确性,它选出的是模型最固执的观点。

这种区别至关重要,因为多数投票已成为 LLM 流水线中一种流行的技巧。模式非常直接:对同一个提示词运行模型多次,收集输出,并保留出现频率最高的答案。在医学影像或垃圾邮件检测等领域,集成方法(ensemble methods)之所以有效,是因为不同的模型或对数据的不同观察会产生相互抵消的独立误差。但大语言模型并不是独立的投票者。它们是一个拥有单一训练历史、一组权重和单一偏见宇宙的系统。当你向同一个模型询问同一个问题 51 次时,你并不是在召集一个委员会,而是在对同一个受访者在略微不同的情绪下进行民意调查。

持续性问题

核心问题在于,LLM 的错误很少是随机的。它们是植根于训练数据和架构中的模式。一个在某次运行中误读了特定 Python 装饰器的模型,很可能会在下一次也误读它。一个因为变量名看起来像密码而幻觉出安全漏洞的模型,很可能在第 47 次运行时再次产生幻觉。你正在平均掉的“噪声”通常只是措辞或格式上的表面差异。底层的推理逻辑往往纹丝不动。

考虑一个具体的例子。假设有一个使用正则表达式解析日志文件的函数。该正则既严格又安全。但字符串 r'...' 包含了一些在不同语境下可能引发注入攻击的字符。让 LLM 审查这段代码。如果模型见过成千上万篇警告日志解析器中正则注入风险的 Stack Overflow 帖子,它可能会将这段安全的代码片段标记为风险。运行一次,你会得到一个误报。运行 51 次,很有可能你会得到 51 个误报,或者至少是压倒性的多数。此时,多数投票反而巩固了这种幻觉。模型是具有持续性的,因此“共识”也是具有持续性的。

这是因为温度(temperature)和采样技巧并不能改变模型所掌握的知识。它们只是重新排列了模型的表达方式。高温度可能会让解释变得啰嗦或简短,可能会替换同义词,但它并不会突然教会模型这个正则其实是无害的。你所投票的差异只是修饰性的,而错误是结构性的。

51 次运行揭示了什么

当我把这 51 个输出铺在桌面上时,模式显而易见。模型并没有对代码进行 51 种不同的解读,而是在用略微不同的口吻排练同一种解读。少数几次运行偏离了预设,提出了边缘情况的修复建议或注意到了无关的风格问题。但占据主导地位的集群——即明显的多数——始终在重复同一个错误的中心论点。那个论点并不正确,它只是显得很“熟悉”。

多数投票的数学基础是独立的伯努利试验(Bernoulli trials)。你需要不相关的错误,多数派的表现才能优于个体。在我的实验中,错误是深度相关的。它们有着共同的根源:模型的训练分布过度加权了某些编程套路。因此,多数投票并没有减少错误,反而放大了多数偏见。它为有缺陷的分析提供了一种虚假的确定感。

这在代码审查中尤其危险,因为开发者会将一致或近乎一致的 AI 输出视为权威。一个犹豫不决的建议很容易被忽略;而一个在 51 次运行中始终如一的建议,读起来就像是“真值”(ground truth)。但事实并非如此。它只是一个“地回路”(ground loop)。

投票真正奏效的地方

这并不意味着你不应该多次运行模型。在任务较浅且错误确实是随机的情况下,多数投票可以有所帮助。让模型在两种语法格式之间做出选择、选择一种变量命名规范,或者从日志行中提取日期字符串——这些低风险任务有时能从重复采样中获益。这种差异是真实的噪声,通过快速投票即可将其清除。

当任务需要对意图进行推理时,问题就开始了。这个身份验证检查应该放在这里吗?这个异步调用安全吗?这个缓存键冲突真的可以被利用吗?这些问题需要对上下文的理解,而不仅仅是模式匹配。模型的模式匹配器在偏差上是确定性的。它会倾向于从训练数据中寻找最常见的答案,而不是针对你的代码库最准确的答案。

更明智的算力使用方式

运行 51 次本地模型会消耗真实的时间和电力。有更好的方式来投入这些算力。如果你想提高可靠性,多样性优于数量。使用两个不同的模型运行