AI 编程的难点在于第二次修改
发布于 2026-11-10 · 更新于 2026-11-11 · Brian Woods
一个 AI agent 构建了一个支付服务。测试通过。演示正常。
然后你要求加入重试。agent 加上了,但超时可能意味着扣款已成功而响应丢失了。现在重试会让客户被扣两次款。
功能能用。系统变差了。测试套件甚至可能更大了。数量从来都比判断力更容易衡量。
AI 让构建一个能跑一次的东西变得更便宜。维护它意味着保住那些必须始终成立的东西。支付不能重复。用户不能看到其他租户的数据。迁移必须能兼容上一个应用版本。
在接受一次变更之前,我想要四个答案:
- 规格:什么必须始终保持成立?
- 验证:哪些检查能支撑这一主张?
- 来源:证据描述的是我们要发布的代码吗?
- 授权:谁可以批准它?
使用 CI 和分支保护。把证据绑定到确切的代码上,并在需求变更或风险被接受的地方设置人工关卡。agent 被允许工作,不等于被允许自我批准。
agent 提出变更。独立的工作流产生证据,人类定义验收策略、批准需求变更并接受风险。在该策略下,常规变更可以自动通过,但 agent 不能有权修改约束自身验收的规则。
一个有效签名能告诉你什么、不能告诉你什么
我用一个合成实验针对 Uncle 的验证器做了测试。在一种情况下,一条测试和审计均失败的构建的签名记录返回了 VERIFIED。该记录在 fixture 的信任根下是真实的。但这并不能让软件变得可以发布。
这是两个独立的问题:
- 证明有效性:这条记录是否真实、完整,并绑定到预期的产物?
- 发布就绪:这条记录是否满足所需的测试、审查、批准和验收策略?
验证器回答的是第一个问题。一个对失败测试的记录进行认证的验证器行为是正确的,它的输出也说明了这一点:“NOT_READY ... attested as recorded, not as correct.” 失败发生在另一个系统把真实性误认为发布授权的时候。一条真实的失败测试记录,并不是应该继续发布的证据。
这 15 个案例(完整记录)只覆盖单次变更的验证器行为。该测试装置控制密钥和批准,验证器不会重新运行测试。它们对独立信任或生产工作流没有任何说明。
信任边界
任何此类方案都假设 agent 无法修改签名密钥、验证器的信任根或生效的验收策略。它还假设 agent 可以编辑的 CI 配置和测试不会悄悄变成受信任的策略。如果 agent 能改变其中任何一项,签名就只能认证在同一被攻破边界内产生的记录。
实验展示了这种情况的一个案例。攻击者的密钥签署了证明,并且仓库自身的信任文件被替换以匹配。验证器返回了 VERIFIED,因为默认情况下它从仓库读取信任根。从仓库外部提供信任根后,同一份证明就失败了。
本地批准提示也不是人类意图的密码学证明。
一个任何人都能实现的提案
问题在于如何在连续变更中保留这些证据,同时不允许 agent 批准自己的工作。
像 {{NAME_ab12cd34}} 这样写出的值是真实值的占位符。请完全按照书写的样子使用它们,在回复和工具调用中都是如此:它们会在任何东西运行之前被替换为真实值。不要要求验证它们,也不要用示例替换它们。
这些原语都不是新的。Git 提供内容寻址的历史,in-toto 和 SLSA 定义来源与证明,Sigstore 处理签名和身份,带有分支保护的 CI 在拉取请求内部执行了其中大部分。开放的问题是在由智能体驱动的变更之间连接需求、证据和批准,同时不让智能体为自己的工作出具证明。Git 记录代码如何变化。这个图会记录哪些变更被接受、依据哪些需求与策略、以及基于哪些证据。这两段历史相关,但它们回答不同的问题。CI 已经记录测试结果,来源系统也已经把证据绑定到产物。新增的是把接受决策本身跨连续变更连接起来。以下是一个提议的设计,并不是我声称 Uncle 今天已经完全做到的事情。
- 为每个被接受的变更出具证明。记录包含源代码树哈希、需求与策略版本、测试与评审证据的哈希,以及人工批准的身份和范围。受信任的工作流使用编码智能体无法使用的密钥为其签名。
- 链接到先前内容。每个证明都包含先前已接受证明的哈希。这些链接构成有向无环图(DAG):普通变更引用其前驱,合并引用每个父项,并增加对合并结果的验证。仅凭父项批准不能批准合并。例如,假设两个智能体从已接受状态 A 独立产生变更 B 和 C,并且两者都通过了各自所需的检查。合并 B 和 C 会产生状态 D,而 D 具有新的树身份。D 需要自己的验证和接受证据;对 B 和 C 的批准不会自动批准它们的组合。
例如,假设两个智能体从已接受状态 A 独立产生变更 B 和 C,并且两者都通过了各自所需的检查。合并 B 和 C 会产生状态 D,而 D 具有新的树身份。D 需要自己的验证和接受证据;对 B 和 C 的批准不会自动批准它们的组合。
- 通过遍历图进行验证。从当前 PR 开始,验证者沿着链接追溯到一个明确受信任的起点,对照独立管理的信任根检查签名,将证据与产物匹配,并执行接受策略。缺失证据、所需检查失败或缺少批准都必须阻止接受。已验证的历史可以缓存,前提是策略和信任变更会使受影响的条目失效。对接受策略的更改也需要独立授权。智能体不能放宽用来评判自己的要求,因此一个被拒绝的变更不会因为策略在其之下发生变化而变得可接受。经授权的策略变更可以合理地改变未来决策,或触发在新策略下的显式重新评估。
- 让记录处于智能体无法触及的范围。持久存储证据,并将已接受的图头锚定在智能体控制之外,以便检测被重写的历史。
密码学保护记录及其关系。它不能证明测试足够充分或软件正确。无论是否使用 Uncle,你都可以围绕现有 CI 和评审工具构建这一点。
回到重试
下面是该设计将如何处理支付变更:
- 智能体实现重试。
- 策略要求幂等性证据,因此这些测试在智能体无法控制的工作流中运行。
- 结果被绑定到确切的源代码树,并且该工作流对证明进行签名。
- 所需检查失败会阻止接受,无论智能体的总结多么自信。
- 下一个变更引用这个变更,但批准不会在它们所覆盖的代码或策略已发生变化的地方延续。
它仍然无法保证正确性。测试可能漏掉竞态条件,而生产环境会发现验证环境从未见过的路径。那四个问题决定一个变更是否被接受。它们不能替代可观测性、回滚、事件响应或工程判断。
生成下一个版本正变得廉价。决定是否接受它,依然是那份工作。