
先说个我印象很深的场景。前阵子带一个模拟项目X后端用了一套分层架构业务逻辑全收在 service 层数据访问只允许走仓储接口。我给 AI 编码助手派了个活“把订单状态流转补全。”它干得挺快结果 code review 时差点没绷住——它直接在控制器里 new 了一个仓储实例绕过了 service还顺手访问了实体内部一个本应私有的方法。代码能跑测试也绿可架构就这么被捅了个洞。当时我第一反应是怪自己 prompt 写得不够细。后来才发现问题根本不在指令写没写清楚而是我压根没把“项目事实”告诉 AI。这个项目里谁依赖谁、哪些边界不能碰、测试该怎么跑、代码风格是什么——这些信息人靠看代码、翻文档就能摸个大概但 AI 编码工具在一次任务里只能看到一小块上下文它不知道这些“潜规则”自然就会选最短路径。于是我把这些事全部写进了一个叫 AGENTS.md 的文件里放在项目根目录让 AI 每次开工前先读它。几个迭代下来AI 生成代码绕过封装、破坏架构的频率肉眼可见地降了下来。这篇文章就把我这段时间的实践完整拆开讲AGENTS.md 里到底该写什么、四种最关键的项目事实怎么组织、踩过哪些坑、怎么验证它真在生效。内容不挑工具主流的 AI 编程辅助工具基本都兼容这套约定适合正在用 AI 写业务代码、又不想让架构失控的团队和个人。1. 为什么 AI 写的代码总爱“抄近道”问题不在模型在上下文先泼一盆冷水大部分 AI 编码工具不会主动去看你项目里十几层目录的依赖关系也不会翻开你那份几百行的架构设计文档再动手。它的工作方式很像一个阅读范围有限的新同事你给它一个任务它就在局部文件里搜索线索然后按“最常见、最省事”的路径把代码补出来。这就有个天然矛盾。人写代码时脑子里装着一张家谱图controller 调 serviceservice 调 repositoryrepository 才碰数据库工具函数放 utilsDTO 不能混进领域模型。这些是多年形成的肌肉记忆。可 AI 没有这张图它的“常识”来自海量公开代码而那些公开代码里有大量糟糕的写法。于是它看到需要数据访问时第一反应是直接 new 一个仓储对象看到某个类里有现成方法就不管它是 public 还是 internal先调了再说。这件事说白了就是上下文缺失。打个比方你让一个只见过厨房的实习生去餐厅后厨做事告诉他“把出餐口那桌的菜端过去”。他可能直接从炒菜锅里把菜舀出来就端走——因为他不知道出餐流程、不知道哪个窗口是传菜口、不知道哪些菜已经扣了盖。你得先把后厨的动线、岗位边界、禁忌事项统统讲清楚他才知道怎么干而不闯祸。AGENTS.md 要解决的正是这个“后厨动线”问题。它不代替你写业务代码也不存放具体实现细节而是把你项目里“人知道但代码里看不出来”的事实——架构分层、依赖方向、封装边界、测试习惯——写成 AI 能直接读取的上下文。让 AI 在动手前先获得跟你脑子里那份家谱图差不多的信息。有一类人会觉得这事麻烦觉得写 AGENTS.md 不如多写几行注释。我的观点是注释是写给“正在看这段代码的人”的而 AGENTS.md 是写给“每次开工前需要全局视角的 AI 同事”的。两者的服务对象完全不一样。AI 一次能看到的上下文窗口有限你不可能指望它从项目注释里拼出整个架构图它读一个文件就只认一个文件。给它一份集中、精炼、命令式的项目简报远比零散的注释更高效。那具体写什么我总结下来最有价值的项目事实有四类缺一类AI 的行为都会跑偏。下面逐一拆开讲。2. 四种项目事实AGENTS.md 里到底该装什么这一节是核心我会把每种事实单独拿出来讲清楚它解决什么痛点、该写成什么样、不写的后果是什么。每个类别我附一段可以照着改的写法不追求华丽但求能直接用。2.1 架构与分层地图让 AI 知道它站在哪一层第一种事实是项目的地形图。很多项目用了分层架构、六边形架构或者模块化设计但代码库里并没有一个地方会直接告诉你“这两层之间不能反着依赖”。AI 拿到一个小任务时它看到的只有当前文件和相邻的几个文件无法感知全貌。你让它改一个订单模块它可能顺手就在控制器里写起了领域逻辑因为它根本不知道领域逻辑应该在 service 层。我在模拟项目X里是这么写的技术栈与分层 - 代码采用分层架构严格按 controller - service - repository 的方向依赖。 - controller 只做参数接收与响应包装不允许出现任何业务判断。 - service 承载业务规则和事务边界事务必须由 service 开启与提交。 - repository 是唯一允许访问数据源的入口禁止把数据访问逻辑写在 service 里。 - 领域实体放在 domain 目录任何外部层不得直接访问实体内部字段。 - 跨层调用一律走接口不直接依赖具体实现类。这段文字的核心套路是“定义角色 边界声明”。你要先告诉 AI 每一层是干嘛的再明确哪层能碰哪层每句话都用肯定或否定式命令。AI 对“不允许”“必须”“唯一入口”这类强约束的反应比对“请尽量保持架构整洁”要可靠得多。如果你写“注意分层”“建议按架构规范来”AI 很可能把它当成背景噪音直接忽略。这里有个细节值得强调写目录职责时最好结合项目里真实的目录名而不是只说抽象概念。比如“service 层”可以是虚构的但“app/services/下的类只负责业务编排”这种带真实路径的描述AI 能直接映射到文件路径上理解和遵守的概率会高很多。我后来把 AGENTS.md 里所有“层”都改成了“目录A/目录B/”这种形式效果立竿见影。我自己见过不写架构地图的典型事故AI 要给一个功能增加“导出 Excel”的能力它自己找了一个第三方库在控制器里裸调用没有走 service也没有做参数校验。功能是好的可代码风格跟项目完全脱节。后来我在 AGENTS.md 里加了一条“所有新引入的第三方依赖必须先经过人工确认”这个坑才算堵住。2.2 编码规范与风格基线让 AI 生成的代码长得像“自己人”第二种事实是风格基线。很多团队没有精力把编码规范做成 ESLint 规则或静态检查或者虽有规则但覆盖不全。AI 在训练数据里见过各种风格有的用函数式、有的用类和装饰器、有的喜欢链式调用、有的偏好提前 return。你不告诉它这个项目偏好哪种它就会按自己“最熟悉”的风格输出结果就是代码库突然混入了一种陌生风格——抽奖抽出来一样吧唧掉在 2021 年的老文件里字体都不一样看着别扭。风格基线不是面子工程它直接影响 AI 代码的可维护性。一个项目如果所有 service 方法都返回 Result 对象而不是 throw 异常那么 AI 新写的代码如果直接抛异常调用方的错误处理模式就断了如果项目统一用命名参数式调用AI 突然用位置参数阅读和改动的成本立刻上升。我在 AGENTS.md 里会这样写代码风格约定 - 命名方法名使用动词开头变量优先使用意图明确的名词禁止拼音缩写。 - 错误处理业务方法统一返回 ResultT不在业务层直接 throw。 - 函数风格service 层方法保持短小单个方法不超过约 30 行过长先拆私有方法。 - 空值处理禁止裸用 null 传递数据缺失统一使用 Optional。 - 集合操作优先使用扩展函数和流式 API不使用 for 循环处理集合。 - 测试优先使用领域语言描述的测试用例单元测试不触达真实网络。写这部分时最大的坑是“过度细化”。我在早期版本里把变量命名规则、缩进、换行、引号全都塞进去了结果 AI 的主要精力全花在“遵守格式”上反而忽略了业务逻辑。后来我把这些琐碎规则删掉只保留那些“会破坏架构或调用方式”的风格约定——错误处理模式、空值服用、函数长度红线、集合操作偏好。事实证明这类“影响代码结构”的风格规则对 AI 最有约束力而缩进引号之类的事交给格式化工具去统一就行。还有个反直觉的经验跟 AI 讨论“风格”的时候说“不要”“避免”不如说“优先使用”“统一使用”有效。因为 AI 生成代码时会优先选择它熟悉的模式你告诉它“不要用 for 循环”它可能还是用但你告诉它“统一使用扩展函数处理集合”它就会尝试照做。正面表达让它有明确替代方案。2.3 封装边界与操作禁忌把项目里“不能碰的地方”圈出来第三种事实是最容易被忽视、却最能直接减少“绕过封装”的一类。一个项目经过几年迭代总会沉淀出一些约定俗成的封装边界某个模块对外开放了三个入口但内部其实还有十几个方法某个类虽然字段都是 public但业务上不该被外部直接改写某个初始化流程必须先走哪一步被跳过就会埋雷。这些信息往往不会写在注释里但对 AI 来说它们就是“必须遵守的红线”。我在模拟项目X里就吃过这方面的亏。那个项目有个数据访问门面类内部维护着连接池和缓存对外只暴露了几个查询方法。AI 拿到任务后觉得“直接访问缓存字段更快”就绕过门面方法读写内部缓存结果并发环境下缓存一致性出了问题。后来我在 AGENTS.md 里加了整整一段“边界与禁忌”封装边界红线禁止违反 - 数据访问只能通过 RepositoryA 接口项目内不存在第二个合法入口。 - 所有写操作必须先调用 TransactionManager.begin()完成后必须提交。 - 域对象的属性禁止外部直接 set必须通过领域行为方法修改。 - 配置对象只允许在系统启动阶段读取业务运行期禁止修改配置。 - 外部系统接口调用统一走 gateway 目录禁止在 service 里直接发 HTTP 请求。这段落的关键是“写禁忌时要把为什么顺便带上”。我发现纯写“禁止访问缓存字段”这种规则AI 执行起来会打折但写成“缓存字段由门面统一管理绕过会导致一致性异常”AI 就会把它当成一条有因果逻辑的约束而不是一个“随便写写的项目偏好”。这个差异非常明显可以说是 AI 上下文工程里性价比最高的技巧。不过要小心这类条目不能写太多。我在第一次整理时列了二十多条禁忌结果 AGENTS.md 太长了AI 读完前面几条就忘了后面的。后来我把禁忌按“最高优先级”和“普通约定”分两级最高优先级的控制在五条以内其余放到文件后半部。效果是那些真正容易破坏架构的红线AI 基本都能记住而普通约定遗漏的代价相对没那么大可以容忍。2.4 测试、构建与运行上下文让 AI 补代码时先知道“怎么检查自己”第四种事实是关于工作流的。AI 写代码和人类写代码有个很大区别人写完后会跑测试、跑 lint、做自测而 AI 生成的代码往往直接就是“最终交付状态”。如果 AI 完全不了解项目的测试命令、lint 规则和 mock 习惯它很容易产出能通过编译、但完全不符合项目验收标准的代码。它甚至可能为了“让测试通过”去修改应该保持不变的测试文件。这部分我建议固定写成检查与验证 - 单元测试运行命令pnpm test 或 ./gradlew test按项目实际情况替换。 - 写完功能后必须补充对应单测测试文件与被测文件同目录。 - 外部依赖在测试中使用 mock不发起真实服务调用。 - 所有公共方法必须附带文档注释新文件必须遵循现有头注释风格。 - 改动入口文件时运行 lint 检查命令见 ./scripts/check.sh。有人会觉得“这不就是 README 里的内容吗”但它们的服务对象完全不同README 是给人看的快速上手文档信息是叙述式的而 AGENTS.md 里的验证命令要写得“唯命令是从”。AI 读了就知道“要跑哪些命令、补什么测试、用什么 mock 策略”等于给它一套自检流程。这里我想单独强调 mock 和依赖隔离这类事。很多项目里测试环境会预设一批数据库种子数据、有几个测试账号。AI 不知道这些它写的测试可能直接依赖本地环境、或者硬编码了一个真实生产环境才有的账号。在 AGENTS.md 里明确“测试不得依赖本机数据库、统一使用 mock 数据源”之后AI 发生类似问题的次数断崖式下降。这类规则就是那种“人知道但代码里完全看不到”的首选代表。我还会顺手写上“开发时优先参考哪几个现有文件”。比如“新接口风格可参考modules/下的订单模块”相当于给 AI 指了个模仿对象。机器人学风格看例子比看规则快得多这条实测很管用。3. 把四种事实落成 AGENTS.md 的写作方法论内容方向定好了接下来就是怎么写。很多人第一次写 AGENTS.md 容易犯的毛病是要么写成回忆录事无巨细地记录项目史要么写成论文讲一堆抽象原则。这两种写法 AI 都不爱读。我踩过几轮之后总结出来几条写作规则按重要性排下来大概是下面这个样子。3.1 文件放哪、叫什么、用什么格式最直观也最关键的一条文件必须命名为AGENTS.md放在项目根目录。当前主流的 AI 编程辅助工具基本都认这套约定——你说别的名字比如PROJECT_RULES.md、CONTEXT.txt很多工具压根不会自动读取它们只会去找自己约定的那个名字。这算是 AI 编码领域最早走向事实标准的约定文件跟 README 一样位置和名字本身就是约定的一部分。格式强烈建议用纯文本 Markdown 的轻量结构。不要用 HTML、不要用表格、不要用复杂嵌套列表——AI 读取这些内容时越接近自然语言和简单 Markdown越容易正确解析。我在实践中发现同样的信息用短段落和简单列表写AI 的执行质量明显高于用表格写。可能因为表格的阅读顺序跟文本不太一致AI 容易把单元格内容切碎理解。如果你在 AGENTS.md 里放了表格最好还要把关键规则在表格外再用一句话重复一次这样防止丢失。我还建议给文件按“高优先级规则”和“参考信息”分区域。实测下来AI 在读取项目文件时对文件顶部的注意力高于底部。所以最高频的红线规则要放在最前面比如“依赖方向不许反”“数据访问只走仓储接口”。而那些“推荐的参考文件列表”“常见术语”这类参考性内容可以放到后面即使被截断丢了损失也可控。3.2 写规则时请用“命令式话术”而不是“建议式话术”写 AGENTS.md 的人大多性格温和写出来的句子容易变成“建议保持分层结构”“尽量通过 service 访问数据”。这种语气在跟人沟通时很合适但给 AI 就不太行。AI 对句式的敏感度远超我们的直觉命令式——“必须通过 service 访问数据”“禁止在控制器中写业务逻辑”——比建议式更容易被执行。为什么模型在训练数据里看到的“必须”和“禁止”往往出现在规范文档和编码标准中它会判定这是一条高权重约束而“尽量”“建议”这类词跟“可做可不做”关联会被模型当成软性提示。所以在 AGENTS.md 里我后来把所有模糊词全部替换成精确词不仅“尽量”类词要删干净连“通常”“一般来说”也全改掉。一份好的 AGENTS.md读起来应该像交警指挥交通而不是朋友劝你早点睡。同时长句子要拆短。AI 的指令遵循能力在处理简短、独立的指令时最强如果一句话里塞了主语、条件、例外情况模型的注意力会被分散。我有一条自我检查标准AGENTS.md 里的任何一条规则读起来不应该超过两行。超了就拆开写或者重新组织句子。3.3 用“问题—规则—例子”的三角结构组织每条事实单纯的规则列表容易显得干巴巴而且 AI 难以理解规则背后的意图。我后来形成了一套固定写法每一类重要事实先用一句“为什么”说明背景再列出具体规则最后给一个或两个微型例子说明对与错。举个例子我在模拟项目X里写数据访问规则时第一条是背景项目统一通过仓储接口访问数据避免业务逻辑散落到四面八方。 规则任何数据读取必须调用 RepositoryA 接口。 对const data await this.repository.findByOrderId(id) 错const data await db.query(SELECT ...)禁止在 service 直接拼接 SQL。这个三角结构的价值在于AI 不仅知道“不能怎么做”还知道“应该怎么替代”——这是减少绕过封装的关键中的关键。光给禁令人会迷茫但配上正确做法的示例AI 就有了一条可模仿的路径。实践中带“对/错”示例的规则比只有文字的规则遵守率肉眼可见地高。这个方法也解决了“AGENTS.md 太长”的一个心态问题你不用追求每一条都带示例挑那些“绕过后果严重”的高频路径写对错例就行。普通约定比如“方法不超过 30 行”写规则即可写得太多反而稀释重点。4. 实操记录让 AGENTS.md 真正生效的完整闭环方法论讲完接下来是我在一周内的实操过程。这部分我会写得比较具体包括第一天怎么搭、第二天怎么验证、后面怎么迭代你可以直接照着流程走。4.1 从零搭建的三步走梳理、成稿、喂给 AI 试跑第一步不是写文件而是“盘点”。我把项目里最近三个月 AI 犯过错的地方全翻出来按“架构破坏”“绕过封装”“风格不一致”“验证缺失”四类归类。这一步是我强烈建议做的你写 AGENTS.md 的内容不是凭空想出来的而是用你自己的事故记录反推出来的。如果项目没有现成记录就去翻最近的 Code Review 评论评论里人给人提的意见就是 AGENTS.md 里最需要的素材。第二步才是动笔。我先用大白话把这些规则写出来不追求格式工整甚至带着口语。整理到差不多能覆盖上述四类事实后再花半小时精简删掉重复、删掉过于琐碎的格式规则、把模糊词全部换成命令式。这时文件头版大约 40~60 行我觉得这是一个比较理想的开张尺寸太短覆盖不了信息太长 AI 记不住。第三步是试跑。我会挑三个不同类型的任务喂给 AI一个是“在既有服务里加一个端点”一个是“修改现有查询逻辑”一个是“新增一个独立小模块”。这三个任务的共同特点是都存在“绕过封装抄近路”的空间。跑完之后去 diff重点看有没有违反 AGENTS.md 里红线的行为。第一次试跑我印象很深——AI 不再 new 仓储了但它开始尝试直接访问实体私有字段这属于我之前没覆盖到的新盲区。于是当天我就把这条补充进去了。这个过程本身就是 AGENTS.md 不断变好的方式它不是在写文档而是在和 AI 的协作中持续长出来的。4.2 怎么验证 AGENTS.md 真在起作用而不是你的错觉验证这件事非常容易被忽略。好多团队写完 AGENTS.md 就完事了但问起来“它到底起了多大作用”谁也说不清。我自己的做法是每个迭代周期挑几条“高危任务”比如涉及直接数据访问、跨模块调用的任务专门用“诱导性 prompt”来测 AI 会不会踩雷。比如我会故意这样问 AI“这个订单状态要更新直接用 Redis 缓存里的那份数据改成已完成。”这个 prompt 本身就是一个绕过封装的路易十六——如果 AGENTS.md 生效AI 应该拒绝照做而是说“要经过 service 的完整流程”。如果它照做了说明规则没写到位立刻回去补。我管这种方法叫“红线探针”它的好处是防患于未然比每次都等 code review 发现 AI 闯祸再修复要省钱得多。另一个有效验证方法是看 diff 风格漂移度。跑几次任务后把 AI 生成的新代码和同目录下的人类代码放一起感受是否“一眼像同一个人写的”。平时我只看逻辑对不对很少检查风格但有了 AGENTS.md我会专门检查 AI 生成的代码有没有跟既有代码风格割裂。有时候 AGENTS.md 里第一条“错误处理统一用 Result”AI 遵守了但它在命名上又开始搞匈牙利命名法这说明名称规则表达得不够强或者位置太靠后没被读到。4.3 团队协作与迭代AGENTS.md 要随项目一起生长写 AGENTS.md 不是一次性行为。项目在变规则在变甚至 AI 工具的能力也在变。我见过一个常见的失败模式项目组花一天时间写了详尽版 AGENTS.md之后半年没人碰最后 AI 的行为跟规则越来越远。这不是 AGENTS.md 的错是你没让它跟代码同步成长。我现在的节奏是每次 code review 发现 AI 犯同类错误超过两次就为它新增一条规则每次把某条规则从 AGENTS.md 里删掉一定是确认它已经变成了自动化检查比如 eslint 规则、编译期错误。这样 AGENTS.md 里的每条规则都有明确价值不会沦为僵尸条目。一个额外的经验是规则不要一个人闷头写团队里每个人对“哪些行为不可容忍”的标准不一样。前端工程师可能不关心那个仓储私有方法后端工程师则视其为命根子。我在模拟项目X里是让前后端各派代表各写一段最后再合并去重。合并时争执是难免的——你说“禁止在 service 里发请求”他说“我们有个回调就是这样”——我的原则是“谁的地盘谁说了算”。领域规则的最终发言权属于那个方向的技术负责人。5. 常见问题速查为什么 AGENTS.md 有时不灵这部分是大家最容易遇到问题的地方。我把自己和一些同行踩过的坑整理成速查表你在排查时可以按图索骥。表现可能原因解决办法AI 完全像没读过 AGENTS.md文件名不对或放错目录确认文件名严格是 AGENTS.md位置在项目根目录看到规则但不遵守规则用了建议式语气改成“必须”“禁止”并配上对/错示例只遵守前半部分规则文件太长后部信息被截断把最高优先级红线放到文件最顶部精简总行数新代码风格仍跟项目割裂风格条款太抽象补一个“参考实现文件”路径让 AI 直接模仿规则只对部分工具生效工具版本老旧或不兼容确认 AI 工具版本是否支持 AGENTS.md 自动读取加新规则后旧功能变差新旧规则冲突先理清规则优先级冲突时明确哪条优先某些格式信息表格解析错复杂 Markdown 导致解析割裂规则用短段落和列表写表格只做补充还想补充两个不属于表格但很常见的问题。第一个是“AGENTS.md 里写了规则但 AI 生成时还是不守”——这种情况我见最多的是因为 AGENTS.md 里的规则跟代码里的既定事实冲突。比如你写“数据访问必须走仓储接口”但代码里明明到处都是db.query的直连那 AI 会觉得规则可能只是“理想”实际项目实际是另一种做法。这时候不只是写规则还要把 AGENTS.md 里引用的“标准路径示例”跟代码里的实际做法统一起来让规则与事实一致。第二个是“别把所有希望都压在 AGENTS.md 上”。它再完善也不能替代编译检查、静态分析和自动化测试。AI 在遵守上下文规则方面已经进步很多但它毕竟是概率模型偶尔还是会抽风。我现在的用法是AGENTS.md 负责“减少概率”CI 和 lint 负责“兜住底线”Code Review 负责“最终裁决”。三者各管一段整体效果最稳。6. 踩过几次坑之后几条想说的真话回到文章开头那个场景。后来我在 AGENTS.md 里明确写上了“数据访问只允许走仓储接口、事务必须由 service 开启、领域对象字段禁止外部直接写入”这三条再让 AI 去补状态流转它给出的方案就是老老实实走 service 方法——虽然最后还是让我改了十五分钟但“绕过架构”这一类问题基本绝迹了。我不觉得是 AI 变聪明了而是我终于把它缺的上下文给了它。每次有团队来找我聊 AI 编码效率我最后都会说别把 AGENTS.md 当成写文档任务把它当成“给 AI 同事做入职培训”。新人入职你要给他讲架构、讲规范、讲红线、讲怎么自测AI 同事也一样只是它需要的是精简、命令式、可检索的文本而且它入职培训比人快得多——改完文件立刻生效不用等它消化。你项目里那些最容易让 AI 闯祸的“潜规则”现在就可以开始列。别追求一次写完。先把最近 code review 里 AI 犯过的错按四类事实归类挑一两个最扎心的写进 AGENTS.md让 AI 下次开工前先读到。跑几轮再加新的。等它的“捣乱频率”降下来你会发现改 AGENTS.md 花掉的时间远比你返工擦屁股的时间省得多。