自我检查与外部验证
模型自评、模型互评与程序化验证的可靠性差异。
一句话理解:让模型“再检查一遍”能抓住一部分粗心遗漏,却抓不住它本来就不知道的错误。验证信号离真实世界越近,就越可靠。
在 Prompt 末尾加一句“请仔细检查你的答案是否正确”,大概是最常见的“验证设计”。它确实偶尔有用,但也很容易带来虚假的安全感:模型几乎总会回答“经检查,结论无误”,有时还会把原本正确的答案“改错”。
这一课比较三种验证者:模型自己、另一个模型、程序与外部环境。它们的可靠性不同,适合的场景也不同。
三种验证者
| 验证者 | 做法 | 能发现什么 | 发现不了什么 | 成本 |
|---|---|---|---|---|
| 自我检查 | 同一个模型、同一份上下文,“再想想” | 格式遗漏、明显的步骤缺失、与清单不符 | 事实错误、数据缺失、它本来就理解错的地方 | 低 |
| 模型互评 | 另一个模型或独立上下文,按评分标准审查 | 语义质量问题、偏离标准、明显的逻辑漏洞 | 评审与生成者共有的盲区,以及评审看不到的事实 | 中 |
| 外部验证 | 代码、测试、数据库读回、API、规则引擎 | 事实与状态是否正确、计算是否准确、规则是否满足 | 无法形式化的质量判断(语气、建议是否合理) | 低到中 |
| 人工专家 | 业务专家复核 | 复杂判断、规则之外的情况 | 规模有限,也会疲劳出错 | 高 |
可以把它们放在一条光谱上:
排序的依据不是“谁更聪明”,而是验证时有没有引入新的、独立的信息。
为什么自我检查不可靠
研究给出了比较一致的结论。Huang 等人在 ICLR 2024 发表的论文《Large Language Models Cannot Self-Correct Reasoning Yet》发现:在没有外部反馈的情况下,大模型很难自我纠正推理错误,有时纠正之后表现反而下降。
同一届 ICLR 上的另一篇论文 CRITIC 则从反方向印证了这一点:让模型在自我批评时调用外部工具,例如用搜索引擎核对事实、用代码解释器调试代码,再根据工具反馈修改输出,效果能够稳定提升。
两篇论文放在一起看,结论很清楚:关键不在“反思”这个动作,而在反思时有没有拿到新的外部信息。
两种做法的差别可以这样对比:
直觉上也好理解:
- 盲区是同一个。 如果模型把日志里的“请求被拒绝”理解成了“请求已成功”,再读一遍时它还是会这样理解。
- 它会被自己的推理说服。 之前的推理过程就在上下文里,读起来连贯合理,模型倾向于认可它。
- 它补不上缺失的数据。 日志接口返回空数组时,“再想想”不会凭空变出日志。
自我检查也不是全无用处。它适合对照明确清单的完整性检查,而不是“判断自己对不对”。例如:“逐条确认输出中每个工单号都给出了结论字段;确认没有遗漏 evidence 字段。”这类检查不需要新知识,只需要细心,成本也低。
模型互评:什么时候有用,怎么用好
当验证对象是语义质量,例如“处置建议是否可执行”“给用户的解释是否有过度承诺”,程序很难写出规则,这时可以请另一个模型来评审。这对应常见 Workflow 模式中的“评估者-优化者”:一个模型生成,另一个模型评估并反馈。
Anthropic 在 Claude Agent SDK 的文章里把这种方式称为 LLM as a judge,适合按“模糊规则”评估输出,同时提醒它不够稳健,还会增加延迟,适合那些“任何效果提升都值得付出成本”的场景。
要让互评真正有效,有几条经验:
- 给独立上下文。 不要把生成者的推理过程一并交给评审,只给任务、证据和待评估的输出,否则评审容易被推理说服。
- 给具体标准。 “请评估质量”不如“建议是否指明了责任方、处理时限和下一步动作,缺一项即不通过”。
- 给证据。 评审要判断结论有没有依据,就必须看到工具返回的原始数据。
- 允许“无法判断”。 证据不足时,让评审说不知道,而不是强行给个结论。
- 尽量换一个模型。 Anthropic 的评估文档建议,一般用与生成模型不同的模型来做评审。
评审模型也有自己的偏差。Zheng 等人在研究 LLM-as-a-Judge 的论文中讨论了位置偏差、冗长偏差和自我偏好偏差。评审提示词的写法、校准方法等细节,放在评分方式一课展开。
程序验证优先:一个分层组合
实际系统里,这几种验证者不是互相替代,而是分层叠加。以工单处理 Agent 的一个结论为例:“问题原因是支付回调失败,订单状态仍停留在未支付;建议重新触发回调并回复用户。”
越靠前的层越便宜、越确定,先把能用程序拦下的错误拦下,再把剩下的语义问题交给模型和人。
把“自我检查”改造成外部验证
很多写在 Prompt 里的“请检查”,都可以换成更可靠的做法:
| 原来的做法 | 改造后的做法 |
|---|---|
| “请检查代码是否正确” | 运行类型检查与测试,把输出交给模型 |
| “请确认计算无误” | 用代码重新计算,比对差异 |
| “请确认引用准确” | 程序检查引用片段是否真的出现在原文中 |
| “请确认邮件已发送” | 查询消息 ID 与投递状态 |
| “请确认 SEO 修改已生效” | 抓取线上页面,检查 title 长度与 canonical 标签 |
| “请确认没有遗漏工单” | 程序比对输入工单列表与输出工单列表 |
常见误区
- 把“反思”当验证。 没有新信息的反思,只是让模型再确认一次自己的想法。
- 用生成模型给自己打分,再把分数当作质量指标。 自我偏好会让分数偏高,也无法发现共同的盲区。
- 有了 LLM 评审就不写程序检查。 能用规则判断的问题交给模型评审,又慢又贵,还不稳定。
- 把人工专家当成最后的万能兜底。 人工复核有容量上限。前几层拦截不力,人工队列很快会被塞满,专家也会开始走过场。
产品经理检查清单
- 当前设计里的“检查”环节,验证者分别是谁?有没有哪一环其实是模型在检查自己?
- 哪些检查可以改写成程序规则、测试或数据读回?
- 需要模型评审的维度是否有明确标准?评审能否看到原始证据?
- 评审是否允许输出“无法判断”?这种情况流向哪里?
- 人工复核的触发条件是什么?预计每天会进入多少量?
练习
从你的 Agent(或一个模拟的工单处理 Agent)中取 10 个输出,其中故意混入 3–4 个有错误的输出(错误的时间计算、编造的日志事件、遗漏的工单)。分别用三种方式检查:
- 让生成模型“请检查你的答案”;
- 用另一个模型,配上具体标准和原始数据进行评审;
- 写一段简单的程序检查(证据回溯、时间重算、工单列表比对)。
记录每种方式发现了几个错误、误报了几个正确输出,写一句你的结论。
延伸阅读
- Large Language Models Cannot Self-Correct Reasoning Yet(Huang 等,ICLR 2024)
- CRITIC: Large Language Models Can Self-Correct with Tool-Interactive Critiquing(Gou 等,ICLR 2024)
- Building agents with the Claude Agent SDK(Anthropic)
下一步
验证发现了问题,下一步是弄清楚“是哪一类问题”。下一课「失败分类」把 Agent 的失败分成五类,每一类对应不同的恢复路径。