跳转到内容

对抗式审查方法论

对抗式审查方法论

学习目标

读完本章后,你将能够:

  • 理解对抗式审查与事后审查的本质区别
  • 应用 CLAIM → EXTRACT → DOUBT → RECONCILE → STOP 五步循环
  • 设计对抗性提示,引导审查者发现问题而非验证结论
  • 实现跨模型升级(Cross-Model Escalation)机制
  • 识别”Doubt Theater”反模式并正确停止循环

为什么需要对抗式审查

AI Agent 在长会话中会积累上下文,这些上下文会将假设悄悄转化为”事实”而无人察觉。一个自信的答案不等于一个正确的答案。对抗式审查的核心理念是:在非平凡决策做出后、成本变高之前,用一个带着”找错”心态的新审查者来交叉检验。

对抗式审查 ≠ 事后审查/review 是对已完成工件的终审判断;对抗式审查是飞行中的逐决策审查——在方向还可以便宜地修正时就发现问题。


什么是”非平凡决策”

对抗式审查仅适用于非平凡决策,不是每个按键都要审查。以下任一条件满足即为非平凡:

条件示例
引入或修改分支逻辑新增 if/else 路径、switch 分支
跨越模块或服务边界两个模块之间的调用契约变更
断言类型系统无法验证的属性线程安全、幂等性、顺序保证、不变量
正确性依赖未来读者看不到的上下文特定于当前会话的假设
影响范围不可逆生产部署、数据迁移、公开 API 变更

不适用:机械操作(重命名、格式化)、明确的用户指令、读取代码、一行变更的明显正确性。


五步循环

CLAIM ──→ EXTRACT ──→ DOUBT ──→ RECONCILE ──→ STOP
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
命名决策 隔离工件 对抗审查 分类发现 有界停止

Step 1: CLAIM — 命名决策

用 2-3 行写下你做了什么决定以及为什么重要:

CLAIM: "新的缓存层在规格描述的读重负载下是线程安全的。"
WHY THIS MATTERS: 此处的竞态会损坏用户数据且 QA 难以检测。

如果你无法用这么紧凑的篇幅写出 CLAIM,那你有的只是一个感觉,不是一个决策。在审查前先厘清它。

Step 2: EXTRACT — 隔离最小可审查单元

新上下文的审查者需要的是工件契约,而不是你的推理过程:

  • 代码:diff 或函数本身,不是整个文件
  • 决策:3-5 句提议加上必须满足的约束
  • 断言:CLAIM 加上支撑它的证据(与 Step 1 的 CLAIM 块分开)

关键规则:剥离你的推理。如果你把结论交给审查者,你得到的会是对你结论的验证,而不是独立判断。单元必须小到审查者一次阅读就能装进脑子——如果是 500 行的 PR,先分解。

Step 3: DOUBT — 用对抗性提示调用审查者

审查者的提示必须是对抗性的。框架决定答案:

对抗式审查。找出这个工件的问题。
假设作者过于自信。寻找:
- 未声明的假设
- 未处理的边界情况
- 隐藏的耦合或共享状态
- 契约可能被违反的方式
- 可能破坏的现有约定
- 意外输入下的故障模式
不要验证。不要总结。找问题,或明确声明
你经过彻底检查后找不到任何问题。
ARTIFACT: <粘贴工件>
CONTRACT: <粘贴契约>

关键约束

  • 只传递 ARTIFACT + CONTRACT,不要传递 CLAIM。把你的结论给审查者会偏向同意。
  • 审查者必须独立判断工件是否满足契约。
  • 对抗性提示优先于角色的默认响应格式——如果角色的默认输出是”优点+缺点”的平衡报告,但你需要的是”只找问题”的输出,必须粘贴对抗性提示来覆盖。

Step 4: RECONCILE — 分类发现

审查者的输出是数据,不是判决。你仍然是编排者。在分类前重新阅读工件文本——橡皮图章式接受审查者的发现和直接忽略它一样是失败模式。

按以下优先级顺序分类(第一个匹配的类别胜出):

优先级类别含义
1合同误读审查者标记问题是因为你提供的 CONTRACT 不清楚或不完整。先修复合同,下一轮重新分类。
2有效 + 可行动真实问题,需要修改工件。修改后重新循环。
3有效权衡问题真实存在,但修复成本大于接受成本。显式记录权衡,让用户看到。
4噪声审查者标记了在你拥有而审查者没有的上下文中实际正确的东西。记录下来,继续前进。

注意:新审查者可能因为缺少上下文而出错。不要因为它是”新鲜的”就盲从。重新阅读工件,分类,然后决定。

Step 5: STOP — 有界循环,不是无限递归

满足以下任一条件时停止:

  • 下一轮只返回琐碎的或已经考虑过的发现
  • 已完成 3 轮循环(向用户报告,不要独自继续第 4 轮)
  • 用户明确说”发布它”

如果 3 轮后审查者仍然发现实质性问题,工件可能还没准备好。向用户报告——3 轮未解决本身就是一个关于工件质量的信息。


跨模型升级

单一模型的审查者与原始作者共享盲点——一个更冷门的、不同架构的模型能捕获这些盲点。

交互式会话:始终提供选项,禁止静默跳过。

升级流程:

  1. 单模型审查完成后,在 RECONCILE 之前暂停并询问用户
  2. 如果用户选择某个 CLI 工具:先验证工具在 PATH 中,再测试它能工作(gemini --version),再确认确切调用方式
  3. 只传递 ARTIFACT + CONTRACT + 对抗性提示——不传递会话上下文,不传递 CLAIM
  4. 注意 Shell 转义:如果工件包含引号、$(...) 或反引号,优先使用 stdin 或 heredoc,而不是内联参数
  5. 将输出带入 Step 4(RECONCILE)

非交互式上下文(CI、定时任务、自主循环):跨模型被跳过,且必须在输出中宣布跳过。

关键安全属性:永远不要在未经用户明确授权的情况下自动调用外部 CLI。每次调用都是独立的授权——工件、提示、标志都会变化,每次都要重新确认。


反模式:Doubt Theater

可检查的信号:在 2 轮或更多轮循环中,审查者发现了实质性问题,但零个被分类为可行动的。

你在做验证,不是在做质疑。停止并升级。


与其他质量门控的关系

方法定位与对抗式审查的关系
多维度质量门控检查 BUILD/TEST/LINT 等维度是否通过对抗式审查补充这些自动化检查——它捕获那些测试无法覆盖的设计决策问题
证据驱动审查要求证据新鲜度,防止假阳性对抗式审查本身就是生成新鲜证据的过程——一轮审查就是一轮新鲜证据
TDD 的 RED 步骤失败的测试是一个证伪尝试当 TDD 适用时,失败的测试就是行为 CLAIM 的质疑步骤
事后审查(/review)对已完成工件的终审互补而非替代——对抗式审查在飞行中捕获问题,事后审查做最终判断

检查清单

应用对抗式审查后,确认:

  • 每个非平凡决策(按上述定义)在确立前被显式命名为 CLAIM
  • 每个非平凡工件至少经过一次新上下文审查(TDD 的 RED 步骤可满足行为 CLAIM)
  • 审查者收到的是 ARTIFACT + CONTRACT,而非 CLAIM 或推理过程
  • 审查者的提示是对抗性的(“找问题”),而非验证性的(“这样好吗?”)
  • 发现被分类(不是橡皮图章式接受),按优先级顺序:合同误读 / 可行动 / 有效权衡 / 噪声
  • 满足停止条件(琐碎发现、3 轮循环、用户覆盖)
  • 在交互式模式下,跨模型被显式提供给用户(无论工件风险高低)
  • 在非交互式模式下,跨模型被跳过且跳过被宣布