资讯动态

AGENTS.md:给AI Coding Agent的架构说明书,根治多语言项目翻车

发布时间:2026/10/17 10:41:52 来源:尧图企业网站定制
这两年 AI Coding Agent 火得一塌糊涂但大家慢慢发现一个问题Agent 写点函数、做个 CRUD 还行一旦碰上那种积累了五六年的多语言多框架老项目它经常好心办坏事。我见过太多翻车案例——它在完全不了解项目架构的前提下直接绕过封装层去改底层数据或者在一个本该走事件驱动的服务里硬塞了一个同步调用更别提把分层架构改成屎山的骚操作。问题的根子不在模型能力而在 Agent 缺少一份真正能读懂的架构说明书。AGENTS.md 就是为这件事而生的。它本质上是给 AI Coding Agent 看的架构契约和 README 给人类看、注释给代码局部做解释不同AGENTS.md 要回答的是这个项目整体怎么组织、什么能碰、什么不能碰、改动应该往哪放。这篇文章我会从原理讲到落地结合多语言多框架仓库的实际案例把 AGENTS.md 从一份希望 Agent 能看懂的文档变成一套可执行、可维护、可验证的项目规范。不管你是个人维护开源库还是团队里管着一个多模块的复杂系统这份指南都值得你照着做一遍。1. AI Coding Agent 为什么总是局部正确整体崩坏1.1 Agent 的工作模式决定了它天生缺少上帝视角先说透一件事AI Coding Agent 和人类工程师的工作方式有本质差别。人进到一个项目里哪怕没人带着也会先翻 README、看目录结构、找架构文档在脑子里建立一张项目地图然后才动手写代码。Agent 不是这样它拿到的是一个被截断的上下文窗口里面装着文件树、当前打开的文件内容以及你 prompt 里给的少量指引。在这种模式下Agent 最擅长的是局部推理看到某个函数它能根据上下文猜出函数意图看到某个接口它能按惯例补出实现。但一旦问题需要全局判断——这个改动会不会破坏模块边界这个依赖方向是不是违反了分层原则——它就抓瞎了。因为没有全局信息它只能在局部找一个看起来最合理的方案而这个方案往往和整体架构冲突。举个我实际见过的例子。一个 Java 后端项目标准的三层架构Controller 层调用 Service 层Service 层调用 Repository 层Repository 层操作数据库。业务方让 Agent 加一个导出用户列表的接口。Agent 没有看架构约束直接在 Controller 里注入了一个 JdbcTemplate写了一段 SQL 把数据查出来返回了。从功能角度说这个接口完全能用从架构角度说它直接让数据访问层穿透到了 web 层后续所有想复用 Service 层业务校验的调用方都会被带偏。1.2 缺少架构上下文时的典型翻车场景根据我观察到的案例Agent 在缺少架构信息时最常踩这几类坑越层调用Web 层直接操作数据库、绕过 Service 层调用 Repository这在分层架构里是重灾区。Agent 分不清职责边界因为代码里没有明确告诉它哪一层允许依赖哪一层。循环依赖在模块较多的项目里Agent 为了复用某个方法直接在 A 模块里 import B 模块而 B 模块本来就在 import A 模块。人看一眼模块依赖图就能避免的事Agent 在单文件上下文里根本察觉不到。破坏聚合边界DDD 项目里聚合根是数据的唯一入口Agent 却可能绕过聚合根直接修改聚合内部的实体状态因为这样看起来改动更小。它不知道这种做法会破坏业务不变式。选错技术栈实现一个项目里既用了同步 HTTP 调用又引入了消息队列Agent 在不了解哪个场景走同步、哪个场景走异步的约定时往往凭自己的偏好选一个结果和整体设计相悖。忽略副作用约定有的项目要求所有更新操作必须经过审计日志Agent 没有这个上下文直接改数据上线后审计记录缺失。这些坑的共同点是代码本身没有语法错误测试也能过但从架构角度看就是错的。传统的错误 Agent 可以通过编译器和单元测试拦住架构错误没有任何自动化工具能拦——除非你提前把架构规则写清楚并且让 Agent 在动手前就看到它。1.3 为什么 README 和注释解决不了这个问题很多人会问我们项目里有 README也有详细的注释Agent 不会看吗答案是看了但没用。README 是写给人类看的它的目标读者是有推理能力和背景知识的工程师。你写本项目采用微服务架构各服务通过 RabbitMQ 通信人类能自动脑补出完整的通信模型但 Agent 不会。它只会把这句话当作一个普通段落权重和你写这是一个电商项目差不多。更关键的是README 通常缺少 Agent 做决策时最需要的两类信息一是什么不能做的负面约束二是代码应该放在哪的映射规则。注释的问题更明显它只存在于局部文件里。Agent 在改 A 文件时看不到 B 文件里关于模块边界的注释。就算它把整个文件树都扫了一遍也不可能读完整个项目所有的注释。你需要的是一个独立的、集中的、Agent 在开始工作前必然读取的文档——这就是 AGENTS.md 的位置。2. AGENTS.md 到底是什么以及它和 CLAUDE.md、.cursorrules 的关系2.1 一份能落地的 AGENTS.md 包含哪些内容AGENTS.md 的灵感其实来自 Anthropic 的 CLAUDE.md 和社区的 .cursorrules但和它们有一个关键区别AGENTS.md 是工具无关的。CLAUDE.md 是 Claude Code 专属.cursorrules 是 Cursor 专属而 AGENTS.md 是一个被多个 Agent 工具广泛支持的通用约定。只要你的 Agent 工具支持读取项目上下文它就能识别 AGENTS.md。这意味着你不需要为每个工具单独维护一份规范。那 AGENTS.md 里到底该写什么我按优先级排一下内容块说明优先级项目概览这个项目干什么的、服务对象是谁必须有技术栈清单语言、框架、关键库及版本约束必须有快速启动命令本地运行、测试、构建、lint 的具体命令必须有目录结构与责任边界每个目录/模块干什么、允许依赖谁必须有架构原则分层规则、数据流方向、事务边界必须有禁止事项明确列出不要做的事和原因强烈建议变更流程加功能/修 bug 时应该按什么顺序操作建议代码风格约定命名、格式化、注释语言等可选注意这里的每一项都不是简单的描述而是要能被 Agent 当成决策依据。什么叫决策依据就是当 Agent 在多个方案之间犹豫时它读到你的规范能直接排除错误选项。我举个实际例子目录结构与责任边界这条差的写法是src 目录是源代码test 目录是测试代码。好一点的写法是src/services 是业务逻辑层只能被 src/controllers 和 src/workers 调用禁止被 src/models 反向依赖所有数据库操作必须经过 src/repositories禁止在 services 里直接写 SQL。2.2 让 Agent 真正读到AGENTS.md 的三个技巧光有内容还不够你还得确保 Agent 在动手之前真的读了、并且读懂了。三个技巧我实测下来很有用技巧一放大指令权重。在 AGENTS.md 开头就写一句你必须在执行任何代码变更前完整阅读本文件并用一个专门的小节说明如果本文件的要求与代码注释冲突以本文件为准。这样一来即使项目里有些历史注释和新架构不一致Agent 也优先遵循规范。技巧二把规范写得像路由表而不是散文。Agent 对结构化信息的解析能力明显强于对长段落的理解。能用列表就不用段落能用表格就不用列表。我见过一份 200 行的 AGENTS.md里面全是密密麻麻的段落Agent 读完跟没读一样而一份 80 行的 AGENTS.md 用树状结构把模块依赖画清楚效果立竿见影。技巧三提供反例作为辅助。单纯的规则是抽象的Agent 理解禁止越层调用这句话字面意思很容易但要真正把它映射到代码上还需要示例。给出常见的反面模式示例并配上为什么这样不对Agent 的识别准确率会显著提升。2.3 什么样的 AGENTS.md 是坏规范我在评估一个 AGENTS.md 写得好不好时通常看它够不够硬。坏规范有一个共同特征全是形容词没有动词。比如项目采用清晰的分层架构代码应该保持高内聚低耦合——这种话人类看着有道理Agent 看着毫无信息量。什么叫清晰什么叫高内聚Agent 无法从这些描述中推导出任何可操作的行为。坏规范的另一类问题是写得太全、太杂把代码风格指南、API 文档、部署手册都塞进来。AGENTS.md 不是知识库它是一份决策规则集——应该只包含 Agent 在做代码变更时需要用到的约束。配置项解释、API 列表、运维命令这些内容放进 README 或 docs 里更合适放进 AGENTS.md 只会稀释重点。我来做一个对比你就明白了坏规范本项目使用微服务架构各服务之间解耦可独立部署。好规范本项目有 auth-service、order-service、payment-service 三个微服务均独立部署服务间只允许通过 HTTP REST 接口通信禁止共享数据库表新增功能必须先定位所属服务再遵循该服务的内部分层。3. 多语言多框架仓库的规范设计写通用规则还是分模块规则3.1 单一 AGENTS.md 的局限与根目录策略在单语言单框架的项目里一份根目录下的 AGENTS.md 通常就够了。但在多语言、多框架的仓库里情况要复杂得多。比如一个典型的全栈仓库前端是 React TypeScript后端是 Python FastAPI可能还有一块 Go 写的异步 worker。语言不同、框架不同、约定不同、测试方式也不同。如果所有规范都塞进一个 AGENTS.mdAgent 在改前端代码时还得在一堆后端规则里搜索自己的那条上下文效率很低。我建议采用根目录 AGENTS.md 子目录 AGENTS.md的分层策略。根目录只写跨模块的全局约束包括项目整体结构和服务划分语言/框架的版本清单全局的架构原则比如模块间通信必须走接口禁止跨模块 import 内部类统一的提交规范、CI 流程然后在每个语言或框架的子目录里再放一份独立的 AGENTS.md只约束该子目录内的改动。比如 frontend/AGENTS.md 只写 React 代码规范、状态管理选型、样式方案backend/AGENTS.md 只写 FastAPI 的分层规则、ORM 约束、异步任务使用方式。这样的好处是Agent 在修改某个文件时读完文件所在路径的 AGENTS.md 就能获得 80% 的决策信息剩下的 20% 才是全局约束它可以从根目录 AGENTS.md 读取。3.2 分模块规则的目录约定与文件命名子目录 AGENTS.md 的摆放位置我建议放在模块根目录下也就是你开始看代码时第一眼能看到的地方。比如repo-root/ ├── AGENTS.md ├── frontend/ │ ├── AGENTS.md │ └── src/ ├── backend/ │ ├── AGENTS.md │ └── app/ └── worker/ ├── AGENTS.md └── main.go注意不同的 Agent 工具对子目录 AGENTS.md 的读取行为不一样。我实测过有些工具只读取根目录的 AGENTS.md有些工具会在文件变更时顺着路径向上查找最近的 AGENTS.md。如果你的工具不支持子目录读取那就要么把所有规范合并到一个文件里要么在根目录 AGENTS.md 里给每个模块单独开辟一个小节。3.3 多语言场景下的通用表达策略多语言项目最容易踩的坑是用某一种语言的思维写规范。比如你写所有类必须定义在 src/classes 目录下这个规则在 Java 里适用在 Go 里就是错的因为 Go 根本没有类你又写所有函数必须返回 error这在 Go 里成立在 Python 里就很奇怪。我的建议是跨语言规则要和语言解耦用概念 意图的方式表达而不是用具体语法表达。举几个例子语言无关的架构意图具体到语言的落地业务逻辑层禁止直接依赖基础设施层JavaService 层禁止注入 JdbcTemplatePythonservice 模块禁止 import db 模块模块间通信必须通过公共接口Gointernal 包之间只允许调公共函数TypeScript禁止跨包直接 import 非 index.ts 导出的符号数据访问统一走仓储层Python禁止在 view 函数里写 ORM 查询JavaRepository 层唯一允许依赖 EntityManager3.4 框架差异带来的额外约束以 React/FastAPI/Go 为例让我拿一个真实的多框架项目来说明。这个项目里有三块React 前端、FastAPI 后端、Go 异步 worker。frontend/AGENTS.md 的核心约束React 项目里 Agent 最容易搞乱的通常是状态管理。如果项目用了 Redux Toolkit但 Agent 不熟悉它可能在组件里随手写了一个 Context 来管理全局状态结果状态散得到处都是。所以我的 frontend/AGENTS.md 里会写死全局状态必须放在src/store下使用 Redux Toolkit 的 createSlice服务端数据请求必须走src/api下的统一封装禁止在组件里直接写 fetch 调用样式只允许使用 Tailwind CSS 或src/styles下的全局样式禁止引入 CSS Modules 或 styled-components组件文件命名统一使用PascalCase.tsx测试文件与组件文件放在同一目录。backend/AGENTS.md 的核心约束FastAPI 项目里Agent 经常分不清 pydantic 模型和业务模型。有的 Agent 直接把 ORM 表对象返回给前端序列化导致字段名和结构完全失控。我的 backend/AGENTS.md 里会写API 请求/响应模型必须定义在app/schemas.py使用 pydantic BaseModel数据库模型定义在app/models.py禁止直接返回模型对象给路由层所有业务逻辑放在app/services目录路由函数只做参数校验和响应封装数据库连接只在app/db.py和app/repositories中使用禁止在 services 里直接写 SQL 语句。worker/AGENTS.md 的核心约束Go worker 项目里Agent 容易踩的坑是 goroutine 泄漏和错误处理不规范。我的 worker/AGENTS.md 里会写所有入口逻辑写在cmd/worker/main.go业务逻辑放在internal/processor每个 goroutine 必须有退出机制禁止无限制的go func()启动错误处理遵循 Go 习惯使用errors.Is/As判断错误类型禁止吞错配置加载统一使用internal/config包从环境变量读取禁止硬编码配置。4. 落地实操从零给一个多模块项目编写 AGENTS.md4.1 第一步梳理架构地图先把事实列出来不要凭记忆写规范先做一次完整的架构梳理。打开项目把下面这些信息收集起来模块清单项目里有哪些独立部署的模块或服务各自用什么语言和框架依赖关系模块之间怎么通信HTTP消息队列gRPC共享数据库目录职责每一个顶层目录在当前语言语境下承担什么责任关键流程一个典型的请求比如创建订单会经过哪些模块和函数现有约定代码里有没有明显的模式比如所有 Repository 都继承一个基类所有 Service 的方法都返回 Result 对象常见卡点团队在过去 review 中反复提出的架构问题是什么这步的产出是一张架构地图它不需要写到 AGENTS.md 里那么精炼但一定要完整。我习惯用 Markdown 文件先记录然后再精简成规范。比如一个订单系统的服务依赖关系可以先记录成用户请求 → api-gateway → order-service (HTTP) order-service → payment-service (gRPC) order-service → inventory-service (HTTP) 所有服务 → mysql (各自独立 schema) 所有服务 → kafka (事件发布/订阅)4.2 第二步设定规范颗粒度把规则分三档写规范不是越细越好写得太细 Agent 记不住反而会忽略关键约束。我把规则分成三档你按优先级写第一档必须遵守违反这些规则会导致架构腐化或线上事故。比如禁止服务间共享数据库表禁止在 Controller/路由中执行耗时超过 500ms 的逻辑。这些都是架构红线必须用强烈的措辞写清楚。第二档推荐模式违反不一定会出事但会让代码偏离团队惯例。比如新增服务时应该先在 docs/architecture/ 下补一页设计文档所有跨服务调用必须使用run_with_timeout包设置 5 秒超时。第三档风格偏好纯代码风格层面的约定。比如Python 文件使用 4 空格缩进Go 结构体字段对齐注释。这些也可以写但建议单独放一个小节不要和架构规则混在一起。写完后你要通读一遍问自己一个问题如果 Agent 只读到了这份文档的前 30%它能不能避免最严重的那类错误如果能说明你排序对了如果不能把红线规则往前移。4.3 第三步写示例而不只是写规则我强烈建议在每个关键规则后面加一个正面示例 反面示例这能让 Agent 的遵循率上一个大台阶。反面示例要具体最好是从真实代码里提取的罪行现场正面示例要简单、直接一看就能照做。我拿一份真实 AGENTS.md 的片段给你看数据库访问约束所有数据库查询必须通过OrderRepository禁止在 Service 中直接使用 SqlAlchemy Session。反面示例禁止def process(order_id: int): session SessionLocal() order session.query(Order).filter(Order.id order_id).one() # ... 直接在 service 里操作 session正面示例推荐def process(order_id: int): order order_repo.get_by_id(order_id) # ... 通过 repo 操作数据这种规则 反例 正例的结构我实测能让 Agent 的错误率降低一半以上。原因很简单LLM 的 few-shot learning 能力天然就这样你给它一个清晰的对照它才更容易学会你的偏好。4.4 第四步用验证任务检查 Agent 是否真的读懂了写完 AGENTS.md 不是终点你得验证它有没有生效。我推荐一个简单粗暴的方法给 Agent 几个故意设陷阱的小任务看它会不会踩坑。比如你的规范里写了禁止在 Controller 中直接调用 Repository你就让 Agent 完成这个任务在UserController中新加一个接口返回指定用户的订单数量。如果 Agent 遵守了规范它应该会去调用 Service 层的方法如果它直接注入 Repository 来执行查询说明 AGENTS.md 没有被有效读取或者你的表述不够清晰。我建议在刚引入 AGENTS.md 的一两周内每次用 Agent 完成代码变更后都做一次 diff review重点看有没有违反架构红线的地方。发现问题后不要急着骂 Agent先回头检查规范表述是否不够具体。大多数情况下规范改得更清晰之后Agent 的行为就立刻改善了。4.5 维护 AGENTS.md 的更新节奏架构是活的AGENTS.md 也需要跟着更新。我的经验是每次发生架构变更时都应该顺手更新对应的 AGENTS.md 小节。比较理想的做法是把 AGENTS.md 的维护纳入代码评审流程——凡是修改了目录结构、模块接口、依赖方舟的 PR必须同步更新 AGENTS.md否则 CI 挂掉。有些团队会在 CI 里加一个轻量检查比如如果本次 PR 修改了模块 A但 AGENTS.md 中关于模块 A 的内容在最近 N 次提交中没有任何更新给出警告。这个检查逻辑不复杂但能有效防止规范腐烂。5. 多语言项目中容易忽略的隐性文化约束5.1 测试风格对 Agent 的影响每个语言社区都有自己的测试文化。Go 项目里大家都写表驱动测试Python 项目里大家更习惯 pytest fixtureTypeScript 项目里 jest 和 vitest 各有拥趸。Agent 默认会按它的训练数据里的最大公约数风格生成测试如果不规范它写的测试很可能和项目里现有的测试风格格格不入。AGENTS.md 里我会专门写一节测试风格至少明确三点测试文件放在哪里和源码同目录还是集中放test/用什么断言风格Go 的assert/requirePython 的pytest.raises覆盖率门槛是多少新增功能要不要强制补测试5.2 依赖管理列表应该直接写清楚多语言项目里Agent 在新增第三方依赖这件事上尤其大胆。它可能为了一个小功能随手 import 一个库完全不考虑这个库是否已经被弃用、是否有安全隐患、是否过大。在 AGENTS.md 里写清依赖清单和新增依赖的审批流程能有效防止这种依赖膨胀。我的做法是给每个模块单独列出允许使用的第三方库清单和禁止使用的库。比如前端模块里写Markdown 渲染不允许引入新的富文本编辑器库统一使用现有react-markdown封装的MarkdownView组件。这样 Agent 在遇到要在页面上渲染一段 Markdown的需求时就能马上找到正确的路径而不是自己上网找一个库装进来。5.3 日志、监控与可观测性约定这是很多人写 AGENTS.md 会漏掉的一环。Agent 生成的代码功能逻辑往往没问题但可观测性几乎为零——不打日志、不加 trace、不设自定义 metric。在多个服务协作的项目里这种代码一旦上线出了问题你根本无从排查。AGENTS.md 里我会写所有关键业务逻辑入口必须记录结构化日志日志必须包含request_id和user_id对外部服务调用必须接入当前的 trace 上下文性能敏感路径需要上报执行耗时。有个小诀窍给 Agent 一个日志工具的示例它就会比干巴巴地写要打日志听话得多。6. 新人引入与团队推广让 AGENTS.md 真正成为团队资产6.1 从我的规范变成我们的规范AGENTS.md 很容易成为某一个人的私藏——架构师写完之后自己用得很爽团队其他人根本不看Agent 也只受执行它的人影响。要让 AGENTS.md 成为团队资产第一步是把编写过程开放出来。我建议在团队内部开一次架构评审会专门讨论 AGENTS.md 的内容。会上让后端、前端、测试的同学各抒己见把他们遇到过的Agent 奇葩行为也加进去。这样的好处是每个人都在这份规范里有贡献他们会主动在 PR 里引用它。6.2 在 CI 中做规范连通性检验AGENTS.md 本身是纯文本无法被静默执行但你可以做一些间接的连通性检验。比如检查 AGENTS.md 中提到的目录路径在仓库里真实存在避免规范指向不存在的路径检查 AGENTS.md 中提到的命令pytest、go build、npm run build能否在 CI 环境执行通过如果 AGENTS.md 中声明了禁止使用某些依赖可以在 CI 里加一个简单的 grep 或依赖扫描任务做硬校验。这些检查逻辑都很简单写起来不费事但会让 AGENTS.md 不只是一份建议文档而是一份可以被自动验证的规范。6.3 持续运营用 Agent 的反馈反哺规范最后分享一个我最近在用的新玩法把 Agent 每次被 review 打回的原因做个统计然后定期更新 AGENTS.md。比如你发现 Go worker 里 Agent 经常忘记处理 context 取消那就在 worker/AGENTS.md 里加一条所有DoSomething方法必须接受ctx context.Context作为第一个参数并遵循取消传播语义。这样一来规范里的每一条都来自真实的失败经验而不是架构师拍脑袋想出来的理论Agent 的升级速度会明显加快。我个人的体会是AGENTS.md 的编写过程其实是把一个团队积攒多年的隐性架构知识显性化的过程。它不只是给 AI 看的更是逼着团队把大家心里都明白但没人写下来的规则落到纸面上。一开始写的时候你会觉得麻烦但坚持一两个迭代之后你会发现不光是 AI Coding Agent 变听话了连团队新人上手的速度都快了不少。最后再分享一个小技巧如果你实在不知道怎么开头先把反面示例写出来。从项目里找 5 个 Agent 曾经生成过的、被 code review 打回的代码片段放进 AGENTS.md 里作为反面教材。这份材料本身就是一份比任何专家都了解你项目的规范草稿。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑