从第三十弹之后,我就一直在琢磨一件事:AI生成的代码越来越快,但Review打回率却一直压不下去。三十二弹那次我做过一个统计,团队里AI参与度最高的几个模块,一次通过的PR不到四成。这个数字让我意识到,问题不在AI写得不够好,而在我们一直在用"事后补救"的思路对待AI代码——先让它写,写完再审查,审出问题再改。改一次、两次、三次,成本全耗在循环里了。所以从三十三弹开始,我把整套思路翻了过来:不做"生成后审查",改成"生成即规范"。这篇第三十六弹,就把这段时间沉淀下来的设计思路、规则层实现、调测配套和最近的新尝试一次讲透。
1. 为什么我坚持"生成即规范"而不是"生成后审查"
1.1 事后修复的代价曲线:一次Review打回背后的隐性成本
先看一个实际场景。以前我们团队让AI生成一个分页查询接口,AI吭哧吭哧几十秒给出几百行代码。乍一看挺像样,类的命名、注释都有。但Review的时候问题来了:分页参数没有校验、返回结构不统一、日志裸奔没有traceId、异常被吞掉直接返回了null。这些问题是靠人眼扫出来的。一个开发同事要从几百行代码里逐个挑出这些毛病,挑出来之后还要在聊天框里一句一句描述"哪里不对、怎么改",AI再改一版,又引入两个新问题,再打回。一来一回一个下午就没了。这个循环里最贵的不是AI生成代码的时间,而是人的阅读时间、上下文切换时间、沟通成本。
我当时做了一个粗糙的统计:一次中等复杂度的AI生成任务,平均要经过2.8轮修改才能进入合并。每一轮Review大概耗时40分钟到1小时。也就是说,一个"看起来只花了5分钟写出来"的接口,实际团队付出的总工时接近4个小时。这个代价曲线和物理世界的工程问题一模一样——水电管线埋好之后,你想再挪一个插座,麻烦程度远高于最初布线的时候。代码也是,生成阶段不堵住问题,后面每一层都会加倍放大。
1.2 "生成即规范"的三层理解
我后来把"生成即规范"拆成三层来落地,每一层解决一个具体问题。
第一层是产出符合规范。AI生成出来的代码,在风格、结构、命名、异常处理这些维度上,直接满足团队约定。不是生成之后让人去对规范清单,而是生成的那一刻就已经是规范的样子。
第二层是规范不依赖人的记忆。这个很关键。团队里总有新人,Review的人也总有疏忽的时候。规范如果只存在于某个文档或者某个人的脑子里,那它就是不可靠的。所以在我们的生成器里,规范是固化在模板和规则里的,AI只是在这个约束空间里发挥,而不是自由发挥之后等人纠偏。
第三层是生成过程可追溯。你让AI生成了一段代码,这段代码是照着哪个模板来的、为什么用了这个模式、哪些规则被触发过、哪些规则被显式豁免了,这些东西要能查。因为技术债最大的来源就是"不知道当初为什么这么写"。如果生成过程本身留下痕迹,后来的人接手代码的时候就能顺着线索理解设计意图,这就从源头上把"注释债"和"文档债"也堵住了一部分。
2. 技术债在AI生成代码里的三种典型形态
谈到"源头杜绝技术债",你得先知道AI生成的代码到底会留下哪几种债。我观察了很长时间,总结出三种最典型、也最隐蔽的形态。
2.1 命名垃圾债:data、result、item 满天飞
AI生成变量名特别喜欢用泛化词。你让它实现一个订单状态流转逻辑,它能给你写出OrderService里全是data、result、tempList、item这种名字。单个看、当场看,好像没什么问题,但一个月后回头维护就抓瞎了——data到底是订单快照还是支付回调?result是校验结果还是保存结果?读代码的人必须沿着调用链去猜,猜错了就改错。
这种债我称之为"命名垃圾债"。它不会让系统立刻崩溃,但它会持续消耗每一个后来看这段代码的人的心智。AI为什么爱这么干?因为大模型训练数据里充斥着各类含糊命名,AI没有"这个名字要被团队其他人看一年"的意识。所以这件事不能靠AI自觉,得靠生成器在模板里强制约定命名模式:业务字段用业务词典的术语,局部变量用意图性命名,禁止裸泛化词。
2.2 结构债:贪吃蛇式方法体
第二种形态更难看出来,因为它不是一眼能扫到的错误,而是结构上的问题。AI生成代码的时候,非常偏爱"把所有逻辑塞进一个方法"的做法。你给它一个需求,它噼里啪啦在一个方法里完成了入参解析、权限校验、状态机判断、缓存读写、仓储调用、异常转换、结果组装。方法长度动辄两三百行。圈复杂度直线飙升。
这种结构被AI拉出来的时候,缺点特别隐蔽——它能跑通,单测还能过。但一旦需求变了,你想在状态机判断那里插入一个新状态,你会发现改动会影响方法里的其他六块逻辑。你不得不先花半天时间把方法拆开,理解每一块的边界,然后才能下手。这就像一棵树,AI把所有枝桠都长在同一个主干上,看着茂盛,风一来全晃。我们在生成器里对方法体长度、嵌套深度、圈复杂度做了硬约束,超标的生成结果直接判定不合格,强制AI拆分。
2.3 契约债:接口参数与返回值像没有合同一样
第三种形态是最让人头疼的,因为它直接影响系统间的协同。AI生成的接口方法,参数经常不加合法性校验,返回值那边也经常不明确说明会不会是空。你调用一个loadUserProfile(id),它可能返回null,可能返回空对象,可能抛异常——但这三种情况在签名上完全看不出来。调用方为了安全,只好写一堆防御式代码:先判id为空、再判返回为null、再包try-catch。每一个调用方都堆一份,代码量膨胀,逻辑分散,真正的业务逻辑反而被淹没了。
这就是"契约债"。它最可怕的地方在于它会传染。一段没有契约约束的代码被三个服务引用,三处都会长出防御逻辑。AI生成代码的时候特别容易忽视这一点,因为它擅长"写出能编译通过的代码",但并不擅长"定义双方都满意的契约"。所以我们的生成器在模板层就把契约固化:参数必须带约束注解、返回值必须明确标注可空性、异常类型必须在文档块中声明。AI生成的代码如果漏了这些,直接不通过生成校验。
3. 规则层设计:把规范变成生成约束
如果"规范"只是写在文档里的建议,那AI生成时根本不会理它。要让生成即规范真正落地,必须把规范变成生成流程里的硬约束。这一节讲规则层的具体设计。
3.1 模板资产库:把"团队共识"变成"生成骨架"
我们做的第一件事,是搭建一个模板资产库。核心逻辑很简单:团队里已经有大量被验证过的代码模式,比如统一返回体Result<T>、统一异常处理器、分页请求模型、幂等校验工具。这些是团队共识,但以前共识只在人的脑子里,现在要把它们做成AI生成时使用的骨架模板。
以REST接口为例,模板骨架里预埋了:
- 统一的Controller层结构:参数校验、权限注解、日志埋点、异常转换各就各位。
- 服务层接口与实现分离:接口定义契约,实现类只负责业务编排。
- 仓储层方法命名规范化:
findById、updateByXxx、existsByXxx这类命名由模板强制约束。 - 状态机、策略模式等场景的骨架代码:AI只需填充少量业务规则,不需要自己重新发明结构。
这个步骤的意义在于:AI不是从一张白纸开始自由发挥,而是从一个"已经合格"的骨架上开始填充血肉。骨架决定了风格的底线,AI再怎么写,风格都不会漂移到规范之外。
3.2 生成后的四道自动闸门
模板保证了风格的基线,但AI在填充业务逻辑时还是可能自作主张。所以我们又建了四道自动闸门,每次生成之后自动跑。
第一道:AST结构校验。用语法树级别的检查器,直接分析生成代码的结构特征。查命名规范是否匹配团队词表、方法长度是否超标、嵌套层级是否过深、类职责是否臃肿。AST校验的好处是不需要编译,速度快,生成后几秒内就能给出结果,AI可以根据反馈立即自我修正。
第二道:静态规则扫描。接入团队已有的静态分析体系,把SonarQube、ESLint、Checkstyle那一层的规则同步到生成校验里。两道闸门的分工是:AST查结构风格,静态扫描查潜在缺陷,比如空指针风险、资源未关闭、垃圾回收隐患。
第三道:编译与最小单测。AI生成的代码必须真实编译通过,同时生成器自动补一个最小冒烟测试,验证主链路能跑通。这一步直接过滤掉一大批"看起来对、跑起来挂"的生成结果。
第四道:风格漂移比对。我们维护了一个历史代码样本库,每次生成后把新代码与同模块的历史代码做特征比对:注释密度、方法平均长度、命名分布、异常处理覆盖比。如果风格特征漂移超过阈值,生成器会提示"与历史代码风格偏离过大,建议参考XX模板重写"。这道闸门特别有用,它防的不是绝对的对错,而是模块内部的一致性——同一个模块里代码风格天南地北,这本身就是技术债。
四道闸门全部通过,AI生成的代码才算合格,才会被提交。这个流程跑下来之后,我们的Review打回率从四成降到了一成以下。最关键的变化是:Review过程从"逐行纠错"变成了"看业务逻辑有没有漏洞",工作效率提升非常明显。
4. 易调测的落地:可观测性和测试同步生成
4.1 "易调测"在生成器里具体指什么
很多代码生成器只关注"能不能跑",不太关注"出了问题好不好查"。但真实业务里,代码写出来只是开始,后面还有联调、测试、线上排查。一套代码如果只在"刚生成的那一刻"觉得满意,上线出问题时却查不出头绪,那维护成本照样爆炸。我在设计这个生成器时,把"易调测"当成一等公民来对待。
"易调测"至少包含三个层次:第一,代码运行时的状态可观测,也就是有日志、有trace、有关键指标;第二,代码的行为可验证,也就是有单测、有边界用例;第三,问题出现时能快速定位到具体模块和方法,也就是日志里有上下文、异常里有线索。第三十六弹的版本里,我把这三层全部做到了生成流程内部。
4.2 调试辅助信息的自动埋点
先讲日志和trace。生成器的模板里预置了埋点能力:每个关键业务方法自动生成日志语句,内容包括类名、方法名、关键入参、耗时。比如一个订单状态流转方法,生成的日志大致是:
LOGGER.info("[OrderFlowService.handleStateChange] orderId={}, from={}, to={}, elapsed={}ms", orderId, fromState, toState, costTime);这段日志不是AI临场发挥写的,而是模板里写死的规则:关键操作必须记录入参和出参,状态变更必须记录前后值。我们做过统计,线上排查问题时,70%的Case靠"某笔订单从A状态流转到B状态这个动作没有被记录"就找到了根因。调测成本降下来,很大程度上是靠这种看似不起眼的埋点。
4.3 单测同步生成:让代码与测试一起出生
另外一个重点是测试同步生成。以前AI只生成生产代码,测试代码要人后补——后补测试这件事本身就很容易被拖延。现在生成器会在生产代码通过四道闸门之后,自动生成配套的最小单测集,逻辑是这样的:
- 从模板中提取方法签名的入参类型,自动构造正常值、边界值、非法值。
- 从静态规则扫描结果里提取风险点,比如可能返回null的路径,自动补空指针回归测试。
- 从异常处理块识别可能抛出的异常类型,自动补异常路径的断言。
- 对有外部依赖的方法,自动识别依赖类型并生成mock桩。
以我之前做的一个订单状态机服务为例。生成器产出了生产代码和一个二十个Case的小规模测试集,覆盖了:从待支付到已支付的正常流转、重复流转被拒绝、非法状态跳转报错、并发流转时状态冲突、仓储返回空时的兜底逻辑。这套测试集不是AI随便编的,而是根据状态机的状态迁移表和校验规则推导出来的。它可能不是完整的全量测试,但它保证了最关键的主链路和最容易出错的边界路径都有验证。这比"代码写完了、测试以后再说"的思路健康太多了。
4.4 生成窗口里的即时修改
调测友好还有一个容易被忽略的点:修改闭环。AI生成代码后,我看了一眼AST校验报告,提示说某个方法缺少对参数非空的约束,静态扫描又提示说路径上有空的返回值风险。如果是在IDE里,我得切出去打开文件定位那一行,然后亲手改。但在生成器里,我直接在生成结果的反馈区把这个消息丢回对话里:"根据AST校验,请给saveOrder方法补充参数非空约束;根据静态扫描,请修复xxx路径的空返回值风险。"AI马上应用修改,然后又跑一遍四道闸门。这个闭环的核心速度优势在于:人不需要在"大量代码"里找"一小处问题",生成器直接告诉你问题在哪,AI直接改。调测这件事,参数和边界的确定性越高,后面的工作就越轻松。
5. 第三十六弹的新尝试:任务分级路由与提示词收敛
前几弹讲的基本都是生成器的规则引擎和模板体系,到了第三十六弹这个节点,我花了比较多精力做两件新事:一是按任务复杂度把生成请求路由到不同的模型,二是把团队规范彻底收敛进提示词上下文。
5.1 按任务复杂度路由模型:别让高射炮打蚊子
AI编程工具(包括Codex这类付费AI编程软件)圈子里的一个现实情况是:不同模型对同一段提示词的产出质量、稳定性和成本差别很大。不区分任务难度一律用最强模型,成本高不说,某些简单任务还容易出现"杀鸡用牛刀反而过度设计"的情况——一个获取列表数据的接口,AI给你抽象出三层继承两个工厂一个策略模式,看着很酷,维护起来只想哭。
我在生成器里加了一层任务分级路由。判断标准有三个:接口数量、依赖深度、业务规则复杂度。接口数量看一次生成涉及几个对外入口;依赖深度看有没有跨服务调用、有没有外部系统交互;业务规则复杂度看有没有状态机、计算逻辑、权限分支。按这三项打分,简单任务走轻量模型,生成快、成本低、不会过度设计;复杂任务走强模型,上下文窗口大、逻辑推理稳、风格更贴近团队模板。实测下来,生成质量几乎没有下降,但单次生成的模型成本降了大概四成,响应速度也快了不少。
5.2 提示词收敛:把规范写进生成上下文
第二件事是提示词优化。第五弹的时候我就强调过提示词对输出质量的影响,但这一弹做得更彻底。以前是把"需求描述"交给AI,规范什么的靠模板隐式约束。现在生成器每次发请求之前,会先拼装一段项目级规范上下文:团队代码风格、禁忌清单、本模块的技术栈版本、线上排查需要的日志埋点要求、最近三个同类任务的生成经验。这段规范上下文不是写死的,是从项目配置里动态读取的。不同项目、不同模块的规范侧重点不同,生成的代码就不会千篇一律。
这里有个踩过的坑要提醒一下:提示词收敛和模板约束不能互相替代。模板决定的是"骨架和结构",提示词上下文决定的是"AI填空时的偏好"。如果你只靠模板,AI还是会按它自己的惯性填业务逻辑,可能跑偏。如果你只靠提示词,AI可能写出风格正确但结构涣散的代码。两者必须配合:模板是钢筋,提示词上下文是水泥,规则层是监理。少了一样,结果都要返工。
最后一件事:这套玩法最值钱的不是代码,是"规范的长尾效应"
上文聊的都是怎么让AI生成规范的代码,但我在实际落地里最深的一个感受是:这套玩法的长期价值,其实集中在规范本身的长尾效应上——它让团队的保守经验变成了一种可以自动传承的资产。以前代码规范存在文档里,文档会过时,新人会忘记翻。现在规范嵌在生成器的模板、规则、提示词上下文里,AI每次生成的每一行代码都在替你执行这些经验。规范不再是一份没人看的文件,而是一个能持续输出合格代码的管线。
如果你也想做类似的事,我的建议是先别急着追求大而全。先挑团队里最痛的一种代码类型,比如REST接口或者数据访问层,做好模板,建立四道闸门里最基本的编译和AST校验,跑通之后再加静态扫描和风格比对。一点一点补,不要想着一步到位。等这套流程稳定了,你再回头看那些被AI代码折磨的夜晚,就会觉得这一套规则引擎和模板资产库,花的时间全都值回来了。这一弹就分享到这,下一弹我打算拆解一下任务分级路由里具体的评分维度和阈值设计,有兴趣的可以先对照自己项目里最耗时的生成任务琢磨一下。