三方对抗式代码评审(Blue Team / Third Party / Adjudication)
这个 skill 要解决什么
单人或单 AI 写代码,最大的风险不是"不会写",而是:
- 用未验证的乐观假设说服自己推迟修复("这个兜底应该够了吧");
- 测试提供假安全感(测试全绿,但功能其实早坏了);
- 为了修 A 而引入 B(新写的修复代码本身没被独立审视)。
这三个问题靠"再仔细看一遍"解决不了——写代码的人和审代码的人是同一个,就一定会为自己辩护。只能靠结构化的对抗关系:
| 角色 | 立场 | 硬性约束 |
|---|
| 蓝军 | 敌意审查——假设代码会出事,去证明 | 每条结论必须附证据链(文件:行号 / 实测命令 / 上游源码);🔴/🟠 必须是实测结论,仅凭推理最高 🟡;禁止空话 |
| 第三方 | 独立审计——不信任任何一方文档,直接读代码 | 逐条复核"声称修了的是否真修了"、专找修改引入的新缺陷、并稽核蓝军漏掉了哪些维度 |
| 中立裁定 | 对双方结论逐条采纳 / 驳回 / 改级 | 必须由与蓝军不同的 agent 担任;当事人不能当法官 |
关键不是"多找两个 AI 看看",而是顺序与互不信任:第三方不信开发团队,裁定方不信蓝军和第三方。任一环节缺失,闭环就破。
配套文件(按需读取)
references/review-dimensions.md —— 完整质量维度清单(19 项)。第 0 步按改动类型选维度时必须读,否则审查会漏掉大片区域。
references/prompt-templates.md —— 三个角色的完整提示词模板 + 占位符约定 + 「设计要点」表(改模板前必读)。第 1/2/3 步派发子代理时直接取用,不要临时自编。
references/quickstart.md —— 面向用户的上手说明(档位选择、什么时候不该用它)。
examples/sample-review.md —— 一次真实评审的产出样例。
⚠️ 能力边界(必须向用户如实说明)
子代理与主代理通常是同一模型,这不是真正独立的第三方。其价值来自角色约束 + 强制证据,而非"另一个 AI 的观点"。
- ✅ 能有效抓出:代码级错误、逻辑漏洞、测试造假、自相矛盾、遗漏分支、声明与实现不符;
- ❌ 抓不出:双方共有的知识盲区(例如对某个上游行为的一致误解)。若某个结论依赖外部系统行为,必须要求实测验证,而不是两个 agent 互相点头。
向用户汇报时,不要说"经独立第三方验证无误",要说"经同模型不同角色的对抗审查"。
🔁 降级模式(宿主无子代理能力时)
若宿主不提供 subagent,只能由同一个 agent 串行扮演三角色。此时:
- 独立性已被显著削弱,第 2、3 步的价值大幅下降;
- 必须在报告开头显式声明"本次为降级模式,角色由同一 agent 串行扮演";
- 不得使用"独立复核""第三方验证"等措辞;
- 有条件时优先换一个有子代理能力的宿主,而不是将就。
执行流程
第 0 步:确定档位、范围与维度
先问用户或从上下文判断档位(默认标准档):
| 档位 | 配置 | 相对成本 | 适用 |
|---|
| 轻档 | 1 个蓝军(聚焦选定维度) | ~1x | 小改动、时间紧 |
| 标准档(默认) | 蓝军全量 → 第三方复核 → 中立裁定,共 3 轮 | ~3x | 一般功能版本 |
| 重档 | 标准档 + 多路子代理并行交叉验证(按维度分组并行审) | ~5-8x | 发布前、重大重构、涉及上游兼容 |
(~Nx 为相对一轮蓝军审查的 token 经验估计,未经精确计量。)
必做四件事:
- 确定基线:
git rev-parse --short HEAD + git status,写进报告表头。
- 把待审状态提交或暂存——让蓝军拿到可复现的基线。工作区一片混乱时审查结论不可靠。
- 选维度:读
references/review-dimensions.md,按"按改动类型选维度"表选出本次必审维度。不要默认全审——19 项全塞进一次审查只会让报告又长又浅。
- 定报告目录(默认
docs/review/)。
Token 纪律(全档位强制,模板已内置)
三轮闭环最大的成本来源是报告互相抄写、逐条平铺展开。执行与改模板时都不得放宽:
- 分级展开:只有 🔴/🟠 条目允许"四要素全展开";🟡 条目总表一行带过,展开内容限一句修复方向。🟡 可压缩不可消失:总表必须逐条列出并带
文件:行号;定级存疑时向上取整。
- 按编号引用:下游角色引用上游结论只写编号+结果(如
B7:✅ 属实落地),禁止重抄上游原文。
- 通过项一行过:第三方对 ✅ 项只给一行证据(
文件:行号),仅 ⚠️/❌/🔁 项写完整证据链。
- 裁定理由限长:每条 ≤3 行,篇幅优先留给「共同前提审查」与「合并执行清单」——那才是用户真正要看的。
- 超量归并:单报告缺陷总条数 >15 时,同类 🟡 必须合并成组,且合并条目须逐一内联各处位置(如"其余 6 处同类错误吞掉:a.js:12、b.js:40…"),不许只给概括。第三方须抽查 🟡 归组项,发现漏升级记为蓝军覆盖度缺口。
- 回传限形:回传正文以所使用模板末尾「落盘要求」所列清单为限(各清单均含报告路径),长文一律落盘。
第 1 步:蓝军评审(敌意审查)
用 subagent 起一个子代理,禁止用 subagent_fork(fork 会继承你的思路,失去独立性)。
从 references/prompt-templates.md 取模板 1,替换所有 <...> 占位符。四个不可省略的要素:
- 要求逐项覆盖选定维度,每项都要有结论(哪怕是"未发现问题")。整项跳过是禁止的。
- 要求落盘并把路径回报——长报告容易在子代理回传时被截断。
- 禁止空话:每条结论必须落到具体代码位置与具体后果。
- 定级与实测绑定:总表每行要有「定级依据」列;🔴/🟠 只能给当场跑过、贴得出命令与输出的结论,仅凭推理的最高 🟡。
- 落盘后机检:报告写完,主代理执行
node <skill>/scripts/check-report.mjs <报告路径>。判红就把报告退回蓝军补证据——不许为了变绿去改总表措辞,那正是这台机检器要抓的动作。没有这一步,第 1 步的所有实证要求都只是自觉。
第 2 步:第三方复核(独立审计)
拿到蓝军报告后,用新的 subagent(不要复用蓝军那个,避免它为自己的结论辩护)。
从 references/prompt-templates.md 取模板 2。除"验证整改是否落地"和"找新缺陷"外,还有第三个方向:
- 稽核蓝军的覆盖度——找出蓝军整项跳过、或"未发现问题"但实际有问题的维度。只验证蓝军说过的话是不够的,否则蓝军的盲区会变成整个流程的盲区。
- 重跑蓝军的实测证据——把标了
实测 的 🔴/🟠 逐条原样重跑,跑不出来即判「证据不成立」并降级。机检器只能验"贴的是不是一条真命令"(可执行程序名 + 参数),命令是否真跑过、跑出的是否是所贴的输出,只有第三方能判断——node fake.js --evidence 形状完全合法。所以这条约束靠两台机器 + 这个角色一起兜。
- 对自己的产出同样取证——第三方的 T 项总表也是六列、也受"未实测不得定高危"约束,落盘后同样跑一次
check-report.mjs。只查别人、不查自己的角色,最后一定会退化成"别人的证据要命令、我的证据靠我说"。
第 3 步:中立裁定
必须起一个全新的 subagent 作为"中立裁定方",不是蓝军,也不是第三方。
⚠️ 为什么不能复用蓝军做裁定:裁定的对象是"第三方对蓝军意见的复核"。若让蓝军自己裁定,它同时是当事人和法官——它会系统性驳回针对自己的批评。这与本 skill 第 1、2 步「禁止复用 agent」的核心原则直接冲突。
"蓝军不信第三方"这个设定通过提示词立场表达,不是通过复用 agent 身份实现。
降级选项:宿主子代理数量受限时,可用 send_message 复用蓝军 agent,但必须在报告里声明"裁定方与蓝军为同一 agent,独立性已降级"。
从 references/prompt-templates.md 取模板 3。它有一项关键职责:
- 审查两方共有的前提——如果蓝军和第三方都基于同一个未经验证的假设,必须标出来并要求实测。这是同模型互搏最大的盲区,也是这个 skill 能提供的最高价值。
第 4 步:主代理执行整改
拿到合并清单后,由你(主代理)亲自改代码,不要外包——整改需要全局一致性判断。
整改纪律:
- 每条改动配一个回归用例。特别是:无测试覆盖的修复必复发。回归用例要写成可重复运行的形式(测试文件或脚本),不是"我当时手工验过"。
- 测试要断言"行为",不要断言"实现字符串"。反例:断言 CSS 里"包含某类名"——这类名会随构建漂移,测试永远绿而功能早坏。正例:模拟真实输入,断言用户可观察的结果。
- 改完必须自己复验:语法检查、全量测试、以及关键修复的最小复现(证明修前坏、修后好)。
- 诚实记录:如果发现自己在上一轮文档里写了错误结论,显式标注作废,不要悄悄改掉。三方评审的价值就在于留下可追溯的纠正记录。
- 改完回头验一遍文档里引用的行号和路径——整改会让行号位移、文件移动会让路径失效。这是本 skill 历史上反复出现的翻车点。
- 不要为了让报告好看而虚报。做不到就写"推迟"并给出经过验证的理由。
第 5 步:收口与归档
- 汇报时明确区分:哪些已修、哪些推迟(附理由)、哪些未能验证。
- 按下方策略归档报告。
- 若涉及发布:确认版本号一致、CI 实际跑过(不是"配置了 CI")、文档与实际改动一致。
报告归档
默认策略按项目可见性决定(选错会造成死链或泄密):
| 项目类型 | 默认做法 |
|---|
| 私有仓库 / 未发布 | 写入 docs/review/ 并加入 .gitignore,内部攻防记录不外泄 |
| 公开仓库 | 要么正常提交(作为质量流程展示),要么 gitignore 并且彻底清理引用 |
# internal review notes (kept locally, deliberately NOT published)
/docs/review/
命名约定(<version> 用版本号或 commit sha):
docs/review/
├─ BLUE-TEAM-REVIEW-<version>.md # 蓝军(含宿主/上游源码级证据)
├─ RESPONSE-<version>.md # 开发团队逐条回应(采纳/部分/推迟/驳回)
├─ THIRD-PARTY-REVIEW-<version>.md # 第三方独立复核(T 项 + 覆盖度稽核)
└─ ADJUDICATION-<version>.md # 中立裁定(对双方结论的最终裁定)
⚠️ 报告若被 gitignore,务必同时清理 README/CHANGELOG 里指向它们的链接——否则发布后是死链。
常见的错误用法
- ❌ 用
subagent_fork 起蓝军 → 继承你的思路,只会附和。
- ❌ 让蓝军自己裁定第三方意见 → 当事人当法官,针对蓝军的批评会被系统性驳回。
- ❌ 第三方只验"修了没" → 丢掉"找新缺陷"和"稽核蓝军覆盖度"两项价值。
- ❌ 凭推理链定 🔴/🟠 → 未实测的高危会稀释真问题的注意力,还会诱导"声称跑过"。高危必须带可原样重跑的命令与输出(
scripts/check-report.mjs <报告.md> 机检这张总表,第三方负责重跑)。
- ❌ 把 19 个维度一次性全塞进去 → 报告又长又浅,真问题被稀释。按改动类型选。
- ❌ 下游报告照抄上游原文 → 三份报告互相复述,token 三倍浪费。按编号引用,只写自己的结论。
- ❌ 把三方报告当成"通过认证" → 同模型互搏抓不出共同盲区;依赖外部行为的关键结论必须实测。
- ❌ 改了代码不补可运行的回归用例 → 下轮评审同样的问题会再次出现。
- ❌ 改完不回头验文档里的行号/路径 → 整改必然造成位移,示例里的行号会全部失效。
- ❌ 报告写得很漂亮但代码没动 → 立刻修订,别把流程做成表演。
- ❌ "配置了 CI"就当"CI 跑过了" → 检查必须真的能失败,永远绿的检查等于没有检查。