小岛AIAI 航行日志

小岛 / 岛刊社 / 文章

Copilot 代码审查会自己关评论了,但人还不能下班

小岛AI

GitHub 把 PR 审查改成有状态的待办清单。Open、已修和上轮漏掉的问题被拆开呈现,团队终于能把复审、修复和放行分开讨论。

AI 编程

一个 PR 进了第二轮审查,右边又多出三条 Copilot 评论。很多人的第一反应大概都是,完了,又改坏了。

但新冒出来的评论,未必是这次提交带来的。它可能只是上一轮没看见,或者已经修过、只是还没被重新确认。把这三件事混成一锅,审查很快会变成一场找评论、点关闭、再找评论的体力活。Agent 写代码越来越快,最先顶不住的往往不是生成,而是这堆状态不明的反馈。

GitHub 在 9 月 18 日正式上线的 Copilot Code Review 更新 ,我觉得最有价值的不是自动关评论,也不是自动生成提交信息。它把一轮复审里最容易被误读的进度摆到了台面上。

这事听起来挺琐碎。可你要是负责过一个有几十条评论的 PR,就知道它有多要命。人最容易在这种地方偷懒,看到绿色勾就默认安全,看到一条新评论就默认是刚引入的 bug。两种默认都不靠谱。

Copilot 新的审查概览会按状态汇总发现

GitHub 官方截图,复审概览不再只是一串零散评论。

GitHub 这次把审查发现分成了三类。

Open 是还没处理的问题,其中带 new 标签的,才表示它可能由新提交引入。Resolved since last review 是 Copilot 在后续复审中确认已经修好的问题。Previously missed 则更有意思,它说的是代码并非这次才写错,只是上一轮审查没有发现,直到这一次才被看出来。

后面这类问题很容易让人误判。假设你刚为一条空指针提示补了判空,复审却又报了一个缓存失效。它可能是补丁把缓存路径弄坏了,也可能那段缓存分支本来就在,只是第一次审查没扫到。两种情况的处置不一样。前者要收紧这次改动的回归范围,后者要问的是,为什么原有测试没有覆盖它。

以前这两种发现都只是一条评论。现在它们有了不同的状态。好家伙,终于不是只会往 PR 右侧继续堆便签了。

这也是我不太认同「评论能自动关闭,审查就省一半」的原因。关闭只是一个动作,复审真正缺的是可追溯的判断。谁确认过修复,确认依据是什么,下一轮又发现了什么,这些东西如果留不下来,PR 再干净也只是视觉上的干净。

GitHub 的新概览会保留每次复审的发现记录,并显示当前判断、使用的审查 effort、严重性和对应的行内评论。被修复的老问题不再和仍然开放的问题挤在一起,后续才找到的旧问题也不会伪装成新提交造成的回归。审查从一堆留言,开始变成一段带状态的变更历史。

这处改变很适合 Agent 产出的 PR。Agent 可以很快给你提交三个版本,也可以很快对着评论连续 patch。速度上来了,评论的寿命也变短了。人工 reviewer 如果只看当前 diff,很难知道某条风险是被处理过、被明确拒绝,还是一路从第一版躲到第三版。

别小看这个差别。团队想要的不是一台永远说「没问题」的机器,而是一份能交接的审查证据。

GitHub 还把评论的自动解决做得更具体了。有人回复要求保持问题打开,Copilot 会尊重这个决定。它根据后续提交判断问题已经处理时,也会用 Won’t Fix 或 Incorrect 这样的原因标记。接受一批符合条件的建议时,Copilot 会生成相应的提交标题和可选说明。

带标题的评论和批量建议的提交信息

GitHub 官方截图,评论有标题,批量采纳建议时可以生成提交说明。

这几项很像界面细节,实际是在补一个经常被忽略的断层。以前我们常能看到一条评论消失,却很难一眼知道它是修了、暂时不修,还是 reviewer 觉得它压根判断错了。状态一旦不清楚,后续复审只好从头猜。猜到后面,大家都会更愿意让评论快点消失,而不是让风险真的消失。很像把终端窗口清空,以为报错已经解决。= =

同周的 GitHub 更新汇总 还提到,Copilot Code Review 会在受保护的范围内使用 shell 工具验证改动,Lite effort 也会汇总多个 Agent 的结果。GitHub 披露的实验里,高、中、低严重性问题的平均处理量分别增加了 47%、31% 和 11%,审查成本约降了 8%。这组数字是 GitHub 自己的实验结果,不是你我仓库的保修单,先把这根钉子钉牢。

更会调用工具的审查 Agent,确实可能多找到一些东西。它能跑构建、跑测试、执行目标脚本,少把阅读 diff 当成唯一证据。厉害了,但这同时会让评论数量和复审轮次继续增长。问题从「有没有 AI reviewer」变成「团队怎样处理 reviewer 的状态」。

这里还藏着一个边界。测试通过只是当前环境里那条路径没报错,不等于需求被满足,更不等于权限、迁移和回滚都没有坑。一个 Agent 如果只在临时环境跑过测试,它交出来的是验证记录,不是放行凭证。人真正要看的,是这条记录覆盖了哪个风险,没覆盖什么风险。

所以一轮复审里最好同时留下三类东西。变更证据是 diff 和提交说明,验证证据是测试、构建或复现步骤,处置证据是为什么修、为什么不修、谁接受剩余风险。Copilot 的状态面板把第三类东西的入口做出来了,团队别再把它浪费成一键清空通知。

这套分法还有个很实际的好处。它让开发者和 reviewer 不必在同一条评论里同时讨论代码、测试和责任归属。开发者可以补 patch,审查 Agent 可以给复验结果,合并人再决定剩余风险能不能进主干。每个人都少猜一点,交接就不会只靠聊天记录里那句「应该没事」。

我建议把下面这张小检查表贴进有 Agent 参与的 PR 模板里。它不要求你相信 Copilot,也不要求你拒绝 Copilot,只要求每一条状态有归宿。

复审前的合并检查

□ Open 中的高严重性问题,是否都有明确结论
□ 每条已修问题,是否能指向修复提交、测试或可复现的验证记录
□ Previously missed 的问题,是否判断过它是本轮回归还是历史漏检
□ Won't Fix 和 Incorrect,是否写明了为何接受这个判断
□ 审查概览显示通过时,是否仍满足仓库自己的测试、权限和人工审批要求

这五行没有任何魔法。它只是把常被揉在一起的三件事拆开,修一个问题,复核一个问题,决定能不能合并。大模型很擅长把前两件做快,第三件目前仍然是团队要承担的责任。

如果你管的是小项目,甚至可以更轻一点。每次复审只盯 Open 和 Previously missed。前者是还欠着的债,后者是测试边界的信号。Resolved 不是不用看,只是不必让它继续占你的注意力。这样比在三十条灰掉的评论里翻昨天的上下文舒服多了。

如果是多人仓库,建议把状态和责任人绑在一起。开发者解释修复意图,Agent 给出复审结果,真正有合并权限的人确认风险是否能被接受。不要把 Copilot 的自动 approval、自动解决或漂亮的概览,当成合并门槛本身。GitHub 对审批能力的说明也写得很清楚,默认不会由 Copilot 直接批准,是否计入 required approvals 仍由组织、仓库和文件路径的规则决定。

这不是保守,是为了让速度留下证据。Agent 让提交像潮水一样涌进来时,最容易被冲走的是那句很朴素的话,谁看过,为什么放行。

Copilot 这次更新把审查界面从评论列表往状态面板推了一步。它不会替团队承担合并后的事故,也不会自动补全你没写的测试策略。可它至少给了一个更好的起点,别再把新问题、已修问题和上一轮漏检的问题,塞进同一个「已读」抽屉。

你们团队在复审 Agent 产出的 PR 时,最常误判的是新回归,还是历史漏检?