一条 CLI 的 PR,夜里被 Agent 来回审了五十多轮。

每一轮看起来都挺合理。审查器提一个问题,写代码的 Agent 改一次,新的 diff 又触发下一轮。到最后,作者不得不手动叫停。不是因为代码一定坏了,而是两台机器已经把彼此困在了一个没有出口的礼貌循环里。

这件事出自 Anthropic 10 月 15 日公开的代码审查复盘。更值得看的是另一个数字,Claude Code 大约九成代码由 Claude 写成,但从 6 月到 9 月,合并的 PR 数量翻了一倍多,需要 revert 的比例反而下降超过四成。

这不是一个关于某个模型多强的故事。

它真正戳到的是一个很现实的问题。Agent 把写代码从稀缺能力变成廉价能力以后,团队最先爆掉的往往不是实现速度,而是验证能力。PR 堆积、CI 排队、reviewer 疲惫、线上回滚,旧流程里每一个原本靠人兜底的环节都会被放大。

如果你在 Java 或 Spring 项目里已经让 Agent 参与开发,这篇文章想聊的不是如何再接一个代码生成工具,而是如何给 Agent 产出的代码造一条能收敛、能追责、也能撤回的验证链。

代码写得更快,审查不该只是更累

传统代码审查有两个任务。

一个是找 bug。另一个常常被忽略,是让团队的人通过阅读彼此的改动,慢慢建立对系统的共同理解。

在 PR 每天只有十几条时,这套办法没什么问题。一个同事花二十分钟看完 diff,顺手指出空指针、事务边界或者命名问题,既挡住事故,也知道系统最近变成了什么样。

可当 Agent 一天能开几十条甚至几百条 PR,逐行阅读会先失去经济性。Anthropic 提到,其 monorepo 每日合入变更从 5 月的大约 2500 次升到 9 月超过 30000 次。人不是审得慢,而是这件事已经超过人的注意力带宽。

很多团队的第一反应会是加一层 AI Review,把人从队列里捞出来。这个方向没错,但只加一个机器人 reviewer,通常会得到两种糟糕结果。

一种是它很保守,评论密密麻麻,工程师开始把 review 当噪声。另一种是它被调得很克制,只有明显错误才敢说话,于是大家以为有了自动审查,实际上安全感只是被外包了。

审查不是一个关卡,而是一组不同能力的组合。单测擅长验证局部行为,类型检查能抓住接口错配,安全扫描能找危险模式,人适合判断需求是否值得做、架构方向是否对、风险是否配得上上线方式。把这些事压给一个 reviewer,结果大概率别扭。

我一直觉得,Agent 时代最需要改掉的一句话是,找个人看一下。

应该改成,哪一种失败,应该由哪一层发现。

从终点关卡,改成持续验证

Anthropic 的做法有个非常关键的转向。代码审查不再发生在 PR 最后,而是从 Agent 开始写代码时就已经开始。

他们让 Claude 不要只说已经完成,而是必须拿出可验证的结果。可能是一组测试结果、一次 build、和设计稿对比的截图,或者浏览器和手机模拟器里的实际行为。之后再让另一个带着新上下文的 subagent 看 diff。

这个动作听上去普通,落到工程里其实很硬。

拿一个 Spring Boot 的订单接口来说,Agent 接到的任务如果只是加一个取消订单 API,它很容易交出 Controller、Service 和 Repository 的几段代码。可一个可验证的任务,输入里应该多出几件东西。

  • 正常取消、重复取消、越权取消分别要有什么响应
  • 库存回补和订单状态变更是否必须在同一事务内
  • 已支付订单走退款流程时,Webhook 重试会不会重复扣减
  • 对外 DTO、OpenAPI、审计日志哪些是兼容性边界
  • 一键验收命令是什么

于是验收不再依赖 reviewer 在几百行 diff 里猜业务,而是让 Agent 先证明自己没有把边界踩坏。

1
2
./mvnw test -Dtest=OrderCancelIT
./mvnw verify

命令很短,背后的含义却不小。你不是让 Agent 写更多测试,而是把可被验证的业务承诺变成提交的一部分。没有这个承诺,后面的 AI Review 再聪明,也只是在猜作者本来想做什么。

这里有一个经常被忽略的坑。测试通过不等于验证完成。Agent 很擅长把测试写成和实现互相迁就的一对。测试名称漂亮,断言也在,真正的异常路径却根本没有碰到。

所以 Anthropic 会让另一个 Agent 用新上下文审查 diff。这个角色不应继续扮演作者的助手,它更像一个故意不相信实现的人。它拿着需求和系统约束,反问每一项证据有没有真的证明行为。

这才是持续验证的第一层。

六层检查不是堆流程,是让漏洞不走同一条路

Anthropic 把一次变更拆成验证、必需 CI、AI 代码审查、安全审查、按风险分级的人类审批、合并队列与灰度发布,底下再放一层快速回滚。每层都有盲区,但它们不该看同一个盲区。

你可以把它翻译成一个更适合大多数团队的版本。

层次 要抓的问题 Java 或 Spring 项目里可以落的动作
作者自证 功能是否真的跑通 集成测试、Testcontainers、前端截图、契约测试
必需 CI 基础质量有没有破 编译、单测、Checkstyle、SpotBugs、依赖漏洞扫描
AI Review 需求和系统约束是否被误解 对照 issue、模块规范、历史调用方审 diff
安全审查 鉴权、数据、命令边界是否失守 SAST、Secret 扫描、敏感路径专用审查
人工决策 方向和风险是否该放行 架构变更、支付、权限、迁移由人拍板
合并与发布 单个 PR 对,组合后会不会错 merge queue、feature flag、灰度、监控

表格看起来像常规 DevOps,区别在责任的重新分配。

低风险的文档改动、只在内部打开的新增功能,自动审查和安全检查都绿了,可以不要求第二个人机械点批准。缓存、自动更新、系统提示词、数据库迁移这类路径,即使 diff 很小,也得提高人类审批级别。Anthropic 的做法里,风险分类器会先给变更分层,另一个分类器再判断这次特殊变更是否仍需要额外的人。CI workflow 和被 code owner 标为敏感的路径始终绕不开人工。

这个设计很适合借鉴,但别急着照搬分类器。大多数团队先把风险写成一个可读的清单就够了。

例如 db/migration、security、payment、webhook、infra 目录至少一位明确的 owner 审批。涉及删除数据、变更鉴权语义、修改异步幂等策略的 PR,要求附回滚方案。不是因为这些路径天然更神圣,而是出错成本和普通样式改动不在一个量级。

风险分级的价值,不是把高风险 PR 卡得更久,而是别再把所有 PR 都按最高风险来审。前者会错失速度,后者一定会把人拖垮。

审查器的 KPI,不该只有找出多少问题

AI reviewer 最诱人的指标是 recall,抓得越多越好。但在 Agent 写代码的流程里,噪声有复利。

一个人看到无关紧要的 Nit,几秒钟就能略过。一个 Agent 看到它,会改代码、提交、重跑 CI、请求复审。另一个 Agent 又会从新的 diff 里找到下一件不太重要的事。五十轮循环不是笑话,它是把每条低质量评论都自动执行之后的自然结果。

Anthropic 对此做了两件很实在的事。

他们把已经引发 incident 的历史 PR、修复提交和 revert 整理成评测集,由熟悉代码的人确认 bug 在哪里。reviewer 每天在这套集合上跑。另一方面,他们跟踪每条评论的结局,开发者是修了、否掉了、承认是刻意行为,还是认为不值得动。还会在已知干净的 PR 上测误报率,尤其关注那种会诱导人做出有害修改的假阳性。

这一点很像给 RAG 做离线评测。你不能只看召回了多少文档,也得看结果有没有真的帮上忙。代码审查也一样,评论数量不是产出,收敛速度和事故率才是。

他们后来把 rounds-to-pass 也纳入指标。调整后,一轮审查加修复就通过的 PR 从 65% 升到 78%,需要五轮以上的 PR 从 8.9% 降到 1.5%,平均通过前审查次数从 2.08 降到 1.32。

这个数字很有启发性。很多团队给 Agent 定目标时只会问,自动生成了多少代码,节省了多少人天。更值得盯的是这些。

  • 一个 PR 从创建到合并,平均有多少次人工介入
  • AI 评论中被接受的比例是多少
  • 同一问题被来回修改几轮
  • 合并后 revert 和 incident 有没有上升
  • 高风险变更的人类审查时间有没有被真正保留下来

如果自动化把人工 review 减半,却让线上回滚翻倍,那只是把成本从 PR 页面搬到了值班电话里。

人没有退出,只是不该替机器看拼写

谈到 AI 代码审查,最容易出现的误解是,人以后只负责点批准。

Anthropic 的表达反而很清楚。人要保留在机器不擅长的决策上,比如要不要做这项工作、高风险代码能不能这样改、架构是否合适、验证证据是否可信,以及上线后谁负责把问题收回来。

其中最后一项非常重要。他们有一条团队规范,谁推动并合入一个中小改动,出了问题通常也由谁修。Agent 可以写、可以审、可以辅助定位,但不能替人拥有后果。

对于平台团队,这比口号更像一条架构原则。Agent 的权限可以很大,责任的归属不能模糊。你可以让它创建分支、跑测试、准备 migration,甚至在 feature flag 下发布;但谁能扩大流量、谁对数据修复签字、谁在事故里做取舍,必须明确是人。

这话听着有点保守,但它不是反对自动化。恰恰相反,只有当回滚路径、告警和 owner 都清楚时,团队才敢把低风险改动交给自动化。

回滚不是失败预案,而是吞吐量的一部分

过去不少团队把回滚当成事故发生后的补救。Agent 参与开发后,我更愿意把它看成正常交付链路的一环。

Anthropic 的合并队列会把每个 PR 和 main 重新组合后再跑检查,避免两个单独通过的改动合起来弄坏主干。新行为通常先通过 feature flag 给员工使用,公开发布也先到一个更早的渠道。出问题时,flag 可以不经重新部署就关掉。

这套安排给了一个很朴素的结论。你不可能靠审查把错误率降到零,尤其当生成速度突然上一个数量级。真正可持续的目标,是尽快发现、尽快缩小影响、尽快恢复。

回到 Spring 服务,至少可以问四个问题。

  • 每一个新 Agent 生成的业务分支,能不能由配置开关关闭
  • 数据库变更是否区分 expand 和 contract 两个阶段,是否允许平滑回退
  • 外部调用是否有幂等键、超时和补偿,避免回滚时制造第二次事故
  • 关键业务指标和 error budget 是否能在灰度阶段看出异常

这些东西看着不像 AI 工程,实际决定了你能把多少工作放心交给 Agent。没有 feature flag 和可观测性,所谓一键生成只是更快地把风险送到生产环境。

别急着复制 Anthropic,先拿一个服务做小实验

Anthropic 有自己的工具链、评测数据和工程规模。普通团队不需要也复制不了整套系统。硬抄六层检查,最后很容易只多出六个机器人和更慢的 pipeline。

比较靠谱的起点是挑一个边界明确、风险中等的服务,跑四周实验。

第一周,把 Agent 的任务模板改掉。每个任务至少带上验收命令、反例、影响模块和回滚方式。别再接受完成了这种交付语。

第二周,在 CI 之后接一个只输出高置信问题的 AI Review。先限制它评论安全、数据一致性、调用链兼容性,不要让它管格式和偏好。每条评论要求给出文件、行号和证据。

第三周,开始记录评论结局和 review rounds。发现反复出现的同类问题,不要继续靠 reviewer 提醒,而是回填到项目规则、lint、测试夹具或代码生成模板里。

第四周,把风险清单接到审批和发布。低风险改动尝试减少一次人工等待,高风险改动仍保留 owner。用 feature flag 和灰度数据守住底线。

这个过程有一点枯燥,没有哪一步像给 Agent 装上魔法。但它会逼团队把过去靠资深工程师脑内记忆维持的质量标准写下来、跑起来、量起来。

五十轮无人值守的审查循环,表面上是个荒诞故事。它提醒我们的却很具体。Agent 可以无限快地写代码,也可以无限勤快地改错。工程系统要做的,不是让它一直工作,而是让它在证据充分时停止,在风险升高时交给人,在出错后能迅速退回。

代码越来越便宜以后,判断和验证会更贵。

团队真正该投资的,正是后两者。

参考资料