当 AI 写了 90% 的代码,Code Review 还应该怎么做?
最近我读了 Claude Code 团队的一篇文章——How the Claude Code team does code review。里面有一个数据很扎眼:
Claude Code 自己大约 90% 的代码已经由 Claude 编写。
更有意思的是,从 6 月到 9 月,他们合并的 PR 数量翻了一倍以上,但需要 revert 的比例反而下降了 40% 以上。这让我意识到一个问题:当 AI 开始大规模生产代码以后,传统 Code Review 的模型可能已经不成立了。
以前我们默认的软件开发流程大概是:
人写代码
↓
提交 PR
↓
另一个人读代码
↓
发现问题
↓
修改
↓
Merge
这里有一个隐含假设:
代码生产速度低于或者接近人类 Review 代码的速度。
但 Agent 出现以后,这个假设正在失效。一个 Claude Code 可以一天生成大量代码,如果继续要求高级工程师逐行阅读所有 Diff,那么很快就会出现一个荒谬的情况:
AI 负责高速生产代码,人类负责低速检查 AI 生产的代码。
最终 AI 没成为瓶颈,人变成了瓶颈。 所以 Claude Code 团队实际上重新定义了一个问题:
Code Review 到底是在 Review 什么?
Code Review 的目标从来不是“有人读过代码”
过去我们经常把“这个 PR 有人 Review 过”等价成“这个 PR 是安全的”。但仔细想想,这只是一个 Proxy。真正的问题其实应该是:
这次修改可能出什么问题?哪个检查最适合发现这个问题?
例如:
语法错误 → Compiler
类型错误 → Type Checker
格式问题 → Formatter
简单规则问题 → Linter
功能回归 → Test
集成问题 → Integration Test
安全问题 → Security Review
架构问题 → Senior Engineer
产品方向问题 → Human
如果一个问题可以被确定性工具发现,那么让一个高级工程师花时间检查它,其实是一种资源浪费。所以我现在越来越倾向于认为:Code Review 的本质不是“读代码”,而是风险控制。 人的 Review 只是其中一种风险控制手段。
Verification 可能比 Prompt Engineering 更重要
这篇文章里我最认同的一个观点,是 Boris Cherny 对 Verification 的强调。简单来说,不要让 Agent 告诉你:
“我已经改好了。”
而是让它证明:
我改好了。
这是 test result。
这是 build result。
这是 lint result。
这是 browser 运行结果。
这是截图。
也就是:
Agent
↓
修改代码
↓
执行验证
↓
获得反馈
↓
继续修改
↓
再次验证
这其实就是一个反馈闭环。我越来越觉得,很多人使用 Coding Agent 时,注意力过度集中在 Prompt 上:
“Prompt 应该怎么写?CLAUDE.md 应该怎么写?怎么让模型理解需求?怎么让模型生成更好的代码?”
这些当然重要。但更重要的问题可能是:
Agent 怎么知道自己做对了?
例如写 Rust,Compiler 本身就是一个非常强的 Harness。Agent 写错了,可以直接跑 cargo check,Compiler 会直接告诉它哪里有问题。修改以后再跑 cargo test,测试继续告诉它行为是不是正确。前端也是一样:
修改 UI
↓
启动浏览器
↓
截图
↓
和设计稿比较
↓
发现偏差
↓
继续修改
所以真正提升 Agent Coding 能力的方式,未必只是:
更聪明的模型 + 更好的 Prompt
而更可能是:
更聪明的模型 + 更好的 Harness + 更短的反馈闭环
AI Review AI 并没有想象中奇怪
Claude Code 团队还有一个很有意思的做法:让 Claude Review Claude 写的代码。
乍看之下有点像:
“AI 写代码,AI 检查代码,那不就是自己批改自己的作业?”
但实际上他们并不是让同一个 Context 里的 Agent 回头看自己的代码。而是重新启动一个拥有 Fresh Context 的 Reviewer,从另一个角度检查 Diff。类似:
Agent A
↓
实现需求
↓
生成 Diff
↓
Agent B(Fresh Context)
↓
Review Diff
甚至可以进一步:
Reviewer A ─┐
Reviewer B ─┼→ 找潜在 Bug
Reviewer C ─┘
↓
Verification Agent
↓
判断 Finding 是否成立
我认为这里真正重要的其实不是“用了几个 Agent”,而是:Writer 和 Reviewer 被拆成了两个不同角色。
Writer 的目标是完成任务,Reviewer 的目标则是证明它哪里可能错。
这两个角色的 Optimization Target 本来就不同。哪怕它们背后是同一个模型,结果也可能完全不同。
但 Agent Review 有一个很现实的问题:它可以无限工作
文章里有一个例子让我印象很深。有一个 PR,一晚上经历了 50 多轮 AI Review。大概是:
Writer 修改
↓
Reviewer 找问题
↓
Writer 修改
↓
Reviewer 又找问题
↓
Writer 再修改
↓
Reviewer 又找问题
↓
...
机器不会累。所以两个 Agent 完全可以:
非常认真地浪费无限 Token。
后来他们分析发现,大约 59% 被后续 Review 反复指出的问题,其实第一次 Review 的时候就已经存在。也就是说 Reviewer 不是一直发现新的 Bug。很多时候只是:
第一轮发现 3 个
第二轮又发现 2 个
第三轮又发现 1 个
第四轮突然又想到一个
于是他们开始限制 Review:
最多三轮
然后:
只 Review 新 Diff
不重复已有 Finding
发现一类问题,一次性检查全部实例
这给我的启发很大。因为 Agent 系统里一个非常容易被忽略的问题就是:
Agent 会不会收敛?
人类工作有天然的停止条件:累了、没时间了、觉得差不多了、deadline 到了。Agent 没有。所以 Agent Workflow 设计必须人为加入 Budget、Round Limit、Stop Condition、Escalation。
否则“更勤奋”不一定意味着“更高质量”。
人类没有退出 Review,只是换了位置
看到这里很容易产生一种误解:
那以后是不是不需要程序员 Review 代码了?
我觉得完全不是。Claude Code 团队真正做的其实是:把人的注意力从低价值 Review 中释放出来。
例如变量命名、格式问题、简单 Bug、明显空指针、测试遗漏、Convention,这些尽量机器处理。而人集中处理:
Should we build this?
架构是否合理?
这个方向是不是正确?
安全边界有没有变化?
这个设计会不会形成错误的 Pattern?
出了问题谁负责?
这些问题最大的特点是:
没有一个明确的 Correct Answer。
Compiler 可以告诉你:
“这个程序编译不过。”
但 Compiler 很难告诉你:
“这个 Architecture 半年后会变成技术债。”
Test 可以告诉你:
“当前行为符合测试。”
但 Test 不知道:
“我们到底应不应该做这个功能。”
所以我认为未来人的价值会逐渐从检查代码有没有写错,转移到:判断什么代码值得写、判断系统应该往哪个方向发展、判断哪些风险值得承担。
Risk-Based Review 比 All-or-Nothing 更合理
传统团队很喜欢制定统一规则:
“所有 PR 必须一个 Approval”
或者:
“所有 PR 必须两个 Approval”
但实际上:
修改 README
和:
修改 Authentication
显然不是一个风险等级。Claude Code 团队采用的是 Risk-Based Review。可以粗略理解为:
| 风险 | 示例 | Human Review |
|---|---|---|
| Low | docs、copy、小修改 | 0 |
| Medium | 普通业务代码 | 1 |
| High | billing、auth、CI、release | 2 |
我很认同这个思路。因为 Review 成本应该和:
Failure Cost
相关,而不是和:
“代码是谁写的”
相关。未来一个很合理的工程模型可能是:
Change
↓
Risk Classification
↓
Low Risk
→ 自动测试
→ AI Review
→ Merge
Medium Risk
→ 自动测试
→ AI Review
→ 1 Human
→ Merge
High Risk
→ 自动测试
→ AI Review
→ Security Review
→ 2 Humans
→ Merge
这里最重要的其实不是 AI。而是:
把工程师的注意力分配给 Failure Cost 最大的地方。
我以前认为程序员必须理解整个系统,现在我开始怀疑了
这篇文章另一个很有争议的观点是:Claude Code 团队没人完整理解整个 Claude Code Codebase,而且他们也不认为这是必要的。以前我们对 Senior Engineer 经常有一种想象:
“整个系统都在他的脑子里。”
他知道哪个模块干什么、数据怎么流、调用链怎么走、哪里不能动,以及历史为什么这么设计。
但随着系统越来越大,这种 Mental Model 本来就越来越难维持。Agent 出现以后可能进一步变成:
我不需要长期记住整个系统。
我只需要在需要修改某个部分时,
快速建立这一部分的 Mental Model。
例如:
我要修改 managed settings
↓
Ask Claude
↓
解释相关模块
↓
解释调用链
↓
解释数据流
↓
解释历史设计
↓
开始修改
也就是从 Persistent Understanding 开始变成 Just-in-time Understanding。
这有点类似程序的 Virtual Memory:不是所有东西一直放在 RAM 里,需要的时候 Page In,不用的时候 Page Out。
而 Claude 某种意义上成了:
Codebase 的 Page Loader。
我觉得这个变化可能比“AI 自动写代码”本身更加深远。因为它会改变工程师学习大型系统的方法。
“You land it, you own it” 可能比 AI Review 更重要
不过整篇文章里,我最喜欢的其实还是这个原则:
You land it, you own it.
Agent 写代码,并不意味着 Agent 负责:Claude 写代码 ≠ Claude 对 Production 负责。 真正的关系仍然是:
你让 Claude 写
↓
你决定 Merge
↓
你负责结果
这个边界必须非常清晰。否则很容易出现一种危险文化:
“为什么出 Bug?Claude 写的。”
这就和:
“为什么出 Bug?Stack Overflow 上复制的。”
一样没有意义。工具没有 Ownership,人有。
真正让 AI Coding 成立的不是“AI 不犯错”
这可能是我读完以后最大的感受。很多人讨论 AI Coding 时,总是在争论:
“AI 会不会写 Bug?AI 生成的代码可靠吗?AI 能不能替代程序员?”
但这些问题可能问错了。因为人类程序员本来就会写 Bug。真正成熟的软件工程从来不是建立在:
“程序员不会犯错”
这个假设上。而是建立在:
“程序员一定会犯错”
这个假设上。然后我们发明了:
Compiler
Type System
Test
CI
Code Review
Canary
Feature Flag
Monitoring
Rollback
AI 也是一样。真正的问题不是:
怎么让 Agent 永远不犯错?
而是:
怎么让 Agent 犯错以后,错误能够快速暴露,而且代价足够低?
于是整个系统变成:
Agent
↓
Verification
↓
AI Review
↓
Security Review
↓
CI
↓
Risk-Based Human Review
↓
Merge Queue
↓
Feature Flag
↓
Gradual Rollout
↓
Observability
↓
Rollback
没有任何一层保证绝对正确。但是每一层都会降低一点风险。这才是真正的软件工程。
我现在怎么看 AI 时代的 Code Review
如果让我把整篇文章压缩成一个公式,我会写成:
过去:
Quality ≈ Good Engineer × Human Review
未来可能更接近:
Quality ≈ Verification × Automated Review × CI × Risk Control × Observability × Rollback × Human Judgment
人的角色没有消失,只是从检查每一行代码,逐渐变成设计系统、定义约束、设置 Harness、判断风险、决定方向、处理异常、承担责任。
我甚至觉得,这可能就是 Agent Coding 真正进入工程化阶段的标志。不是某一天 Claude 突然可以:
“一次生成 10 万行完美代码。”
而是我们的软件工程体系逐渐变成:
即使 Agent 每天生成大量代码,即使它偶尔犯错,系统依然能够稳定运行。
换句话说:
AI Coding 的终局可能不是让 AI 变得绝对可靠,而是让“AI 不可靠”这件事变得可以被工程化管理。
这和几十年来软件工程解决人类程序员不可靠的问题,其实是同一件事。只不过现在,代码的生产速度突然提高了一个数量级。而 Code Review,也必须跟着重新设计。
参考
原文:How the Claude Code team does code review https://claude.dev/blog/solving-code-review-at-anthropic/