作者:Andrea Griffiths
排版:Alan Wang
你很可能已经批准过一个智能体生成的 Pull Request,只是自己没有意识到。测试通过了。代码看起来也很整洁。于是你完成了合并。
但它实际上是由智能体生成的——而这种轻松批准的感觉,恰恰就是问题所在。
2026 年 1 月发布的一项研究《More Code, Less Reuse》发现,相比人类编写的代码,智能体生成的代码在每一次变更中都会引入更多冗余和更多技术债务。代码表面看起来十分干净。技术债务却悄无声息地积累着。而根据同一项研究,代码审查者实际上还会对批准这类代码产生更强的信心。
这并不是在主张放慢开发速度。而是在主张更加有意识地进行审查。两者之间存在着本质区别。
More Code, Less Reuse
https://arxiv.org/abs/2601.21276/?wt.mc_id=3reg_webpage_reactor
智能体生成的 Pull Request 已经占满了代码审查带宽
代码审查的数量已经达到了惊人的规模。GitHub Copilot Code Review 已经完成了超过 6000 万次代码审查,并且在不到一年的时间里增长了 10 倍。如今,GitHub 上每五次代码审查中,就有一次以上涉及智能体。而这还只是自动化代码审查这一环节。Pull Request 本身的增长速度,已经超过了审查者能够处理的速度。
传统的流程——提交 Review 请求、等待代码所有者审核、完成合并——正在失效。因为一个开发者可能在午饭前就已经启动了十几个智能体会话。开发吞吐量已经呈指数级增长。而人工代码审查能力却没有。两者之间的差距正在不断扩大。
你一定会审查智能体生成的 Pull Request。真正的问题是:当你进行审查时,是否能够发现真正重要的问题。
究竟是谁(或者说是什么)编写了这个 Pull Request
在查看任何一行 Diff 之前,你首先需要建立一个关于审查对象的认知模型。
一个编码智能体,是一个高效、严格按字面理解需求、遵循已有模式进行工作的贡献者。但它对你的故障历史、团队积累的各种边界场景经验,以及那些没有写进代码仓库里的运行约束,一无所知。它会生成看起来已经完成的代码。但这种“看起来已经完成”的失败模式,本身就是危险的。
真正掌握这些上下文的人,是你。这不是一种负担。而是代码审查真正的职责所在。代码审查中无法被自动化替代的部分,是判断力。而判断力,建立在只有你才拥有的上下文之上。
给 Pull Request 作者的一点建议
如果你准备提交一个由智能体生成的 Pull Request,请在请求代码审查之前,先修改一下 Pull Request 的描述。智能体总是喜欢写得过于冗长。它们会花大量篇幅描述一些本应该通过代码本身去理解的内容。当上下文确实有帮助时,可以直接在 Diff 中添加注释。并且,在标记其他审查者之前,请先自己完成一次 Review。这不仅是为了检查代码是否正确。也是为了向其他人表明:你已经确认智能体真正理解并实现了你的设计意图。
当 Pull Request 是由智能体生成时,审查自己的 Pull Request 并不是一个可选项。这是对审查者时间最基本的尊重。
现在,把视角重新回到代码审查者。Pull Request 已经进入了你的待审列表。作者已经完成了他们该做的事情。接下来,就是你需要重点关注的内容。
需要重点关注的危险信号
1. 操纵 CI
智能体也会让 CI 失败。而当 CI 失败时,它们有一条最直接的路径让测试重新通过:删除测试。跳过 Lint 步骤。在测试命令后面加上 || true。有些智能体真的会这么做。
任何削弱 CI 的修改,都应该被直接阻止。没有例外。在批准任何智能体生成的 Pull Request 之前,请检查:
覆盖率阈值是否发生了变化?
是否删除、重命名或者标记跳过了任何测试?
工作流是否停止在 Fork 或 Pull Request 上运行?
是否有任何 CI 步骤被放到了此前不存在的条件判断之后?
以上任何一个问题只要答案是“是”,在继续审查之前,都必须要求作者给出明确解释。
2. 代码复用盲区
这是作为代码审查者投入产出比最高的一件事情。智能体会寻找已有实现。它们会在代码库中找到某种模式,并直接复制这种模式。很多时候,它们甚至不会检查是否已经存在一个完成同样功能的工具函数。
常见表现包括:
新增了一个与已有工具函数功能重复、只是名字略有不同的新工具函数;
相同的校验逻辑在多个地方被重新实现;
从零开始编写了一个中间件,而实际上共享模块里已经存在完全相同的实现;
出现多个“几乎一样”的 Helper,只是名称不同。
智能体能够获取的局部上下文,并不能覆盖整个代码仓库。而你可以。
对于智能体 Pull Request 中新增的每一个 Helper 或 Utility,都快速搜索一次。如果发现已经存在等价实现,不要只是留下一条评论。要求在合并之前完成整合。否则,留下重复逻辑的代价就是:未来的智能体会再次把它当作已有模式,然后继续复制扩散。
💡小技巧:对于超过一定规模的智能体 Pull Request,可以要求作者必须说明新增工具函数的理由。这样可以在问题出现早期就发现重复代码。
3. 幻觉式正确性
最容易发现的幻觉,是调用了不存在的 API,或者引用了作用域之外的变量。CI 通常能够捕获这些问题。真正危险的是另一种更隐蔽的幻觉:代码可以正常编译,所有测试全部通过,但代码依然是错误的。
例如:分页中的 Off-by-One 错误。测试永远不会覆盖到的某个分支中缺失权限校验。智能体没有考虑到某个边界场景,导致校验逻辑提前返回。或者只有在大规模并发情况下才会暴露出来的竞态条件错误。
不要只是快速浏览代码。而是要真正沿着执行路径追踪。选择 Diff 中最关键的一条执行路径。从输入开始,一路跟踪每一次转换,直到最终输出。
重点检查:
边界条件(零值、最大值、空值)
外部输入是否缺少校验
每一个分支是否都进行了权限检查
是否存在令人意外的条件判断逻辑
同时要求新增一个测试。这个测试必须能够在修改之前失败。如果智能体连一个能够发现自己声称修复 Bug 的测试都写不出来,那么要么修复是不完整的,要么它对问题本身的理解就是错误的。
4. 智能体“失联”
你认真完成了一次代码审查。详细解释了问题。提供了背景信息。甚至给出了建议方向。然后,Pull Request 安静了下来。或者智能体回复了,但完全没有理解你的意思,不断在同一个问题上原地打转。你又投入了一轮时间。结果依然没有任何有价值的进展。
规模较大的 Pull Request,如果缺少结构化实现计划,通常都与智能体后续放弃任务或理解偏离高度相关。Pull Request 越大、范围越不明确,你投入大量 Review 时间却最终一无所获的概率就越高。
在深入 Review 一个大型智能体 Pull Request 之前,先查看它的历史记录。之前几轮是否能够及时响应?是否存在明确的实现计划?还是智能体只是直接开始写代码?
如果没有计划,那么在写下第一条 Review 评论之前,就先要求对方拆分任务。可以直接复制下面这段模板:
“这个 Pull Request 太大了,如果没有更清晰的实现计划,我无法完成代码审查。你能否将它拆分成更小、更明确的功能单元,或者补充一个说明,解释每个部分的作用以及为什么采用这样的结构?完成之后我很乐意继续 Review。”
态度坚定。内容简短。不针对个人。却能够帮你节省一个小时的时间。
5. 工作流中的不可信输入
CI 智能体中的提示词注入是真实存在的风险。但很多人还没有足够重视。典型模式:智能体工作流读取 Pull Request 描述、Issue 内容或者 Commit Message。这些内容被直接插入 Prompt。Prompt 被发送给模型。模型输出再被传递给 Shell 命令执行。整个流程运行时还拥有 GITHUB_TOKEN的权限。
当你审查任何调用 LLM 的工作流时,以下问题都应该直接阻止合并:
是否未经清洗,就将来自用户、Pull Request 描述、Issue 内容或 Commit Message 的不可信输入插入 Prompt?
GITHUB_TOKEN是否拥有写权限,而实际上只需要读权限?
模型输出是否未经校验,就直接作为 Shell 命令执行?
Secret 是否可以被智能体访问,或者可能被打印到日志中?
在允许合并之前,应当要求满足以下条件:
在 Workflow YAML 中采用最小权限原则(permissions: read-all是一个合理的默认配置);
在任何不可信内容进入 Prompt 之前,完成清洗和引用处理;
将“分析”步骤与“执行”步骤分离,对于任何涉及生产环境的操作增加人工审批环节;
永远不要对模型输出执行 eval。
时间 |
步骤 |
需要执行的操作 |
1–2 分钟 |
快速浏览并分类 |
查看文件列表和 Diff 的规模。这是一个范围较小的任务(文档、CI、小型改动),还是一个复杂变更(涉及多个文件、业务逻辑、性能或测试)?这种分类将决定后续整个代码审查的深度。 |
2–3 分钟 |
优先检查 CI 相关变更 |
在阅读任何一行业务代码之前,先检查所有涉及 .github/workflows、测试配置、覆盖率设置或构建脚本的修改。任何削弱 CI 的改动都应该立即标记出来。这是第一道“停止检查”。 |
3–5 分钟 |
检查新增工具函数 |
搜索新增的函数、Helper 或模块。针对每一个新增内容,快速在仓库中搜索是否已经存在类似实现。凡是重复实现已有功能的代码,都应当标记出来。 |
5–8 分钟 |
追踪一条关键执行路径 |
选择最重要的一处逻辑变更,沿着完整路径进行追踪:输入 → 转换 → 输出。检查边界条件、权限控制以及是否存在意外的分支逻辑。这一步绝不能省略。 |
8–9 分钟 |
检查安全边界 |
如果这个 Pull Request 涉及任何调用 LLM 或处理不可信输入的工作流,请按照前面的安全检查清单逐项核查。 |
9–10 分钟 |
检查安全边界 |
如果这个 Pull Request 涉及任何调用 LLM 或处理不可信输入的工作流,请按照前面的安全检查清单逐项核查。 |
什么情况下应该要求拆分成更小的 Pull Request:
Diff 涉及五个以上彼此无关的文件。
你无法用一句话概括这个 Pull Request 的目的。
智能体没有提供实现计划,或者 Pull Request 描述为空。
CI 正在失败,而 Diff 中唯一的修改却只是测试文件。
先让 Copilot 进行代码审查
把自动化代码审查用于它最擅长的事情:在人工开始 Review 之前,先发现那些机械性的低层问题。Copilot Code Review 可以发现:
风格不一致的问题;
明显的逻辑错误;
缺失的错误处理;
类型不匹配。
它负责完成底层扫描工作。这样,你就可以把时间投入到真正需要判断力的工作中。而这部分,才是真正值得你花时间的地方。
把它看作代码审查的前置步骤,而不是替代方案。先让 Copilot 运行一次。如果它已经发现了一些显而易见的问题,就让作者先完成修改,然后你再投入自己的 Review 时间。
你还可以针对团队的实际情况,通过自定义指令进一步优化这一流程:
标记所有修改 CI 阈值的变更;
自动发现新增 Utility,方便进行重复代码审查;
检查所有外部输入是否都经过了验证。
你的指令越具体,自动化审查就越有价值。
💡 小技巧:最近,我尝试使用 Copilot SDK,把自己的代码审查清单直接固化下来。与其每次 Pull Request 都手动重复执行同样的安全检查,我构建了一个自动化工作流,把我个人的审查清单——例如:管理接口是否进行了身份认证,测试是否真正被执行,环境变量是否进行了安全处理,自动应用到每一个 Diff 上。如果发现关键问题,它就会直接阻止合并。
判断力才是真正的瓶颈,而这并不是坏事
代码的规模正在不断增长。Pull Request 的数量也在不断增长。你花在扫描模板代码上的时间,应该越来越少。
真正不会减少的是:你所掌握的上下文。那些关于系统的知识,那些没有写在任何文档里的经验,正是它们赋予了你的代码审查真正的价值。而这部分工作,也是无法被自动化替代的。
三点总结:
任何削弱 CI 的修改,都应该直接停止审查并要求说明。
让智能体先完成扫描,而你负责追踪关键执行路径。
对于复杂的智能体 Pull Request,把“危险信号检查清单”作为默认的审查标准。
阅读文档 >
https://docs.github.com/copilot/how-tos/use-copilot-agents/request-a-code-review/use-code-review/?wt.mc_id=3reg_webpage_reactor