AI Coding 走到今天,早就不是"能不能生成代码"的问题,而是"生成的代码你敢不敢合进主干"的问题。我自己在团队里推 AI 辅助开发这半年多,最深的感受是:AI 写代码的速度越快,质量治理的手段就越不能停留在旧时代。你不可能再用"逐行 review + 全量回归"去对抗 AI 一分钟生成几百行代码的节奏,那会被活活累死,而且依然拦不住事故。
我们需要一套新的治理思路:用工程规范卡住源头,用代码评审识别风险,用风险驱动的测试策略把有限的验证资源投到最可能出事的地方。这套组合拳打下来,不敢说 AI 代码零事故,但至少能把"惊喜"变成"已知风险",把崩塌式的返工变成可控的迭代。
这篇文章不聊概念,就聊我在真实项目里怎么把这三件事落地的。
1. AI 代码带来的是新问题还是老问题,先弄清质量退化在哪
AI 代码的缺陷,表面上和人类程序员写出来的缺陷很像:逻辑错、边界漏、命名烂。但底层成因完全不同。人类写错代码,往往是理解偏差或者粗心;AI 写错代码,很多时候是因为它对上下文的理解是"局部正确、全局缺失"。
我在项目里实际摸过一轮 AI 生成代码的质量,归纳下来有三类最常见的问题。
第一类是 API 幻觉型缺陷。AI 会给你写出一个看起来很合理的调用,但那个方法的参数名、返回值的语义、甚至整个方法是否存在,它都敢编。比如我让 AI 写一个配置热更新模块,它直接调用了一个从未在项目里定义过的ConfigLoader.refreshWithRetry(),编译报错还算好的,更坑的是它在某些动态语言里头不做任何校验,运行到线上才知道崩。
第二类是职责混淆型缺陷。AI 很擅长"看起来完成了任务"。你让它写一个缓存刷新函数,它把缓存失效逻辑、数据库回源逻辑、还有告警逻辑全部塞进同一个函数里,代码量巨大、耦合度拉满。单元测试能过,代码能编译,但换一个人来维护就是噩梦。这类问题在纯逻辑推导上没问题,可一旦放到真实工程环境,就是架构腐化的种子。
第三类是上下文截断型缺陷。AI 的注意力窗口有限,它看到最近 20 行代码时逻辑是对的,但没看到 200 行之前的全局状态假设。最典型的是权限校验:AI 在某个服务里生成的新接口,完全没有沿用服务原有的鉴权中间件,因为它"没看到"。这一类最危险,因为它不会暴露在编译期和单测期,只会在生产环境给你致命一击。
那为什么传统质量流程守不住这些坑?原因很简单:传统流程建立在"人类作者可控"的前提下。逐行 code review 要求人完全理解每一行代码的意图,但 AI 生成的代码往往量太大、来得太快,人的注意力根本覆盖不过来。传统测试要求你基于需求文档写用例,但 AI 代码经常在需求不明确的时候就开始"自由发挥"。所以不是老方法错了,是它的假设前提失效了。我们需要的不是更慢更细的 review,而是更聪明的治理。
2. 工程规范:把"AI 能干什么"变成"AI 被允许干什么"
很多团队引入 AI Coding 的第一反应是"放开用",然后发现质量失控,再一刀切"禁止用"。这两条路我都见过,也都不赞成。正确的方式是给 AI 划定一个"施工围栏",在围栏内它随便跑,围栏外一律禁止。
2.1 一套在我团队里跑通的 AI 操作规范
我没有搞那种挂在 Wiki 上吃灰的长篇制度,而是定了一条简单到可以贴在显示器上的规范,我管它叫"AI 操作三段式"。
第一段是任务描述必须完整。给 AI 的任务里,必须包含四样东西:需求目标、输入输出边界、受影响模块清单、可执行的验收标准。比如不能只说"写一个用户列表接口",要说"为用户管理模块提供一个分页查询接口,输入 page/pageSize,输出 id/name/email/status 字段,状态字段只允许 enabled/disabled 两种取值,需遵循该模块现有的统一异常处理规范,验收标准是单测覆盖分页边界与非法参数分支"。信息密度完全不同,产出的代码质量也完全不同。
第二段是强制小步提交。AI 生成的代码,不允许一次提交超过一个模块的变更。哪怕它一次生成了三个关联文件,也要拆成三次提交,每次提交之间可以穿插人类 review。这一步极其重要,因为 AI 代码一旦聚集成大块,出问题时你根本不知道是哪一段引入的。
第三段是禁止 AI 单飞。AI 生成的代码必须由一个人类所有者认领,后续改动、故障排查、评审意见都挂在这个人名下。没有所有者的代码不允许合入主干。这条规则在心理层面上的效果远大于流程层面,它杜绝了"这不是我写的所以我不负责"的甩锅心态。
2.2 上下文工程:把约束写进提示词里
规范再好看,如果只靠人肉提醒,很快就会被遗忘。更靠谱的做法是把约束直接写进"提示词"里头,把工程规范变成 AI 的默认上下文。
我现在给团队搭了一个内部的"项目上下文包",里面包含五类内容:项目目录结构说明、核心模块职责表、通用返回格式定义、全局异常处理约定、以及依赖组件的版本清单。这些内容每一次与 AI 交互时都会附带进去。
有人觉得这太麻烦,我可以负责任地说:这五分钟的麻烦,能省掉后面五个小时的返工。我在一个模块开发里做过对比实验,直接把同样的需求发给 AI,一遍是纯文字描述,一遍是带上下文包的描述。前者生成的代码里,有 30% 的接口路径不符合项目现有的 RESTful 约定,需要人工修正;后者的代码一次就贴近了项目风格。
再一个经验是"上下文,宁可冗余不要缺失"。有些团队为了让 AI 更高效,喜欢把上下文精简到极致,这恰恰是灾难的开始。我自己踩过的坑是:让 AI 改一个日志工具类,没给它附上项目的日志脱敏要求,结果它引入了大量敏感字段的打印逻辑,差点把用户手机号打到日志里去。从那以后,我的原则变成:上线前的 AI 代码,上下文宁可多给 20% 也不要少给 1%。
2.3 测试概念前置:让 AI 先写测试再写实现
在做工程规范时,我强烈建议加一条:对复杂逻辑模块,要求 AI 先输出测试用例,再输出实现代码。有人说这太理想化,但实际操作下来,这一条对质量提升的效果立竿见影。
原理也不复杂。AI 在"先写测试"的模式下,必须把需求转化成可验证的行为描述,它就会被迫去明确边界条件、异常分支、返回值类型。这些原本是藏在代码逻辑里的隐含假设,被测试用例逼着显性化了。等它在写实现的时候,其实是照着测试用例去凑逻辑,对需求的偏离就少了一个量级。
我在某个数据处理模块里试过这个流程。AI 先生成了 8 个测试用例:正常值、空数组、全 null、非法类型、边界值、并发调用、超时场景、以及数据量超过阈值时的降级行为。然后照着这些测试去写实现,最后跑测试,第一版就通过了 7/8,只有一个并发场景暴露了共享状态未加锁。未加测试先行的一版,同样是这个模块,核心功能跑通但边界场景挂了三个,排查花了我一个下午。
3. 代码评审:给 AI 代码做分级审查,而不是逐行死磕
代码评审是 AI Coding 质量治理里最容易被误解的一环。有很多人听说 AI 代码危险,就要求团队保持"逐行 review"的传统。我的看法恰恰相反:如果 AI 代码还需要你逐行 review,说明前面的工程规范和任务切分没有做好。评审的正确姿势是"识别风险等级,只对高风险区域做深度审查",其余部分走常规检查。
3.1 从"审代码"升级为"审风险"
我把 AI 代码评审的关注点从"这行写得对不对"迁移到"这段代码会给系统带来什么不可控的风险"。具体来说有三个问题优先回答:它改变了哪些模块之间的边界,它是否引入了新的第三方依赖,它是否触碰了全局共享状态。
这三个问题指向的是同一种担心:AI 生成的代码,最薄弱的不是单行逻辑,而是它和外围世界的交接处。一个负责用户登录的函数,内部逻辑写得再漂亮,如果它在边界处没有透传原有的事故追踪 ID,那出了故障你连日志都串不起来。这种问题靠逐行看很难发现,但用"边界视角"去看一眼就能暴露。
我的建议是,评审 AI 代码时,先看 diff 的"接缝部分":文件头部的 import、函数的签名、与外部模块的调用关系、错误处理是否落入全局兜底机制。接缝干净了,内部逻辑出问题的概率就会低很多。
3.2 四层审查深度的选择
我把评审强度分成四层,根据代码的风险评分来选择。第一层是变更范围审查,只核对 Diff 是否在任务描述声明过的文件范围内,找出"偷偷改了不该改的文件"的 AI 行为。第二层是接口契约审查,核对新的函数签名、参数结构、返回结构与调用方是否对齐,有没有破坏已有契约。第三层是逻辑深度审查,针对核心算法、状态机、并发控制等高风险代码做逐行推演。第四层是安全合规审查,主要检查敏感数据、鉴权逻辑、注入风险、加密算法的选用是否合规。
我要求团队给每个评审任务打一个 1 到 4 的等级。新增一个无关紧要的展示接口,走 1 级就够;改动支付状态流转的,至少走到 3 级;涉及用户数据导出、密钥管理、权限提升的,直接顶到 4 级。
这样分级的好处是节省人力不流于形式。团队成员不会因为每一个 AI 提交都做深度 review 而疲于奔命,也不会因为深度 review 只存在于口号中而形同虚设。
3.3 一份可以抄走的 AI 代码评审清单
我整理了一份评审检查清单,不一定适合所有团队,但作为起点非常实用。清单分成八个问题,评审人只需要逐项回答是或否。
第一条:AI 是否修改了任务描述未提及的文件,如果有,理由是否可靠。第二条:是否新增第三方依赖,如果是,版本有无锁定,来源是否可信。第三条:是否存在"看起来正确但永远走不到"的分支,比如无用的异常处理、不可能为真的条件判断。第四条:错误处理是否会被外层拦截,还是吞掉了关键错误信息。第五条:是否直接访问了全局可变的共享状态,绕过所属模块的接口。第六条:敏感数据是否做了脱敏和最小化访问。第七条:函数或类是否保持了单一职责,有没有把两个以上不相关逻辑揉在一起。第八条:变更有没有配套的测试,测试是否覆盖了边界和失败分支。
这套清单执行了三个月,我最大的体会是:AI 代码评审中最高频的问题不是逻辑错误,而是"多管闲事"。AI 特别容易在实现需求顺手把日志格式改了、把某个常量重命名了、把无关模块的格式调整了。这类问题虽然不致命,但会污染 Git 历史、加大 diff 审查难度、增加未来排查的噪音。清单第一条就是冲着这个去的。
4. 风险驱动测试:把稀缺的测试资源投向高危区
AI Coding 带来的一个隐性问题是:代码产出量上升,测试资源并没有同比上升。如果继续按照"所有代码同样对待"的策略去写测试,要么测试覆盖跟不上,要么测试深度不足,最后还是漏。所以必须引入风险驱动的测试理念,把验证资源集中到风险最高的那部分 AI 代码上。
4.1 什么是 AI 代码的"变更地图"
在规划测试策略时,我先画一张 AI 代码变更地图。地图的横轴是"变更面积",指一次 AI 提交涉及的代码范围,比如新增文件数、修改行数、涉及的模块数。纵轴是"业务影响",指这个模块一旦出错会造成的损失级别,比如影响用户资金、影响核心链路、只影响边缘页面。
这两个维度一交叉,就得到四个象限。大面积高影响区域是最优先保障区,必须做全量回归加集成测试,最好还要有性能压测。大面积极低影响区域,可以做冒烟级别的检查,不用投入过多精力。小面积高影响区域,一定要做深度测试,因为变更小不代表风险小,支付模块改三行也是大事。小面积低影响区域,交给常规的单元测试覆盖就够了。
这个地图的价值在于,它能把有限的测试资源从"均匀撒胡椒面"变成"精准滴灌"。我有一段时间团队测试人力特别紧张,靠这个地图硬是把上线前的测试时间压缩了 40%,同时线上事故没有上升,核心原因就是我们把时间花在了能产生验证价值的地方。
4.2 风险评分卡:把直觉变成可计算的分数
为了让风险地图不靠拍脑袋,我设计了一个五维度的风险评分卡。评审人或负责人拿到一份 AI 代码变更后,按以下维度打分,每个维度 1 到 5 分,总分 5 到 25 分。
第一个维度是变更密度,新增代码行数除以涉及文件数,密度越高风险越高。一个文件塞了 500 行新代码,与五文件各加 50 行,前者风险大得多。第二个维度是依赖广度,变更代码直接调用的外部模块数量,调用越多,出问题的波及面越广。第三个维度是共享状态触碰频率,是否操作了全局配置、共享缓存、数据库连接等公共资源,触碰越多越危险。第四个维度是历史缺陷密度,该模块过去三个月内缺陷单数量,历史包袱越重越容易翻车。第五个维度是修复复杂度,假设上线后出了问题,回滚容易吗?紧急修复需要在多长时间内完成?涉及跨团队协调的,自动加高分。
我建议团队定一个阈值,大于等于 18 分的变更必须走"测试强化通道",也就是不仅要跑常规测试,还要额外加一轮针对性的集成测试和故障演练。15 到 17 分走标准测试流程,低于 15 分的走轻量验证即可。
这个评分卡跑起来以后,团队的测试决策就从"感觉哪个模块重要"升级成"依据分数分配资源"。测试工程师再也不用为了哪些用例该优先执行跟开发扯皮,分数就是依据。
4.3 红队测试:主动给 AI 代码找茬
对于高评分模块,我还建议引入"红队测试"的思路。这个做法本身在安全领域很常见,但用在 AI 代码质量治理上同样有效。
具体做法是:在 AI 完成一个高风险模块后,测试人员不按需求文档测试,而是扮演一个"恶意破坏者"去尝试击穿系统。输入极端参数、模拟鉴权绕过、直接修改变量权限、用并发请求冲击状态机、在配置文件中混入非法格式——所有你能想到的坏招都往上面招呼。
红队测试在 AI 代码上特别有价值,因为 AI 生成代码往往在"正常路径"上表现良好,但在"对抗性路径"上容易出岔子。比如它可能对正常输入做了详尽的校验,但对"空字符串加超长字符串拼接"的组合场景完全没有防御,直接导致内存异常。
有一次我们让 AI 写了一个数据导出功能,正常测试全过,红队测试时测试伙伴传了一个包含 500 万行的请求,AI 代码直接把所有数据一次性加载进内存,服务差点被打挂。如果不是红队测试提前暴露,这一版上线就是一个严重的稳定性事故。
4.4 回归策略:AI 代码能不能合入,最终看"回归是否可信"
风险驱动测试的最后一个环节是回归策略。我的原则是:高风险 AI 变更要过两轮回归,第一轮在合入前,跑完该模块的关联用例,第二轮合入后的夜间回归,覆盖全天链路。低风险变更只需要合入后的常规回归。
很多团队在 AI 代码合入后只跑一遍对应模块的测试就大功告成,这其实是不对的。AI 代码的隐性耦合经常体现在"改动 A 模块,影响 B 模块的非功能性表现",比如性能下降、内存占用升高、响应超时概率变大。这些只有放到全链路回归环境里才能暴露出来。
我现在在团队里推的是"AI 代码变更必须带一条回归基线",基线内容包含该模块近两周的调用量峰值、P99 时延、错误率。合入前对比这三个指标,发现任何一个劣化超过 20%,立即回退,不给 AI 代码带病合入的机会。
5. AI 代码质量治理的本质,是把信任变成验证
走到这一步,我想坦白分享一件事:AI Coding 质量治理,最大的敌人不是 AI 本身,而是我们自己对"AI 很聪明"的过度信任。很多事故的根源,是开发者在 AI 生成代码后下意识地认为"它既然能写出来,应该就是对的",于是放松了审查和测试的标准。
我在团队里反复强调一句话:AI 代码不是"代码",它是"建议",是需要被验证的建议。你可以把它当成一个极其高效、从不抱怨、但偶尔极具创造力的初级工程师,你当然用它的产出物,但 absolut 需要你来把关。这个心态上的转变,可能比任何工具和规范都重要。
实际跑了一段时间之后,我团队里 AI 代码的合入率没有变低,但线上事故率显著下降。原因很简单:前期该卡的口子都卡住了,所以后期的火警自然变少了。我个人最深的体会是,质量治理不是一套静态的制度,而是一个和人、和工具、和流程持续磨合的动态过程。今天适用的规则,可能下个月就随着模型能力的提升而需要调整,保持"视验证为常态"的态度,才是长期稳定的基石。
最后再分享一个小的实操技巧:每当我发现某个 AI 生成的模块质量特别差,我不会只修代码,而是回去追问"当初给 AI 的上下文里到底缺了什么"。十有八九会发现,是任务描述缺少了某个边界约定,或者项目规范没有沉淀成 AI 可读的文档。把这一次失败转化成上下文包里新增的一条规范,团队的质量水位就会往上走一格,而且是不可逆的那种。