我们之前说过,Claude Code 自身约 90% 的代码都是由 Claude 编写的。那么,在如此大的产出量下,我们是如何审查代码的?还有人真正在阅读代码吗?如果出了问题,谁来发现它?
本文介绍 Claude Code 团队的代码审查流程及其演变。从6月到9月,合并到 Claude Code 代码库的拉取请求增加了一倍以上,而需要回滚的比例下降了超过 40%。
我们没有取消审查。但我们确实将大部分阅读工作转移到了机器上,针对人的时间和注意力进行了优化,并投入大量资源使撤销错误变得快速而容易。
重新思考代码评审的目的
当智能体编写代码时,变更数量会快速上升。在 Anthropic 的单体仓库中,每天落地的变更从今年 5月的约2,500个增加到9月的超过30,000个 。
Claude Code 位于自己的独立仓库中,与单体仓库分开,但它也承受着巨大压力。当你以这样的速度发布时,手动的、逐行的代码评审即使不是不可能,也极其困难。
代码评审承担两项工作:
- 在发布之前发现并修复问题
- 在团队中建立共享的上下文和代码库理解
本文主要聚焦于发现和修复问题,但我们会在接近结尾时回到第二项工作。
我们认为,"是否有人读过这段代码?"是"这个变更可能出什么问题,以及哪种检查——自动的还是人工的——是发现它的正确方式?"这一问题的不精确替代指标。
提出这个问题也改变了评审发生的 时机 。以前,评审是道路尽头的关卡:写代码,开一个 PR,等待你的同事。
现在,评审持续运行,更像你写作时的拼写检查。大多数变更在被要求人工查看之前,已经由 Claude 审查并修复过至少一次。这能捕获大多数常规错误,并将团队的注意力留给更高层次的问题和审查。
稀缺资源:人的时间与注意力
我们希望将人的时间和注意力保留给只有人类才能解决的问题,并确保自动化检查捕获其余问题。以我们当前的变化速度,人类仍然有难以置信的大量工作要做,而且我们的团队几乎每天都会遇到新的、前所未有的挑战。
人的时间涵盖评审成本的两面:人们花在评审上的时间,以及他们花在修复坏代码造成的破坏上的时间。如果时间只是转移到了后者,削减前者并无帮助。
因此,目标是让 Claude Code 各仓库(CLI、桌面和网页应用以及移动应用)中的大多数拉取请求在最多只有一名人类参与的情况下合并,这个人可以是作者本人,同时回退和事故率不增加。为了衡量人的时间,我们跟踪每个 PR 的人工批准次数(中位数和第95百分位)、人工评论数量,以及 PR 等待人工处理的时长。回退率和事故率是护栏:如果它们上升,说明我们没有节省人的时间,只是转移了它。
一个变更的生命周期
一个典型的变更,从工程师的笔记本电脑(或 Slack 中的 Claude 会话)开始,要经过多层代码评审。
逐层解析
1. 在任何人查看之前工作已被验证
现在大部分审查发生在 PR 存在之前。我们给 Claude 一个它可以运行的东西——比如测试、构建或一张与设计对比的截图——并要求它展示输出,而不是说完成了。然后由一个子代理以全新的上下文审查 diff。这两个习惯都来自我们的 最佳实践指南.
在打开 PR 之前,我们许多人还会运行几个内部技能:一个寻找 bug,一个简化 diff,还有一个进行端到端行为检查。UI 变更还会根据我们的设计准则进行检查。
创建 Claude Code 的 Boris Cherny 曾说,给 Claude 一种验证其工作的方式 可能是最重要的事情 ,对于获得好结果而言。他估计这会使最终结果好两到三倍,并写道:“验证在每个领域看起来都不同。它可能简单到运行一条 bash 命令,或运行一个测试套件,或在浏览器或手机模拟器中测试应用。”
当自动审查者不断标记同一问题时,我们会从源头修复它: 在技能中、通过 lint 规则,或通过更新如下指令文件:
CLAUDE.md告诉 Claude 这个项目是什么:技术栈、约定、目标和非目标。每次审查都会加载它,因此在大型代码库中我们保持它简短,并从这里指向其他文档。审查者还会标出违反其中约定的代码,以及使其中某条内容过时的更改。REVIEW.md,由代码所有者编写,告诉审查者在他们负责的代码部分什么最重要。我们会单独检查审查者是否真的遵循它。好的版本都很简短。它们说明在该仓库中什么算失败(对文档来说是"它撒谎",对配置来说是"它错误路由"),限制吹毛求疵的数量,列出要跳过的路径,并要求以文件和行号作为证据,而不是凭名字猜测。它们还要求摘要以一个计数开头,并在没有需要修复的内容时明确说明。
2. 每个拉取请求都进行 AI 审查
每个拉取请求在人工查看之前都会得到一次 Claude 审查。它结合整个仓库和 PR 声明的意图来阅读 diff,并提出问题:这个更改是否解决了它的问题、是否符合系统、或者破坏了其他东西?
对于错误修复,它会寻找根本原因。公开版本 Code Review for Claude Code现已在 Team 和 Enterprise 计划上全面推出,而 /code-review 在本地运行一个更轻量的版本。
当我们 启动研究预览时,获得实质性审查评论的内部 PR 占比从 16% 上升到 54%。超过 1,000 行的大多数 PR 会得到发现,而大多数小的 PR 返回时是干净的。管理员可将每个仓库设置为 Quick、Standard 或 Deep。当一个被遗漏的错误造成的损失超过额外的审查时间时,Deep 是值得的。
发现结果在人工审查之前会由其他智能体验证。 多个智能体同时查找错误。然后由一个单独的小组对每个发现进行投票,只有当足够多的智能体同意它是真实问题时才会发布。仅涉及风格、诊断或清理的发现会被丢弃。我们在保留这些过滤器之前在自己的 PR 上进行了 A/B 测试。剩下的内容以按严重程度排序的内联评论形式出现。每条都标记为 Important、Nit 或 Pre-existing,这样 PR 没有引入的错误就不会看起来像是作者的责任。
每个发现都必须被回应。 你要么修复它,要么给出理由解决该讨论串。通常一个智能体会连夜接手修复,所以作者回来时会看到一个已经又经历过一轮审查的 PR。
3. 可以阻止合并的安全审查
安全审查也有自己的自动化审查。只要来自错误审查或安全审查的任何发现仍未解决,PR 就无法合并。你要么修复它,要么用简短理由关闭讨论串,这就是你清除误报的方式。
如果后来的提交修复了该问题,该发现会自动清除。你可以使用开源的安全审查 GitHub Action 或 /security-review 命令设置同样的东西。设置方法在 Claude Code 的自动化安全审查.
4. 会阻止合并的自动检查
常规的:lint、类型检查、每个平台上的测试,以及构建。(我们写过关于为这种规模扩展 CI 的文章,见 这里。)一个典型的 CLI 拉取请求在任何人查看之前可能要运行数十项检查。PR 模板会询问更改是如何测试的以及如何撤销它。Claude 可以填写这些内容,但要求该更改的人要对其签字确认。
5. 按风险分级的人工批准
文档修复和自动更新程序更改具有不同的风险,因此会得到不同的审查。
| 风险 | 示例 | 人工批准 |
|---|---|---|
| 低 | 文档、文案、仅内部功能、隐藏在 flag 后面的增量更改 | 自动化审查和安全检查通过后无需人工批准 |
| 中等 | 普通的产品变更,以及涉及缓存、自动更新器或系统提示词等敏感区域的变更 | 一个人 |
| 高 | 风险最高的代码,外加一小组始终需要两个人的路径 | 两个人 |
由变更决定层级,而不是由作者决定。 一个分类器读取变更并选定其风险层级。第二个分类器判断这个特定变更即使在层级显示不需要时是否仍需另一个人。某些路径始终需要一个人,包括所有者列为敏感的任何内容以及任何 CI workflow 文件。
只有受信任的作者才能走较轻量的路径。 只有仓库受信任名单上的作者才能走较轻量的路径,主要是拥有该仓库的团队。其他所有人都需要第二个人来批准。代理(agent)的批准也绝不能算作人。自动化审查可以放行低风险变更,但不能填补需要人类的席位。
无论谁提示了这次变更,都要对其负责。 在代理撰写的 PR 上,指挥代理的人算作所需的审阅者之一,与他们亲自编写代码时的要求相同。
一次批准只覆盖一个特定的提交。 如果系统无法担保的新提交落地,例如代理的推送或有人手动解决的合并,批准必须重新给出。
6. 合并队列、标志和渐进式发布
合并队列会在应用更改后针对 main 重新运行每一项检查,因此两个各自单独通过的 PR 不可能合并成一个损坏的 main。新行为通常先通过 flag 面向 Anthropic 员工发布,我们大量的内部使用往往会在用户之前暴露回归。公开发布先到 latest 频道。 stable 频道随后跟进。
7. 快速检测,快速回滚
有些错误仍会漏网,所以最后一层是关于快速发现它们。flag 无需部署即可关闭。Claude Code 有每周轮值的 on-call 制度,事故复盘会追问哪一层本应发现该问题。
发现错误的合并仍取决于作者和 on-call,以及 revert 和 incident 仪表盘。我们还没有在这些数字变化时收紧审批的熔断机制;这里的工程师希望在更多代码走向零人工合并之前先有这些机制。
一位同事说,放慢速度确实能降低错误率,但主要是因为你做的所有事情都变少了。我们更愿意在更快地发现和修复问题上提速。
我们如何让审查者变得更好
我们的代码审查流程在不断循环改进。
任何事故现在都会变成一个 eval。 团队收集了以往引发事故的 PR,包括它们的 fix-forward 和 revert,并让熟悉那些代码的工程师确认每个 bug 及其所在位置。审查者每天对该集合运行。
我们通过观察人们对评论的处理来衡量噪音。 如果不介意标记大量非 bug,就很容易抓到更多 bug,所以我们需要对此加以约束。我们把审查者留下的每条评论按 PR 上当事人的回应方式排序:修复了、说是错的、说该行为是有意的,或决定无关紧要。我们还会在已知干净的 PR 上运行审查者,并统计它多久报告一次本会导致某人做出有害改动的发现。我们写下的优先级是:先抓真实 bug,再减少审查轮次。
当作者是 agent 时,噪音的代价更高。人可以在几秒钟内忽略一个 nit。而 agent 会去修复它,这意味着又一次提交和又一轮审查。
审查必须收敛。 一个 agent 作者和一个 agent 审查者可以让彼此无休止地忙碌下去。一个 CLI PR 在一夜之间经历了超过五十轮审查和修复,才被其作者叫停。
当我们对审查者反复标记的内容运行 git blame 时,其中约 59% 是自审查者第一轮起就已存在的代码。审查者很少发现新 bug,它只是每一轮多找出一些旧 bug。
我们自己把情况弄得更糟了。我们已习惯默认运行多轮,因为每一轮总能抓到新东西。这在高风险改动上是值得的,但不该用在每个 PR 上。团队现在在追踪通过轮次的同时也追踪召回率,并改变了复审方式:
- 轮次上限。 三轮之后,审查者会要求作者退一步重新考虑整体方案。
- 仅对 diff 复审 在前几轮之后。
- 标记该类 bug, 让作者修复每一处实例,而不是一行。
- 不再重复 已发布过的发现。
审查 agent 也会在夜间对现有代码运行,帮助我们在旧 bug 出现在别处之前抓住它们。
人类保留在环节中的位置
把一位资深工程师从深度工作中抽出来去发现一个常规错误,其代价远高于自动化审查。在 Anthropic,我们的工作已经从阅读每一个 diff 转向机器不擅长的那些决策:
- 我们到底该不该构建这个东西? 方向、品味和范围。一个团队在宣布其审查瓶颈已解决后,仍然对来自团队之外的改动保留人工审查,因此总会有人提出"我们到底该不该做这件事?"
- 高风险代码 例如计费、自动更新器和 CI 工作流。
- 架构 即会为他人树立可复制模式的架构。
- 审读证据。 测试输出、运行的命令及其返回结果、截图、审查者的发现。如果你说不清这些检查会漏掉什么,那就要求一次真正的审查,而不是快速的批准。
- 对结果负责。 每一个上线的改动都有一个负责人,无论是谁敲下的代码。
在团队内共享上下文
代码评审的第二个职责一直是传播对代码库的理解。阅读队友的 diff 是你了解发生了什么变化以及各部分如何契合的方式。如果机器完成了大部分阅读工作,那人们还怎么学习代码?
我们对此没有正式的流程。团队中没有人对 Claude Code 保持着完整的心智模型,我们也不认为有人需要这样做。当有人想了解代码库的某一部分时,他们会让 Claude 为这一小部分专门写一份讲解。这只需要几分钟,并且反映的是代码当前的真实状态。

我们中有些人更进一步,让 Claude 构建一个小型工件,将代码库的那部分可视化,并以这个人喜欢的学习方式来讲解它。
如果目标是善用人类的注意力,这比逐行阅读琐碎的 diff 更好。一行文案的修改几乎教不了你什么。针对你即将修改的模块的一份讲解却能让你学到很多。我们默认在公开 Slack 频道中工作的文化也有帮助,因为你能在他人构建的同时看到他们在做什么。
“谁合入,谁负责”
如果你合入了一个小型或中型变更,而之后仍然出了问题,团队惯例通常是由你来修复它。有几件事可以避免这种情况变得糟糕:
- 变更很小, 因此易于评审、调试和回滚。
- 一切都是可逆的。 功能开关、回滚和分阶段发布可以在几分钟内撤销大多数错误。
- 影响范围决定标准。 代价高昂的代码会得到更多的人力和更多的检查。
- 回归会很快浮现 通过遥测和内部使用。
- 这不是为了追责。 负责修复意味着你拥有最多的上下文;事故复盘关注的是系统。
责任也是共享的。团队中许多人都在 公开频道 中工作,任何人都可以看到他人在构建什么、接手一个话题,或让 Claude 去填补一个空白,而且反馈也来自不拥有该代码的人。这种开放性是在每一行代码上都不设门槛的情况下保持高质量的重要原因。
当我们改变方向时
智能体让开始做一件事变得廉价,所以有些工作不应该被合入。通常频道里的某个人会问为什么、指出一个更早的决定,或建议一条更简单的路径,然后作者就关闭或重塑这个 PR。
由于代码写起来很快,关闭 PR 并不会让人觉得是一种损失。关键在于尽早在线程中提出不同的方向,而不是作为一个阻塞性的评论出现在已完成的 PR 上。
你如何在你的团队采用这一流程
要在你的团队中这样做所需的大部分要素今天已经存在。
在拉取请求之前
- 给你的智能体提供它可以运行的检查,列在一份简短的
CLAUDE.md中,再加上运行格式化工具和 linter 的 hooks。 - 在本地运行
/code-review和/security-review,或者用一个全新上下文的子智能体进行评审。 - 添加一个
REVIEW.md,并把重复出现的评审意见移进去。
在每个拉取请求上
- 要求使用 CI,并在 PR 模板中加入 "Testing"、"Risk" 和 "How to revert"。
- 在一个仓库上添加 AI 审查者(Code Review for Claude Code,或 Claude Code GitHub Action),调整
REVIEW.md几周,然后再推广。 - 添加自动化安全审查,并要求在合并前解决每一个审查线程。
- 使审查力度与风险相匹配:对常规更改快速过一遍,对漏掉 bug 代价高昂的更改进行深入审查(Code Review 中的 Quick、Standard 或 Deep)。
- 限制审查轮数;在前几轮之后,只重新审查新的 diff。
批准
- 写下风险等级,依据变更本身而非作者来设定;从严格开始,再根据证据放宽。
- 为你信任的作者保留较轻量的批准路径。
- 使用 CODEOWNERS 和分支保护,确保 auth、billing、CI 和 release 工作流以及安装程序始终需要真人参与。
- 绝不让机器人的批准取代必需的人类批准;在有新提交时撤销已有的批准。
合并之后
- 使用合并队列、功能开关、内部优先使用、分阶段发布和一步回滚。
- 将事故和回滚转化为评估集,并在评审器的提示词、工具或模型发生变化时重新评分。
- 以人工时间作为衡量指标,并以回滚率和事故率作为守护指标。
这一切将走向何方
Code Review 的 公告 表示批准拉取请求仍然由人来决定;该产品发布的是审查发现,而不是批准。我们自己的仓库更进一步,让所有者决定哪些低风险更改仅凭自动化检查即可合并,而且这条界线还在不断移动。
当一次审查遗漏了某些内容时,我们会询问模型当时面前缺少什么,并将修复方案放入 CLAUDE.md、一个技能或一项新的检查中。目标从未改变:减少每次更改所需的人工时间,同时回滚次数不多于以前。
如果您的团队允许智能体打开拉取请求,我们希望听到您自动化了哪些检查、哪些检查仍然需要人来完成,以及您认为我们有哪些做得不对的地方。
感谢 Emma Webb、Michael Segner 和 Amie Rotherham 的审阅。
