让 Agent 自己检查自己,为什么总是通不过?
自审(self-review)在 Agent 里失败率极高,不是因为模型不够聪明,而是检查者和执行者共享了同一个错误前提。本文拆解审查层失效的四个机制,并给出真正能拦住错误的工程做法。
几乎每个做 Agent 的团队都试过同一个方案:让模型执行完任务以后,再问它一句”请检查你刚才的输出是否正确”。
结果通常是——它说”看起来没问题”。
一个明明把两个日期搞混的行程表、一份引用了不存在文献的报告、一段漏了边界条件的代码,经过”自检”之后依然原样交付。于是有人下结论:模型没有自审能力。这个结论一半对,一半完全搞错了失败原因。
一、自审为什么系统性失效
同源性错误(最致命)。检查者使用的是和执行者相同的权重、相同的上下文、相同的错误理解。你让它检查”2026 年 3 月有 31 天”这种错误,它心里的日历和刚才写的时候是同一本,看不出问题。审查能发现的是”和上下文矛盾”的错误,发现不了”上下文本身错了”的错误。
被自己的输出锚定。上下文里已经存在那份答案,模型的任务变成了”为这份答案找支持理由”,而不是”从零推导一遍再比对”。这是典型的确认偏误,且随着答案越长越严重。
缺少外部事实。没有工具、没有检索、没有测试执行的自审,本质上是在做语言上的自我安慰。它只能评估”读起来像不像对的”,而绝大多数错误恰好读起来很像对的。
激励方向不对。如果你在提示里写”请仔细检查确保没有问题”,模型倾向于给出”已检查,无问题”的结论——因为那是最短路径。想让它挑出问题,就得明确告诉它”这里至少存在两个问题,请找出它们”,这会显著改变产出,但代价是会编造问题。
二、把”自审”拆成四种不同的东西
工程上更有效的做法,是不要再把审查当成一句提示,而是拆成四个可独立实现的机制:
| 机制 | 谁来做 | 能拦住的错误 | 拦不住的 |
|---|---|---|---|
| 规则校验 | 代码 | 格式、枚举、范围、必填 | 语义错误 |
| 事实核对 | 检索/工具 | 引用不存在、数据不符 | 逻辑推演错误 |
| 独立性审查 | 另一模型/另一上下文 | 遗漏、指令未遵守 | 共享的前提错误 |
| 执行验证 | 测试/沙箱 | 代码跑不通、结果不一致 | 需求理解偏差 |
关键是每一层都不假设上一层是对的。
规则校验先上,别浪费 token。日期格式、金额区间、枚举值、链接可达性、JSON schema,这些用代码几十毫秒就能查完。很多团队把这些交给模型查,既慢又不准。
事实核对必须有外部锚点。报告里的每个数字、每个人名、每个引用,都要能回溯到一个检索到的片段或工具返回结果。做法是要求执行者在输出时携带 claim → source_id 的映射,审查环节只做机械比对。没有 source_id 的断言直接标记为”未核实”,而不是”通过”。
独立性审查要切断上下文。把执行者的完整推理过程藏起来,只给审查者三样东西:原始需求、交付物、(可选)被引用的材料。它不知道执行者”当时是怎么想的”,因此不会被带偏。实践中,只给需求和产物、不给过程,能多抓出 20%–30% 的问题。
执行验证交给环境。代码就跑测试,SQL 就在只读库上跑一遍看是否报错,链接就真去请求一次。任何可以”跑一下就知道”的东西,都不要问模型。
三、审查提示应该怎么写
如果你只能改一个地方,把审查提示从”请检查”改成带具体检查项的清单,并强制结构化输出:
你是审查员。你只能依据下面给出的【需求】和【材料】做判断。
不要假设交付物是正确的。对每一项输出 pass / fail / unknown。
unknown 表示材料中无法确认,不得填 pass。
检查项:
1. 是否完整覆盖需求中的每一个要求(逐条列出对应位置)
2. 每个数字、日期、名称是否能在材料中找到出处
3. 是否存在超出材料范围的结论
4. 是否存在自相矛盾之处
输出 JSON:{ "items": [{"id":1,"verdict":"","evidence":"","note":""}], "overall": "" }
三个细节值得注意:允许 unknown 是这套设计的灵魂,它把”没查到”和”查了没问题”分开了;逐条列对应位置逼着模型真的去定位;overall 不能覆盖条目,任何一条 fail 都直接导致整体不通过,否则模型会用”总体良好”抹平硬伤。
四、成本和收益怎么权衡
全套审查会让成本翻倍甚至三倍。务实的做法是按风险分级:
低风险输出(闲聊、草稿、内部备忘):不做审查,靠人事后看。 中风险输出(对外邮件、报价、客服答复):规则校验 + 事实核对。 高风险输出(代码入库、合同条款、对外报告、金额相关):四层全上,且必须有人工签核节点。
另一个省钱的手段是只审动作,不审全文。Agent 要执行写操作时,审查的重点不是它的解释文本,而是即将发出的结构化参数:收件人是谁、金额多少、删的是哪几条。这些字段小、可机检,成本极低而拦截价值极高。
五、一个判断标准
判断你的审查层是否真的在工作,看一个指标:它的拒绝率。
如果审查环节从来没否决过任何输出,它不是在做审查,是在盖章。健康的区间通常在 5%–20%——低了说明检查项太软,高了说明执行环节本身有问题,该往上游修。
把这句话记下来:审查的价值不在于让模型说”没问题”,而在于它有能力说”有问题”,并且说得出是哪里。做不到这一点的自检,写一百遍也不如一段三行的校验代码。