
1. 先说我为什么在项目里新增了一份给AI看的代码规范这事说起来有点意思。我们团队从半年前开始全面引入AI辅助编码从最早的对话式生成代码到后来把AI Agent直接塞进IDE和CI流程里产线速度肉眼可见地提起来了。但差不多第二个月开始代码review的负责人跟我抱怨说现在看代码的时间反而变长了不是看功能实现而是在帮AI擦屁股。我一开始以为只是个别现象后来统计了一下问题清单发现共性非常明显全局变量满天飞、一个函数写了两百行、异常被静默吞掉、同名方法在两个模块里行为不一致、新增依赖不打申请、测试干脆不写。这些不是业务复杂度造成的是AI生成代码时没人给它立规矩造成的。后来我做了个决定像给新人制定开发规范一样给AI也制定一份专门的代码规范。这份规范不是贴在Wiki里让人看的而是直接作为约束条件注入AI的工作上下文让它每次动代码之前都必须先看到这些规则。两三个月跑下来AI提交的代码质量稳定了一个档次人工review的纠错性反馈大幅减少我现在可以比较有底气地说这条路是通的。这篇文章就把整个过程拆开来讲为什么AI写的代码会越写越乱给AI定规范和给人定规范到底有什么本质区别规范文件具体该写哪些内容、放在什么地方、怎么让它真正生效以及运行一段时间后团队发生了什么变化。如果你所在的项目也在大量使用AI写代码而且你已经开始觉得AI写的东西能跑但越来越难维护那这篇文章应该能帮你少走不少弯路。2. 给AI定规范和给人定规范根本不是一回事在讲具体规范内容之前我花了很长时间想明白一个问题AI不是人不能拿管理人的方式去管理它。很多团队给AI定规范直接把团队原有的《Java开发规范》丢给AI结果发现效果很差原因就在这。2.1 人的规范靠自觉AI的规范靠上下文人的代码规范本质是一种事后的、靠自觉的东西。规范文档放在Wiki里新人入职看一眼老员工也不是每条都记得靠的是code review兜底。你写代码的时候IDE旁边并不会弹出一个你违反了第3.2条规范的提示。AI不一样。AI没有长期记忆它每次生成代码时唯一能依赖的约束条件就是当前上下文窗口里的内容。你给它看的规范它在这次生成时会遵守你没给它看的规范它对天发誓也不会主动执行。所以AI规范的第一个原则是必须注入到AI的工作上下文中而且是每次生成代码都能看到的位置。换句话说AI看规范不是靠自觉是靠你喂给它什么。这就像你请了一个很强的外包工程师他能力没问题但每接一个项目就得重新读一遍你的开发文档读到了就遵守读不到就按自己的习惯写。2.2 AI规范要用指令句式不是参考句式人的规范文档常用应避免使用全局变量建议使用依赖注入这种描述性语言。对于人来说够了因为人能理解背后的设计意图也明白什么时候该变通。AI不一样。模型的本质是概率生成描述性语言给它的约束力非常弱。实测下来同样一条规则用禁止在业务代码中使用全局可变状态和用业务代码中不允许出现var globalXXX ...所有状态必须显式声明在类或函数作用域内这两种表述AI的遵守率差了非常多。前者AI大概率当废话跳过后者它才会真正当一回事。所以在制定AI规范时我定了一个硬性要求所有规则必须明确区分**禁止做什么和必须怎么做**而且尽量给出反例与正例的对照。别跟AI讲道理直接告诉它这个不行用那个替代。2.3 AI规范必须可自动校验不能只靠人看人的规范写再好最终还是要人去看。AI生成代码的量级是人写的好几倍光靠人目测review根本看不过来。所以AI规范还有一个隐藏要求凡是能用工具自动check的规则就不要只停留在文字层面。比如不允许出现未捕获的异常这种规则你给AI提示一百遍它还是可能在某些角落漏掉。但你在lint或CI里配置一个规则让漏掉的代码直接构建失败AI下次就会特别老实。文本规范解决的是AI的主观能动性问题工具规则解决的是底线兜底问题两者缺一不可。在这里也顺手列个表把人和AI的规范差异说清楚维度给人看的代码规范给AI看的代码规范作用时机事后对照、抽查、review事前注入每次生成都影响语言要求描述性、解释意图指令式、禁止/必须、带示例承载形式Wiki、文档、PDF上下文文件、rules文件、agent指令包执行保障人为检查静态检查、CI流水线自动拦截更新频率低频年更高频跟随AI表现持续迭代粒度原则性为主细节到命名、函数长度、依赖清单3. 这份AI代码规范具体写了什么可直接抄走明确了原则之后最重要的就是内容本身。我们项目的AI规范文件不是一篇散文而是一份结构化、指令化的操作手册。下面我把核心章节和代表性规则列出来你可以直接拿着裁剪成适合自己的版本。3.1 技术栈与依赖红线这一节解决的是AI最爱犯的毛病自作主张引入新东西。AI对项目现有的技术栈是有感知的但这种感知很浅一旦遇到它觉得这里用个第三方库更方便的场景它就很容易随手给你加一个依赖。短时间看是省事长期看就是依赖爆炸、版本冲突、许可证风险全来了。我们的规范里对应写的是禁止在未经确认的情况下新增任何第三方依赖。框架选型必须遵循项目现有技术栈后端Spring Boot 3.x MyBatis-Plus前端Vue 3 TypeScript禁止引入新的框架。如确实需要引入新依赖必须先在对话中说明依赖名称、版本、用途、体积和替代方案得到确认后才允许写入pom.xml或package.json。禁止将AI建议但未经验证的依赖直接写进构建文件未使用的依赖必须在提交前移除。禁止通过npx、mvn dependency:get等方式临时拉取依赖绕过依赖管理。3.2 代码风格与结构约束这一节最核心的目标是约束AI生成代码的形态与边界。AI很擅长写长函数——因为它缺少拆分的必要性这种审美判断只知道把逻辑从头到尾输出完。我们当时统计过AI生成的Java方法体有接近三成超过80行有些甚至一个方法里同时处理了参数校验、状态转换、持久化和日志打印。规范如下单个方法体的代码行数不超过50行超过必须拆分。这个数字我们定得比较保守目的是逼迫AI主动考虑抽象。禁止在Controller中直接写SQL、操作Redis或调用第三方APIController只允许做参数接收与结果返回。业务逻辑必须下沉到Service层。类的行数不超过300行。超过时AI必须主动拆分为多个类并确保单一职责。方法的入参不超过5个。超过时使用参数对象封装。这条能有效避免AI生成那种一长串参数的可读性灾难。禁止使用var/auto绕过显式类型声明除非项目本身的代码风格允许。字符串拼接待SQL、日志、URL、文件路径时必须使用模板或占位符禁止手动拼接。3.3 错误处理与边界条件这是AI的另一个重灾区。AI生成代码时倾向于走正常路径——数据能查出来、接口能正常返回、文件一定存在。它对异常分支和边界条件的想象力非常有限。规范措施所有调用外部服务、数据库、文件系统的代码必须显式处理失败分支。允许抛出异常但不允许catch后什么都不做。禁止catch(Exception e)后打印日志就算处理完必须包含可执行的降级逻辑或重新抛出业务异常。所有接口的入参校验必须在进入业务逻辑之前完成不允许在Service内部才发现参数为空才抛出NullPointerException。对数组、集合、字符串的所有下标/索引访问必须考虑越界和空值场景不允许假设数据一定存在。如果AI生成的分支逻辑中出现了else必须检查else分支内是否为重要状态赋值或异常处理禁止空else。3.4 数据一致性与并发安全AI对并发场景的处理能力目前是比较弱的。它知道加锁这个词但什么时候该用乐观锁、什么时候用悲观锁、什么时候用分布式锁它经常判断错误。规范里我们写了非常明确的判定标准共享可变状态在并发场景下必须显式使用锁、原子类或不可变对象禁止直接使用普通字段跨线程读写。禁止在多线程环境下使用SimpleDateFormat、HashMap等非线程安全类除非每次使用时重新new。对于事务方法禁止在事务内做远程调用、长时间IO或等待锁防止长事务阻塞数据库连接池。批量数据处理时必须考虑分批提交或分页禁止一次性加载全表数据到内存。涉及金额、库存、积分等关键数据的更新必须在更新语句中包含条件判断防止覆盖写。例如UPDATE t SET status 2 WHERE id ? AND status 1。3.5 测试与验证要求AI生成代码之后自动补测试这个能力其实是有的但前提是你明确要求它做。你不说它默认只写主代码。我们加了这一节每次生成或修改功能代码后必须同步生成或更新对应的单元测试测试类与主代码类同包、同模块。测试方法命名使用方法名_场景_预期结果格式例如calculateFee_当金额为负时_抛出异常。禁止删除或注释已有测试除非测试因需求变更而失去意义此时必须同步更新测试。对于对外暴露的接口测试必须覆盖成功路径、参数错误、依赖服务异常三个场景。生成的测试不要求100%覆盖率但核心业务分支覆盖要求不低于80%。3.6 安全与合规红线AI对数据安全和合规的理解本质上是训练数据里的常识而不是你项目的规矩。所以安全红线必须写得又细又硬禁止在代码中以明文形式出现密码、Token、API Key、数据库连接串等敏感信息。所有密钥必须通过配置中心或环境变量注入。日志输出禁止打印完整的用户手机号、身份证号、银行卡号、支付单号等个人敏感信息必须脱敏。禁止将生产环境的数据库地址、内网域名、服务器IP硬编码进代码或配置文件。SQL操作禁止通过字符串拼接方式执行即使是mybatis的${}也不允许必须使用预编译占位符#{}。涉及文件上传的接口必须校验文件类型白名单和文件大小禁止使用原始文件名直接写入磁盘。不熟悉的加密/签名算法禁止自己实现必须使用项目已引入的标准库组件。3.7 文档与注释AI写注释的能力从话痨到失语都有多数情况是给每行代码都加一句没营养的注释。我们直接做了限制禁止为方法内部的每一行代码写注释。允许在方法头部注释说明业务逻辑、入参含义、出参约定、异常类型。对非显而易见的复杂逻辑比如状态机转换、位运算、正则表达式必须在逻辑上方用自然语言解释意图。公共方法必须使用Javadoc或TSDoc规范生成文档注释参数、返回值、异常必须齐全。AI生成的注释中禁止出现由于、因为、如果需要修改这里等含糊表述。注释必须精确说明做了什么和为什么这么做。4. 规范文件放哪、怎么让它生效决定了它会不会成为摆设内容写好了如果只是存在一个文件里扔到仓库根目录那它跟Wiki里的文档没有任何区别。要让AI真的遵守关键在于它能不能在每个工作环节都看到这些规则并且违反规则能不能被自动拦截。4.1 把规范做进AI的可加载上下文里现在主流AI编程工具基本都支持rules文件机制。我的做法是把规范拆成两层第一层是RULES.md放在仓库根目录部分工具也约定读取.cursor/rules、.claude/rules等目录工具会自动把它挂载到每次会话或每个文件编辑的上下文中。这一层的规则是常驻的AI只要在这个仓库里活动就必须持续看到这些内容。第二层是按模块细化的规范文件比如docs/ai-rules/backend-rules.md、docs/ai-rules/frontend-rules.md放在具体代码模块内。这些文件不会被全局加载但在AI处理对应模块代码时可以通过提示词工具或MCP配置把模块规范动态注入。这样做的好处是避免了大而全的规则把所有会话上下文都占满AI反而抓不住重点。文件结构大致是这样的project-root/ ├── RULES.md # 全局规则第一优先级 ├── .cursor/rules/ # AI工具自动读取的规则目录 │ ├── 01-global-rules.mdc │ ├── 02-backend-rules.mdc │ └── 03-frontend-rules.mdc ├── backend/ │ ├── docs/ai-rules.md # 后端专属规则 │ └── src/... ├── frontend/ │ ├── docs/ai-rules.md # 前端专属规则 │ └── src/... └── docs/ └── ai-code-standards.md # 给人阅读的完整规范原文4.2 用静态检查和CI机制兜底文本规范的力量终归有限所以我把能自动化的部分全部拆解成工具规则。ESLint、Checkstyle、SpotBugs、SonarQube这些工具能把规范里的大部分内容变成自动校验项。举几个实际配置的映射关系禁止catch后不处理异常 → SpotBugs规则REC_CATCH_EXCEPTION禁止明文密钥硬编码 → 自研扫描脚本基于正则匹配检测常见密钥格式禁止直接拼接SQL字符串 → PMD规则或Checkstyle自定义规则方法体不超过50行 → Checkstyle的MethodLength限制禁止在Controller中直接操作持久层 → ArchUnit单元测试做架构约束这些规则直接进CI流水线提交代码时自动执行。不要觉得服务器上跑一遍会拖慢效率实际上从长期看机器拦截一次违规比人review时争论十分钟要便宜得多。AI被CI打回几次之后生成代码时就会长出记性。4.3 规范文件要设计成AI一眼能找到重点这里有个很实用的经验RULES.md的头部一定要放摘要索引就像一个AI快速导航。因为AI虽然有上下文但上下文太长它会失去注意力专业说法叫lost in the middle。如果规范有几百行模型在处理任务时未必能全部有效利用。我们的RULES.md开头是这样写的# AI代码规则本仓库强制约束 优先级此文件优先级高于AI默认输出习惯。如果项目内其他文档与本文件冲突以本文件为准。 摘要 - 新增依赖必须申请本仓库只允许使用pom.xml/package.json中已存在的依赖。 - 方法体不超过50行Controller禁止直接写SQL。 - 所有外部调用必须处理失败分支catch禁止吞异常。 - 禁止硬编码任何密钥禁止打印未经脱敏的个人数据。 - 每次提交必须包含或更新相关单元测试。 - 详情见docs/ai-code-standards.md这几行摘要虽然短但每一句都对应一个高频违规点。AI哪怕只读到前缀都能在生成代码时被拉回正确的轨道而详细规范作为补充在它需要时可以继续阅读。4.4 在AI提示词里叠加当前任务约束除了全局规则我还建议在发起具体任务时在提示词里主动声明本次任务的约束范围。比如让AI改一个支付服务的方法时提示词里显式加上遵循RULES.md中的错误处理与数据一致性规则和本次不允许修改的模块包括xxx生效概率会显著提高。这种方法适用于那些需要AI在特定任务中绕过全局规则临时特批的情况。比如系统架构明确允许某个非常规写法那么临时约束可以覆盖全局规则但必须在对话里说清楚这是例外仅本次任务有效。5. AI代码规范运行三个月后团队发生了什么变化规范从1.0版本开始运行到现在差不多过了三个月。不说虚的直接看几个可量化的变化。第一是代码review的焦点彻底变了。以前review AI的代码主要精力在纠错——这个异常应该抛出去这个scope不对这行不应该出现在Controller里。现在这些问题被规则前置拦掉了大部分review开始聚焦业务逻辑是否正确、接口设计是否合理、性能有没有隐患。这是质的区别。第二是AI写的代码和个人写的代码风格收敛了。最直观的感受是同一模块里不会再出现两种截然不同的命名习惯和结构组织方式。以前AI和人对同一个功能的实现方式经常是各写各的现在因为AI有强约束人也会被代码风格反推着往同一个方向走。第三是CI的红灯减少了不少。以前CI失败的原因很多都是一些低级错误漏了分号、缩进不对、依赖没引全、日志级别写错。规范上线后这些静态层面的低级错误工具规则直接兜住了。AI在本地生成代码时就会根据反馈修正很少带着明显错误试图蒙混过关。当然中间也踩过一些坑值得单独说一下。规则数量不是越多越好。我们第一版规范写了接近五十条规则把AI上下文填得满满的。结果效果反而差AI处理复杂任务时会分心部分规则被它选择性忽略那些最关键的几条红线反而约束力下降了。后来砍到了二十条核心约束效果立刻回暖。目前我们的策略是RULES.md里只放最核心的、最频繁触发的规则其余细枝末节的全部下沉到具体模块的规则文件里按需加载。规范要跟上AI能力的更新但它不等于补丁式更新。AI模型升级到新版本之后代码生成能力和风格都会变化原来会犯的错误可能不犯了但新的问题又会冒出来。我现在的做法是每月花半天时间过一遍近期AI代码的问题清单把高频问题加入规范同时把已经不再出现的问题从规则里拿掉。规则是活的不能写死。规则冲突要有明确的优先级声明。一次项目中AI同时读到了团队老规范文档和新的AI规则文件两条对Controller层能否直接调用第三方SDK的定义是相反的AI默认采取了老规范的做法结果被CI拦下。后来我在所有规范文件头部都加了一行本文件与其他项目文档冲突时以本文件为准并且把所有AI会读取的文档都检查了一遍避免规则冲突导致AI行为飘忽。还有一个小细节规范文件里每条规则尽量写一句话为什么但不是给人看的是给AI判断是否适用用的。AI在不完全匹配的场景下可以根据规则意图做类比推理。比如Controller禁止直接写SQL的意图是分层清晰和可测试性当AI面对一个是否把Redis操作放进Controller的问题时它能根据意图推导出也不该放。有了意图说明规则从死规矩变成了活经验。最后分享一个实际操作里的技巧如果你现在就要开始给项目里的AI定规范我建议不要一次写完所有条目再发布。更好的做法是先定一个只有五到六条最核心红线的初版比如禁止乱加依赖、方法不能过长、异常不能吞、密钥不能硬编码、必须写测试跑一到两周观察AI在这几条上的遵守率。然后把这段时间发现的高频问题一条一条补进去。我自己实际测试中第一批规则里禁止catch后什么都不做和禁止硬编码密钥是见效最快的几乎改完就能看到AI的产出变化。而方法体不超过50行这条AI一开始不太适应需要CI的硬拦截配合两周之后它才逐渐养成拆分习惯。给AI定代码规范这件事本质上不是限制AI而是帮AI把正确的事做对把不该做错的事挡在提交之前。很多团队踩的坑其实是没想明白这个逻辑对AI寄予了太高的自觉性期待结果就是AI自由发挥团队疯狂救火。希望这份经验能帮你绕开这些弯路。