直接输出博文正文,不加任何元信息说明。
1. 先聊一个扎心的现实:提效是真的,烂摊子也是真的
我所在的团队全面铺开AI编程助手大概有大半年了。刚开始那阵子,效率提升确实肉眼可见——以前一个中等复杂度的接口要写半天,现在让AI先起个框架,我再改改逻辑,一上午能搞定两三个。团队里有人做过粗略统计,在部分重复度高的模块上,单人产出接近原来的三倍。当时的感觉就是,这工具真香。
但三个月之后,我们开始陆续收到一些奇怪的反馈。测试说某个老功能莫名其妙出问题,代码review的时候看到一些很别扭的实现,甚至有一次线上事故,最后定位到是一段AI生成的代码在边界条件下踩了坑。这段代码当时review的时候,大家都觉得没毛病,甚至觉得写得挺漂亮。
于是我们停下来做了一次回看。复盘的结果并不让人意外:AI编程助手解决的是“写代码”的效率问题,但它没有解决“代码是否该这么写”“这样写会不会埋雷”的判断问题。效率翻倍的同时,代码提交的体量也跟着翻倍,review的成本、出错的基数、隐藏的技术债同步放大。提效300%不是神话,但“提效300%同时留下一堆烂摊子”也不是危言耸听。
这篇文章不聊怎么用AI写代码,我想重点聊聊另一个话题——当AI成为团队的主要生产力之后,代码审查里那些容易被忽视的盲区。这些盲区是我们团队在实战中踩出来的,也是很多引入AI编程助手的团队大概率会遇到的问题。下面逐一展开。
提示:这篇文章适合所有已经在用或准备用AI编程助手的开发者、技术管理者阅读。如果你是个人开发者,同样有参考价值——你不需要应对团队协作,但你需要对自己写的代码负责。
2. 盲区一:测试覆盖率很好看,但全是“虚胖”
我们团队当时对AI生成代码有一个明显感受:AI特别擅长写单测。你让它补测试,它会很积极地生成一个test_xxx.py,用例名字起得规规整整,断言写得像模像样,跑起来全绿。覆盖率从60%一路涨到90%,团队一度很兴奋。
直到线上出了问题,我们回去翻测试,才发现问题所在。
2.1 AI生成测试的几个典型“虚胖”表现
第一,只测了“成功路径”。AI生成测试用例时,天然倾向于模拟“输入正常、流程跑通、结果符合预期”的场景。但真实世界里,用户不会按照你的预期操作。参数传空值、网络超时、数据库连接丢失、并发访问、中间过程抛异常——这些场景在AI生成的测试里占比很低。看起来代码覆盖率很高,但核心的异常处理逻辑几乎没测到。
第二,断言写得过于宽松。我见过AI生成的测试,调用一个函数之后只断言“没有抛异常”,或者只断言返回值不为空。比如断言一个列表的长度大于0,而不是断言等于某个具体值;断言返回结果是某个类型,而不是断言结果内容正确。这样的断言跑10次绿10次,但几乎没有验证任何实质逻辑,等于没测。
第三,mock过度导致测试失真。AI特别喜欢mock。它会把数据库连接mock掉、把外部API mock掉,甚至把被测函数内部依赖的好几个方法全部mock掉。结果就是这个测试跑起来飞快,但它测的其实是一个“空壳”——被mock掉的部分正是最容易出错的部分,而它恰恰没有被测到。
2.2 一个印象深刻的返修案例
有一次我review一段支付相关的代码,AI生成了一段生成订单号的逻辑。代码本身没有问题,但它的单测只覆盖了“正常生成”这一个场景,断言是“结果不为空”。我当时让同事补几个用例:并发场景下订单号是否会重复、系统时钟异常时是否会回退、传入空参数时是否抛异常。结果没过多久,还真测出问题来了——高并发下订单号出现了重复。如果只看覆盖率数字,你根本发现不了这个隐患。
实操心得:从现在开始,review测试代码时先问三个问题——它有没有测“失败路径”?它的断言是在验证“结果”还是在验证“不报错”?它mock掉的东西是不是被测对象真正依赖的核心逻辑?如果三个问题的答案都不够满意,这测试就是虚胖,宁可不要也不能让它给你虚假的安全感。
2.3 怎么审查AI写的测试代码
我的经验是,审查AI生成的测试代码比审查业务代码更重要,因为测试是最后一道防线。具体操作上,可以按这个顺序来:
- 打开测试文件,先看
import和mock部分。如果mock的深度超过两层,就要警惕——这个测试可能已经不是在被测逻辑上验证了,而是在mock配置上自嗨。 - 看断言方式。优先找“等于具体值”的断言,如果一大片都是
assertIsNotNone、assertTrue(result)这种,直接退回重写。 - 看边界用例。把线上的真实坑当成输入条件,反向测试下AI生成的测试有没有覆盖到。
- 有条件的话,跑一下变异测试(mutation testing)。思路很简单:故意在源码里植入一个Bug,看看测试能不能发现。如果发现不了,说明测试的“防守能力”不够,覆盖率再高也没用。
3. 盲区二:AI生成的代码看着顺眼,但安全问题得靠人肉排雷
如果说测试问题属于“内部隐患”,那安全问题就是“外部的雷”。而这恰恰是AI编程助手最让人头疼的地方——它生成的代码语法上挑不出毛病,但安全上可能漏洞百出。
3.1 为什么AI代码容易出安全问题
AI模型是在海量公开代码上训练的,而公开代码的质量参差不齐。换句话说,AI从数据里学到的不仅是好的写法,同时也学到了大量有过安全漏洞的写法。更关键的是,AI在生成代码时只看到你给出的上下文,它不能像有经验的工程师那样,在脑海里建立一个“信任边界”的概念——它不知道哪些输入来自用户、哪些数据是敏感的、哪些操作需要经过权限校验。
我见过最典型的例子是,AI在一个用户登录的功能里生成了一段查询数据库的逻辑,直接拼接了前端传来的参数。代码跑起来没问题,功能也正常,但从安全角度看这就是一个标准的注入漏洞入口。如果不是后来做安全扫描发现,这个坑要等上线被攻击了才暴露。
3.2 AI代码里最常见的三类安全问题
根据我们团队一段时间的统计,AI生成代码出现安全问题的场景主要集中在三类:
第一类是输入校验缺失。AI生成的接口,默认相信参数是好的。它能帮你写好接收参数、处理业务的代码,但往往不会帮你做足够的校验和清洗。特别是在处理文件上传、URL参数、JSON报文这类内容时,缺少校验等于把大门敞开。
第二类是敏感信息处理不当。AI生成代码时会把一些关键信息直接写进日志、写进响应体、甚至硬编码在代码里。数据库连接串、内部API的Token、加密密钥——这些本该放在配置中心或环境变量里的东西,AI倾向于图省事直接写在代码文件里。如果这个仓库是公开的或者权限管理不严,等于把家底直接亮出来了。
第三类是依赖引入未加约束。AI生成代码时,会根据它训练数据里的“习惯”帮你引入第三方库。它不会考虑这个库是否维护、是否存在已知漏洞、许可证是否合规。有时候它甚至会引入一个版本很老但文档齐全的库,仅仅因为训练数据里这个库出现频率高。
3.3 审查时可以怎么应对
安全审查靠人工逐行读代码是不现实的。我的思路是分三层:
第一层,在提交之前跑一遍自动化工具。静态代码扫描工具大致扫一遍安全问题的重灾区。不用追求完美,把这个作为代码进入review之前的一道门槛,效率很高。
第二层,review时重点关注“输入进来的地方”和“输出出去的地方”。凡是接收外部输入的,都要看它有没有校验。凡是把数据拼接到查询语句或命令里的,都要看它有没有用安全的参数化方式。不要跟着AI的逻辑逐行看代码,那样你很快就会被带进它的思路里,忘了自己本来要找什么。
第三层,搞一个“敏感词”审查清单。比如直接搜索代码里有没有出现密钥相关的字段名、有没有把请求体原样打到日志里、有没有在响应里回显了内部信息。这些检查可以提前做成脚本,每次review的时候跑一遍,成本低收益高。
提示:我强烈建议任何团队在使用AI编程助手时,都把它生成的代码当作“新员工写的代码”来对待。新员工对项目不熟悉、对安全红线不敏感,需要老员工严格把关。AI也一样——它甚至比新员工更危险,因为新员工知道自己不懂会问,AI却总是表现得充满自信。
4. 盲区三:AI提效越快,架构腐化得越悄无声息
如果说前两个盲区还算“显性”问题,那第三个盲区就是“隐性”的,也是我认为危害最大的——架构层面的逐步腐化。
团队用AI助手一段时间后,我们会发现代码仓库里出现了一些微妙但让人不太舒服的变化:同类逻辑出现了好几个略有不同的实现、一个本可以共用的方法被复制了多份、模块之间的依赖关系越来越绕。这些变化不是某一次大重构造成的,而是很多个“小改动”累积出来的。
4.1 AI为什么容易让架构变乱
核心原因在于:AI是一个“局部最优”的工程师,不是一个“全局最优”的架构师。
当你给AI一个具体的任务,比如“在某个模块里加一个功能”,它倾向于在当前文件、当前函数的基础上做最小改动。它不会跳出来思考:这个功能是不是应该抽成一个公共方法?是不是应该放到另一个模块?是不是应该先改一下现有的数据结构让整体更合理?在AI的训练数据里,绝大多数任务都是“在特定位置改特定代码”,所以它的生成结果也是这种风格。
这会带来两个直接的后果。一是重复代码迅速膨胀。同一个逻辑在三四个地方出现,每个地方略有差异。AI不会主动帮你消除重复,因为它每次只看到局部。二是模块边界变得模糊。功能与功能之间的依赖关系越来越隐晦,今天让AI加一个查询功能,它可能顺手在A模块里直接调用了B模块的内部方法,而不是通过公共接口。短期看功能实现了,长期看这个项目就变成了“鱼塘”状态。
更麻烦的是,提效速度越快,腐化速度越快。如果靠人肉手写代码,一天写200行,架构腐化的速度是可控的。有了AI,一天产出1000行,腐化速度直接乘以五。以前可能需要半年才能感觉到的架构恶化,现在一两个月就开始发臭了。
4.2 一个让我印象深刻的“重构事故”
我们团队有一个模块,原本结构很清晰。有一天要加一个新功能,同事用AI生成了实现代码,直接在业务逻辑里硬编码了一些原本应该走配置的数值。当时review的时候没太在意,觉得功能没问题就行。结果过了两周,另一个功能也要用类似配置,同事不知道之前已经硬编码过了,又用AI生成了一遍。半个月后,同一个配置在三处地方出现了不同的硬编码值。那个模块维护起来开始变得非常痛苦,改一处另外两处不跟着变,线上就出问题。
后来我们花了一个下午,把所有硬编码值统一收敛到配置中心,又把三处重复逻辑抽成了公共方法。功能不变,代码量直接砍掉三分之一。这个事故给了我们一个很深的教训:AI生成代码的效率提升,不能以牺牲可维护性为代价,否则就是借钱搞建设,账越欠越多。
4.3 架构审查的实操方法
架构层面的腐化很难靠review单个PR看出来,因为它是在很多个PR里一点点累积的。我的做法是:
- 每次review时,不只问“这段代码对不对”,还要问“这段代码该不该出现在这个文件里”。如果AI生成的代码明显改变了某个模块原有的职责边界,要特别警惕,宁可多花时间把它放到正确的位置。
- 定期做“重复代码扫描”。用工具扫描仓库里是否有相似度很高的代码片段。如果同一段逻辑出现三处以上,就把它列为一个技术债条目,安排时间统一抽取。
- 控制单次PR的规模。AI生成代码速度太快,一不留神就是一个上千行的PR。PR越大,review的注意力越分散,越容易放过架构问题。我们现在的规则是:单次提交原则上不超过300行,超过的需要在PR描述里说明原因。
实操心得:如果你觉得自己的团队代码库正在被AI“一点点搞乱”,有一个低成本判断方法——找一个新同事,让他只看代码和注释,不看任何外部文档,在某个模块里完成一个小需求。如果他在理解上下文上花了大量时间,或者在改一个功能时被相邻模块的耦合坑了好几次,那基本可以判断架构已经开始腐化了,和AI提效多久没直接关系,但AI通常会加速这个过程。
5. 审查机制自己的“死穴”:人脑在AI提效面前会失灵
前面聊了三个盲区,但这三个盲区都指向同一个问题——人类的review能力在AI提效面前没有同步提升。这才是最根本的死穴。
一个开发者用AI每天产出的代码量是原来的2到3倍,但团队里review的时间并没有增加。结果是,每个PR越来越大、越来越难review,human reviewer在高强度阅读代码后注意力迅速下降,慢慢演变成“看一眼没啥大问题就点通过”。代码质量的责任逐渐从review环节滑落,完全压在了AI生成质量上,而AI生成质量的稳定性大家都清楚——时好时坏。
5.1 “看不过来”和“看不懂”是两码事
AI提效后,review面临两类问题。一类是“看不过来”:PR体量太大,时间有限,review变成签到打卡。另一类是“看不懂”:AI生成的代码可能采用了某些非常冷门但能跑通的写法,review者不熟悉这个模式,虽然看起来奇怪但说不清哪里有问题,最后碍于面子放过去了。
这两类问题的本质都是认知过载。人脑处理复杂信息的能力是有限的,当AI把信息量翻三倍之后,我们还在用原来的方式做review,效果注定打折。
5.2 我们是怎么重新设计审查流程的
发现这个问题之后,我们没有退回“禁止用AI”的老路,而是把流程改成了“多级防线”的模式:
第一级是自动化工具。所有的AI生成代码,先跑一道自动化的静态检查、安全扫描、测试覆盖率校验。这一级不考虑代码质量高不高,只考虑有没有明显的问题,帮人类把低级的坑先排掉。这一级是纯粹的门槛,没过直接退回。
第二级是分级审查。高风险模块(比如支付、权限、外部接口对接)的改动,require资深工程师逐行review。低风险模块(比如纯展示型页面、内部管理后台的非核心功能),review可以拉通走查,甚至交由自动化工具完成大部分校验。把有限的review时间集中在真正高风险的地方。
第三级是审查清单。我们把review的检查项固定下来,不需要每次从零开始判断,直接在几个维度上过一遍。清单不是摆设,而是一种对抗认知疲劳的手段——当你的大脑在几百行代码里已经疲惫不堪时,清单能把你拉回正轨。
5.3 一个很有效的“反向审查”思路
这里分享一个我们后来总结出来的独特做法:让AI去审AI。
具体操作是:拿上一个AI生成的代码作为一个新任务输入给AI模型,让它以“资深reviewer”的视角找问题。AI审代码时会给出一些很有价值的反馈,比如“这段代码缺少对空值的处理”“这个函数的命名有歧义”“这个逻辑分支有冗余”。
当然,AI审查AI的结论不能直接采信——它会误报,也会漏报。但它有一层意义很重要:它能帮你从“逐行阅读模式”切换到“挑剔模式”。当你已经有了一份AI给出的疑似问题清单,你再去看代码时会带着问题意识,效率完全不一样。
提示:我经常跟团队说一句话:“AI生成代码、AI审查代码、人工做决策。”这个流程说起来简单,但执行时最难的一点是让reviewer真正愿意做“决策”,而不是把AI的结论直接复制粘贴成review意见。做决策的意思是——这个问题是否值得修、是否必须现在修、是否影响用户、是否需要进一步确认上下文。这一步只能靠人。
6. 建立你自己的“AI代码审查体系”的四个关键动作
最后,把前面提到的所有方法论整理成一套可落地的动作,每个团队都可以直接参考。不需要全部照搬,根据团队规模、业务复杂度、AI使用深度来做减法。
统一AI使用规范。不要每个人自由发挥地让AI帮你写代码。我们现在的习惯是:让AI“写框架、写测试、做重构建议”,不让AI直接改核心逻辑。每一条规则都是从实际教训里提练出来的。
把审查清单文档化。文档里记录安全、测试、架构三个维度的核心检查项,新成员加入团队时直接拿这份文档做培训素材,而不是靠口口相传。
给AI代码打标记。我们要求团队在PR描述里注明哪些代码是AI生成的、哪些是人工编写的。不是为追责,而是让reviewer有针对性地调整审查力度——AI生成的代码要重点看边界条件、安全校验和异常处理。
安排“技术债回补”时间。AI提效释放出来的人力,不能全部投入新功能开发,要拿出一部分做代码质量维护。我们现在的节奏是每隔两到三个迭代,留出半天到一天专门处理测试补强、重复代码清理、模块边界调整。这事看起来占用产能,实际上省下的远比分掉的成本多。
实操心得:在引入这套体系之前,我们团队的PR平均review时长大概是40分钟,但很多review是“形式主义”的,并没有真正发现问题。现在我们把流程理顺之后,虽然PR依然多,但每一条review的效率和准确度都明显提升。更重要的是,线上事故率降下来了,测试和运维的返工也少了。AI提效省下来的时间,终于有一部分真正回到了团队自己手里。
坦白讲,AI编程助手带来的这一波效率提升是大趋势,没有哪个团队能置身事外。但效率提升和代码质量从来不是自然成正比的,用得好是杠杆,用不好是埋雷。从我个人的实际体会来说,AI最理想的定位不是“帮你写代码的助手”,而是“帮你快速完成无争议部分的加速器”——真正的判断、决策、取舍,还是得靠自己。别让提效的数字冲昏了头,毕竟账面上的效率再好看,线上出问题时没人关心你的AI跑了多少行代码。