ARTICLE DETAIL

资讯详情

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

AI代码审查实战:四条清单与两次打回复盘

AI代码审查实战:四条清单与两次打回复盘 我们团队的代码仓库里现在每十次提交里至少有三次是AI生成的。不是我赶时髦是大家确实把AI用起来了写单元测试、补DTO、生成SQL、做重构。但热闹归热闹我作为负责最终代码审查的人这半年最大的感受是AI写得快错得也“聪明”。它不是简单地把接口写错而是能在你疏忽的边界条件、鉴权逻辑、异常路径上一本正经地埋雷。所以我把这段时间的审查经验沉淀成了四条清单还打回过两次AI代码。今天就把这四条清单和两次打回的完整过程展开聊聊希望能给同样在审AI代码的同学一些参考也顺便说说怎么让AI代码少被打回。1. 为什么AI代码必须走人工审查1.1 AI写得快错得也“聪明”先说个反直觉的现象AI生成的代码单测通过率其实很高。这是因为它写单测的时候通常会照着实现逻辑去编用例而不是照着需求文档去编用例。也就是说代码和测试能自洽但需求和代码未必自洽。你让它写“查询用户列表已离职的不要显示”它可能生成一句WHERE is_deleted 1看着没毛病但is_deleted 1到底是“已删除”还是“未删除”完全取决于表设计。如果语义反了单测照样全绿因为AI写测试时会引用同一个错误条件。真到了业务上线上用户列表可能直接空掉一大半。AI大模型本质是“根据上下文预测下一个token”它擅长让代码看起来流畅、结构完整、注释到位但它在理解业务语义方面高度依赖提示词提供的信息。如果你把需求写得太简略它会用训练数据里的“最常见理解”补齐而这个“最常见理解”很可能不是你真正想要的。比如产品经理说“查询时排除已删除用户”AI有可能在没有任何依据的情况下自作主张把“删除标记”理解成“状态字段等于某个魔法数”。这种错误不跑真实业务数据是测不出来的这就是AI生成代码必须走人工审查的根本原因。1.2 人工审查的定位不是不信任而是兜底我经常碰到的另一个极端是要么完全不信AI要么完全信AI。这两种心态都会出事。完全不信等于放弃了提效工具团队里其他人都开始用AI写代码你一个人守着旧流程最后你会发现根本审不过来完全相信就是把一个概率模型当成了确定性系统。AI写一万行代码其中九千行没问题剩下的一千行往往不是明显的语法错误而是“看起来合理”的逻辑坑。AI代码审查不是想象中的“逐行挑刺”更像飞机驾驶里的机长和副驾驶AI是副驾驶能帮你巡航、计算、提示但起飞、降落、突发故障这些关键时刻决策权必须在人手里。人工审查不需要把每一行都读过去而是抓AI最容易出问题的四类点需求符合性、安全合规、工程质量、可维护性。这四类恰好是AI这种“文字接龙模型”的薄弱环节——它不是不知道怎么写代码而是不知道你的业务、你的安全红线、你的团队习惯。后面四条清单就是从这四类里沉淀出来的。2. 我总结的四条审查清单四条清单不是一次想出来的是打回几次AI代码后慢慢沉淀的。每条对应一个问题类别。我审查AI代码时会把清单打开一项一项过就像登机前的地勤检查一样。这份清单的核心思路是不管AI代码看起来多“漂亮”只问四个问题——它真的满足需求吗它安全吗它配得上团队标准吗它不会给未来埋雷吗2.1 清单一需求符合性——代码“对”不代表“正确”“对”和“正确”是两回事。编译通过、单测通过只是“对”满足业务目标才是“正确”。AI生成的代码特别容易在“看起来正确”上发力却在语义层面翻车。审查这一条时我会把需求拆成三列正常路径、异常路径、边界条件。然后对照代码逐行确认AI最爱忽略的就是第一列的“正常路径”之外的场景。具体翻车例子我见过很多需求是“查询某段时间内的订单”AI写成了WHERE create_time NOW() AND create_time NOW() 1 DAY结果查的不是“某段时间”而是“今天”需求是“如果配置不存在就用默认值”AI写成了“如果配置不存在就报错”完全反了需求是“对一个可能为空的列表求和”AI直接遍历没做空值判断。边界值、空集合、超大值、并发场景这些都是AI的天然盲区因为它在预测时倾向于“最常见的情况”而真实业务里最常见的情况往往是“有数据、有权限、参数合法”。审查AI代码时看到注释里写“根据需求实现”千万别放松警惕那只是AI在给自己壮胆不代表它真的理解了需求。2.2 清单二安全与合规——AI最会“一本正经地埋雷”安全问题是AI代码最隐蔽的雷区。它生成的代码往往格式规范、接口完整但鉴权、越权、输入校验、敏感信息泄露这些细节AI会默认省略。原因不难理解训练数据里大量示例代码为了“简洁”会略掉生产环境的防护细节。比如直接写SELECT * FROM orders WHERE user_id ?看着参数化查询没问题但接口里压根没校验当前登录用户是不是这个订单的主人谁传一个别人的orderId就能查到别人的订单。所以审查第二类清单时我会对所有接收外部输入的地方走一遍“攻击者视角”这个入口如果是恶意用户能不能被利用能不能越权能不能注入能不能通过日志把手机号、身份证打印出来我见过AI生成的导出接口直接把用户手机号明文写进日志里美其名曰“方便排查”这在合规场景下就是事故。还有一次AI在处理文件上传时直接拿前端传的文件名拼到路径里路径穿越漏洞就这么来了。安全清单不需要每行都看但要重点检查所有新增的Controller接口、文件读写、SQL拼接、第三方调用这几类高危点。2.3 清单三工程质量——让代码经得起半年后的自己工程质量的审查主要看重复代码、命名、函数长度、圈复杂度、异常处理和魔法数。AI代码在这个维度上往往极端分化要么特别工整变量名、缩进、注释无可挑剔要么特别机械用if (type 1) ... else if (type 2) ...堆出一堆魔法数生成两个几乎一样的方法只差一个参数然后复制粘贴十遍。我打分时不会要求一次生成就达到天花板标准但至少要有基本可读性。典型要打回的情况包括一个方法写了300行圈复杂度爆表catch块里啥也没干异常被静默吞掉出现大量data、info、temp这种看不出含义的命名。更离谱的一次AI为了“严谨”给一个普通方法加了三层Optional判空结果里面还有一句.get()直接可能抛异常等于把空指针风险藏在了“看起来很稳”的包装里。审查这条清单时我会用格式化工具和静态扫描先做“机器初审”把明显问题筛掉然后集中精力看逻辑。机器抓不到的才是真正需要人的经验的地方。2.4 清单四可维护性与演进——别让AI给项目“盖危楼”最后一条清单我会看这次改动是否符合团队现有架构约定依赖方向是否正确有没有引入新的复杂模式是否存在过度设计。AI特别喜欢照搬训练数据里的“最佳实践”一个两三个分支的小功能它能给你生成一个接口、两个抽象类、四五个实现类还用上策略工厂理由是为了“未来扩展”。问题是你现在压根不知道有没有未来这堆抽象反而成了团队里所有人维护的负担。审查时我会问自己一个很朴素的问题“这个改动未来三个月内会不会出现多个变体”大概率不会那就不需要模式。我还会看一眼新增的依赖数量如果AI为了一个小功能引入了一整个开源库那基本可以打回。团队里其他人能否一眼看懂是比“设计优雅”更高的标准。毕竟代码是写给团队看的不是写给设计模式教材看的。清单核心检查目标AI常见翻车点需求符合性业务输入、输出、边界、异常路径边界条件遗漏、需求理解偏差安全与合规鉴权、越权、注入、敏感信息接口无权限、参数校验缺失、日志泄密工程质量可读性、重复、命名、复杂度魔法数、重复代码、空catch、滥用判空可维护性架构一致性、扩展性、过度设计为假想需求堆模式、引入不必要依赖3. 两次打回两个真实案例复盘四条清单是“纲”两次打回是“目”。我挑两个印象最深的完整复盘一下当时我怎么审、为什么打回、最后怎么让AI改对。这两个案例一个栽在安全上一个栽在过度设计上基本代表了AI代码审查里最典型的两类问题。3.1 第一次打回看似完美的接口漏了鉴权背景是一个内部运营后台需要新增“按条件导出用户列表”接口。AI基于现有代码风格一次性生成了Controller、Service、Repository、DTO还配了单测PR提上来流水线全绿。我审的时候第一眼看到的是“代码很规整”但打开清单二往下核对时问题立刻暴露接口没有加任何权限注解任何登录后的普通运营都能调用。更严重的是导出条件里的部门ID完全由前端传入没有从当前登录用户上下文取一个普通员工可以把整个公司的用户数据导走。打回时我在PR评论里写了两条硬意见“第一该接口仅管理员可访问请补权限校验第二数据范围必须取自登录人信息不要信任前端传参。”那会儿AI还不会“自己反思”我直接把期望改法也写出来了使用PreAuthorize限定角色数据权限从安全上下文获取。把安全约束补充到提示词里重新生成后第二次代码就正常了。这个案例让我印象特别深因为AI不是不会写安全代码是我们没把安全边界说清楚。从那以后我所有涉及接口的提示词里都强制加一句安全要求是什么、谁能访问、数据范围从哪里取。3.2 第二次打回为“未来需求”写出的过度设计第二个案例是一个“根据业务类型返回对应通知模板”的小功能。需求明确逻辑就是两三个分支。AI生成的代码交上来打开文件我愣了一下一个接口、两个抽象类、四五个实现类甚至还用上了策略工厂。功能确实实现了但引入的类数量超过业务本身的复杂度。对一个两三个分支的映射来说这样的设计让新同学光看懂就要花半天。打回理由我写得很直接“当前场景不需要策略模式请改为简单的if-else或switch等出现更多类型时再重构。另外请不要照搬网上的标准设计以团队现有代码风格为准。”AI为什么会这么写因为训练数据里的“高质量代码”强调设计模式、强调开闭原则AI把这些当成了安全牌但它不理解你的团队规模、项目阶段和维护成本。修改之后AI给了一个30行的普通方法逻辑清晰测试也够用。后来我在提示词模板里加了一句话“保持简单避免不必要的抽象优先使用项目中原有的写法。”这个案例告诉我审查AI代码时“过度设计”比“功能错误”更隐蔽因为功能测试全通过但它会慢慢拖垮代码库的可维护性。3.3 两次打回给我自己的教训两次打回之后我给自己定了三条规矩。第一条审查顺序不能乱先需求再安全再看设计。如果先看代码风格很容易被规整的格式迷惑跳过真正的要害。第二条打回意见要“可执行”AI不是人不能领会“你自己想想哪里不对”必须给出具体位置、具体原因、期望改法。第三条不要带预设立场AI代码值得被认真对待就像同事代码一样审查目的是守住交付质量不是证明AI不行。这两次打回也直接推动了团队流程变化。我们在PR标题加[AI]前缀让reviewer第一时间知道这是AI生成的代码从而按不同的注意力分配来审。流程上看起来是小事实际效果很明显大家不再“一刀切”地信任或怀疑AI而是会认真打开清单过一遍。4. 怎么让AI代码少被打回审查前的“前置动作”打回成本很高最好的办法是让AI在生成时少踩坑。与其事后审不如事前把条件定清楚。这一章我总结了四个很有效的“前置动作”它们不是理论是我在这半年里逐步试出来的。4.1 给AI喂“足够像需求文档”的提示词很多人把提示词当“一句话需求”来写比如“写一个用户导出接口”。AI只能根据这句话用训练数据里最常见的实现补全这等于把需求二义性直接带进了代码。我的做法是用“输入、输出、约束、异常、安全”五要素结构来写提示词把业务的关键信息都框住。差提示词 用Java写一个用户导出接口 好提示词 实现一个导出用户列表的接口要求如下 输入查询条件姓名模糊、部门ID可选、分页参数 输出CSV文件流包含用户名、手机号、部门名 约束日期格式统一为yyyy-MM-dd手机号做脱敏 异常查不到数据时返回空文件接口报错时走统一错误码 安全接口需登录后访问仅ADMIN角色可调用导出数据范围限定在当前登录人所属部门五要素不是越多越好而是把业务关键信息写清楚AI就不会“自由发挥”。审查时我也会拿着提示词原文对照代码逐条核对。如果提示词里写了“仅ADMIN可调用”代码里却没有对应鉴权那问题就非常明确直接打回。4.2 要求AI自检但别把自检当结果我在提示词最后经常加一句“请先列出该实现可能出错的5个边界场景再输出代码。”这个做法很有效。AI“自检”产生的列表能帮你快速定位审查重点比如它会主动列出“空值、超大分页、并发写入、无权限、参数非法”这些场景。你别把它当成质量担保它只是在基于概率做预测但至少给出了值得关注的线索。有一次AI在自检列表里写“未校验上游参数为空”我顺着这条把对应代码翻出来果然真没校验。如果它没写这一条我可能要按照清单慢慢找才能发现。但也有翻车的时候AI自检写的风险清单和代码完全对不上那说明提示词给的需求信息不够或者上下文太长模型已经“晕”了。这种情况建议拆任务不要硬问下去。4.3 拆小任务分批合并与审查AI生成一个500行的大功能时前后逻辑特别容易不一致前面定义了变量后面没用中间生成重复逻辑后面甚至忘了前面的约束。所以我现在会把一个需求拆成几个前后依赖的小任务逐个生成、逐个审、逐个合像搭积木一样。每批代码控制在100到200行左右review效率最高。前后依赖怎么处理先让AI生成接口定义和DTO审完确认边界再让它生成实现最后生成测试。每步都有明确边界问题能更早暴露。之前我们一次合并一个巨型AI PRreview一次要两小时还容易漏改成小步提交后每次15分钟就能搞定而且AI的“幻觉”概率明显下降因为每一步的上下文都更短、更聚焦。5. 审查工具与提效技巧5.1 静态检查工具是“初审”人是“终审”工欲善其事必先利其器。我推荐的工具组合是SonarQube、ESLint、CheckStyle、SpotBugs、CodeQL或者Semgrep具体选哪个取决于团队技术栈。工具擅长干两件事抓重复代码、算圈复杂度、扫硬编码密钥和SQL注入模式。这些交给机器又快又准。但工具是有局限的。它不理解业务上下文看不出“部门ID应该从Session取而不是从请求参数取”这种问题。我见过有人拿SonarQube扫一遍就当审查完了这是自欺欺人。工具把你的代码格式、重复度、复杂度管住了剩下那些真正要命的业务语义、权限设计、架构一致性才是人工审查的存在意义。正确用法是把静态检查接到PR流水线机器能抓的先抓完人再集中精力看机器抓不到的部分这样两边效率都最高。5.2 让AI帮我审AI同行评审的新玩法这个玩法是我最近三个月才开始的效果出奇地好用一个AI模型审查另一个AI生成的代码。具体做法是把四条清单、AI生成的代码、原始提示词需求描述一起发给审查模型让它按清单逐项找问题。两个模型上下文不同、训练偏好不同互相找茬能发现各自盲区。代码生成模型可能习惯省略安全校验审查模型却会敏感地指出来。实操格式很简单给审查模型的指令是“你是资深代码审查专家请按以下四条清单审查代码输出问题列表、严重级别和修改建议。”它返回的报告我会当“候选问题”清单来处理。有一次它指出“该方法可能产生NullPointerException”我一看确实AI代码里对Optional.ofNullable的返回值直接调用了.get()这种审查模型确实能帮上忙。当然AI审查结果不能直接当结论因为审查模型也可能幻觉最终拍板的一定是人但它能帮你节省大量大海捞针的时间。5.3 记录问题分类沉淀团队清单我建议团队维护一个文档就叫《AI代码审查问题清单》。每次打回记录问题类别、代码片段、触发原因不需要写长篇大论一两句话就够了。三个月后统计你会发现规律非常明显。我这边最近三个月的数据是边界条件遗漏占38%缺少安全校验占24%过度设计占15%需求理解偏差占13%其他占10%。这个数据能反哺流程。边界条件最多就在提示词模板里强制要求AI列出边界场景过度设计频发就加“保持简单、避免不必要抽象”的约束安全校验不足就要求所有接口的提示词都必须包含安全条款。下个季度再统计打回率明显下降。这份清单不是用来追责的是用来改进整个AI辅助开发流程的。6. 常见问题与排查技巧实录6.1 常见问题速查表整理一张速查表覆盖我在实际审查AI代码时最常遇到的问题按“现象、原因、排查方法、处理建议”四列列出方便你在PR评审现场拿过来直接对照。问题现象可能原因排查方法处理建议编译和单测全过但功能不对AI基于实现编造自洽测试未对齐需求拿需求逐条对照代码分支补充需求描述明确输入输出和边界打回重写接口缺少权限校验提示词未提安全要求训练数据默认省略检查所有新增Controller的鉴权注解在提示词加入安全约束补充权限代码代码特别“华丽”类多好几倍训练数据偏好设计模式统计新增类和方法的数量对比业务复杂度要求保持简单按团队现有风格实现日志打印手机号、身份证未把敏感字段纳入约束搜索日志语句中的个人信息字段打回并修改日志在框架层加脱敏单测覆盖率高但边角全空AI喜欢生成正向路径用例抽查测试断言是否有效异常分支是否覆盖补充边界和异常用例要求先写自检清单重复代码严重大任务拆分不足AI复制粘贴式生成用重复代码检测工具扫描拆分任务、小步提交、提取公共方法6.2 避坑技巧别让AI代码悄悄溜进主线第一在PR标题前缀[AI]让reviewer一开始就知道这是AI生成的代码。我们试过加了前缀之后AI代码的平均review时间反而更合理因为大家不带着“AI就是不行”的预判也不带着“机器肯定没问题”的松懈注意力分配更准。第二强制在PR描述里附上“提示词原文”。审查者能对照“你让AI做什么”和“AI做了什么”很多问题一眼就看出是对齐问题还是实现问题。如果提示词里写了“仅ADMIN可调用”而代码里没有那就不用多废话直接打回。第三设置合入门禁没有人工review记录AI代码不允许合入。这个过程刚开始麻烦一些但能压住“AI一把梭”的冲动。尤其是支付、鉴权、数据处理这类高敏感模块尽量不让AI从零生成而是给AI一个经过验证的正确模板让它照着改成功率远高于裸写。第四也是我最近很喜欢用的一个小技巧让AI先生成“审查自查清单”再生成代码。它写代码时会更关注自己列出的风险点相当于在生成阶段就埋下了一次“软检查”比事后打回省事得多。最后说两句实在话。我做AI代码审查这半年最深的体会不是“AI写代码不行”而是“审查AI代码的重点和审查人写代码的重点不一样”。人写的代码你会下意识怀疑逻辑AI写的代码你会下意识相信格式。格式越漂亮越要记得打开清单一条条核对需求和边界。现在我的工作台上还贴着那四条清单每次review AI代码都过一遍打回率从最初的七八成降到了两三成。如果你也在审AI代码不妨从第一条开始试试别相信注释去看分支。
返回列表