
1. 为什么AI写代码总是不守规矩1.1 现象一行热搜词背后的真实工作场景最近一段时间“go在ai”“编码添加编码规范约束”这两个词条开始在技术社区里频繁出现。我一开始没太当回事直到自己手头一个订单模块的改造项目被AI“坑”了一把才意识到这个问题的分量。当时我让AI写一个分页查询接口需求很简单按订单状态过滤支持页码和每页条数参数返回规范的分页数据结构。结果AI交出来的代码功能上完全能用但实现路径让我血压直接拉满——它为了“更聪明的实现”绕过项目里统一封装好的数据访问层直接在Controller里组装查询条件还顺手定义了一个新的分页返回类型。代码能跑但和团队既有架构完全不搭评审会上被同事追着问了半天“这是谁写的”。这件事让我想明白一个道理AI编码工具的能力边界不在于“能不能写”而在于“知不知道你的项目是怎么写的”。大多数时候代码质量失控不是因为模型不够聪明而是因为约束根本没有传递到AI的上下文里。于是我开始系统研究“AI编码的项目规范约束”——也就是project规范把团队多年沉淀下来的架构约定、代码风格、提交流程转成AI能读取、能理解、能执行的规则体系。这篇文章我不会去讲那些“AI会取代程序员”之类的空话而是基于最近的实战经验把如何为AI编码建立项目规范约束这件事拆开揉碎约束什么、怎么落地、生效原理、踩坑排查、效果如何。适合正在重度使用AI编码工具、被生成代码“野路子”搞到头疼的开发者以及想把AI编码纳入团队规范化流程的技术负责人。1.2 认知误区不是AI不够聪明是没给它“上下文”先纠正一个普遍存在的误区。很多人觉得AI生成代码不符合项目规范是模型能力不行所以换个更强的模型就能解决。我在实践里的结论是模型能力确实会影响代码质量的上限但规范一致性主要取决于上下文而不是模型智力。打个比方一个刚入职的资深工程师技术能力再强第一天上来也不可能写出完全符合团队风格的代码。因为他不知道你们的目录结构为什么这样划分不知道你们对事务边界有什么特殊约定不知道为什么错误处理统一走某个自定义异常而不是直接抛RuntimeException。这些知识只能通过团队规范文档、代码评审意见、历史提交记录来获得。AI编码工具面临的困境一模一样。它在大规模训练语料里学到的是“通用编程常识”但你的项目有大量“本地知识”——私有架构约定、内部工具库、领域术语表、编码习惯。这些信息不会自然出现在模型的输出里除非你用某种机制把它喂进去。这就引出了project规范概念的核心价值它不是一份写在Wiki里没人看的文档而是一套结构化、机器可读、能持续注入到AI编码流程里的约束体系。它的作用相当于把老师傅脑子里那些“只可意会不可言传”的规矩变成AI在工作开始时就能看到、能遵守的显式契约。2. 项目规范约束到底在约束什么2.1 规范约束的四个核心维度在动手设计规范之前需要先回答一个问题project规范到底应该管到什么程度我的经验是约束太少等于没约束约束太多会让AI的产出变得僵硬甚至影响功能实现质量。合理划分维度是第一步。维度一架构边界。这是最重要的约束直接决定AI生成的代码会不会破坏系统架构。典型内容包括分层职责Controller层只做参数校验和响应组装Service层承载业务逻辑数据访问层统一走仓库接口、模块依赖方向订单模块不允许反向依赖用户模块的存储实现、扩展点约定新增支付方式必须实现指定接口并注册到工厂。我在实践中发现明确声明“不允许做的事”比声明“应该做的事”更有效因为AI特别容易在遇到能力边界时自作主张开辟新路径。维度二代码风格与模式。这一块很多团队会忽略觉得风格问题让lint工具管就行。但实测下来AI生成的代码在lint级别往往没问题问题出在“软性风格”上——比如项目习惯用Result对象包装返回值而不是裸返回实体、分页查询必须走项目封装好的PageQuery基类、日志必须包含traceId和业务单号。这些约定很难用lint规则表达但一旦写进规范文件AI的执行率非常高。维度三工作流约束。AI编码不止生成代码还涉及提交信息、分支策略、变更范围。我在规范文件里明确要求commit信息必须遵循Conventional Commits格式并用中文描述核心改动、AI不得直接修改主干分支、生成的变更请求必须包含自测结果说明。起因是有一段时间AI生成的PR描述极其敷衍评审人根本看不懂改动意图浪费了大量沟通成本。维度四安全与合规边界。这个维度目前讨论的人不多但我觉得最值得投入。AI生成代码时可能无意识地把敏感信息写进日志、绕过权限校验、直接在代码里拼接SQL。规范文件里必须划出红线区域涉及资金计算、用户敏感信息、权限判断的代码AI只能生成草案必须标记为“需人工重点审查”。另外要明确规定AI生成的内容不得包含注释掉的调试代码、不会输出密钥或内部地址。2.2 约束粒度要适配编码流程的不同阶段规范约束不是一份文件打天下粒度和形式要跟随编码流程切换。我在实际操作中把它们拆分成了三档。需求到设计阶段的粗粒度约束。这个阶段AI主要用于方案咨询、代码影响面分析、生成任务拆解。规范约束重点放在“框架级事实”上项目技术栈、目录结构、关键模块职责、核心依赖版本。粗粒度约束的目的是让AI在理解任务时建立正确的全局认知避免从一开始就跑偏。编码阶段的精确约束。当AI开始实际写代码时约束要下沉到函数级、类级。比如“查询列表必须分页”“状态流转只允许通过状态机服务变更”“禁止在Service层直接调用外部接口”。这个阶段我倾向于把规范按模块拆分让AI只加载与当前任务相关的规范片段既保证精度又控制上下文长度。评审阶段的兜底约束。AI生成的代码进入人工评审或自动检查阶段后规范约束的作用从“指导生成”变成“校验结果”。这块要靠CI流水线里的静态检查、lint规则、架构守护工具来落地保证AI的输出即使没有完全遵守规范也不会漏过防线。三档粒度的协同逻辑很简单粗粒度负责方向正确精确粒度负责细节对齐兜底粒度负责风险拦截。缺少任何一环规范约束的效果都会明显打折。3. 把规范落成AI看得懂的文件结构3.1 规范文件的关键设计位置、命名与读取优先序规范的内容再完善如果形式不对AI可能根本不会读取。这是我在踩坑后最想强调的一点。AI编码工具在工作时会主动读取项目里特定名称的文件来做上下文初始化。不同工具支持的规则文件类型不完全一样有的读取根目录下的规则描述文件有的会识别项目说明文档有的支持仓库级别的自定义指令。但有一个共同规律越靠近项目根目录、命名越标准的文件越容易被工具自动加载。所以我的建议是把核心规范放在项目根目录下用一个固定的、行业内通用的文件名比如项目说明文件或贡献指南文件这类约定俗称的命名。不要起一个特别文艺的名字比如“code-spirit.md”这种AI工具未必能识别那这份规范就形同虚设。另外要处理好文件的层级关系。我实测下来三层结构最稳第一层项目根目录的全局规范文件放所有模块共用的底线规则。第二层各模块目录下的局部规范片段只放该模块的特殊约定。第三层变更请求模板或提交信息模板约束AI提交产物的格式。这样设计的好处是AI在处理具体模块任务时只需要加载“全局规范当前模块的局部规范”两份内容上下文开销很小约束精度反而更高。如果一份文件塞了几百行全项目规则AI实际执行时容易“忘记”后半段内容。3.2 一份可执行的项目规范文件的基本结构直接给一个我验证过比较有效的规范文件结构模板仅供参考。注意这份模板的精髓不在于字段齐全而在于每条规则都具备“可执行性”——要么能被AI直接翻译成代码行为要么能被CI自动检查。# 项目说明 ## 项目简介 一句话说明项目职责、核心业务领域、主要用户角色。 ## 技术栈 列出核心语言、框架、数据库、消息队列、缓存等关键组件及版本。 ## 目录结构与模块职责 逐个列出顶层目录/模块的职责边界明确“哪个模块不允许做什么”。 ## 核心编码约定 1. 列表示例Controller只负责参数校验、调用Service、封装响应禁止在Controller写业务逻辑。 2. 列表示例所有对外接口返回值使用Result包装。 3. 列表示例分页查询必须使用项目统一的PageQuery基类。 4. 列表示例日志必须包含traceId与当前业务单号。 ## 禁止事项红线 - 禁止在代码中硬编码数据库账号、密钥、内部服务地址。 - 禁止在Service层直接操作Entity对象必须先转换为DTO。 - 禁止绕过权限校验直接暴露内部接口。 ## 验收清单AI生成或修改代码后必须自查 - [ ] 变更是否涉及的模块边界 - [ ] 是否遵循了项目统一的分页、异常处理、日志规范 - [ ] 是否新增了未在目录结构中声明的文件 - [ ] 是否遗留调试代码或无用导入这份文件写完后我一般会让AI先“复述”一遍规范要点确认它真的读进去了。如果复述内容有明显偏差说明文件本身的结构或表达还有问题需要修改而不是硬用。提示规范文件不要写成散文尽量用“规则示例反例”的形式。实测下来给一个“正确示例”比写十句“应当这样做”更有效。AI对示例的模仿能力远超对抽象规则的遵循能力。4. 让约束在真实编码流程里生效的工程手段4.1 双通道注入提示词注入与系统级文件规范文件放在项目里不代表AI就一定会用。要让约束真正生效我的经验是走双通道注入。第一通道是会话级提示词注入。每次启动新任务时在对话开头固定粘贴一段精简版的“核心规范摘要”内容控制在300字以内只包含架构红线、命名风格、错误处理约定三个要点。这样即使AI没有读取完整的项目规范文件也能在会话开始时获得关键约束。第二个通道是工具级的全局配置注入。现在主流的AI编码工具基本都支持用户级或项目级的配置项可以在其中持久化规范文件路径甚至直接嵌入规范规则。我试下来工具级配置的优先级通常高于普通文件读取而且不受对话上下文长度影响稳定度很高。双通道的关键区别在于提示词注入是“这次任务记住”工具级配置是“每次任务都知道”。只有后者才能形成稳定的约束基线。我现在的工作流是用提示词注入强调本次任务的特殊注意事项用系统级配置承载全量规范两条线互不干扰。4.2 编码工具内置规则配置的适配思路不同的AI编码工具对规则文件的支持方式不一样。我重点测试了三种类型IDE插件类、命令行Agent类、以及AI原生IDE类。IDE插件类的适配重点是找到设置里的“项目规则”或“自定义指令”入口把规范文件的路径配置进去或者直接把规范内容粘贴到对应文本框。这类工具的优点是和编辑器集成度高缺点是通常只对当前文件或当前会话生效跨会话需要依赖文件的自然读取。命令行Agent类的适配方式更灵活。它支持用命令行参数指定额外的规则文件或者在项目根目录维护一份固定命名的规则文件。这类工具会主动读取这些文件并把内容注入到任务的系统提示词里。实测在执行多文件重构任务时命令行Agent对规则文件的遵循度最高因为它从头到尾拥有完整的上下文管理能力。AI原生IDE类的做法介于两者之间。它可以同时读取项目级规则文件、用户级规则、以及会话内提示词但三者的优先级排序因产品而异。我的建议是不要把关键约束同时放在多个层级里否则一旦发生规则冲突排查起来非常费劲。尽量让“项目规则文件”成为唯一权威来源。4.3 把规范约束前置到代码评审链路规则文件再有说服力AI也有可能偶尔“忘事”。所以规范约束必须前置到代码评审与CI链路里形成闭环。我在项目里部署了三层兜底机制。第一层是静态检查工具覆盖命名规范、未使用变量、危险函数调用等硬性指标。第二层是自定义的架构守护脚本专门检查“禁止事项”里的内容——比如扫描Service层是否有直接操作Entity、分页查询是否走了统一基类。第三层是变更请求模板里面嵌入了AI必须填写的自查清单如果清单没勾完变更请求会被标记为草稿。这套机制跑起来之后AI生成的代码即使违规也会在进入主干之前被拦截。而且我发现一个附加价值当AI看到返回的报错信息时它会主动反思并修正代码甚至可以学习到新的项目规则。这相当于每次编译错误和lint失败都在给AI做一次规范训练。坚持两周后AI生成代码的初始规范符合率明显提升评审环节的沟通成本大大降低。5. 规范约束失效的常见原因与排查链路5.1 排查第一步确认约束是否真的进入了上下文无论规范设计得多好第一个要排查的问题永远是AI到底有没有看到这些约束很多所谓的“规范失效”其实是约束根本没进入模型上下文。我常用的验证方法很简单。在对话中直接问AI“请复述本项目的核心架构约束与禁止事项。”如果AI能准确列出内容说明规则已进入当前上下文如果回答含糊、编造、或者只凭通用经验猜测那说明规范文件没有被读取或注入。这个测试一定要在任务开始前做而不是等代码生成完再判断。任务一旦展开上下文会被代码片段占满规则被“挤出去”的概率很高。所以我在正式编码前有一个固定动作先发一条指令让AI确认规范要点确认无误后再发实际任务。如果AI复述失败排查方向有两个一是规范文件的命名和位置是否被当前工具识别二是工具级配置里是否真正配置了规则来源。这两条都确认没问题但AI依然“看不见”那就进入第二步排查。5.2 排查第二步观察决策边界与文件读取优先序AI编码工具在读取项目文件时通常不是把整个仓库一次性塞进上下文而是按需读取、分片加载。优先级一般是当前打开的文件、项目根目录的说明文件、被代码引用到的相关文件、任务路径上涉及的文件。所以当规范失效时要检查规范文件是否位于“AI会主动读取”的高优先区域。比如你为了整洁把规范文件放在docs/constraints/子目录里而项目根目录只有一份空泛的READMEAI很可能根本不会遍历到深层目录。我自己的做法是在项目根目录的说明文件里放一份“规范索引”用列表形式列出每个约束文件的路径和一句话摘要。这样AI即使不读取完整规范也会通过索引知道去哪里找。如果索引也没有那就需要回到3.1提到的基础命名规范用项目根目录的固定文件名来承载核心约束。另外要注意规范文件本身的体积。我踩过一次坑把全项目数百条规范塞进一个大文件AI在长上下文处理时对文件后半段的关注度急剧下降。后来我改成按模块拆分每个文件控制在50行左右执行率立刻提升。5.3 排查第三步区分模型能力问题与规范表达问题如果AI确实读到了规范但还是不遵守那问题往往出在规范本身的表达方式上。这一步需要冷静分辨是模型能力不足还是我们的规则写得让人模型理解不了。典型表达问题包括三类。第一类是规则抽象度太高。“保证代码质量”这种话对AI毫无意义它没有能力判断什么是“质量好”。要改成可操作的行为描述比如“所有新增公共方法必须包含Javadoc注释说明参数含义与抛出异常场景”。第二类是规则互相矛盾。比如既要求“使用项目统一的分页基类”又在示例代码里放了一个原生Pageable用法AI会无所适从。解决方式是为每条核心规则配一个“标准示例”示例本身成为规则的锚点。第三类是规则与上下文信息错位。AI容易混淆“项目全局规则”和“本次任务特殊要求”。如果在规范文件里混入了某个特定模块的一次性要求AI可能会在其他模块里也尝试套用。我的做法是把“通用约束”与“场景专属约束”分文件存放并在提示词里明确当前任务属于哪个场景。如果以上问题都不存在AI仍然在特定类别的任务上反复违反规范那大概率是模型对这类任务的底层倾向太强需要人工审查重点把关。我一般会在规范文件里把这类操作标记为“高风险变更必须人工复核”而不是继续和模型死磕。6. 落地效果与团队推广的一线体会6.1 可量化提升与不可避免的代价规范约束体系在我负责的订单模块试运行了一个月这里提供一组真实观察数据供参考。返工率的变化最明显。AI生成代码中“需要人工大范围修改”的比例从最初的大约四成降到了两成以下。这里的“大范围修改”指的不是改变量名之类的小调整而是重构方法结构、挪动模块边界、替换数据访问方式这类结构性改动。有了规范约束后AI在生成初始版本时就更贴近团队预期评审从“改怎么写”变成了“局部微调”。规范对齐度我做了个粗略统计定义是“AI生成的代码在不经修改的情况下能被直接合并的比例”。前两周这个数字波动很大有时某类任务能达到八成有时某些场景又跌回三成。后来把规范按模块拆分并增加示例之后整体稳定在了六成左右。对于需要人工介入的剩余部分主要集中在复杂业务逻辑和架构权衡上这本来也是AI不擅长、必须人管的环节。但要说代价也确实是有的。最大的代价是规范体系的维护成了持续性工作。项目架构调整了规范文件要同步更新新引入的技术栈要补新规则甚至AI工具版本升级后读取规则的行为变化也要重新验证。我试运行前两周耗费了大量时间在规范文件本身上如果不打算长期维护后面规范会逐渐和实际项目脱节。6.2 从个人配置到团队规范的几个坑落地过程中最有价值的几个教训值得单独列一下。第一规范约束一定要版本化管理。我最初直接在编辑器里改规则文件改完就生效导致后面出了问题根本不知道是哪条规则改错的。后来把所有规范文件纳入代码仓库用变更记录追踪每次修改问题定位快了很多。规则即代码维护方式也应该按代码标准来。第二规则不能只增不减。团队快速迭代时很容易往规范文件里堆规则每遇到一个问题就加一条。两个月下来文件膨胀到两百多行AI的执行效果反而变差。后来我定了一个原则每条规则必须能在最近的代码评审中找出对应的真实案例否则就删掉。规范是用来解决真实问题的不是为了看起来完备。第三团队推广时要让AI“现身说法”。直接把规范文件丢给同事大家往往没感觉。更好的方式是我在团队内部分享时现场演示先让AI在不加载规范的状态下生成一段代码再加载规范重新生成一次对比两次产物的差异。这个演示比任何讲解都有说服力团队看完后主动开始维护规范文件的意愿高了很多。从结果倒推AI编码的项目规范约束这件事本质上不是在约束AI而是在把团队积累的“隐性知识”显性化、结构化。规范文件写得越清晰AI生成的代码越像团队自己人写的代码。这份工作前期会有一些维护成本但它换来的是从“每次评审都像开盲盒”到“AI产出可预期”的质变。只要团队愿意持续投入维护这套project规范就能一直发挥杠杆作用。