ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

AI生成代码的审查策略与落地指南:从风险分层到人机协作

AI生成代码的审查策略与落地指南:从风险分层到人机协作 你这个问题我最近被问得耳朵都起茧了。起因是团队里新来的小朋友用AI写了个分页查询接口跑起来没问题代码也工整他觉得自己效率起飞。结果代码评审的时候我发现他对NULL值的处理逻辑是反的那种场景在测试环境压根触发不了上了生产必然出事故。那一刻我意识到AI写代码这事带来的不是要不要审查的问题而是怎么审查的问题彻底变了。先说结论人不但要审而且要比以前更会审。但不是让你像个扫描仪一样逐行盯语法那是最没价值的部分。AI写代码一小时上线火葬场一秒钟这种事故在每个用AI编程的团队里都在反复上演。这篇文章我想把我这段时间摸索出来的审查策略、踩过的坑、以及一套可复用的人机协作流程完整地分享出来。1. 先搞清楚一件事AI写出来的代码到底哪里不可信很多人对AI编程有个误解觉得AI既然能通过那么多编程测试写出来的代码应该比普通人靠谱。实际上完全不是这么回事。你得先明白AI写代码的本质才能知道该盯什么地方。1.1 AI不是在理解而是在预测——这句话决定了审查的必要性大模型写代码的原理本质上是根据你给的上下文逐个预测下一个最有可能的Token。它跟一个程序员坐在那里思考这个业务逻辑该怎么实现是完全不同的路径。程序员写代码是在用逻辑推导AI写代码是在做概率匹配。这意味着什么意味着AI产出的代码在语法层面几乎不会错因为语法是它训练语料里最庞大的模式。但在语义层面可能错得离谱因为语义需要结合你的业务上下文、你的数据结构、你的边界条件而这些AI只能靠猜。我打个比方你就懂了。AI写代码就像一个读了海量菜谱、但从没下过厨的人你让他报菜名、写配料表他能写得很漂亮。但真要他根据你家冰箱里剩的食材做一顿晚饭他可能给你做出一道理论上存在但根本无法下咽的菜。审查就是那个尝菜的过程。所以审查的第一个原则出来了语法不用细看逻辑必须深究。你跟AI较劲缩进、命名、分号纯属浪费时间你要盯的是它有没有真正理解你的业务约束。1.2 AI写代码的四种典型错误模式这段时间我用AI写了大量代码把它出的错归了个类基本逃不出这四种依赖幻觉AI引用了不存在的库、过时的API、或者张冠李戴的方法名。它靠概率拼接出看起来合理的调用但实际编译都过不了或者运行时才炸。这种错在写Python的项目里尤其多见因为Python的动态特性让很多错误延迟到运行期才暴露。上下文缺失AI不知道你的项目里已有工具函数、既有数据格式、团队约定导致它自己造了一套轮子或者生成的代码风格跟整个项目格格不入。这种错最隐蔽因为它跑得通但维护起来是灾难。版本漂移AI的知识有截止日期但依赖库一直在更新。它可能给你写了一个新版本已经废弃的API还可能把废弃的原因都讲得头头是道。这种错测试环境发现不了只有升级依赖或部署生产时才炸。边界条件失明AI生成的代码对正常路径处理得很好比如用户正常传参、数据正常存在、网络正常响应。但一旦遇到空集合、NULL值、超时、并发冲突它的处理往往非常幼稚甚至直接漏掉。你在审查的时候重点就是对照这四类错误去找。尤其是第四类我在这上面吃过大亏。2. 逐行审查没有过时过时的是逐行审查的姿势我知道看到这里有人会问那到底还逐不逐行看了我的答案是看但不全看要有策略地看。逐行审查这个动作本身不过时过时的是不分轻重缓急每行都看的姿势。人的注意力是稀缺资源你把精力耗在无关紧要的代码上真正有风险的地方反而会漏掉。2.1 按风险分层决定审查粒度这也是我作为资深开发者在实践中摸索出来的一个重要经验——任何代码审查方法的核心都是识别风险。高风险区域必须逐行看涉及资金交易、用户权限、数据删除、并发处理、加解密逻辑的代码这部分代码一旦出错就是事故级问题。对于这类代码不仅AI生成的代码要逐行看你自己写的代码也该逐行看这是底线。中风险区域重点看业务核心逻辑、状态流转、接口对接的代码。这些地方需要看整体逻辑是否自洽分支是否完整错误处理是否到位。可以做函数级的通读而不用一行一行抠。低风险区域抽样看UI组件、模板渲染、工具脚本这类代码错了一般不影响核心业务而且错误也容易被测试或人工操作暴露。这种抽样检查两三处确认AI的代码风格一致就够了。那么怎么判断风险的高低呢我有个土办法想象这段代码在凌晨三点出了故障你会不会被叫醒。会那就是高风险。不会那就是低风险。用这个标准去划分审查精力非常管用。2.2 从审查代码到审查意图人在AI时代真正的价值审了这么多AI生成的代码之后我最大的体会是代码审查的核心矛盾已经不再是代码对不对而是代码是否实现了真正的意图。传统代码审查里你大部分的注意力确实放在对不对上——有没有空指针、有没有资源泄漏、有没有语法错误。但AI把对不对这件事处理得已经很好了真出错也是上面说的那些模式化错误看多了就能看出来。真正需要人来把关的是代码是不是你想要的东西。举个例子。你的业务需求是会员过期后保留数据30天再清理AI可能给你写了一个每天定时清理过期会员数据的任务。代码本身没有任何语法问题逻辑也自洽但它把保留30天这个关键业务规则漏掉了。这种错你逐行看代码是看不出来的因为代码内部逻辑是通的。你必须拿着需求文档去对才能发现AI把意图理解偏了。所以我现在审查AI代码第一件事不是读代码而是回顾需求。把需求的关键约束列出来比如保留30天仅限付费用户失败要重试然后一个个去代码里找对应实现。找得到过找不到打回重写。这比逐行阅读有效得多。这里也引入一个热词里提到的概念——AI Agent。我观察到不少团队开始用独立的AI Agent专门做代码审查做法很有意思让一个Agent写代码让另一个Agent审代码人只做最终的仲裁。这确实能解决一部分AI看AI的盲区但我的经验是AI审查工具能看到的是一致性和规范性看不到的是业务正确性。如果你的需求描述本身就有歧义那你让多少个Agent来审都审不出问题来。这也是我为什么强调人审意图不可替代。2.3 用AI审AI辅助工具的价值与局限要说彻底不用AI做审查也矫情了。我自己现在就把AI辅助审查当成流水线上的一道工序AI生成代码之后先让另一个AI从找Bug的角度去读一遍把可疑点标出来我再针对性地去看这些点。这本质上是拿AI当放大镜画可疑区域它能把一些明显的模式问题快速找出来。但实测下来你有两件事必须心里有数AI审查的召回率高但准确率低。它会标出一堆可能有问题的代码其中大部分其实没事。你要是每条都信反而会被带偏。AI审查对错误模式敏感对业务逻辑迟钝。它擅长发现这里少了个判空那里可能除零但发现不了这个接口的语义跟产品文档不符。所以我的用法是让AI审查结果作为线索而不是结论。最关键的那些风险点永远要人自己过一遍。这是底线思维。3. 我现在的实操工作流AI写、人审、AI再审光讲道理不落地都是耍流氓。下面我把目前带着团队在跑的一整套流程摊开来讲你可以直接照着抄。这套流程的核心思路是把AI当成一个效率极高的初级工程师配一个严格的Code Review流程。3.1 一套可复制的人机协同审查流程我建议所有准备引入AI编程的团队都把这个流程刻进DNA里。总共四道关卡第一道写提示词时就把约束焊死。这是最常见被忽略的一步。很多人用AI写代码提示词就写帮我写一个用户列表接口然后AI就自由发挥了。你应该把约束写进去用什么框架、要处理NULL值、错误码格式、禁止引入新的依赖、性能要求、边界条件。我后面会给你一个可以直接抄的提示词模板。这一步做得好后面审查能省80%的力气。第二道让AI自审一遍。生成代码后不要直接拿过来而是先用一条追问指令让AI自查请检查你刚才生成的代码找出所有可能的边界情况、安全隐患和逻辑漏洞列出清单。这招儿特别管用因为AI在生成模式和审查模式下调用的知识路径不一样很多生成时忽略的问题在审查模式下能自己发现。我实测过最少能找出两三个真实的问题。第三道人工重点审查变更点。这是人唯一必须亲自下场的地方。我会这样要求自己从git diff里只针对本次改动的代码做审查不碰无关内容。重点按你说的风险分层来高风险逐行看中风险看逻辑低风险扫一遍。尤其是看看AI有没有违反约束、有没有漏掉边界条件。第四道用CI里的自动化检查收底。人工审查完合入代码之前再让流水线里的静态检查、单元测试、覆盖率检查跑一遍。把AI生成的代码纳入和人类代码完全相同的质量门禁。这样即使前面漏了什么后面还有兜底。3.2 具体案例拆解让AI写一个订单超时关闭功能为了让你看得更明白我拿最近做过的一个真实功能当例子。需求是这样的用户下单后如果30分钟内未支付需要自动把订单状态改为已关闭并释放库存。我先把需求拆成几条硬约束写进提示词使用Spring Boot的Scheduled实现定时扫描每次扫描只处理状态为待支付且创建时间超过30分钟的订单必须使用悲观锁防止并发重复关闭关闭成功后调用库存服务释放库存失败要记录日志并重试禁止引入新的依赖AI很快就生成了一份代码看着也挺像回事。但我审查的时候发现了三个问题问题一边界条件算错了。AI写的是order.getCreateTime().before(new Date(System.currentTimeMillis() - 30 * 60 * 1000))看起来对但它用的是本地服务器时间而订单创建时间是数据库写入的UTC时间。时区一换算等于30分钟变成了一个不确定值。问题二悲观锁只锁了查询没锁住后续操作。AI把Lock(LockModeType.PESSIMISTIC_WRITE)只加在了查询单个订单的方法上但扫描未支付订单这个批量查询用的是普通查询然后在内存里一个一个处理。两个线程同时扫到同一批订单时锁根本不起作用。问题三库存释放重试逻辑缺失。AI实现了失败记日志但没做重试。这导致一旦库存服务临时抖动订单关闭了库存却没释放用户就白白占了库存。你发现没有这三个问题每一个通过逐行审查都能发现但每一个都需要你有足够的业务理解和系统思维。AI写代码只负责把功能拼出来你负责把系统的正确性兜住。这个例子的排查方法可以拆解为先审查时间字段的来源与使用再审查锁的覆盖范围最后审查事务的一致性和容错性——这就是一套完整的AI代码审查清单。3.3 审查清单我每次合并代码前必过的5分钟检查每次合代码前我都会快速过一遍下面的清单确保没有遗漏。你可以把它截图存下来当自己的人工审查SOP。有没有违反提示词里写的硬约束比如禁止引入新依赖扫一遍pom.xml或package.json的diff。是否存在NULL值和空集合的处理这是AI最容易漏的地方。逐个找方法入口参数和返回值。事务边界是否完整多条写操作是否处于同一个事务失败时能否回滚。并发安全是否考虑共享变量、数据库行锁、乐观锁版本号的设置是否合理。外部调用是否有超时和重试AI默认不会帮你想这些超时熔断得人盯。日志是否包含了关键上下文出故障时能不能根据日志定位问题。异常处理是否掩埋了问题AI特别喜欢catch (Exception e) { log.info(xxx) }这种要打回重写。实测下来这套检查做完5分钟内搞定但能把90%的AI生成的隐蔽问题拦在合入之前。4. 我把踩过的坑整理成了一份AI代码审查速查表最后这部分我把自己和团队在实践里踩过的坑以及对应的排查思路和解决方案整理成了速查表。以后你拿到AI写的代码不知道怎么审直接对着查就行。4.1 七个高频翻车现场翻车场景一AI引入了根本不存在的依赖。现象编译报错报错信息指向一个从未见过的库。原因训练数据里的幻觉。排查方法看代码导入语句去仓库搜包名搜不到就是幻觉。解决方案提示词里明确禁止引入新的依赖。翻车场景二SQL查询只覆盖了正常路径。现象测试环境数据少跑得很顺生产数据量大慢查询拖垮数据库。原因AI不会主动考虑索引和查询计划。排查方法拿到SQL先去EXPLAIN一下。解决方案提示词里要求所有查询必须走索引或者干脆让AI生成后自己先优化一遍再交给你。翻车场景三异步任务丢失异常。现象Async方法里抛异常主线程完全感知不到。任务失败静默整个业务流程断了。原因AI默认不会给你的异步方法配异常处理器。排查方法检查每个Async方法有没有对应的异常处理。解决方案写提示词时明确要求所有异步方法必须捕获异常并记录完整堆栈.翻车场景四AI自己造了一个轮子并绕过了你的公司基础库。现象公司明明有统一的Result返回类和BaseServiceAI重新定义了一套类似的。原因上下文不足。排查方法审查import语句看有没有引入公司内部工具类。解决方案把公司基础库的用法写进提示词或直接让AI参考同目录下的既有代码。翻车场景五错误信息被AI吞掉了。现象errorMessage被覆盖成固定的系统繁忙真实的异常信息丢失。原因AI过度追求用户体验。排查方法全局搜索catch日志。解决方案提示词里要求所有异常必须保留原始异常信息并完整记日志。翻车场景六测试代码和生产代码混在一起。现象AI从一个训练语料里抄了一段把测试用例写进了src/main/java。原因极少见但一旦出现极难排查。排查方法看文件目录结构检查是否在main目录下出现了Test注解。解决方案审查时看一眼目录结构就够了。翻车场景七过时的API按新语法调用。现象比如用了javax.annotation.Resource而不是jakarta.annotation.ResourceSpring Boot 3升级后直接报ClassNotFound。原因AI训练数据混入了多个版本的项目。排查方法核对报错信息的类路径。解决方案升级依赖后全局搜索旧包名。4.2 我的策略转变从不信任到分层信任最后说说我个人的心态转变。刚开始用AI写代码那阵子我的策略是AI写的每一行我都亲自重写一遍结果效率没提升多少还把自己累得够呛。后来我换了个策略分层信任。第一层信任靠测试兜底。我给AI生成的代码补上关键路径的单元测试和集成测试只要测试过了我就信任它大部分路径是对的。第二层信任靠静态检查兜底。代码风格、基础规范这些交给工具去查我不再人工盯。第三层信任靠的是前面说的那些高风险管理。我真正信得过的AI代码不是它写得多么完美而是它经过了完整的测试和审查链条。现在的状态是AI负责把想法变成代码我负责把代码变成可靠的产品。效率高了不少质量也守得住。在实际操作中我还养成了一个习惯小步提交频繁审查。不要一次性让AI生成上千行代码让它一个函数一个函数地写写完一个立刻审一个。这跟人类开发的小步提交原则完全一致但在AI协作场景下尤其重要。因为AI一旦写长了上下文会漂移前面遵守的约束后面就忘了。你小步审等于把它的记忆力问题提前暴露在可控范围内。这套打法跑下来我的代码评审会议少了一半但线上事故也少了对半。这就是我今天想分享的全部内容。最后再分享一个小技巧——如果你也在用AI编程不妨给AI一个专家角色的提示词前缀比如你是一名有10年经验的Java架构师请考虑并发与安全后再输出代码。这听起来像是玄学但实测下来比不加前缀的效果好很多生成的代码在边界条件的处理上明显更稳。
返回列表