← Blog
·9 blog.minutes

开发者审查 AI 生成代码指南

AI 在每个拉取请求中编写的代码越来越多。以下是有效审查 AI 生成代码的方法——该关注什么、该信任什么、以及何时重写。

代码审查一直是为了在错误进入生产环境之前捕获它们。但当代码是由 AI 助手而非人类同事编写时,审查的动态就发生了根本性变化。AI 犯的错误与人类犯的错误不同,你需要检查的内容也与同行评审中不同。

本指南涵盖了经验丰富的团队在审查 AI 生成代码方面所学到的经验。它按 AI 模型持续产生的几类问题组织,这样你就可以运行系统化的检查清单,而不是依赖针对人类代码开发的直觉。

为什么 AI 生成代码需要不同的审查标准

人类开发者犯的错误集中在疲劳、分心和知识差距上——疲惫的开发者遗漏边界情况,分心的开发者忘记处理错误,初级开发者使用反模式因为他们不知道更好的方法。AI 模型犯的错误集中在完全不同的维度上:幻觉、上下文盲点和风格不一致。

一个编写了未处理空值输入的函数的人类开发者,很可能知道应该处理只是忘了。而一个编写了相同函数的 AI 则真的不知道在你的代码库中 null 是否可能发生——除非你明确告诉它。这个区别很重要,因为修复方式不同:人类需要提醒,但 AI 需要在提示词中编码约束或在审查中被捕获。

理解这种差异是有效 AI 代码审查的基础。你不是在检查开发者是否细心。你是在检查 AI 是否有足够的上下文来生成正确的代码,以及它的输出是否与你代码库中它看不到的隐含约定一致。

检查项 1:幻觉的 API 和导入

AI 生成代码中最常见的问题是使用不存在的库、函数或 API。AI 模型被训练生成合理的代码,它们会自信地为从未发布的包生成导入语句,并调用从未存在过的方法。这并非恶意——而是模型在训练中看到的真实包之间进行插值,并发明了一个看起来合理的桥梁。

// AI 生成的代码看起来合理,但导入了一个不存在的函数
import { renderAsync } from 'react-dom'; // renderAsync 不存在
import { optimize } from 'lodash/fp/string'; // lodash 中不存在此路径

// 你实际需要的内容
import { renderToString } from 'react-dom/server';

修复方法很简单但很重要:对照实际文档验证每个导入和 API 调用。不要因为代码能编译就认为 API 是正确的——某些幻觉函数具有看似合理的签名,能通过 TypeScript 检查但会在运行时失败。审查应包括对你无法识别的任何导入进行快速合理性检查。

检查项 2:缺少错误处理

AI 模型倾向于生成快乐路径。它们非常擅长编写函数的主要逻辑——循环、转换、返回值——但非常不擅长处理出错时的情况。网络请求缺少 catch 块。文件操作缺少错误处理。异步函数缺少拒绝处理器。

这不是因为 AI 不能编写错误处理。如果你明确要求,AI 会生成全面的 try-catch 逻辑。问题在于模型的默认行为是编写最简单的可用版本,而错误处理不在那个默认范围内。每次 AI 生成代码的审查都应该包含一次专门检查错误路径的环节。

  • 每个异步函数都应有 catch 或拒绝处理器。
  • 每个外部 API 调用都应处理网络错误、超时和意外的响应格式。
  • 每个数据转换都应处理 null、undefined 和意外类型。
  • 每个文件或数据库操作都应处理权限错误和资源缺失。

一个有用的技巧是运行一个简单测试:从 AI 生成的代码中移除 try-catch 块,看看剩余的逻辑是否仍然合理。如果是,AI 可能没有深入思考错误处理。如果逻辑依赖于错误处理才能运行,那么 AI 就正确地将它集成进去了。

检查项 3:风格和约定不匹配

每个代码库都有不成文的代码风格约定。团队使用提前返回而不是嵌套 if。错误消息遵循特定格式。变量名使用特定模式。在数百万公共仓库上训练的 AI 模型会生成反映所有这些仓库统计平均值的代码,而不是你代码库的特定约定。

结果是代码能工作但感觉陌生。它使用与周围代码不同的命名约定、模块结构或错误处理模式。这种不一致积累得很快——五个以五种不同隐含风格编写的 AI 生成函数会创造一个感觉不连贯、更难维护的代码库。

最好的缓解措施是在提示词中包含风格示例。从同一模块粘贴一个有代表性的函数,并说「使用这种风格」。这给了 AI 一个具体的参考,覆盖它的训练默认值。在审查时,检查生成的代码是否能像是编写了周围模块的同一个人所写。

检查项 4:过度工程和不必要的抽象

AI 模型有很强的抽象倾向。面对一个简单的问题,它们常常会生成一个类层次结构、一个接口、一个工厂和三个工具函数——而一个单一函数本来就够了。这种倾向来自训练数据,其中过度代表了结构良好的开源库,而简单脚本和一次性函数代表不足。

AI 模型默认倾向过度工程。你的审查应该默认倾向简洁。AI 引入的每个抽象都需要对照一个更简单的替代方案来证明其存在的合理性。

审查时,问自己:这段代码需要类吗,还是函数就够了?这个接口被多个实现使用吗?提取这个工具函数能节省足够的重复来证明间接性合理吗?如果上述任何一个答案是「否」,那么 AI 可能过度工程了,更简单的版本更好。

检查项 5:安全漏洞

AI 模型是在包含安全漏洞的代码上训练的。它们从这些代码中学习模式,包括脆弱模式。虽然现代模型更擅长避免 SQL 注入等明显问题,但它们仍然会产生包含微妙安全问题的代码,需要审查者捕获。

  • 检查生成的代码中是否有硬编码的秘密、API 密钥或凭证。
  • 验证用户输入在使用前是否经过验证和清洗。
  • 检查受保护操作上是否存在身份验证和授权检查。
  • 确保生成的 SQL 查询使用参数化语句,而不是字符串拼接。
  • 验证文件路径不是从未经信任的输入中构造的(未经清洗)。

对于处理敏感数据或用户输入的 AI 生成代码,安全导向的审查环节是不可协商的。AI 不知道你系统的哪些部分是安全关键的——除非你告诉它。如有疑问,在合并之前对生成的代码运行静态分析工具。

检查项 6:与现有架构的一致性

AI 模型孤立地看待每个请求。它们不知道你的团队上个季度决定使用 React Query 处理所有数据获取、API 始终返回驼峰键、或项目使用特定的状态管理模式。它们生成的代码内部是一致的,但可能违反在当前文件中不可见的架构决策。

这正是人类审查者创造最大价值的地方。你知道记录在 ADR 中的决策、团队讨论中涌现的模式、以及没有在任何单个文件中捕获的设计约束。要对照这些不可见的约束来审查 AI 生成的代码,而不仅仅是检查正确性和风格。

构建可持续的审查流程

随着 AI 生成越来越多的代码库内容,审查流程需要扩展。一个四人团队手动审查每一行 AI 生成的代码很快就会筋疲力尽。可持续的方法是将自动化检查与聚焦的人工审查相结合。

自动化检查应在人类看到代码之前捕获幻觉导入、风格违规、缺少错误处理和常见安全问题。这将 AI 特定审查缩小到一组较小的问题:架构一致性、设计决策以及 linter 无法检测到的微妙问题。

目标不是消除对 AI 生成代码的人工审查。而是通过过滤掉工具能自动捕获的问题,将人类注意力保留给只有人类能做出的判断,从而使审查尽可能高效。有了正确的流程,审查 AI 生成的代码可以比审查人工编写的代码更快、更可靠——因为 AI 的错误更可预测。