ARTICLE DETAIL

资讯详情

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

给AI编程流程制定代码规范:从AGENTS.md到三层结构设计

给AI编程流程制定代码规范:从AGENTS.md到三层结构设计 上个月我们组在代码评审时爆发了一场小争吵导火索是一段AI生成的状态机实现。写代码的同事说他逻辑核过、测试也过了但另一位负责维护订单模块的同事看完直接回了句“这代码单独看没毛病但它把我们整个模块延续两年的错误处理风格全改掉了。”单看每个commit都合理串起来就是一次没有评审记录的小型架构漂移。这事之后我做了一个决定给项目新增一套专门给AI编程流程制定的代码规范。我说的“AI代码规范”不是写给人类开发者的开发手册也不是那种挂在wiki里吃灰的制度文档而是给Claude Code、Cursor、Copilot、Cline这类AI编程助手用于对齐项目上下文的行为准则。它解决的核心问题只有一个让AI产出的代码稳定符合团队既有约定而不是每次生成都凭概率去猜。如果你正在高频使用AI提交代码或者已经被AI那种“平均风格”坑过几次这篇内容应该能帮你少走不少弯路。1. 为什么我决定给AI单独制定一套代码规范1.1 AI眼里其实不存在“项目约定”人类开发者进入一个新项目会做几件很自然的事翻历史代码、看提交记录、问同事某个包为什么这么写。这些动作背后是在获取“项目约定”。约定不等于规范文档它是散落在代码、注释、review记录里的隐性知识。AI编程助手不一样。它每次会话开始时对项目基本一无所知看到的只是你塞给它的那点上下文。模型生成代码时会强烈倾向于输出它在训练数据里见过最多、最“平均”的写法而不是你们团队特有的写法。这就是为什么你让AI写一个错误处理它大概率会按最通用的模式来哪怕你们项目里所有代码都用了另一种封装。这不是模型笨而是它在没有额外约束时默认选择概率最高的输出。要让它遵循项目约定唯一的办法是把约定显式写出来喂给它。否则AI每生成一段代码都是在和你们的历史约定做一次隐形的概率对抗。1.2 传统的人类规范文档AI其实读不进去我们原本不是没有规范。团队wiki里有一份五千字的《开发规范》从命名、分层到commit message格式都写了。我一开始也试着把这份文档直接丢给AI当上下文效果很差。原因是AI读规范和人类读规范完全两码事。人类看文档会跳读能根据当前任务快速过滤无关内容AI虽然能把文档塞进上下文但它对文档里所有文字的注意力是相对平均的。导致一个典型问题规范里写“一般情况下请使用构造器注入”AI会把它理解成“偶尔可以不遵守”。规范的初衷是留点弹性结果弹没了。更麻烦的是传统规范里大量解释性文字、背景说明、“为什么这么写”的内容本身会稀释真正的约束性指令。AI抓不住“哪些是硬性规定、哪些是背景介绍”。所以给AI用的规范必须重构话语体系把硬性规则和解释说明清晰分隔开甚至只保留规则本身。1.3 给AI定规范本质是上下文工程想清楚这一点很重要。给AI制定代码规范本质不是“定制度”而是做上下文工程。代码规范是团队知识沉淀的产物但传统沉淀形式是给人看的。AI参与的开发流程出现后团队知识多了一个新的消费对象——模型。你要做的是把“人读的知识”转换成人机共读的、结构化的行为约束。具体来说这套规范要达到三个目标。第一可加载AI在启动任务时能自动读到不需要每次手工复制粘贴。第二可执行每条规则都是明确指令没有“尽量”“可能”这类模糊措辞。第三可校验规则描述的行为能被静态检查、代码评审或测试所验证。后面这三个目标会贯穿整个方案的设计。2. 给AI的代码规范长什么样三层结构设计如果只把规范写成一个超长文档那等于没写。我给项目设计的规范分三层每层解决不同粒度的问题也匹配不同的AI工具加载机制。2.1 第一层项目宪法全仓统一约束第一层放在仓库根目录命名为AGENTS.md我习惯叫它“项目宪法”。它回答的是“在这个项目里所有人都必须遵守什么”这类全局问题。内容不用多一般不超过40条但每一条都必须能映射到一个真实的项目事故或长期约定。下面直接上一份精简版模板你可以复制到自己的项目里改。# AGENTS.md — 项目级AI协作规范v1.4 ## 项目背景 - 后端Go 1.22 gin MySQL/RedisDDD分层interface/application/domain/infrastructure - 前端Vue3 TypeScript Vite - 部署K8s Helm配置统一走 config center ## 硬性禁止项 - 禁止修改 domain/ 目录下实体的公共方法签名如需变更先写设计提案 - 禁止在 infrastructure 层之外的任何地方直接引用 gorm.DB 类型 - 禁止通过 init() 初始化业务依赖依赖注入必须走 constructor - 禁止新增全局变量 ## 强制要求 - 业务错误必须用 errors.WithStack 包装并统一返回 *appError - 日志必须结构化采用 logger.Info(ctx, user.created, user-id, userID) 格式 - 所有对外HTTP接口的 handler 层必须显式传递 trace-id 参数 - 新写代码优先放到已有文件里除非当前文件超过800行否则不要新建文件注意到没有这份规范里没有一句背景解释。每一条都是“禁止X”或“必须Y”这是和人类文档最核心的区别。如果你想说清楚背景放到规范文件末尾的“背景补充”区块里并用分隔线隔开。2.2 第二层技术栈与模块约束第二层是模块级规则放在关键子目录下比如 /src/user/AGENTS.md、/cmd/worker/AGENTS.md。它解决的是局部问题这个模块有什么特殊约定、依赖边界是什么、哪些外部包的用法在本模块内是禁用的。模块级规则的优势是“就近加载”。AI在处理某个目录下的文件时工具会自动加载该目录的AGENTS.md这样规范跟任务的距离更近被遵守的概率更高。举个例子我们用户模块的局部规则文件长这样# /internal/user/AGENTS.md ## 模块边界 - 本模块禁止依赖 order 域的任何内部 service需要订单数据时通过事件发布/订阅 - Repository 只允许出现在 infrastructure 层domain 层禁止出现 SQL - 所有 DB 查询方法必须接收 context.Context 参数禁止使用 context.Background() ## 编码约束 - 用户实体的状态变更必须通过 domain event 记录禁止直接改 status 字段 - 查询列表接口默认必须支持 page/pageSize 参数返回体使用统一 PageResult 结构模块级规范的建议篇幅是5到15条。太少说明没总结出局部约束太多说明项目模块划分可能已经失控了。编这个文件时最好拉到对应模块过去三个月的review记录看看哪些问题反复出现。2.3 第三层任务级动态约束第三层不放在文件里它出现在每个AI任务启动时的prompt中。作用是针对这一次任务给出特殊约束覆盖项目规范和模块规范之外的临时要求。我整理了一套任务级约束的模板推荐直接用本次任务约束 - 只修改【模块/文件】其他文件除非必要否则不要动 - 不允许对非相关代码做重构 - 保持对外接口兼容不得修改已有方法的签名 - 提交信息必须遵循 conventional commits 格式 - 本次任务生成的代码必须自带单元测试任务级动态约束的优先级最高。我后面会细说优先级设计这里先记住一句话离任务越近的规则AI越容易遵守。文件里写了十条规则可能不如你在prompt末尾加一句“本次只准改这三个文件”管用。3. 怎么让AI真正“看见”并遵守规范规范写出来只是第一步怎么让AI每次都能读到并且服从才是真正花时间的地方。3.1 文件位置、命名与目录覆盖规则目前主流的AI编程工具对规范文件的支持越来越统一。Claude Code会自动加载CLAUDE.mdCursor从某几个版本开始支持 .cursor/rulesCline、Continue等开源工具对AGENTS.md的支持也比较成熟。我的建议是以AGENTS.md为唯一事实源根目录放全局规范关键子目录放局部规范。然后让CLAUDE.md只写一行引用避免两份文件内容漂移。具体做法# CLAUDE.md 请先阅读根目录的 AGENTS.md并严格按照其中的规则执行。 子目录下的 AGENTS.md 优先级高于根目录文件当两者冲突时以子目录文件为准。文件加载遵循就近优先的原则。AI在处理 /internal/user/xxx.go 时会同时读到根目录和 /internal/user/ 下的AGENTS.md遇到冲突时以离任务更近的模块级文件为准。这里有一个很容易踩的坑多个规则文件内容重复且互相矛盾。比如根目录写“禁止直接使用 gorm.DB”但 /internal/user/AGENTS.md 里又写了“查询必须通过 gorm 链式调用实现”AI就会陷入随机选择。解决方法是每个目录的规范只补充该目录独有的约束不要重复粘贴全局规则。3.2 把规范写进任务启动流程规范文件被动加载还不够。AI工具加载AGENTS.md是有条件的——不是每个工具、每个模式都会自动读取。为了确保万无一失我把规范引用做进了任务启动模板。在团队内部的需求模板里我加了一个“AI编码注意事项”字段每次下发给AI的任务描述默认会在开头带上这句话你是一名资深Go工程师请先阅读根目录 /AGENTS.md 和本次任务涉及模块下的 AGENTS.md然后严格按照规则完成任务。规则中未明确允许的写法默认视为不允许。最后一句“规则中未明确允许的写法默认视为不允许”很关键。它把AI的默认行为从“按训练分布自由发挥”切换成“按规则约束谨慎输出”语气不一样结果差别很大。实测下来加了这句话之后AI生成代码的风格稳定性提升明显。如果是个人项目或者工具不支持自动读AGENTS.md可以把规范文件路径直接贴在prompt里让AI自己读效果比不贴好很多。3.3 CI增加一道“AI代码体检”闸门规范写得再好AI总有走神的时候。所以我在CI流程里加了一道针对AI生成代码的检查闸门作为兜底。做法是在git提交信息里识别AI参与标记。Co-Authored-By这个trailer现在很多AI工具会默认带上我们就在pre-commit或CI脚本里检测如果提交包含该标记就自动启用更严格的规则集。更严格的规则集包括三块一是ESLint或golangci-lint里项目和AI自定义的额外规则二是自定义AST检查脚本扫描某些约定是否被破坏比如是否出现了规则文件中禁止的调用模式三是自动跑一次相关模块的单元测试AI改动的文件必须测试覆盖率达到预设阈值。这个闸门一开始会误伤主要是有时候AI参与但改动很小没必要跑全套。后来我们加了一个优化只对AI改动行数超过20行的提交启用完整检查。少了就当普通改动处理效率明显提升了。4. 实施过程中的关键细节与避坑记录4.1 规则要写成“命令”不是“建议”这是给AI写规范和给人写规范最大的区别。人看到“建议使用构造器注入”知道这是强约束AI看到这句话会把它当成一个概率非常高的建议但内心并不排斥偶尔违背。为了让指令风险最小化措辞上要非常刻意。我踩过几次坑之后总结了三句话不要用“尽量”“推荐”“通常”这类弹性词直接写“必须”“禁止”“不要做X”不如“请使用Y替代X”有效因为AI不知道X的替代方案时可能绕回去用X每一条规则尽量跟一个正面小例子或反例AI对例子的理解远强于抽象描述举一个实际改过的例子。最初规范写的是“不要使用fmt.Errorf推荐使用errors.Wrap”。AI生成代码时仍然混着用。改成下面这样的格式后立即稳定了错误处理业务错误必须使用 errors.WithStack(err)禁止使用fmt.Errorf示例 if err ! nil { return nil, errors.WithStack(err) }没解释原因没有“为了统一可观测性”这类背景只给命令和示例。AI就能精确复制。4.2 防止规则库“年久失修”规范文件最大的敌人不是AI是过期。项目演进之后当初的约束可能已经不再适用但规则文件还在AI会老老实实地遵守一条已经没有意义的规则甚至因此拒绝正确的实现。我为每份规范文件加了version和last_reviewed字段每季度安排一次规则评审会。同时明确了一条流程新规则从提出到正式生效必须先经过两周的“试行期”。试行期内规则写在任务级动态约束里如果两周内有效避免了原本的问题再正式写入AGENTS.md。有一个更细的经验是某条规则如果被AI连续违反三次以上先别急着加大惩罚力度——比如在文件里加更多感叹号、大写、重复强调这些都没用。大概率是规则本身描述有歧义和现有代码范式冲突或者AI在实际场景里找不到符合该规则的写法。这时候应该回看AI生成的代码理解它为什么不遵守然后改规则的描述而不是改规则的语气。4.3 规则冲突时的裁决原则规则一多冲突不可避免。我为团队定了一个明确的优先级排序任务级prompt约束 模块级AGENTS.md 根目录AGENTS.md 模型默认行为为什么会这样设计因为离任务越近的指令越具体越具体的东西应当覆盖越通用的约束。如果用户在prompt里说“本次暂不考虑错误处理先打通主流程”那模块规范里的“必须errors.WithStack”就让位。同时我建了一个rules-issues.md专门记录出现的规则冲突和AI违反规则的反例。这个文件的价值是让规则评审会不再靠空想而是有真实案例可以对照。每一条冲突记录都包含冲突双方、出现的场景、当时的处理方式。等积累了一定样本再批量调整规范。5. 常见问题与排查技巧实录5.1 规则都在可AI就是不遵守怎么办我遇到“AI不守规矩”的时候会按以下顺序排查。第一步确认AI真的读到了规则。直接在对话里问它“请列出你当前的代码规则逐条说明。”如果它总结不出来说明规则根本没被加载进上下文这时候要解决加载机制。第二步检查规则之间有没有互相矛盾。拿一个典型代码示例跑一遍看不同规则会不会给出不同做法。第三步如果规则没问题把“已经不遵守或经常不遵守”的行为放到“硬性禁止项”里并给出一个反例。第四步换更强的模型或调整模型参数。推理能力弱的模型在长上下文里本来就容易“失忆”有时候不是规则的锅。还有一个容易忽略的点AI在超长对话里会逐渐偏移初始指令。如果对话轮次很多后边几轮的输出往往不如开头遵守规则。这时候宁可新开一个会话把关键上下文重新粘进去也不要硬在一个超长对话里继续生成。5.2 不同模型对规范的遵循能力差异很大实测下来不同模型对显式规则的遵循能力差距相当明显。Claude系列的长上下文遵循能力比较稳开启规则文件后能持续稳定输出GPT系列在明确指令下表现也不错但对话变长后偏离的概率更高一些开源或者推理能力稍弱的模型在上下文较长时很容易把规则“忘”在中间部分只记住开头和结尾的指令。这个差异带来的调整是如果你主力模型是弱模型规范文件结构要调整为“最重要的规则放在文件开头和末尾”并且把规则数量压缩。一开始我们给所有模型用同一套规范后来针对弱模型单独出了一份精简版把40条压缩到12条只保留硬性禁止项和最高频必须项遵守率立刻上来了。5.3 规范会不会拖慢AI生成代码的效率短期看会有一点点适应成本。最初一周AI生成代码后需要额外检查规则执行情况单次任务耗时可能会增加一些。但整体来看返工大幅减少合入主干后的review争吵也少了很多实际是赚的。关键点是规范不能贪多。如果你一口气堆60条规则AI的注意力会被分散反而容易每条都不认真遵守。我的建议是从10条核心规则开始跑一个月把最高频的返工问题解决了再逐步增加。规范数量控制在40条以内比较合理超过就要考虑拆分到模块级文件而不是堆在根目录里。最后再说一个我的个人体会。给AI定规范这件事最难的是克制——克制自己想把所有经验都写进去的冲动。规则文件不是越厚越好每条规则都必须对应一个真实问题宁缺毋滥。我们跑了大概一个季度之后AI提交的代码被review打回的频率明显下降。更意外的是这些规则后来也成了新人入职的上手材料他们看完AGENTS.md比看wiki文档更快理解了项目的关键约束。如果你也在被AI代码风格不稳定折磨建议从一页纸的规则开始先定十条真正有用的不要一上来就写一部法典。
返回列表