代码变廉价后的评审方法:以证据和影响范围决定审查深度
O'Reilly Radar 作者 Markus Eisele 提出,智能体大量生成代码后,评审不应逐行阅读,而应把证据作为接受代码的前提:实现前约定预期行为与影响范围(blast radius),再用双向追溯检查实现与测试是否存在未经要求的行为漂移。他以退款服务为例说明,小改动可能带来大影响范围,且测试与实现可能共享同一错误理解,因此仍需人工核对断言含义。
O'Reilly Radar· Markus Eisele·2026-10-16 18:54· 2 小时前AI 评分62
代码变廉价后的评审方法:以证据和影响范围决定审查深度
代码变廉价后的代码评审
AI 导读
O'Reilly Radar 作者 Markus Eisele 提出,在智能体大量生成代码的时代,评审不应逐行阅读,而应把证据作为接受代码的前提。做法是在实现前约定预期行为和影响范围(blast radius),用双向追溯检查实现与测试是否存在未经要求的行为漂移。
正文
在我上一篇文章中,我提出智能体开发需要足够的规格说明,使正确性可被检验。一个简短的提示词可以快速启动实现,但仍需有人判断结果是否符合我们的预期。不过,我留下了一个相当实际的问题没有回答。智能体写完代码之后,我们该如何评审?
你可以给智能体一个明确的任务,然后得到一个带有测试的正式实现。构建通过,代码看起来也合理。现在必须有人批准这个拉取请求,而这个人拥有的时间与代码生成变廉价之前大致相同。
逐行阅读每一处改动是一种做法。但如果生成代码的每一次增加都需要相应增加人工检查,评审就会持续限制我们能接受多少改动。我们需要一种方法来判断哪些地方值得投入这种检查。
我的做法是把证据作为接受智能体生成代码的前提条件。在实现开始前,就预期行为和预期影响范围达成一致。然后用证据检查是否存在漂移,并决定代码的哪些部分需要直接检查。到目前为止,这听起来像是测试驱动开发。但当所有测试都通过,而智能体添加了没人要求的行为时,会发生什么?
小改动也可能有大影响范围
用一个虚构的小例子。假设我们要给退款服务添加一个审批步骤。超过 €100 的退款需要获得授权员工的批准,服务才能发送支付请求。恰好 €100 则不需要这一额外审批。关于谁可以发起退款的现有规则继续适用。
一个智能体实现了审批步骤并添加了测试。在更新支付集成时,它还在超时后添加了重试。这看起来相当合理。网络调用会失败,重试是常见的工程实践。
但超时给我们留下了另一个问题。提供商可能已经发出了退款,只是响应丢失了。再次发送请求可能会导致二次退款。这是否会发生,取决于提供商如何处理重复请求,以及我们的代码如何使用该行为。审批功能可能是正确的,而新增的重试引入了另一个独立问题。我可以想象,人工评审只关注被要求的功能,很容易忽略关于支付行为的新决策。
所谓影响范围,我指的是一个错误的后果能扩散多远。如果智能体把重试放在共享的支付客户端中,它可能影响每一笔退款,包括低于审批阈值的那些。这一改动现在超出了我们要求的功能范围。统计改动行数不会告诉我们这一点。
把影响范围本身作为一条评审标准。确定一次改动允许影响哪些操作,然后检查实现是否停留在该边界内。还要考虑一个错误有多难撤销。部署上一个版本并不能追回已经被重复退款的钱。
双向寻找漂移
这正是我希望审查流程能够暴露出来的那种偏差。我们需要检查所要求的行为是否存在,并检查可能影响系统的其他行为。
对于双向追踪这些关系,有一个既定的名称:双向可追溯性。NASA 的软件工程指南描述了如何通过实现和验证来追踪需求,包括发现没有父需求的功能。我认为这个基本思路可以很好地应用到普通的拉取请求中。
对于每个重要需求,我们应该能够找到实现它的代码以及支持它的检查。从实现往回看,我们应该能够解释为什么某个行为变更属于这个拉取请求。一个额外的私有方法通常不需要太多讨论。一个改变资金流动方式的重新尝试则需要一个我们可以审查的理由。
当然,计划外的添加并不自动就是错误。重新尝试可能是必要的。实现往往会揭示原始规范遗漏的东西。一旦我们理解了新行为的后果,并就如何检查它达成一致,我们就可以接受它。在那之前,它仍然是一个未决事项。
智能体可以帮助识别这些关系。把商定的规范和实际的仓库变更交给它,让它找出缺失或未解释的行为。对于退款服务,这应该包括已更改的支付客户端,即使智能体自己的摘要只提到了审批功能。从已更改的文件开始,这样摘要就不会决定要检查什么。还要顺着这些变更追踪到它们的调用方。一个共享客户端可能会改变未被编辑的代码的行为。
测试可能犯同样的错误
虽然这是我们在审查中关注的一个大致方向,但这些链接本身对正确性说明不了什么。一个方法可以引用正确的需求,但仍然实现错误。一个测试可以恰好有我们希望看到的名称,却检查错误的结果。
再考虑一下阈值。假设智能体把“超过 100 欧元”理解为“100 欧元及以上”。它在编写测试时也使用了同样的解释。实现要求恰好 100 欧元时需要审批,而测试也期望这种行为。一切都通过了,因为代码和测试是一致的。
在单独的 CI 环境中运行该测试会重现这种一致性,但不会发现预期结果是错误的。我们仍然需要有人根据商定的行为来检查断言的含义。把一些审查时间花在这些预期结果上。对于这样的需求,在实现之前就边界示例达成一致是相当容易做到的。100 欧元的退款无需额外审批即可进行。多一分钱就必须等待。然后审查者可以检查测试是否真的观察到了这种差异。让测试观察服务向支付提供商发送了什么。如果服务也可以立即发送付款,那么检查是否创建了审批请求是不够的。对于超过阈值的退款,测试应检查支付请求在审批之前不能离开服务。这就在请求退款的位置检查了规则。
对于重要规则,你可以再进一步。在一次受控的测试运行中临时移除审批检查,看看相关测试是否会失败。如果它仍然通过,那它给我们的保护就非常有限。Google 的代码审查指南要求审查者考虑的正是这类问题:当代码被破坏时,测试会失败吗?
让另一个 agent 提出我们遗漏的用例,并检查断言是否与需求相符。不过,要把实际的检查留给人工审查者。不同的模型仍可能产生同样的误解。有一些研究支持这种谨慎态度。一项2026 年关于 LLM 需求符合性判断的研究发现,模型会拒绝正确的实现,却接受有缺陷的实现。该研究使用的是编程基准,因此它并不能告诉我们每个审查 agent 在生产代码库中会如何表现。但它确实给了我们一个理由:在判断代码是否满足需求时,不要只看模型自信的解释。
让证据易于检查
要求每个 pull request 都附上一份简短的审查记录。它应当把预期行为与各项检查关联起来,并暴露仍然悬而未决的决策。对于我们假设的退款改动,它可以这样开头:
- 约定的行为:超过 €100 的退款在付款前需等待授权审批。恰好 €100 则不需要这一额外审批。
- 证据:边界测试检查付款请求何时发出。审查记录链接到这些断言以及本次修订的 CI 结果。
- 附加行为:支付客户端现在会在超时后重试。
- 影响范围:如果重试作用于共享客户端,所有退款请求都可能受影响。审查其现有调用方。
- 未决问题:测试未覆盖服务商在超时前完成退款的情况。安全的重新尝试行为仍有待确定。
从这份记录开始审查。检查审批断言是否表达了约定的规则,以及结果是否支持它。然后检查重试路径,因为那里的证据和预期范围都不完整。要求补充一个覆盖不确定服务商响应的测试,或者从本次改动中移除重试。这个未决问题已经变成了一个具体的审查决策。把每一项主张都链接到支持它的检查。“测试通过”太笼统,帮助不大。审查者需要看到哪些测试是针对正在审批的修订运行的。如果 agent 在该次运行之后改动了实现,就要刷新证据。
审查对检查的改动
还要把检查与约定的基线进行比较。假设早先的一个验收测试预期 €100 的退款会继续执行,但 agent 把它更新为预期发起审批请求。新的实现和新的测试现在彼此一致。把两者与约定的需求进行比较,就能暴露出含义的变化。agent 并不一定是在试图隐瞒什么,这种情况也会发生。更新测试以匹配新行为是日常开发的一部分。审查者需要判断这个新行为是否是预期内的。对验收标准的改动同样值得关注,原因也相同。
有时新行为会是正确的做法。也许业务实际上希望从 €100 起就需要审批。没问题,我们可以修改需求。记录下这个决定,并在接受实现之前审查其后果。悄悄修改规格以匹配代码,只会让我们达成一致,却无法解释我们是如何走到这一步的。
按影响范围设定审查深度
让审查的深度与潜在影响和证据强度相匹配。一份报告只能暴露它所检测到的缺口。即使代码依赖错误假设,测试也可能通过。要求直接检查支付路径,因为一个错误可能导致资金被转移两次。追踪受影响的调用,即使其中一些位于 diff 之外。
对于影响有限且已有既定检查的常规变更,审查者可以少花时间重建实现。理由很具体:受影响的行为已被理解,检查覆盖了其可能的失败。当影响范围不明确时,在批准变更前先调查清楚。偶尔也检查那些流程视为常规的变更。如果这些审查不断发现缺失的假设,就先改进检查,再依赖它们进一步减少检查。这为团队提供了一种根据实际接受的代码来检验其审查策略的方法。
让证据成为开发周期的一部分
以下是我推荐的流程。在生成开始之前,开发者与需求负责人就行为及其预期影响范围达成一致。智能体在该范围内实现并准备一份简短的审查记录。CI 对提议的修订运行检查。审查者检查证据并调查偏差,在后果严重时直接检查代码。通过受控发布上线,然后利用生产中的实际情况来改进检查和规格说明。

让审查记录成为完成定义的一部分。提交变更的开发者对其准确性负责,即使记录由智能体撰写。审查者负责接受决定。重要主张若证据不足,则保持未决。如果实现影响的操作多于约定,在继续之前先解决这一范围变更。
对于退款示例,这意味着一旦其检查支持约定的行为,且审查者已检查相关支付路径,审批功能就可以继续推进。新增的重试需要自己的理由。它可以被移除,或作为明确的添加进行审查,并附上证据表明重复请求不会发出重复退款。这建立在熟悉的开发实践之上。验收示例在编码前阐明意图。CI 重复检查,小规模发布限制暴露。该提案将这些实践围绕审查决定结合起来,以便在实现到达时证据可用。它还使审查工作可复用:一旦审批边界被正确检查,后续变更可以运行相同的测试。
保持影响范围受控
将审批功能与共享支付客户端的重新设计分开,除非两者需要一起变更。分开的拉取请求有助于审查者评估每个决定,但控制影响范围也取决于实现。共享客户端中的一行更改仍可能影响每个调用方。
对发布也采用同样的纪律。在系统支持的情况下,先将变更暴露给有限群体(A/B),观察受影响的行为,然后再扩大推广范围。对于退款,在任何真实支付之前仍需进行充分检查。从一个服务开始,让这成为变更进入评审的常规方式。要求提供证据,记录预期影响范围,并对无法解释的行为保持关注,直到有人解决它。随着检查赢得信任,减少例行的逐行审查。在错误会带来严重后果的地方保留直接检查。这是一种具体的方式,既能接受更多由智能体生成的代码,又能让每个变更的影响保持可理解且可控。
来源:O'Reilly Radar · oreilly.com
来源:RadarAI · aihot.news