给编程智能体建立可执行验收门槛
文章提出用可执行的完成标准约束编程智能体,明确允许修改的范围、可观察结果和必须提交的证据。由独立流程决定是否验收,防止把修改文件或局部测试通过当成任务完成。
AI 深度解读
AI 编程助手改完文件、写出一段完成说明,任务就算结束了吗?作者的答案是:不算。代码看起来合理、测试文件已经存在,都不能证明用户要求的结果真的发生了。
这篇文章提出了一套可执行的完成标准:先约定改动边界和验收条件,再提交与代码版本绑定的证据,最后由独立流程决定是否通过。它值得读的地方,是把「让 Agent 更认真」变成了程序员可以落进 CI、浏览器检查和代码审查的工程约束。
开工前,先写清什么结果才算完成
作者把任务拆成两个决定:实现,是 Agent 提交了什么改动;验收,是证据能否证明目标成立,而且改动没有越界。
两者容易被混在一起。一次测试通过,只能支持它实际覆盖的行为;页面截图正常,也不能证明截图之外的布局、键盘操作和加载状态都正常。Agent 对生产数据、部署配置和团队隐含约定的了解,也可能不完整。
因此,完成标准要在授予写权限之前确定。不能等代码改完,再让实现者解释怎样才算成功。
下面这份合约解决的是:结算税费任务允许改哪里,以及必须通过哪些检查。
task_id: checkout-tax-042
goal: "Calculate regional tax before rendering the order total"
scope:
allowed_paths:
- apps/checkout/**
- packages/tax/**
forbidden_paths:
- infra/**
- db/migrations/**
acceptance:
- id: unit-tax
kind: command
run: "pnpm test --filter tax -- --runInBand"
expects: { exit_code: 0 }
- id: total-visible
kind: browser
route: "/checkout?region=CA"
expects:
text: "Tax"
screenshot: true
- id: no-regression
kind: command
run: "pnpm lint --filter checkout"
expects: { exit_code: 0 }
policy:
max_files_changed: 8
human_review_required: false
要看清 allowed_paths 和 forbidden_paths:即使功能正确,修改了禁止目录,也应当验收失败。max_files_changed: 8 则进一步限制改动规模。
好条件需要同时满足三点:结果可观察,范围有边界,第三方能检查。「正确处理税费」太宽泛;「指定地区的结算页显示税费,并在总额前呈现」才接近可验收的要求。
不过,这份示例本身也暴露了问题:浏览器条件只写了出现 Tax 和保存截图,没有明确校验税额、计算顺序或税费行位置。可执行的条件只是起点,条件是否覆盖真实需求仍然要由人判断。
证据要绑定代码版本,验收者要收回写权限
作者要求每项条件都有一份证据回执(receipt)。它记录的不是「我测过了」,而是哪条命令、什么环境、哪个版本,以及留下了什么产物。
原文示例把任务 checkout-tax-042 绑定到提交 9ac63c1。命令证据记录退出码 0、输出摘要 sha256:... 和日志位置 artifacts/unit-tax.log;浏览器证据记录预览地址、截图 artifacts/total-visible.png,以及检查时间 2026-11-11T10:20:00Z。
浏览器检查还应记录视口;API 检查应保留脱敏后的请求结构和响应断言。大段输出可以用哈希摘要配合产物路径引用,避免把秘密或完整日志塞进聊天记录。
关键在于能追溯、能复查。旧提交上的绿灯,不能自动给新提交背书。
最终验收可以交给确定性的 CI,也可以加入受限的 AI 验证者。作者建议让类型检查、单元测试、契约测试、改动范围检查和部署冒烟测试先行;截图是否覆盖某条用户流程等需要判断的部分,再让 AI 参与,并要求它指出证据和不确定性。
下面的代码展示了验收顺序:先核对提交和路径,再逐项独立复查。
type Verdict = "accepted" | "rejected" | "needs_review";
async function verify(task: Task, receipt: Receipt): Promise<Verdict> {
if (!sameCommit(task.proposedCommit, receipt.commit)) return "rejected";
if (!pathsAllowed(task.scope, await changedPaths(receipt.commit))) return "rejected";
for (const criterion of task.acceptance) {
const evidence = receipt.criteria.find((item) => item.id === criterion.id);
if (!evidence || evidence.status !== "passed") return "rejected";
if (!(await independentlyRecheck(criterion, evidence))) return "rejected";
}
return task.policy.human_review_required ? "needs_review" : "accepted";
}
最关键的是 independentlyRecheck:回执里写着 passed,验收者也不能照单全收。但原文没有给出这个函数的实现,如何复查、花多少时间,仍需要团队自己补齐。
验证者默认只有读取权限和有限的测试执行权限,不能改测试、扩大允许目录、修改合约,也不能悄悄跳过不稳定检查。失败时,它应返回条件 ID、实际结果、产物位置和能否安全重试,让实现者继续修复。
任务状态也不能只有一个 done。作者要求只有 accepted 能解锁合并、部署、计费或向客户宣告完成;needs_review 用来承接仍需判断的情况。这里有个未完全对齐的细节:正文和问答建议证据不完整时进入 needs_review,示例代码却把缺失证据直接判为 rejected。落地前必须统一处理规则。
检查要覆盖风险,也要防止验收标准被改松
测试通过不等于所有任务都完成了,不同改动需要不同证据。
UI 修改需要相关视口的浏览器检查、无障碍断言,以及保存在模型上下文之外的截图。关键转化流程可以增加简短的人工验收。截图只能说明某一刻的画面,不能代替键盘导航和加载状态验证。
数据库迁移应在可丢弃数据集或可回滚事务中检查行数、约束、幂等性和降级路径。外部集成要记录沙箱账号、fixture ID、限流结果和 webhook 结果;涉及写入时,还要确认没有重复副作用。
安全敏感改动则应先检查禁止依赖、秘密泄漏、权限变化和出站访问规则。功能跑通,依然可能因为扩大影响范围而不合格。
为了避免实现者无意间「迎合检查」,作者还要求从干净检出或隔离 worktree 运行验证,保护测试文件和验收合约,标记新增依赖,并对关键行为优先使用黑盒断言。合约和回执结构都要版本化;调整标准,应当触发一次新的审查。
推行时也不必一次铺满。作者建议从返工较多的工作流开始,每项任务设置 3 到 5 条验收条件,先让其中一项检查独立执行,再观察提案通过率、逐项拒绝原因、验证耗时、验收后重开率,以及每个验收通过任务的成本。
我的判断
我赞同它把验收权从实现者手里分离出来。对于前端和全栈团队,这与已有的 PR、CI 和预览环境流程可以接上,未必需要再搭一套多 Agent 系统。单个编码 Agent 加 CI,就能建立基本边界。
但文章给出的是工程方案和示例,没有提供团队实测的通过率、返工率或成本对照。它引用 Agent 评估工作,也不能直接证明这套流程在一般团队里一定更划算。
真正费工夫的地方,是把自然语言要求写成可靠断言,以及维护环境、fixture 和证据产物。独立执行能减少自我确认,却无法弥补错误的验收标准。
因此,我会把它用于容易漏验、越界或反复返工的任务。对于低风险的小改动,现有 CI 和人工审查可能已经足够,额外包装一层回执未必带来相称收益。
能拿来做什么
- 给常见前端修复准备一份小型验收模板,写清目标路由、视口、可见结果和允许修改的目录,先把「页面修好了」变成可复查的条件。
- 让 Node 或全栈项目的 CI 保存命令、退出码、提交标识和产物位置,确保审查者能确认本次改动确实接受过检查。
- 将验收合约和关键测试移出编码 Agent 的默认写入范围,由独立流程复跑检查;标准需要调整时,单独审查调整理由。
- 从一个返工较多的任务队列试行,记录 3 到 5 条条件各自的拒绝原因与验证耗时,再决定增加哪些检查。