Vibe Coding 代码审查指南:AI 代码安全合并与上线
你让 AI 修一个登录问题。几分钟内它改了 18 个文件、补了测试,告诉你「所有检查均已通过」。页面能打开,登录也成功。
最危险的时刻就在这里。人很容易把「它跑通了」误读成「它值得合并」。
AI 把写代码的速度推到了一个新高度。但它没有同步降低理解代码、验证业务规则和承担线上事故的成本。AI 一次生成几百行不费力,审查者必须逐项确认这些代码没有越权、没破坏旧流程、没引入不必要的依赖——出事了能回滚。
这篇文章只有一个核心观点: 代码可以由 AI 写,合并决定不能交给「感觉」。
Vibe Coding 到底是什么
先把概念摆正。Vibe Coding 最初描述的是一种**「接受生成结果、通过运行和继续提示迭代、但不真正阅读代码」**的开发方式。Martin Fowler 在讨论这个概念时强调:不查看生成代码是 Vibe Coding 的关键特征。如果你持续理解、检查和负责代码——那更接近 Agentic Programming,不是严格意义上的 Vibe Coding。
所以「Vibe Coding 的代码审查」听上去有点矛盾。更准确的场景是:你可以用 Vibe Coding 快速探索想法,但当代码准备进入共享仓库、连接真实数据、开放给用户或部署到生产环境的那一刻,必须切换工作模式。
这条界线比「是否使用 AI」重要得多。一个只在本机跑、当天就删的页面,可以接受轻审查。一个处理用户身份、支付或医疗记录的系统——即使只改了三行代码,也不能靠试用几次决定是否上线。
为什么 AI 代码让审查更容易失效
四个原因,每个都在你身边发生:
代码产量超过了人的理解速度。 传统开发中,作者写代码的同时建立心智模型。AI 生成代码时,作者可能只知道目标和最终效果——不知道中间为什么加了某个缓存、为什么改了权限中间件、新依赖是否真的必要。PR 看起来完整,但没有任何人真正「拥有」这段代码。
「测试通过」可能只是测试了 AI 自己的假设。 让同一个 Agent 写功能再写测试,常见结果是两者共享同一处误解。需求要求「只有订单所有者才能退款」,AI 理解成「登录用户可以退款」,然后按这个错误实现写测试。全绿。只能证明代码符合测试,不能证明实现符合业务。
模型倾向于完成任务,而不是质疑任务。 为了让功能跑通,AI 可能关闭证书校验、放宽跨域策略、用管理员密钥、把异常吞掉、绕过原有抽象。这些改法在本地演示里非常有效——风险被推迟到生产环境才爆发。
表面错误容易发现,语义错误更隐蔽。 语法错误编译器就拦住了,页面崩溃一眼能看到。真正难查的是权限边界、并发状态、金额精度、事务一致性、时区、重试幂等和数据迁移。这些问题未必立即报错,却可能在三个月后造成重复扣款或越权访问。
第一步不是看 Diff,是给改动分级
不要一上来就逐行看代码。先给这次改动定个级。
Thoughtworks 在讨论 AI 辅助开发的审查强度时,提出三个判断维度:出错概率、错误影响、错误是否容易被发现。 把它们用到 Vibe Coding 上:
| 等级 | 典型场景 | 最低审查要求 | AI 能否独立审查 |
|---|---|---|---|
| L0 可丢弃 | 本地原型、一次性数据转换、无真实数据演示 | 运行结果 + 冒烟测试 + 确认不含密钥 | 可以辅助 |
| L1 低风险 | 内部工具、小范围使用、不处理敏感数据 | 人工看 Diff + 自动测试 + 依赖与密钥检查 | 不应作为唯一批准者 |
| L2 业务系统 | 客户可见、连接数据库、影响订单或核心流程 | 独立人工审查 + 安全扫描 + 回滚方案 + 分阶段发布 | 不能 |
| L3 高风险 | 身份权限、支付、金融、医疗、基础设施 | 威胁建模 + 领域专家审查 + 完整测试 + 变更审批 | 不能,不适合纯 Vibe Coding |
最实用的规则是:影响越大、问题越难被用户立即发现,人工审查就越不能省。 如果一次错误能悄悄污染数据库三个月,它的审查强度显然不能跟一个配色错误一样。
五层审查:从需求到运行
第一层:需求审查——AI 做的是正确的事吗?
别急着看代码。先让作者写清楚:本次改动解决什么问题、明确不做什么、验收条件是什么、哪些旧行为必须保持不变。然后对照 PR 的文件清单,检查是否出现超出范围的修改。
一个「修改按钮文字」的任务却改动了路由、认证中间件和数据库模型——这不是 AI 能力强,是范围失控了。最有效的处理不是继续审几百行 Diff,而是要求拆分或重新生成。
第二层:结构审查——代码是否属于这个项目?
查看变更是否遵守现有架构:文件放置是否合理、依赖方向是否正确、是否复制了已有工具函数、是否绕开统一权限层、是否引入第二套状态管理。
AI 很容易写出「独立看没问题」的代码,但不知道团队为什么禁止在控制器里直接访问数据库。代码审查的价值之一,就是把这些仓库级约束重新施加到生成结果上。
大 PR 先看文件树和调用链,再按风险读:认证、数据写入、外部接口和迁移文件优先;纯样式和机械生成文件靠后。 不要从第一行读到最后一行——那会把注意力平均消耗在风险完全不同的内容上。
第三层:行为审查——用反例而不是演示证明功能。
「点击按钮成功」只是正向路径。AI 生成代码尤其需要补充负向和边界测试:
- 未登录用户、普通用户和管理员分别会发生什么?
- 空值、超长输入、非法格式和重复请求如何处理?
- 网络超时后重试,会不会重复创建订单或重复扣款?
- 两个请求同时修改同一条数据,结果是否一致?
- 旧数据、旧客户端和旧配置是否仍然兼容?
测试最好由另一个上下文独立生成——不要把实现过程的全部对话直接交给测试 Agent,而是给它原始需求、公开接口和风险清单,让它从对抗角度找漏洞。
第四层:安全审查——沿着数据流寻找信任边界。
沿「输入从哪里来→经过什么处理→最后流向哪里」检查:
- 输入:请求参数、文件、Webhook、环境变量是否被当作可信数据?
- 处理:是否存在字符串拼接查询、命令执行、不安全反序列化、路径穿越?
- 权限:认证之后是否仍在每个资源操作点检查授权,而不是只判断「用户已登录」?
- 输出:页面、日志和错误信息是否泄露敏感字段、内部路径或令牌?
- 秘密:API Key、密码、私钥是否进入代码、示例文件或提交历史?
- 依赖:新增包是否必要、是否维护、版本是否有已知漏洞?
尤其警惕「为了让它工作」而出现的配置:关闭 TLS 校验、允许任意来源跨域、使用通配权限、生产环境打开调试模式、把管理员令牌发到浏览器端。这些改动不会让测试失败,却会直接削弱系统边界。
第五层:运行审查——出了问题也能被控制。
上线前还要检查:
- 数据库迁移是否向前兼容、能否回滚、会不会长时间锁表?
- 新增配置是否有安全默认值,缺失时是明确失败还是带病运行?
- 日志、指标和告警能否定位问题,又不会记录隐私数据?
- 外部 API 的超时、重试、限流和费用是否受控?
- 能否通过功能开关、灰度发布或快速回退降低影响?
如果审查者无法回答「半夜收到告警后怎样判断和回滚」,这次改动还没达到生产就绪。
AI 审 AI 的正确姿势
让另一个模型审查生成代码有价值——速度快,能发现遗漏测试、空值处理、死代码和部分安全问题。
但要避免一个常见错误:把代码交回原 Agent,问一句「请检查是否有问题」。 模型很可能沿用此前的假设,给出笼统自我确认。
正确做法是开一个独立审查会话,只提供原始需求、架构约束、Diff 和测试结果,要求它:
- 只报告影响正确性、安全、兼容性或运维的具体问题
- 按严重程度 P0/P1/P2/P3 排序
- 每条结论给出文件位置、触发条件和影响
- 无法确认时明确写出需要补充的证据
- 给出能证明修复有效的测试,而不是直接大面积重写
可直接用的提示词:
你是本次变更的独立代码审查者,不参与实现。
原始需求:[粘贴需求和验收条件]
项目约束:[架构规则、权限模型、兼容要求、禁止事项]
变更内容:[提供 git diff 或 PR]
请优先检查:
1. 实现是否偏离需求或改变未声明行为;
2. 权限、输入验证、敏感数据、注入和密钥风险;
3. 并发、事务、重试、幂等、时区和金额精度;
4. 数据迁移、兼容性、回滚和可观测性;
5. 测试是否只验证正向路径,是否与实现共享错误假设。
只输出可执行的发现,按 P0/P1/P2/P3 排序。每条包含:
- 文件和代码位置
- 触发条件
- 实际影响
- 判断依据
- 最小修复建议
- 应补充的测试
不要评价代码风格,不要重复静态检查器能直接发现的问题。
没有足够证据时标记「待确认」,不要猜测。GitHub Copilot Code Review 的设计也体现了正确边界——它提交的是 Comment,不是 Approve 或 Request changes,不计入必需审批,也不会阻止合并。AI 评论是审查线索,不是合并授权。
把审查变成门禁,而不是自觉
当 AI 可以持续生成和修改代码时,只靠「提交前记得检查」很快会失效。把关键约束放进仓库和 CI:
强制通过 Pull Request 合并。 保护主分支,禁止直接推送,要求至少一名独立审查者批准。敏感目录用 CODEOWNERS 指定负责人。已批准后又有新提交的 PR,应撤销旧批准重新审查——避免最后一次 AI 修改绕过人工判断。
把必要检查设为 Required Status Checks。 最低门禁通常包括格式检查、Lint、类型检查、单元测试、集成测试和构建。GitHub 要求必需检查针对最新提交通过后才能合并,这能防止「上一版测试通过,随后又改了代码」的假安全感。
补上安全自动化。 代码扫描在 PR 中标记潜在漏洞;Dependency Review 显示新增、删除和升级的依赖及已知漏洞;Secret Scanning 的 Push Protection 在密钥进入仓库前阻止推送。自动工具覆盖不了全部风险,但能把审查者的注意力留给业务逻辑和权限边界。
限制一次变更的认知负担。 一个 PR 只解决一个清晰问题。生成代码太多时要求 Agent 分阶段提交:先接口和测试,再核心实现,最后接入和清理。不要把重构、依赖升级、格式化和业务功能混在一次提交里。小变更不只更容易阅读,也更容易回滚和定位责任。
一个「能跑但不能合并」的真实例子
需求:给后台增加「重置用户密码」功能。
AI 几分钟生成页面、接口和邮件模板,测试通过。演示时管理员输入邮箱,用户收到重置链接,一切正常。
按五层审查继续往下看:
- 接口只检查用户是否登录,没有检查是否具备管理员权限
- 返回信息会暴露某个邮箱是否已注册
- 重置令牌没有过期时间,使用后也没有失效
- 令牌以明文写入数据库和日志
- 接口没有限流,可以被批量调用发送邮件
- 测试只覆盖「管理员成功重置」,没有普通用户、重复使用、过期令牌和并发请求
这些问题都不妨碍正向演示,却每一个都足以阻止上线。
Vibe Coding 审查最需要改变的思维:不要问「它能不能工作」,要问「谁可以让它工作、在什么条件下工作、失败时会伤害什么」。
提交前检查清单
- 需求、非目标和验收条件已经写清
- PR 只包含一个意图,没有隐藏重构和无关格式化
- 至少一名人类能够解释核心调用链和关键取舍
- 正向、反向、边界、权限和失败路径均有验证
- 高风险逻辑没有只依赖同一个 AI 生成的测试
- 认证、授权、输入、输出、日志和密钥已经检查
- 新增依赖经过必要性、维护状态和漏洞检查
- 迁移、配置、监控、灰度和回滚方案明确
- CI 针对最新提交通过,安全告警已有明确处置
- AI 审查意见已由代码或测试验证,而不是直接接受
- 最终批准者知道自己在批准什么,并愿意承担上线责任
Vibe Coding 最适合缩短「从想法到可运行原型」的距离。它不应该缩短「从未知代码到可信软件」所需的证据链。生成越快,团队越要把风险分级、独立测试、安全检查和合并门禁做成默认流程。
真正成熟的 AI 编程不是让人退出开发过程,而是把人的注意力从敲击每一行代码,转向定义约束、审查高风险决策和验证系统行为。你可以不亲手写完每一行,但上线前,必须有人真正读懂它、证明它,并对它负责。

评论(0)