验证门


文档摘要

验证门 本节摘要:Agent 不被允许给自己的工作打「完成」。验证门(verification gate)读范围契约、反馈日志、规则报告、diff,回答一个问题:这个任务真的完成了吗?门说否,任务就没完成——无论聊天怎么说。诊断很经典,Agent 太容易宣布成功,三种失败形状主导:「看起来不错」(模型读自己的 diff 判它对)、「测试通过」(说得很自信,却无测试真跑的记录)、「验收达标」(验收标准被松到意为「任何像完成的东西」)。工作台的修法是一道验证门,读 Agent 已产出的工件,做裁决:门是确定性的,在版本控制里,接进 CI,Agent 贿赂不了它。

验证门

本节摘要:Agent 不被允许给自己的工作打「完成」。验证门(verification gate)读范围契约、反馈日志、规则报告、diff,回答一个问题:这个任务真的完成了吗?门说否,任务就没完成——无论聊天怎么说。诊断很经典,Agent 太容易宣布成功,三种失败形状主导:「看起来不错」(模型读自己的 diff 判它对)、「测试通过」(说得很自信,却无测试真跑的记录)、「验收达标」(验收标准被松到意为「任何像完成的东西」)。工作台的修法是一道验证门,读 Agent 已产出的工件,做裁决:门是确定性的,在版本控制里,接进 CI,Agent 贿赂不了它。本节定义门检查什么(全部验收命令跑了且退出零、范围无禁用写、无越界写、全部 block 规则通过、无 null 退出码、动过的文件匹配 allowed),区分 warn(注释裁决)与 block(阻止 passed: true),并立铁律门必须确定性而非概率性——同样的工件集每次产出同样裁决,无 LLM judge(LLM judge 属审查者第 39 节,那里目标是定性评估而非状态)。门发一份报告、一条路径(outputs/verification/<task_id>.json,CI 消费同一路径,多门多路径会分叉真相之源),且拒绝无例外——block 发现不能被 Agent 覆盖,只能被人覆盖,带记录的 override_reasonoverridden_by 用户 id,覆盖是签名变更而非 Agent 决定。本节用标准库实现 verify(task_id, artifacts) 纯函数,跑三个场景(干净通过、范围蔓延、缺验收),并给五条把门从「又一个 lint」抬到「决定边」的生产模式:纵深防御(pre-commit→CI→pre-tool authz→pre-merge 多层)、确定性检查为主模型 judge 只管细微(Anthropic Hybrid Norm:可验证奖励答「解了吗」、LLM 量表答「可读/安全/合规吗」)、签名覆盖日志非 Slack 线程、覆盖率底线为一等检查(防 Agent 偷删失败测试让报告保持绿)、--strict 模式把 warn 升 block(发布分支/阻断 PR/事故分诊时)。读完本节,你能把规则、范围、反馈收口成一道 Agent 无法绕过的闸。

对应原课程:Phase 14 · Lesson 38 · verification-gates(原英文 phases/14-agent-engineering/38-verification-gates/docs/en.md)。前置:第 33 节(规则)、第 36 节(范围)、第 37 节(反馈)。

学习目标

阅读完本节,你应当能够:

  1. 把验证门定义为工作台工件上的确定性函数
  2. 把规则报告、范围报告、反馈记录、diff 组合成单一裁决
  3. 发一份审查者 Agent 与 CI 都能读的 verification_report.json
  4. 任何 block 严重度失败上拒绝推进任务,无例外
  5. 说出五条把门抬到「决定边」的生产模式。

一、问题与直觉

Agent 太容易宣布成功。三种失败形状主导:

  • 「看起来不错。」 模型读自己的 diff,判它正确。
  • 「测试通过。」 说得自信。没有测试真跑的记录。
  • 「验收达标。」 验收标准被松到意为「任何像完成的东西」。

工作台的修法是一道验证门,读 Agent 已产出的工件,做裁决。门确定性。门在版本控制里。门接进 CI。Agent 贿赂不了它

这是第 26 节「成功幻觉」的终极防线,也是第 31~37 节所有面的收口——指令、状态、范围、反馈全部汇进这一道闸,它给出一个不可贿赂的「完成」判定。

门检查什么

检查 源工件 严重度
全部验收命令跑了 feedback_record.jsonl block
全部验收命令退出零 feedback_record.jsonl block
范围检查无禁用写 scope_report.json block
范围检查无越界写 scope_report.json block 或 warn
全部 block 严重度规则通过 rule_report.json block
反馈里无 null 退出码 feedback_record.jsonl block
动过的文件匹配 scope.allowed_files 两者 warn

warn 发现注释裁决;block 发现阻止 passed: true

确定性,非概率性

门必须对同样的工件集每次产出同样裁决。无 LLM judge。LLM judge 属审查者那侧(第 39 节),那里目标是定性评估,而非状态。

一份报告,一条路径

门每个任务收尾发一份 verification_report.json,写在 outputs/verification/<task_id>.json。CI 消费同一路径。多门多路径会分叉真相之源。

拒绝无例外

block 严重度发现不能被 Agent 覆盖。它们只能被人覆盖,带记录的 override_reasonoverridden_by 用户 id。覆盖是签名变更,不是 Agent 决定。

二、从零实现

原课程 code/main.py 实现:

  • 每种输入工件的加载器(本地全 stub,让本节自包含)。
  • 一个 verify(task_id, artifacts) -> VerdictReport 纯函数。
  • 一个展示每检查结果与最终通过/失败的打印机。
  • 三个任务场景演示:干净通过、范围蔓延、缺验收。

Step 1:输入工件加载

def load_artifacts(task_id): return { "diff": git_diff_vs_main(), "scope_report": json.load(open(f"outputs/scope/{task_id}.json")), "rule_report": json.load(open("rule_report.json")), "feedback": read_jsonl("feedback_record.jsonl"), }

Step 2:verify 纯函数(确定性)

def verify(task_id, artifacts): findings = [] # 1) 验收命令跑了且退出零 for cmd in artifacts["scope_report"]["acceptance_criteria"]: rec = find_feedback(artifacts["feedback"], cmd) if rec is None: findings.append(block("ACCEPT-RAN", f"{cmd} 未跑")) elif rec["exit_code"] is None: findings.append(block("ACCEPT-NULL", f"{cmd} 无退出码")) elif rec["exit_code"] != 0: findings.append(block("ACCEPT-FAIL", f"{cmd} 退出 {rec['exit_code']}")) # 2) 范围 if artifacts["scope_report"]["forbidden_hit"]: findings.append(block("SCOPE-FORBIDDEN", str(...))) if artifacts["scope_report"]["off_scope"]: findings.append(warn("SCOPE-OFF", str(...))) # 3) block 规则 for r in artifacts["rule_report"]: if r["severity"] == "block" and not r["passed"]: findings.append(block("RULE-" + r["slug"])) passed = not any(f.severity == "block" for f in findings) return VerdictReport(task_id, passed, findings)

Step 3:写报告 + CI 消费

def emit(verdict): path = f"outputs/verification/{verdict.task_id}.json" atomic_write(path, json.dumps(asdict(verdict), indent=2)) # 一份报告一条路径 return verdict.passed # CI: 非 True 即拒合并

运行 python3 code/main.py 会输出三份裁决报告,各存脚本旁。

生产模式(把门抬到决定边)

四加一条模式,把门从「又一个 lint」抬到「决定边」。

纵深防御,非单门。 pre-commit 钩子 → CI 状态检查 → pre-tool authz 钩子 → pre-merge 门。每层确定性,所以一层失败被下一层抓。microservices.io 2026-03 的 playbook 说得明白:pre-commit 钩子不可绕过,因为与模型侧技能不同,它不依赖 Agent 听指令。验证门坐在 CI / pre-merge 层。

确定性检查防御,模型 judge 只管细微。 Anthropic 2026 Hybrid Norm 配对:可验证奖励(单元测试、模式检查、退出码)答「代码解决问题了吗?」——LLM 量表答「代码可读、安全、合规吗?」。门跑第一类;审查者(第 39 节)跑第二类。混了会塌掉信号

签名覆盖日志,非 Slack 线程。 每次覆盖在 outputs/verification/overrides.jsonl 发一行:时间戳、发现码、原因、签名用户、当前 HEAD 提交。运行时拒绝任何缺签名的覆盖;审计轨迹 git 跟踪。这是覆盖策略覆盖戏剧之间的线。

覆盖率底线为一等检查。 一个 coverage_report.json 喂一个 coverage_floor(默认 80%)检查。门在测得覆盖低于底线、或低于上次合并的底线超 1 个百分点时失败。没这检查,Agent 会偷删失败的测试,验证报告保持绿。

--strict 模式把 warn 升 block。 对发布分支、阻断 PR、或事故后分诊,--strict 让每条警告硬失败。标志按分支 opt-in;非全局默认,因为「全严格」腐蚀日常流。

💡 设计要点:验证门是工作台流的决定边——其他所有面都在它上游。它的力量来自三件事:确定性(同工件同裁决,LLM 贿赂不了)、单一真相路径(一份报告 CI 与人同读)、签名覆盖(block 只能被人带理由覆盖,是审计变更非 Agent 决定)。这与第 31 节「验证是 fails closed 的函数」、第 26 节「重探查真实状态查成功幻觉」完全合流——门就是把这两条纪律落成一道不可绕过的闸。

三、框架对比

运行时 门如何接
CI 步骤 verify_agent job 对 Agent 最终工件跑门;合并保护无 passed: true 即拒
Pre-handoff 钩子 Agent 运行时在生成交接文档前调门;无绿裁决即无交接
手动分诊 操作员在 Agent 声称成功而人怀疑时读报告

门是工作台流的决定边。其他所有面都在它上游。

四、可复用产物

原课程 outputs/skill-verification-gate.md:把门接进特定项目——哪些验收命令喂它、哪些规则 block 严重度、哪些越界写被容忍、覆盖审计日志怎么存。

五、练习

  1. (Medium)coverage_floor 检查:测试命令必须产至少 80% 覆盖报告。决定哪个工件带底线。
  2. (Medium) 支持 --strict 模式,把每条 warnblock。记录 strict 模式是正确默认的情况。
  3. (Medium) 让门除 JSON 外还产 Markdown 摘要。论证哪些字段进摘要。
  4. (Hard)time_since_last_human_touch 检查:人击键 60 秒内编辑的文件免越界标记。
  5. (Hard) 在你产品的一个真实 Agent diff 上跑门。多少发现是真的,多少是噪声?门要在哪长?

本节要点回顾

  1. Agent 不给自己打完成:验证门读范围/反馈/规则/diff,答「任务真完成了吗」,门说否即没完成。
  2. 三种失败形状:「看起来不错」(读自己 diff)、「测试通过」(无跑的记录)、「验收达标」(标准被松)。
  3. 门确定性、版本控制里、接 CI:Agent 贿赂不了它。
  4. 七类检查:验收命令跑且退出零、无禁用写、无越界写、block 规则全过、无 null 退出、文件匹配 allowed。
  5. warn 注释 vs block 阻止 passed:true
  6. 确定性非概率性:同工件同裁决,无 LLM judge(judge 属审查者第 39 节,管定性非状态)。
  7. 一份报告一条路径:outputs/verification/<task_id>.json,CI 与人同读,多门多路径分叉真相。
  8. 拒绝无例外:block 不能被 Agent 覆盖,只能被人带 override_reason + overridden_by 签名覆盖。
  9. 五条生产模式:纵深防御(pre-commit→CI→authz→merge)、确定性为主 judge 管细微(Anthropic Hybrid Norm)、签名覆盖日志非 Slack、覆盖率底线(防偷删测试保绿)、--strict 升 warn 为 block。
  10. 决定边:其他所有面在门上游;第 31 节「fails closed 函数」+ 第 26 节「重探查状态」的合流落地。

下一节,我们给通过验证门的产物加一道定性关卡——审查者 Agent:一个独立工人,用不同角色(只读建造者产物、只写审查报告),用 LLM 量表回答「可读、安全、合规吗」,把「建造者批自己作业」变成「同行评审」。


发布者: 作者: Rohit Gupta 转发
评论区 (0)
U