
这段时间团队里一直在做AI辅助编程的深度落地用下来最大的感触是AI确实能写代码但它写出来的代码默认是“全网平均水平”而不是你项目的平均水平。前阵子我们项目里正式新增了一份专门给AI制定的代码规范这期间踩了不少坑也沉淀了一套自己的方法论写出来分享给正在头疼AI产出代码质量的团队。先说背景。项目从去年开始大规模使用AI编程从IDE插件到独立Agent都试了一圈效率提升确实明显但随之而来的问题是AI生成的代码风格五花八门命名混乱、分层随意、异常处理缺失、安全漏洞频发每次Code Review都像是在开盲盒。大家一开始觉得是AI能力不行后来发现问题的根源在于——我们从来没有正儿八经地告诉AI这个项目的代码到底该怎么写。人类开发者入职要看新人文档、要过代码规范、要在Review里被反复纠正AI却一上来就直接裸奔训练数据里的“平均风格”就是它的默认风格。所以这次我们做的就是给AI补上一份它必须遵守的“入职手册”本文就把这份规范的内容、制定思路和落地过程中的经验教训一并说清楚。1. 为什么要单独给AI制定一份代码规范人类规范和AI规范的差异很多人第一反应是项目不是已经有代码规范了吗直接把现成的规范丢给AI不就行了。这个想法我们一开始也有实际跑下来会发现完全行不通。人的代码规范一般长这样“Service层禁止直接使用Mapper必须通过Repository中转”“事务注解只允许加在Service实现类上”“返回给前端的实体类不得直接暴露数据库字段”。这些话人类开发者能看懂因为人脑会自动补全上下文知道“禁止”背后的原因是什么知道什么场景算违规、什么场景算特例。但AI不一样。AI对自然语言的理解是概率式的你告诉它“禁止”它可能理解为“建议不要”你告诉它“必须”它可能理解为“大多数情况下要”。更麻烦的是人的规范通常描述的是意图和原则缺少具体的正反例AI在生成代码时就会按照训练数据里的最高频写法来输出十次有八次会踩中规范的红线。所以给AI看的代码规范本质上不是一份“规范”而是一份“约束性Prompt工程文档”。它需要满足三个条件确定性每一条规则都要有非黑即白的判断标准不能用“尽量”“优先”“合理”这类模糊词。可执行性规则要细到AI能在生成代码时直接套用而不是让它自己去领悟。嵌入性规范不能独立于开发流程存在必须能被注入到每一次AI生成任务的上下文里。理解了这三点再回头看市面上的通用做法——把Wiki里的代码规范复制粘贴到对话窗口里——你就会明白为什么效果那么差。AI的上下文窗口有限你的规范可能比它一次能处理的Token还长贴进去之后AI只能在前面部分保持注意力后面早就忘了。这就要求规范的形态必须重新设计而不是简单复用现成文档。2. 落地第一步梳理项目里的“高频雷区”和“核心约定”制定AI代码规范的第一步不是急着写规则而是先做一次系统性的盘点。我们花了大概两天时间把最近三个月AI生成的所有代码提交记录拉出来逐个Review统计出AI最容易犯的错误类型和频率。这里要特别强调一下“盘点”的意义AI代码规范一定要基于你项目真实的痛点来定制而不是照搬网上的某个AI编码规范模板。每个项目技术栈不同、架构约定不同、团队偏好不同AI犯错的模式也完全不同。比如我们项目用的Java 21 Spring Boot 3 MyBatis-PlusAI犯的最多的错是这几类第一分层混乱。Re: zero生成代码时经常把业务逻辑直接写在Controller里或者跳过Service层直接在Controller里new一个Mapper来查询数据库。第二异常处理缺失。AI生成的代码里大量存在吞异常的情况——catch Exception之后打印一行日志就完事完全没有向上抛错或转换为业务异常的意思。第三实体类设计随意。用LocalDateTime还是Date、字段命名是否带类型前缀、是否使用包装类型AI总是按训练数据的平均概率来选择而这些细节恰恰是团队代码规范里最在意的。第四也是最隐蔽的SQL和MyBatis-Plus的用法问题。比如分页查询不校验页码、批量插入不处理主键冲突、逻辑删除字段被直接拿来当普通字段用这些都是只有踩过坑的人才知道的约定训练数据里根本不会体现。把这些高频问题整理成一张表格每一项都标注上发生的频率、影响的严重程度、涉及的代码分层或模块然后从中筛选出Top 10左右的高价值规则。规则数量不要贪多AI的注意力是有限的你给它五十条规范它可能一条都记不住给它十条关键规范反而能确保每条都被执行。有了这样一份“高频雷区清单”接下来写的每一规范条目都是有的放矢的。这比凭空想一个“AI代码规范”要靠谱得多因为每一条规则背后都有真实的事故案例支撑你在写具体表述时也更有底气。3. 规范的具体形态一个可被AI理解的规则清单长什么样盘点完之后就是重头戏——把盘点结果转写成一份AI能真正理解和执行的规范文档。我们最终把它命名为AI_CODING_RULES.md放在项目根目录方便各种AI工具通过路径直接加载。这份文档的结构我建议按“通用原则、编码风格、分层架构、API与数据库、异常与日志、安全与测试”来划分。听起来和人的规范文档结构差不多但每条规则的表达方式必须彻底重写。我这里拿我们项目里的几条规则做例子你可以感受一下差别。通用原则层最容易出问题的其实是包名和类名的语义一致性。比如一个用户模块AI可能在一次会话里生成UserController、UserInfoController、MemberController三个不同命名的Controller原因只是它认为这几个名字都“挺合适”。所以我们的规则明确写了每个模块必须有且仅有一个对外Controller命名必须与模块名一致新增Controller前必须先检查已有Controller是否已覆盖当前功能。这种规则对人是废话但对AI是必要的确定性约束。编码风格层我们重点管住了两个细节点。第一是日志AI特别喜欢动不动就来一个log.info(xxx data)我们的规则清掉了所有字符串拼接日志统一要求使用占位符log.info(xxx: {}, data)并明确禁止打印任何敏感字段和全量SQL。第二是注释AI生成的注释经常是“这段代码用于获取用户列表”完全正确的废话规则里直接写了一刀切的要求代码本身能表达意图的情况下不允许添加任何解释性注释只有非业务的技术决策才需要注释说明原因。API与数据库层这块规则最多也最细。接口定义上我们要求所有REST接口返回统一响应体ResultT分页返回PageResultT禁止把MapString, Object当万能返回类型。数据库操作上有一条规则专门针对MyBatis-Plus的selectList严禁在循环里调用查询方法必须一次性查出后在内存里做关联匹配。单看这条规则没什么稀奇的但AI在生成批量接口时特别容易写出循环查询而且性能测试还很难发现这种问题。每条规则我们都尽量配了正例和反例篇幅不长但足够明确。这里要说明一下这份文档不仅要给AI看也要给人看所以表达上还是需要一定的可读性不能纯写成“冷冻的提示词”。4. 如何让AI每次都“想得起”规范上下文注入的工程化方案好规范文档写完了怎么让AI在每次生成代码时都带上它这是整个落地过程中最难、也最有意思的一部分。你不可能指望开发者每次在对话窗口里手动粘贴一份几百行的规范大家嫌麻烦而且不同人粘贴的版本可能还不一样。我们试验了三种方案最终形成了混合策略。第一种方案在IDE插件里配置全局指令。像JetBrains AI Assistant和CI面上这些AI插件一般都有Global Instructions或者自定义规则的地方可以把规范文档的核心摘要配置成每次对话都会自动携带的指令。这个方案的优势是零成本、全自动Chat模式下所有成员都能覆盖到。缺点也明显上下文窗口被挤占规范太长时反而干扰AI理解当次的业务提问所以这里只能放“核心摘要版”大约300字以内。我们放的是总共七条不可违反的高压线禁止循环查询数据库、禁止裸返回内部实体、禁止吞异常、禁止字符串拼接日志、禁止未经确认直接修改公共模块代码、禁止生成未使用的import和字段、禁止在Controller里写业务逻辑。第二种方案针对独立Agent做系统提示词嵌入。我们团队用了一些能独立执行多步骤任务的Agent这类Agent可以通过System Prompt加载规范。这个方案能承载更长的规则内容因为系统提示词不占对话上下文Agent执行的第一步就会自动读取规范文档。我们是把完整版的AI_CODING_RULES.md放在一个约定好的路径下并在系统提示词里写明“第一步读取项目根目录下的AI_CODING_RULES.md并对其中的规则逐条自检后再开始生成代码”。实测下来这个方案的成功率很高因为Agent有了一个“显式的读取动作”而不是被动等待规范被塞进上下文。第三种方案Review阶段用自动化检查工具兜底。再好的规范注入也不能保证AI百分百不违反规则。所以我们给CI流程加了一步提交代码时自动跑自定义规则检查。像Java项目可以加PMD和Checkstyle的自定义规则把规范里的核心条目转写成自动检查项。比如禁止循环内查询数据库这条用静态分析工具是能识别出来的。这个方案的价值在于形成闭环AI违反规范被工具拦截开发者修改下次AI再生成时就会因为类似代码被Review过而变得更收敛。要特别提醒的是第三种方案不能完全依赖现成的开源规则集因为那些规则也是“通用水平”拦截不了你项目里真正在意的那几条约定。花一个下午把高频雷区清单转写成自定义检查规则投入产出比是很高的这部分我们后续可以单独详细聊。5. 实测数据对比有规范和无规范AI代码到底差多少光说不练没什么说服力。这里分享一组我们内部的实测数据你就能直观感受到给AI制定代码规范的价值。我们选了三个典型的业务开发任务做对照测试一个是标准的分页条件查询接口一个是用户下单并扣除库存的复杂事务方法还有一个是需要对接第三方API并做异常兜底的同步接口。每个任务让AI分别在没有规范注入、有摘要版规范注入、有完整版规范读取三种情况下各生成一遍代码然后由两个资深工程师盲评。结果非常有意思。无规范直接生成时第一个分页查询接口就出现了两个问题PageNum和PageSize没有做边界校验、返回值直接暴露了数据库实体。第二个复杂事务方法更惨直接在Controller里加了一个事务注解而且异常处理是catch之后printStackTrace。第三个接口倒是完成了基础功能但没有统一响应体包裹超时配置写死成5秒完全没法上线用。有摘要版规范注入后明显好转分页查询接口的校验加上了事务方法也能基本做到分层清晰异常处理逻辑也规范了。不过第三个对接第三方API的任务还是出了幺蛾子——AI把第三方返回的整个JSON塞进了响应体因为摘要里没有覆盖“对外返回结构必须裁剪”这一条。完整版规范读取的效果是三个任务一次通过率最高所有硬性规则都被遵守代码Review基本只需要看业务逻辑不需要动结构。最惊喜的是事务方法AI不仅正确处理了事务边界还根据规范里“事务方法不允许被同类内部调用”的规则主动调整了调用方式。这种推理能力不把规范喂到它嘴里它是不会自动触发的。当然这个对比也暴露了一个现实规范覆盖的越全AI的表现越好但规范的维护成本也在上升。所以我们最终采用了“核心摘要常驻完整规范按需读取CI工具兜底”的三层架构在效果和维护成本之间取了平衡。6. 踩坑实录给AI立规矩过程中遇到的意外情况制定和落地AI代码规范的过程中我们也走了不少弯路这里集中分享几个比较典型的坑希望能帮后来者跳过。坑一规范写得太“人类化”AI假装遵守实则跑偏。比如我们最初有一条规则写着“确保数据查询效率”AI确实没在循环里查询了但它把一次全表查询的结果在内存里反复过滤性能比原来更差。后来我们把这条规则改成具体的硬性约束“单个请求内数据库查询次数不得超过N次”这类可量化指标AI才能真正落地执行。坑二规则之间有冲突AI不知道听谁的。我们项目里有一条规范说“禁止使用Date统一使用LocalDateTime”但同时又有一条“禁止写类型转换工具类”AI生成代码的时候就会困惑——万一第三方SDK返回Date怎么办后来我们把类似的冲突场景都做了优先级说明规则本身也加了“除非是对外SDK必须使用的类型”这类例外条件彻底消除歧义。坑三AI对“规范文档”本身的黏性不够。我们最初在系统提示词里写“请遵守项目规范”结果AI压根没有主动去查看规范文件的动作等于白说。后来改成“第一步必须读取AI_CODING_RULES.md并从中提取本次任务需要遵守的规则”效果一下子就不一样了。这里的关键是给Agent一个强制性的行为序列而不是依赖它自己觉得“该去看看规范”。坑四规范被人为绕过。这个坑很隐晦但很重要一旦开发者觉得AI生成的代码要改来改去太麻烦就会在Prompt里补充“不用管那些规则直接生成就行”AI是会顺从的。所以光有规范和工具还不够还要在团队层面达成共识——AI代码规范和人类代码规范是同等地位的都不允许通过自然语言指令绕过。我们最后甚至还约定Review时如果发现AI故意违反规范整个任务打回重写不允许手动修修补补就提交。7. 维护与迭代这份规范应该是活的不是一潭死水最后聊聊AI代码规范的更新机制。这是最容易被忽视、但长期来看最重要的一块。我们的规范文档从初版到现在已经迭代了十几个版本每次迭代基本都来自两个触发点。第一是新增了技术栈或中间件规范必须同步扩展。比如我们后来接入了Redis缓存就新增了缓存Key命名规范、缓存穿透防护要求、以及禁止缓存业务实体对象等条款。第二是有新的AI违规模式暴露出来比如某个模式在Review中反复出现但规范里没覆盖到我会第一时间把它补进去然后在下个迭代周期重新跑一遍AI生成测试集验证新规则确实能被AI遵守。每次迭代规则都建议同步测试集。我们不光是改文档还会维护一个包含十几个典型任务的小测试集每次规范更新后让AI在同样的Prompt下重新跑一遍测试集对照前后差异确认更新没有引入新的问题也没有让AI“矫枉过正”。有一个经验值得分享不要一口气加太多规则。AI对规则的遵循程度和规则总量之间有一个心理物理曲线规则加到一定数量后每新增一条之前的某一条被无视的概率就会上升。所以我们把规则分为“不可违反的高压线”和“建议性的偏好”两档高压线控制在十条左右其他偏好放在附录里只对特定任务类型注入。这样既保证了核心约束的执行率又不至于让AI因为规则过多而变得过度保守、不敢正常写代码。另外规范文档本身建议纳入Code Review的检查范围。项目里任何一次技术方案讨论如果产生了新的约定应当顺手更新AI_CODING_RULES.md这样才能保证人写的代码和AI写的代码长期保持一致不会出现“人类规范一套、AI规范另一套”的分裂状态。