对抗性审查(Adversarial Review)
0. 核心定位
当一个 AI(编程 agent、写作 agent、方案 agent)交付了代码/方案/设计,在用户验收之前,由对抗视角做系统性破坏测试——既攻击交付物本身,也攻击交付过程中的声明。
审查对象是三方整体,不是孤立的交付物:
① 原始需求 —— 用户当时到底要什么(原始 prompt / 需求描述 / 任务书)
② 交付物 —— AI 实际产出的东西(代码 / 方案 / 设计 / 文档)
③ 完成声明 —— AI 声称自己做了什么("已完成""已测试""修复了")
- ② vs ③ 对照 → 查虚假声明(F3)
- ① vs ② 对照 → 查需求缩水(F2)
- ① vs ③ 对照 → 查承诺落空
三方缺失时不臆测、不阻塞:相应检查项降级为「未覆盖」,在报告盲区段声明。
四条边界(违反任何一条即跑偏):
- 不替代验收决策——输出风险清单,用户做最终判断
- 不做建设性补全——只攻击和暴露,附修复方向但不重写
- 不审查「能力边界」本身,只审查「证据链」——能力是运行时配置(模型×工具×connector×权限),动态变化;声称做过 X 就要拿出做 X 的中间产物,拿不出一律按「未验证声明」处理(详见 D0)
- 不追求零问题——价值在于把问题按风险显性化;找不到高等级风险就明说,禁止凑数
1. 触发判定
| 触发 | 不触发 |
|---|---|
| "对抗性审查""验收一下 agent 写的代码""这个方案靠谱吗""AI 写的这个能信吗""帮我挑刺""红队审查" | 「这个怎么样」「看看如何」类随口一问(重型流程不被无意激活) |
| agent 完成任务后用户要求验收 | 用户自己写的东西要求 review 情绪/风格 |
| 贴入其他 AI 工具的产出要求把关 | 用户明确只要夸奖或只要执行 |
2. 审查流程(七步,顺序不可乱)
第一步:三方输入收集
- 当前会话内的 agent 任务:直接从对话上下文提取三方输入
- 跨工具场景:要求用户贴入;用户只给交付物时如实标注"只有交付物"
- 原始需求缺失时先问用户能否提供;不能提供则记录为盲区,继续
第二步:建立攻击地图
列出四张清单:
- 需求原子条目——逐字引用用户原文,禁止改写式转述(改写会把审查方自己的解读混入需求,同会话场景下这是 F2 漏检的主通道)
- AI 的声明清单(所有"已完成/已测试/已修复")
- 外部依赖清单(API、库、文档、数据源)
- 交付物结构与信任边界
复杂对象(>500 行代码 / >3000 字文档 / 改动 ≥5 个文件)必须先展示攻击地图给用户确认火力点。
歧义处理:同一原文存在两种合理读法时标「歧义」并暂停,待用户裁决读法后再定级。
第三步:D0 交付真实性审查(先行,不过 D0 不进 D1-D4)
传统审查假设"作者想交付对的东西但可能疏忽";AI 审 AI 必须先怀疑"交付声明本身可能不成立"。
D0 动作 1:需求符合性矩阵
| # | 原始需求条目(逐字引用) | 状态 | 差异说明 |
|---|
状态:已满足 / 部分满足(差异说明)/ 未满足 / 无法判断 / 歧义待裁决。 纪律:拟判「未满足」的条目必须回读原文二次确认。
D0 动作 2:声明证据核验(走证据链三问)
对 AI 的每条完成声明:
- 这个声明依赖什么能力?(读图 / 联网 / 执行代码 / 访问文件)
- 有没有该能力被实际调用的中间产物?(OCR 输出文本、工具调用记录、命令 stdout、fetch 到的原始内容)
- 中间产物能否被抽验?(由审查方执行:产物细节 vs 原始来源抽查比对;无法访问原始来源时标「建议人工验证」,不得跳过)
标注三档:有证据 / 未验证声明 / 虚假声明(产物与声明矛盾)。
证据分级:宿主系统记录的工具调用痕迹(强证据)> 文本形式的 stdout/OCR 输出(弱证据,必须配合第 3 问抽验)。
能力探针(可选):当审查结论本身依赖"AI 当时是否具备某能力"时,做一次最小实证(让它现场读图说一个细节 / 现场访问 URL 返回具体内容)。注意:探针仅对"生产方 = 当前会话可调用的 agent"有效;跨会话/跨工具场景统一走「未验证声明」处理,当前 agent 的探针结果证明不了当时那个运行时的能力。
D0 动作 3:幻觉依赖排查
列出交付物引用的所有外部事物(API、库、配置项、命令参数、文档、数据源),抽查高风险项的可验证性——查官方文档/源码,不信 AI 的记忆。未抽查项在报告里声明。
第四步:D1-D4 通用维度审查
顺序:D2 安全 → D1 正确性 → D3 健壮性 → D4 现实性
| 维度 | 核心提问 | 检查点 |
|---|---|---|
| D1 正确性 | 它在什么情况下会产出错误结果? | 逻辑漏洞、边界条件、隐含假设不成立 |
| D2 安全性 | 它能被怎么滥用? | 注入/越权、数据泄露、恶意输入 |
| D3 健壮性 | 它在什么负载/异常下会崩? | 异常处理缺失、资源耗尽、并发竞争、依赖失效 |
| D4 现实性 | 真实世界会和它的假设差多远? | 事实准确性、信源可靠性、过度工程、二阶效应 |
深度参数(默认"标准"):
- 快速:完整 D0 + D2 最高危项;报告只列 P0/P1
- 标准:六类失效模式 + D0-D4 全过
- 全面:含小概率高损害场景 + 二阶效应
第五步:自对抗一轮
对每个 P0/P1 发现问三问:「有没有可能这其实不是问题?AI 是不是已经防了/声明了?我是不是误读了需求?」扛不住的发现降级或删除。
常见误报模式清单见 references/self-adversarial.md。
第六步:结构化输出(报告模板见第 4 节)
第七步:(可选,用户要求时)复检模式
- AI 修复后再次调用,对照原问题清单逐项验证
- 复检同样要证据:不能只听 AI 说"已修复"
- 问题清单落盘:首轮审查完成后,将问题清单(编号/等级/位置/状态)写入项目 memory(
.workbuddy/memory/当日日志),供跨会话复检对照 - 跨会话复检时先读 memory 中的原清单,输出「原问题 → 修复证据 → 复检结论」对照表;原清单缺失时声明并降级为全量重审
3. 审查靶心:六类 AI 特有失效模式
(详表+历史案例见 references/failure-modes.md)
| # | 失效模式 | 典型形态 | 审查手法 |
|---|---|---|---|
| F1 | 幻觉 | 编造 API/库/配置项/引用 | 所有外部依赖可验证,查官方文档 |
| F2 | 需求缩水 | 5 条约束只做 3 条且不声明 | 需求逐条对照,产符合性矩阵 |
| F3 | 虚假完成声明 | "已测试"但没跑过 | 所有声明要可复核证据 |
| F4 | 过度工程 | 简单需求引入复杂抽象 | 每层问"去掉损失什么" |
| F5 | 谄媚隐藏 trade-off | 只给用户想听的路线 | 检查是否呈现真实选择和代价 |
| F6 | 上下文遗忘 | 后半段忘记前半段约束 | 早期约束清单逐项核验 |
4. 风险定级(先查矩阵,再套覆盖规则)
3×3 定级矩阵:
| 概率 \ 损害 | 损害高 | 损害中 | 损害低 |
|---|---|---|---|
| 概率高 | P0 | P1 | P2 |
| 概率中 | P1 | P2 | P3 |
| 概率低 | P2 | P3 | P3 |
覆盖规则:
- 不可接受类损害无视矩阵:资金损失、用户数据泄露、公开发布的事实性错误、核心需求缺失、核心功能不可用、安全被实际攻破——最低 P1;概率 ≥ 中 → P0
- 已发生 = 概率高:问题在审查时已发生(需求已被砍、声明已落空),概率按高计
- 损害看后果不看修复难度:「易修」不降级;修复成本在修复建议里另行考量
置信度(每条发现强制标注):
- 高 = 已确认(代码行/原文/可复核证据佐证)
- 中 = 合理推断,写明依赖的假设
- 低 = 理论可能,需进一步验证
本 skill 自身的发现同样受此约束,禁止为显得确定而夸大。
5. 对抗性思维的五个手法(审查引擎)
- 翻转假设:把每个「默认成立」的前提列出来,逐个问"如果它不成立呢"
- 恶意输入构造:不构造合理输入测功能,专造离谱输入找崩溃
- 攻击路径推演:每个问题写清「从哪进入 → 触发什么 → 造成什么后果」
- 声明-证据对照:对每句"已完成/已验证",问"证据在哪?我能复现吗?"
- 换位视角:把自己当成接手这个交付物的人——三个月后半夜出问题时,我会恨这个 AI 什么?
每个手法至少产生一个候选发现,或显式声明该手法无发现(防止只挑顺手的手法用)。
6. 报告模板(严格)
# 对抗性审查报告:[交付物名称]
## 总览
| 项 | 值 |
|---|---|
| 交付物 | [类型 + 名称] |
| 生产方 | [哪个 AI / agent / 工具] |
| 审查方与生产方 | 同源(自审,可能共享盲区,关键发现建议异源复核)/ 异源 |
| 审查深度 | 快速 / 标准 / 全面 |
| 三方输入完整性 | 需求 ✓/✗ / 交付物 ✓ / 声明 ✓/✗(缺项标注) |
| 发现问题 | 致命(P0)×n / 严重(P1)×n / 一般(P2)×n / 提示(P3)×n |
| 一句话结论 | [最致命的问题,或"未发现高等级风险"] |
## 交付真实性核验(D0)
### 需求符合性矩阵
| # | 原始需求条目(逐字引用) | 状态 | 差异说明 |
|---|---|---|---|
### 声明证据核验
| # | AI 的声明 | 核验结果 | 证据 |
|---|---|---|---|
(核验结果:有证据 / 未验证声明 / 虚假声明)
### 幻觉依赖排查
[抽查的外部依赖项及验证结果;未抽查项声明]
## 问题清单(正确性/安全性/健壮性/现实性四维发现)
### 问题1【严重 P1】:[问题标题]
- **位置**:[文件:行号 / 文档章节 / 流程节点]
- **攻击路径**:[从哪进入 → 触发什么 → 造成什么后果]
- **失效模式**:[中文名为主、代号进括号,如"需求缩水(F2)";不适用写"——"]
- **风险等级**:严重(P1)· 概率高/中/低 × 损害高/中/低
- **置信度**:高 / 中(依赖假设:xxx)/ 低
- **修复方向**:[一句话方向]
## 自对抗记录(可选但推荐)
[被降级/删除的候选发现及理由]
## 未覆盖的盲区(必填,要有实质内容)
- [缺什么信息/能力导致没查的部分]
## 验收建议
[可验收 / 修复致命·严重问题后验收 / 打回重做——措辞用"建议"]
中文化纪律(强制):报告是给用户看的验收工具,不是内部工作底稿。所有代号必须中文名在前、代号退到括号:风险等级写「严重(P1)」,失效模式写「需求缩水(F2)」,维度写「交付真实性核验(D0)」「问题清单(四维发现)」。连续出现同一代号时首次展开、后续可简写。违反此纪律的报告视为不合格输出。 对外发布纪律(强制,2026-08-25 增补):审查结论若要转化为对外公开内容(站内文章、公众号、技术社区、发布包),代号连括号标注也一并删除,只保留中文表述——写「需求缩水」而非「需求缩水(F2)」,写「2 个一般问题 + 5 个小问题」而非「P2×2 + P3×5」,写「交付真实性核验」而非「交付真实性核验(D0)」。可保留的英文仅限专有名词(产品名/模型名/安装命令/仓库名)。教训来源:8/25 出稿「AI 审 AI」手记时把内部代号原样搬进对外文章,读者完全看不懂,被 ts 打回重改。
7. 输出纪律
- 每个问题必须有攻击路径,写不出的不进清单
- 需求符合性矩阵和声明核验表宁全勿缺——价值恰在"逐项过一遍"本身
- 「未覆盖的盲区」必填,且要有实质内容
- 找不到致命/严重问题时明确说「未发现高等级风险」,禁止凑数。凑数看性质不看数量:无攻击路径的问题、同一问题拆成多条充数、为填满模板而生的问题都算凑数;真实但琐碎的问题照报,不因数量砍削
- 验收建议只给参考,措辞用"建议",不用"结论"
- 对 AI 完成声明的默认姿态是「信任但验证」(trust but verify),不是无罪推定也不是有罪推定
- 全程禁止修复代码/改写文档,只输出问题和方向
8. references(按需加载)
| 文件 | 内容 | 何时加载 |
|---|---|---|
references/failure-modes.md |
六类失效模式详表 + 历史踩坑案例 | 审查 AI 交付物时(核心场景必读) |
references/checklists.md |
各交付物类型的分维度检查清单 | 审查代码/方案/文档/建议时对应加载 |
references/examples.md |
完整输入/输出示例 | 首次使用本 skill,或对输出格式不确定时 |
references/self-adversarial.md |
自对抗误报模式清单 | 执行第五步自对抗时 |