Claude Code 团队如何进行代码审查

当代理产出代码的量如此之大时,你如何进行代码审查?在 Claude Code 团队,一旦我们实现了高覆盖率和深度审查,我们就开始优化,以找到不会增加回滚或事故的最少人工审查时间。

中文
复制
深色社交卡片:左侧一个橙色像素小生物的标志,中间上方框着 Engineering 一词,右侧是白色的英文标题 How the Claude Code team does code review

我们之前说过,Claude Code 自己的代码有大约 90% 是 Claude 写的。那么,以这样的产出速度,我们怎么审查代码?现在还有人读代码吗?出了问题,谁来兜底?

这篇文章讲的是 Claude Code 团队的代码审查流程,以及它是怎么演变的。从六月到九月,Claude Code 代码库合并的 pull request 数量翻了一倍多,而需要回滚的比例下降了 40% 以上。

我们没有取消审查。但我们把大部分阅读工作交给了机器,把优化目标放在人的时间和注意力上,并投入大量精力让回滚变得又快又容易。

重新思考代码审查的目的

当 agent 写代码时,变更数量会快速上升。在 Anthropic 的 monorepo 里,每天落地的变更从今年五月的约 2,500 次增加到九月的 30,000 多次。

Claude Code 有自己的独立仓库,不在 monorepo 里,但同样承受着很大的压力。以这样的速度交付,逐行人工审查即使并非不可能,也极其困难。

代码审查有两个作用:

  1. 在代码上线前发现并修复问题
  2. 在团队内建立共享的上下文和对代码库的理解

本文主要讨论发现和修复问题,第二个作用留到接近结尾时再说。

我们认为,“有没有人读过这段代码”并不能准确回答“这次变更可能出什么问题,哪种检查——自动的还是人工的——才是抓出它的正确手段”。

换一个问法,也改变了审查发生的时机。以前,审查是终点前的一道关卡:写代码、开 PR、等同事来看。

现在,审查是持续进行的,更像是写作时的拼写检查。大多数变更在被要求人工查看之前,已经至少被 Claude 审查并修复过一次。这样能拦住大部分常规错误,把团队的注意力留给更高层次的问题和审视。

稀缺资源:人的时间和注意力

我们希望把人的时间和注意力留给只有人能解决的问题,其余的交由自动化检查兜底。以我们目前的变更速度,人要做的工作仍然多得惊人,团队几乎每天都会遇到新的、前所未有的挑战。

人工时间涵盖审查成本的两端:人花在审查上的时间,以及人花在修复坏代码造成的问题上的时间。如果这些时间只是转移到了后者,削减前者就没有意义。

所以目标是:Claude Code 各仓库(CLI、桌面端和 Web 应用,以及移动端应用)中的大多数 pull request 最多只需一个人参与就能合并,这个人可以是作者,同时回滚和事故不增加。为了衡量人工时间,我们追踪每个 PR 的人工批准数(中位数和第 95 百分位)、人工评论数,以及 PR 等待某个人处理的时间。回滚率和事故率是护栏:如果它们上升,我们就没有节省人工时间,只是把时间挪了个地方。

一次变更的生命周期

一次典型的变更,从工程师的笔记本电脑(或 Slack 里的一个 Claude 会话)出发,要经过多层代码审查。

拉取请求的检查,从上到下。在拉取请求之前,工作已经过验证。在每个拉取请求上:必需的 CI、Claude 代码审查和安全审查,全部自动化,然后是基于风险的批准,由人决定。然后是合并队列,合并后先内部使用的功能标志、逐步发布,最后一步是观察、向前修复或回滚。
图 A 大部分路径是自动化的;人的注意力集中在风险所在之处

逐层拆解

六层自上而下堆叠:验证、必需 CI、AI 审查、安全审查、人工批准、合并队列加标志。每层的漏洞位置各不相同。从某一层漏洞漏过的问题会被后续层拦截;有一个问题穿过每一层的漏洞,最终落入底部的快速回滚。
图 B 每一层都能捕捉一些问题,也会漏掉另一些。很少有能通过所有层的,其余的由回滚处理。

1. 先自行验证,再交给别人看

如今大部分审查都发生在 PR 创建之前。我们给 Claude 一些可以实际运行的东西——测试、构建,或一张用来和设计稿比对的截图——要求它展示输出结果,而不是口头说一句“做完了”。随后由一个 subagent 带着全新的上下文审查 diff。这两个习惯都来自我们的最佳实践指南。

开 PR 之前,很多人还会跑几个内部 skill:一个专门找 bug,一个精简 diff,一个端到端检查行为。UI 改动还要对照设计规范过一遍。

Claude Code 的创造者 Boris Cherny 说过,给 Claude 一个验证自己工作的方式,大概是最重要的一件事,这是取得好结果的关键。他估计这能让最终结果好上两到三倍,并写道:“验证方式因领域而异。可能只是跑一条 bash 命令,跑一套测试,或者在浏览器或手机模拟器里把应用测一遍。”

自动审查反复指出同一个问题时,我们从源头修: 改 skill、加 lint 规则,或者更新这类指导性文件:

  • CLAUDE.md 告诉 Claude 这个项目是什么:技术栈、约定、目标和非目标。每次审查都会加载它,所以在大型代码库里我们把它写得很短,其余内容从它指向别的文档。审查器也会标出违反其中约定的代码,以及让其中某一行过时的改动。
  • REVIEW.md 由代码所有者撰写,告诉审查器他们负责的那部分代码里什么才重要。审查器是否真的照做,我们另行检查。写得好的都很短。它们会说明在这个仓库里“出问题”长什么样(文档仓库是“它在说谎”,配置仓库是“它把请求路由错了”),限制吹毛求疵的数量,列出要跳过的路径,并要求给出文件和行号作为证据,而不是从名字猜。它们还会要求摘要以数量开头,没什么可改的时候就直接说没什么可改。

2. 每个 pull request 都过 AI 审查

每个 pull request 在有人看之前,都会先过一遍 Claude 审查。它对照整个仓库和 PR 声明的意图来读 diff,然后问:这个改动解决了它要解决的问题吗?符合系统设计吗?有没有弄坏别的东西?

修 bug 时,它会去找根因。公开版本 Code Review for Claude Code 现已在 Team 和 Enterprise 套餐上正式可用,/code-review 则在本地运行一个更轻量的版本。

我们推出研究预览版时,内部 PR 中获得实质性审查意见的比例从 16% 升到了 54%。超过 1,000 行的 PR 大多能查出问题,小 PR 则大多干干净净地通过。管理员可以为每个仓库设置 Quick、Standard 或 Deep。如果漏掉一个 bug 的代价高于多花的那点审查时间,Deep 就值得开。

发现的问题先由其他 agent 验证,再交给人审查。 多个 agent 同时查找 bug,然后由另一组 agent 对每条发现投票,只有足够多的 agent 认定确有其事,这条发现才会被发布。只涉及风格、诊断信息或清理工作的发现会被丢弃。这些过滤规则在保留之前,我们先在自己的 PR 上做了 A/B 测试。剩下的以行内评论的形式呈现,按严重程度排序。每条都标记为 Important、Nit 或 Pre-existing,这样 PR 本身没有引入的 bug 就不会看起来像是作者的错。

每条发现都必须有回应。 要么修掉,要么写明理由把讨论串标记为已解决。通常 agent 会在一夜之间把修复做完,作者回来时,PR 已经又过了一轮。

3. 能拦住合并的安全审查

安全也有自己的自动审查。只要 bug 审查或安全审查中还有任何一条发现未关闭,PR 就不能合并。你要么修掉它,要么用简短的理由关闭讨论串——误报就是这样清除的。如果后续的提交修复了该问题,这条发现会自动消除。你也可以用开源的 security review GitHub Action 或 /security-review 命令实现同样的效果。配置方法见 automated security reviews in Claude Code。

4. 能拦住合并的自动化检查

常规的那一套:lint、类型检查、各平台上的测试,以及构建。(关于如何为这样的量级扩展 CI,我们写过一篇文章。)一个典型的 CLI pull request 在有人看之前可能就要跑几十项检查。PR 模板会要求说明改动是如何测试的、如何回滚。Claude 可以帮你填,但提出改动的人要对它签字确认。

5. 人工审批,按风险分级

修改文档和修改自动更新程序,风险不一样,审查方式自然也不同。

风险示例人工审批
低文档、文案、仅内部使用的功能、藏在开关后面的增量改动自动审查和安全检查通过后,无需人工审批
中普通产品改动,以及缓存、自动更新程序、系统提示词等敏感区域的改动一人
高风险最高的代码,外加一小批始终需要两人审批的路径两人

定级看改动本身,不看作者。 一个分类器读取改动内容,判定其风险等级。第二个分类器则判断:即便等级显示不需要,这次改动是否仍需另一个人介入。有些路径始终需要人工审批:负责人标记为敏感的任何内容,以及所有 CI workflow 文件。

只有受信任的作者才能走轻量通道。 只有仓库受信任名单上的作者才能走轻量通道,名单上主要是负责该仓库的团队。其他所有人都需要第二个人审批。agent 的批准也永远不能算作人的批准。自动审查可以让低风险改动通过,但填不上需要真人的那个位置。

谁发起改动,谁就担责。 对于 agent 写的 PR,指挥 agent 的人算作所需的审查人之一,与他亲手写下这些代码无异。

一次批准只覆盖一个特定的 commit。 如果之后又来了系统无法担保的新 commit,比如 agent 推送的,或有人手动解决的合并,就必须重新批准。

6. 合并队列、功能开关与渐进式发布

合并队列会把变更应用到 main 上,重新跑一遍所有检查,因此两个各自都能通过的 PR 不会合到一起把 main 搞坏。新行为通常先藏在功能开关后面,只对 Anthropic 员工开放,而我们自己的重度使用往往能在用户之前暴露回归问题。公开发布先走 latest 渠道,stable 渠道随后跟进。

7. 快速发现,快速回滚

总有些错误会漏过去,所以最后一道防线是尽快抓到它们。功能开关不用部署就能关掉。Claude Code 有每周轮换的 on-call,事故复盘会追问本该由哪一层拦住这个问题。

发现一次糟糕的合并,仍然要靠作者和 on-call,也要靠 revert 和事故看板。我们还没有这样的熔断机制:当这些数字变化时自动收紧审批。这里的工程师希望在更多代码转向零人工合并之前先把它做出来。

一位同事说,放慢速度确实能降低出错率,但主要是因为什么都做得更少了。我们更愿意在发现和修复问题上变得更快。

我们如何让 reviewer 变得更好

我们的代码审查流程在一个循环里不断改进。

现在任何事故都会变成一个 eval。 团队收集了过去引发事故的 PR,连同它们的 fix-forward 和 revert,并让熟悉那段代码的工程师确认每个 bug 以及它所在的位置。审查者每天都会跑一遍这个集合。

一个事故或回滚会成为经专家检查的案例,并被加入 eval 集。对审查者的更改会进入每天的 eval 运行,针对每个案例进行评分;如果分数上升就保留该更改,如果没有上升就放弃,然后循环从下一个更改重新开始。
图 C eval 随每次事故而增长,而对审查者的每一次更改都会针对全部内容进行评分。

我们通过观察人们如何处理评论来衡量噪声。 多抓几个 bug 很容易,只要不介意误报大量并非 bug 的问题,所以我们需要对此加以约束。我们把审查者留下的每条评论按 PR 作者的回应方式分类:改了、说这是错的、说这是有意为之,或者认为无关紧要。我们还会让审查者跑那些已知干净的 PR,统计它报告出“会让人做出有害改动”的问题的频率。我们写下来的优先级是:先抓真正的 bug,其次才是减少审查轮次。

作者是 agent 时,噪声的代价更高。人可以几秒钟就把一个吹毛求疵的意见打发掉。agent 会去改,于是又多一个 commit、又多一轮审查。

审查必须收敛。 agent 作者和 agent 审查者可以让彼此无限期地忙下去。有一个 CLI 的 PR 一夜之间经历了五十多轮审查和修改,最后作者才把它叫停。

我们对审查者反复标记的内容跑了 git blame,其中约 59% 是审查者第一轮时就已经存在的代码。审查者很少在发现新 bug,它每轮只是多找出几个旧 bug。

这个问题是我们自己弄严重的。我们习惯了默认跑好几轮,因为每一轮总能抓到点新东西。对有风险的改动这或许值得,但不是每个 PR 都值得。团队现在把通过所需轮次和召回率放在一起跟踪,并改了复审方式:

  • 轮次上限。 三轮之后,审查者会请作者退一步,重新考虑方案。
  • 只审 diff 的复审,在最初几轮之后启用。
  • 标出 bug 的类别,让作者修掉所有同类实例,而不是只改一行。
  • 不重复已经发过的发现。

审查 agent 还会每晚跑一遍现有代码,帮我们在旧 bug 冒到别处之前把它们抓出来。

收敛工作前后:一轮审查和修复后通过的拉取请求从 65% 升至 78%;需要五轮或更多轮的拉取请求从 8.9% 降至 1.5%;通过所需的平均审查次数从 2.08 降至 1.32。
图 D 收敛变更后每个内部拉取请求的审查轮次减少

人类仍然把关的地方

把一个资深工程师从深度工作中拉出来,只为抓一个常规错误,代价远高于自动化审查。在 Anthropic,我们的工作已经从逐行读 diff,转向机器做不好的那些判断:

  • 这东西到底该不该做? 方向、品味和范围。有个团队宣称审查瓶颈已经解决,但对来自团队外部的改动仍保留人工审查,好让有人问一句“这事我们到底该不该做?”
  • 高风险代码,比如计费、自动更新器和 CI 工作流。
  • 架构,即会被别人照抄的模式。
  • 读证据。 测试输出、跑的是哪条命令、返回了什么、截图、审查者的发现。如果你说不清这些检查会漏掉什么,就要求一次真正的审查,而不是图快批一下。
  • 对结果负责。 每一行上线的改动都得有人担责,不管是谁敲的。
自动化检查贯穿始终,有五个由人做决定的节点:是否构建、风险代码、架构、解读证据,以及承担结果。
图 E 人们从阅读每一处差异转向机器不擅长的决策

在团队中共享上下文

代码审查的第二项职责,一直是让团队对代码库的理解得以传播。读同事的 diff,你才知道改了什么、各部分是怎么拼起来的。可如果大部分阅读都交给机器,人又怎么熟悉代码?

我们没有为此定什么正式流程。团队里没有人脑子里装着 Claude Code 的完整模型,我们也不认为有谁需要这样。想弄懂代码库的某一部分时,就请 Claude 针对那一块写一份讲解。几分钟就能拿到,而且反映的是代码当下的样子。

图表标题为“如果大部分阅读都由机器完成,人们又如何学会代码?”左侧的网格代表代码库,其中几个方块被高亮标为托管设置,也就是你想理解的那部分。一条标有“就这一部分询问 Claude”的箭头指向两种结果:Claude 会撰写一份反映代码当前状态的说明,并且对某些情况,Claude 会构建一个小型产物,将该部分代码可视化。底部一行说明:逐行阅读琐碎的差异几乎学不到什么;而针对你即将修改的模块提供一份说明,则能让你学到很多。

我们中的一些人更进一步,让 Claude 做一个小工具,把代码的那部分可视化出来,再按这个人喜欢的学习方式讲给他听。

如果目标是把人的注意力花在刀刃上,这比逐行读那些无关紧要的 diff 强得多。改一行文案,你几乎学不到什么。而针对你即将改动的模块来一份讲解,你能学到很多。默认在公开 Slack 频道里干活的文化也有帮助,别人在做什么,你边看他们做就边知道了。

“你合入,你负责”

如果你合入了一个小改动或中等改动,之后还是出了问题,团队惯例通常是由你来修。有几件事让这件事不至于变糟:

  • 改动都很小,所以容易审查、调试和回滚。
  • 一切皆可回退。 开关、回滚和分阶段发布能在几分钟内撤销大部分错误。
  • 影响范围决定门槛。 代价高的代码,参与的人和检查都更多。
  • 回归暴露得快,靠遥测和内部使用就能发现。
  • 这不是追责。 负责修复意味着你最了解上下文;事故复盘看的是系统。

责任也是共担的。团队里很多人都在公开频道里工作,谁都能看到别人在做什么、接上一个话题,或者让 Claude 去补一个缺口,反馈也来自并不拥有这段代码的人。质量能一直保持在高位、又不必对每一行都设卡,很大程度上靠的就是这种开放。

当我们改变方向

Agent 让启动一件事变得很便宜,所以有些工作本来就不该合入。通常是频道里有人问为什么、指出之前的某个决定,或者建议一条更简单的路子,然后作者关掉或重塑这个 PR。

既然代码写得快,关掉 PR 也不觉得是损失。诀窍是在话题里尽早提出另一个方向,而不是等 PR 做完了再留一条阻塞性评论。

怎么在你的团队里采用这套流程

要做这件事,大部分东西今天就已经有了。

提交 PR 之前

  • 给 agent 一些它能自己跑的检查,写在一个简短的 CLAUDE.md 里,再加上跑格式化和 linter 的 hook。
  • 在本地跑 /code-review 和 /security-review,或者让一个全新上下文的子 agent 做审查。
  • 加一个 REVIEW.md,把反复出现的审查意见挪进去。

每个 pull request

  • 要求 CI 通过,并在 PR 模板中加入「测试」「风险」和「如何回滚」。
  • 先在一个仓库上接入 AI 审查器(Claude Code 的 Code Review,或 Claude Code GitHub Action),花几周时间调优 REVIEW.md,再逐步推广。
  • 加入自动化安全审查,并要求合并前解决所有审查讨论。
  • 审查力度与风险匹配:常规改动快速过一遍,漏掉 bug 代价高昂的地方则深入审查(Code Review 中的 Quick、Standard 或 Deep)。
  • 限制审查轮次;前几轮之后,只重新审查新增的 diff。

审批

  • 把风险等级写下来,按改动本身而非作者来定级;一开始从严,有证据后再放宽。
  • 对信任的作者保留更轻量的审批路径。
  • 用 CODEOWNERS 和分支保护,让认证、计费、CI 与发布流程、安装程序始终需要真人审批。
  • 绝不让机器人的批准替代必需的人工批准;有新提交时撤销已有批准。

合并及之后

  • 使用 merge queue、feature flag、先内部使用、分阶段发布,以及一步式回滚。
  • 把事故和回滚转化为 eval 集,每当审查者的 prompt、工具或模型发生变化就重新评分。
  • 衡量人工投入的时间,以回滚率和事故率作为护栏指标。

接下来的方向

Code Review 的发布公告说,批准 pull request 仍然由人来做决定;产品给出的是发现的问题,不是批准。我们自己的仓库走得更远,让仓库所有者决定哪些低风险改动可以仅凭自动化检查合并,而这条界线还在不断移动。

当审查漏掉问题时,我们会追问模型当时手上缺了什么,然后把修正写进 CLAUDE.md、skill 或一项新的检查。目标没有变:每次改动花更少的人工时间,回滚不比以前多。

如果你的团队让 agent 提交 pull request,我们想知道:你们自动化了哪些检查,哪些仍然需要真人,以及你认为我们哪里做错了。

感谢 Emma Webb、Michael Segner 和 Amie Rotherham 的审阅。

来源: claude.dev← 返回首页