审查 AI 代码,从核对差异开始
文章建议把 Agent 总结视为待验证的主张,逐项对照实际代码变更。针对单次提交和功能分支,解释 git show 与不同 git diff 比较方式的用途,帮助确定审查范围。
AI 深度解读
AI 写完代码,留下一段流畅的总结和跨越多个文件的 diff,很容易让人产生「看着没问题,可以合并」的感觉。作者提醒:总结描述的是 Agent 想做什么,代码差异才记录它实际做了什么,审查要做的就是核对两者。
这套方法适用于 Claude Code、Codex、Cursor 等工具:先确定比较范围,再看文件分布,按依赖关系读代码,最后验证总结中的承诺。文章没有给出效率实验,却提供了一套可以直接照着执行的审查顺序。
先确认你看到的 diff 包含什么
作者把 Agent 的交付分成三种,每种的审查入口不同。
如果交付是单个提交,用 git show <sha> 同时查看提交说明和差异。先读说明,但把它当作待核实的主张。例如说明声称「修复日期解析」,接下来就要找出解析行为究竟改在哪里。
如果交付是一个分支,最容易混淆的是下面两种比较:
git diff main...feature使用三个点,查看 feature 相对它与 main 的共同祖先发生了什么变化,通常适合审查分支自身的修改。git diff main feature直接比较两个版本,也可以写成git diff main..feature。期间 main 上新增的内容也可能体现在差异中,不能全部归到 Agent 头上。
两者回答的问题不同。比较范围选错,后面的阅读再认真,也可能追查一批根本不属于这次任务的变化。
如果 Agent 只修改工作区、没有提交,单看 git diff 还不够:它不会展示未跟踪的新文件。作者建议运行 git status 查看 untracked 列表,或者用 git add -N .,让新文件进入 diff 视野,再用 git reset 撤销。
文件没进入审查视野,就谈不上代码审查。
辅助脚本、测试夹具和新建文件,都可能比总结里提到的更多。
按依赖读代码,才能看出修改是否成立
作者建议先看整体分布,不要一上来就逐行阅读。这两条命令分别展示修改规模和文件状态:
git diff --stat main...feature
git diff --name-status main...feature
要留意的是两行都用了 main...feature,统计和文件列表必须与后续审查采用相同的比较范围。
拿到列表后,先问三个问题:这些文件都属于任务范围吗?改动集中在哪里?测试是新增、修改,还是删除了?
一个「日期解析修复」如果同时改了 lockfile、CI 配置和无关组件,就需要解释。所谓小修复如果集中在一个文件里改了 300 行,也应该优先阅读。尤其要看被修改的断言:测试变绿,可能来自实现修好了,也可能来自预期被改成了迎合当前实现。
接下来不要被文件名的字母顺序牵着走。作者推荐按以下顺序阅读:
- 类型、接口、schema 和配置,先看约定发生了什么变化。
- 核心实现,检查新逻辑怎样满足这些约定。
- 调用位置,确认上下游已经同步。
- 测试,判断它们究竟证明了什么。
每一块差异都要放回所在函数里理解。条件判断只改两行,影响却可能延伸到整个控制流程;diff 往往恰好省略了判断它所需的上下文。
这对前端和 Node 项目很实用。接口类型改得自洽,不代表调用方仍然维持原有行为;调用处不报错,也不代表参数含义没有变化。
总结中的每一句承诺,都要找到代码证据
作者最有价值的提醒,是把「代码看起来合理」换成「修改是否解决了原因」。
先尝试用一句话描述 bug 的成因。如果讲不出来,就很难判断新增的空值检查、重试或吞掉异常的 try/except,到底解决了问题,还是把症状藏了起来。
再挑一个改名或修改签名的函数,沿调用链检查。旧名字和新名字都搜一遍,既找遗漏调用,也看有没有调用方为了适配新函数而偷偷改变行为。
同样需要单独追问的,还有未要求的重构、整文件格式化、默认值变化和新增依赖。它们各自都需要理由,不能被「顺手优化」一笔带过。
总结说「增加了输入校验」,就定位校验代码;说「全部测试通过」,就自己运行测试;调用了某个库函数或配置项,就跳到定义,确认它真实存在,也适用于项目使用的版本。
有疑问可以让 Agent 解释,但解释仍需验证。能指出具体代码行的回答更容易核查,措辞自信本身没有证明力。
作者为这套阅读流程开发了 Mac 应用 Yenpo,提供行内 diff、本地语言服务器(LSP)的定义跳转与引用查找,以及全文搜索。
它要求 macOS 14 或更高版本。语言服务器不随应用打包:Swift 和 C 系列使用 Xcode 提供的服务,其他语言依赖 PATH 中的安装,rust-analyzer 支持一键安装。未提交改动可以直接在 diff 中跳转定义,提交和分支则需要打开编辑器中的文件。
可选的 AI Reader 使用用户自己的模型提供方,会展示读过的文件、执行过的搜索,并提供可点击的 file:line 引用。默认只读,开启 Allow Edits 也只对下一条消息有效。
它读取本地 Git 仓库,不集成 Claude Code、Codex、Cursor 或 GitHub,也不负责驱动 Agent。作者同时明确:Git、编辑器和审查纪律已经能完成大部分流程。
我的判断
我赞同把 Agent 总结当作待核实的说明。它给审查者提供的是检查线索,不能替代证据。按依赖阅读也比逐文件浏览更容易串起行为变化。
但文章没有给出缺陷检出率、审查耗时或工具对照数据,所以这是经验工作流,不能据此认定 Yenpo 比现有编辑器更高效。它的 AI Reader 让回答更便于核查,也不代表回答一定正确。
原文对直接比较的用途还需收紧理解:git diff main feature 展示两个快照的差异,并不等同于预测真实合并结果。
另一个前提是改动能被拆成小步骤。作者建议每个逻辑步骤提交一次,在步骤之间审查,避免两小时后才面对大 diff。这方向合理,但提交数量多不代表可审查;每一步仍要能解释目的,保留足够上下文。文章也没有展开大型重构如何拆分、跨模块行为如何验证。
能拿来做什么
- 给日常 AI 编程任务增加明确交付要求:每完成一个逻辑步骤就提交,提交说明写清改了什么、为什么改,并在继续下一步前完成审查。
- 审查前端或 Node 分支时,先用
--stat和--name-status确认范围,再沿类型约定、实现、调用方、测试的顺序阅读;本地改动额外检查未跟踪文件。 - 对每次 bug 修复写出一句成因描述,再检查代码是否直接处理它;对被修改的测试断言,核对新预期是否仍符合需求。
- 把 Agent 总结拆成可验证事项,逐条定位实现、检查依赖定义并运行相关测试;遇到读不完的大 diff,先要求拆分,再继续评审。