1. 无状态模型的痛点:为什么 AI 编程总在“重复造轮子”
先讲一个我自己的经历。去年年初,我带着团队做一个内部代码评审辅助工具,基本思路是把新提交的代码片段交给大模型,让它对照团队编码规范做静态检查。第一版跑通时效果还不错,模型能准确识别出命名不规范、缺少边界校验这些基础问题。但用了不到两周,问题就暴露出来了——每次评审都像面试一个失忆的新人。
代码里明明有全局约定“所有对外接口必须显式校验参数”,但模型每次评审时都会漏掉这条规则;上一轮刚指出“日志禁止打印敏感字段”,下一轮遇到同样的模式它照样无视。后来我意识到,这不是模型能力的问题,而是我调用模型的方式有问题——每次对话都是独立的,模型既不知道你这个项目的背景,也记不住五分钟前你刚跟它强调过什么。这就是典型的无状态模型困境。
当时团队内部的讨论很有意思,有人说干脆把规范文档塞进 Prompt 里,有人提议做向量库做长期记忆,还有人建议在代码仓库里放一份“给 AI 看的说明书”。现在回头看,这三种方案恰好对应了 AI 程序设计中记忆工程的三个不同方向,而最终把我们引向 AGENTS.md 声明式配置的,是第三种思路的极致化。
先把这个痛点说透。无状态模型的核心特征是:每次 API 调用都是独立的请求,模型不保留任何跨请求的记忆。你可以在单次对话里塞很多上下文,但下一次调用必须重新组织。对 AI 编程场景来说,这意味着三件很消耗精力的事:
- 重复灌输项目背景:技术栈、目录结构、模块关系、编码规范,每次开新对话都得从头讲一遍。团队里有新人加入时,这个培训成本更高。
- 规则只能靠“临时强调”:你在某次评审中要求“DTO 不要直接暴露给控制器层”,但这句话只存在于那次对话的上下文窗口里。下一次评审,模型又回到“无记忆”状态。
- 约定无法沉淀:代码评审中产出的改进建议、设计决策、踩坑记录,本来应该变成项目资产,但因为模型不记得,这些知识就流失了。
最终让我下决心系统性解决这个问题的场景,是一个调用链评审任务。当时需要模型分析一个跨模块的数据流,我把五个模块的关键代码都贴进对话里,并在开头详细写了项目背景和评审重点。结果评审到第三个模块时,模型突然把第一个模块的技术栈记错了——它以为我们还是用旧版依赖注入框架。那一刻我意识到:光靠单次对话的组织能力已经到极限了,必须把“记忆”本身工程化。
2. 记忆工程的三个技术方向:缓存、向量检索与声明式配置
既然要解决“模型记不住”的问题,第一步是想清楚有哪些可行的技术路线。我不太建议一上来就追新框架,而是先把问题拆解成三个维度:记忆的存储位置、记忆的读取方式、记忆的更新机制。围绕这三个维度,我梳理了三种主流方案,并且各自做了小规模实验。
2.1 方案一:历史对话缓存(短期记忆路线)
这是最直观的做法——把过去的对话记录持久化,下次调用时自动带上最近几轮的内容。很多 AI 编程工具内置的“会话记忆”就是这个原理。实现上通常用一个 JSON 文件或者轻量数据库存对话历史,调用时按时间倒序拼进系统提示词。
这个方案的优点是简单、无侵入,几乎不需要改业务代码,接上就能用。但我的实测体验是,它的天花板很低:对话历史越长,Token 消耗越大,而且历史里的无关信息会稀释模型的注意力。有一次我把两周内的评审记录都拼进去,结果模型在长篇历史里“迷失”了,反而忽略了当前代码里一个明显的空指针问题。
所以我的判断是:对话缓存适合短周期的交互场景,比如连续调试一个函数,但撑不起“项目级长期记忆”的诉求。
2.2 方案二:向量检索增强(长期记忆路线)
第二种方案是当时团队里呼声最高的——把项目文档、代码片段、历史评审结论做向量化,存入向量数据库。每次调用前,根据当前问题的语义相似度,召回最相关的几条记忆,拼进 Prompt。这套做法在大模型应用里通常被称为 RAG(检索增强生成)。
我花了一周时间把内部的知识库文档和部分代码注释做了向量化,效果确实比纯对话缓存好很多——至少模型能想起来“这个项目的鉴权方式是基于 Token 的中间件实现”。但实测中也暴露了两个麻烦:
- 召回粒度不好控制:向量检索返回的是“语义相似”的片段,但“相似”不代表“对该任务正确”。容易出现召回内容与当前问题只是主题相近、实际用处不大的情况。
- 知识更新的滞后性:项目约定是动态演进的,今天刚决定废弃某个模式,向量库里昨天的切片还在强调它。你得维护一套索引重建流程,这在节奏快的迭代期里很占精力。
向量检索适合知识库内容庞大、无法靠人肉维护 prompts 的场景。但对一个中小型项目来说,它的运维成本偏高,而且“记忆的准确性”没有一个强保障。
2.3 方案三:声明式配置(规范性记忆路线)
第三种思路和前面两种完全相反——不依赖模型自己去“回忆”,而是把该记住的事情显式地写下来,在每次调用时作为固定上下文加载。这就是 AGENTS.md 这类声明式配置的核心哲学:记忆不是模型内部的黑盒状态,而是一份人可以阅读、评审、版本管理的文本资产。
在我实际测试中,这个方案给我最大的感受是“确定性”。同样是回忆项目约定,向量检索是“尽力而为”的相似度匹配,而声明式配置是“白纸黑字”的强制加载——只要配置里写了,模型每次都会看到。没有偶然性,不存在召回不到的情况。
当然,它也有自身的问题,比如配置一长,Token 开销会涨,而且如果配置组织得不好,反而会干扰模型对当前任务的理解。但这些问题可以通过结构设计来控制,我在后面专门用一节来讲。
三种方案对比下来,我的结论是:它们不是互斥关系,而是分层关系。AGENTS.md 适合承载最稳定、最不可动摇的“项目宪法”,向量检索适合承载频繁变动的“活知识”,对话缓存适合承载短周期内的“临时上下文”。如果只让我选一个优先落地,我一定选声明式配置,因为它性价比最高、最容易起步,而且能立刻缓解“重复灌输上下文”的疲劳。
3. AGENTS.md 声明式配置的本质:把团队约定“机器化”
先说清楚一个容易混淆的概念:AGENTS.md 不是一个软件、不是一个框架,它就是一个约定俗成的文件名——放在项目根目录下的 Markdown 文件,专门写给 AI 编程代理看。它的定位类似于项目里给人类看的最初级的 README,但两者最大的区别在于:README 是给人读的,信息密度和组织方式未必适合模型直接理解;AGENTS.md 是给 AI 看的“开机初始化文件”,要求结构清晰、指令明确、冗余度低。
这个设计背后的原理,其实是把“隐性的、分散在团队大脑里的上下文”转化为“显性的、集中存储的文本文件”。以前你告诉新人“先看看代码规范,再了解一下我们项目的模块边界”,现在你把这些话说给 AI 听,并且希望它每次开工前都自动读到。用一个接地气的类比来说:
无状态模型像一个每集都重新开始的电视剧,观众每次都得回忆前情提要;而 AGENTS.md 相当于把前情提要固定在片头,观众不用回忆,直接看片头就知道人物关系。
在工程实现上,AGENTS.md 的价值还体现在三个具体的方面:
- 版本可控:它是一份普通文本文件,可以纳入 Git 管理。每次修改都有 diff、有提交记录、能回溯,这比在对话里“口头上”约定一条规则可靠得多。
- 人机共读:文件本身也是团队新人的入门文档,新人看到 AGENTS.md 就知道“这个项目有哪些硬性约定”,等于一份活的团队规范。
- 低耦合接入:目前的 AI 编程工具和代码助手大多已经在兼容这种文件约定。你不需要写任何代码,只需要把文件放进仓库,部分工具在扫描项目结构时会自动加载它。
3.1 为什么选 Markdown 而不是 JSON / YAML
我见过有人用 JSON 或 YAML 写过类似的配置文件,配套写了 schema 校验、字段提示器,搞得很工程化。但实测下来,我建议默认选 Markdown,理由很实际:
- 模型对自然语言的指令理解比对结构化字段更稳健。你写“所有对外接口必须显式校验参数”,模型理解得比人还好;但如果你把这句话拆成
param_validation: required这样的字段,模型反而要额外做一层“解码”,还可能解错。 - Markdown 的维护门槛极低,任何能打开文本编辑器的人都能改。如果你的团队有非技术角色参与,比如产品经理想加一条“UI 文案不要用专业术语缩写”,改动成本基本为零。
- 层级结构天然适合表达“原则 → 细则 → 示例”这种知识模型。用
##、###做分区,模型在取用上下文时更容易形成结构认知。
当然,对于想用程序自动解析配置的场景,MD 的灵活性反而是缺点——不好做严格校验。但 AGENTS.md 的核心读者是 AI 模型,不是程序代码,所以这个缺点影响不大。
3.2 声明式配置的读取机制:每次对话都强制加载
关于 AGENTS.md 的加载机制,很多文章写得含糊。我从一个工程实践的角度说一下它的“工作过程”,简单说就是三步:
- AI 编程工具在打开一个项目时,会扫描项目目录,发现根目录下存在 AGENTS.md 文件。
- 工具把文件内容自动注入到当前会话的上下文窗口(通常拼在系统提示词附近,优先级高于用户输入)。
- 用户在对话中提问、补全代码、做评审时,模型始终能看到这份文件的内容,而且每次新开会话都会重新加载。
这个机制决定了它的一个特性:配置的“保质期”取决于仓库更新频率。你改了 AGENTS.md,下次会话就会读到新版本——这比改完向量库还要跑索引任务简单得多。
我亲手做过一个压力测试。在一个中等规模的后端项目里放了一份约 120 行的 AGENTS.md,然后连续开了十个新会话,让模型分别回答“这个项目用什么语言”“模块 A 和模块 B 之间的依赖方向”“上线前需要跑哪些检查”之类的问题。结果十个会话全部答对,没有一次需要我重复解释背景。这个小实验基本验证了它的实用性。
4. 从无状态到有状态:我踩过的配置坑与实操模板
理论讲完,该到实战部分了。我之前在一篇文章里提过一个观点:AGENTS.md 不是写得越多越好,而是写得越对越好。这里说的“对”,包括内容分层、指令强度分级、负面清单的写法,以及最容易被忽略的——更新节奏。
4.1 配置内容的组织逻辑:宪法、操作手册、负面清单三段式
我参考多个项目的落地经验,把 AGENTS.md 的内容拆成三层:
| 层次 | 定位 | 内容示例 | 重要性 |
|---|---|---|---|
| 项目宪法 | 不可动摇的基本原则 | 技术栈、模块边界、数据流方向、安全红线 | 每次调用必须加载 |
| 操作手册 | 指导 AI 如何完成常见任务 | 测试怎么写、命名规范、提交信息格式 | 任务相关时加载 |
| 负面清单 | 明确禁止做的事 | 禁止硬编码密钥、禁止绕过中间件、禁止在日志打印敏感字段 | 每次调用必须强调 |
这种分层的好处是,模型在长上下文里能够更快定位到“当前任务该看哪一段”。我在配置开头还会写一个“索引段”,用两三行告诉模型这份文件的结构,类似目录。实测下来,这能有效减少模型“沉浸”在无关段落里的情况。
4.2 一份可以直接改用的 AGENTS.md 模板
下面这个模板是从一个模拟项目里提炼出来的,我自己在几个项目里反复调整过,可以直接复制后按需修改。注意格式上我刻意做了精简,只保留最重要的区块。
# AGENTS.md ## 项目身份 - 项目代号:某内部服务(替代名) - 主要语言:Java 17 + Spring Boot 3.x - 构建工具:Maven - 数据库:PostgreSQL 15,禁止使用 MySQL 专属语法 ## 架构红线 - 模块依赖方向:controller -> service -> repository,禁止反向依赖。 - 所有外部接口必须在 service 层做参数校验,controller 层不写业务逻辑。 - 消息队列只在 producer/consumer 模块使用,禁止在业务模块直接引入。 ## 编码约定 - 命名字典:类名用名词(如 OrderService),方法名用动宾(如 createOrder)。 - DTO 与 Entity 必须字段映射,禁止直接暴露 Entity 给前端。 - 日志规范:统一使用 Slf4j 占位符写法,禁止字符串拼接。 - 日期格式:对前端输出一律使用 UTC 时间戳,本地时间只在展示层转换。 ## 测试要求 - 新功能必须附带单元测试,覆盖率不低于 80%。 - Mock 规则:外部依赖用 mock,数据库用 Testcontainers。 - 禁止在测试里使用 Thread.sleep 等待异步结果。 ## 负面清单(Never Do This) - 禁止硬编码数据库连接串或密钥,所有配置走环境变量。 - 禁止在异常处理时 catch 后吞掉异常,必须记录日志并向上抛出。 - 禁止修改已上线的数据库表结构,变更必须走迁移脚本。 - 禁止在代码仓库提交本地生成文件(target/、node_modules/ 等)。用的时候有两点要注意:
- “项目身份”段落别写太长,两三行足够。它只是帮模型快速定位上下文,不是项目简介。
- 负面清单的每一项,尽量配半行解释,比如“因为运维会告警”或“因为会拖垮查询性能”。模型如果只知道“不能做”而不知道“为什么不能做”,在面对变体场景时往往判断不准。
4.3 第一次落地时的三个典型错误
我把自己第一次配置 AGENTS.md 时踩过的坑总结一下,这几条应该能帮你少走弯路。
错误一:把所有东西都塞进去。我当时把二三十条细节全写进文件,结果单次上下文直接多出三千多个 Token,而且模型在处理具体任务时反而频繁被无关条目干扰。后来我做了取舍:只保留“如果不遵守会造成事故”的条目,其余有弹性的建议移到项目 Wiki。
错误二:配置和代码规范脱节。如果 AGENTS.md 里写的约定,代码里根本没有体现——比如你规定“禁止直接暴露 Entity”,但控制器里全是 Entity 作为入参——那模型就会困惑,不知道该信哪个。配置必须与真实代码保持同步,否则它就是一个会误导模型的“过期地图”。
错误三:把 AGENTS.md 当成一次性工程。第一次写完后,我大半年没动它。结果项目引入了新的缓存组件,架构红线变了,文件里却没更新。直到某次评审时模型还在按旧规则检查,我才意识到这种文件的“时效管理”决定它的生死。现在我的习惯是:只要架构或规范发生变更,第一件事就是同步更新 AGENTS.md,把它当成一份有生命力的活文档,而不是发霉的世外桃源。
5. 与向量检索的协同:声明式记忆做骨架,检索做补充
前面说过,AGENTS.md 适合承载稳定知识,但它对“频繁变化的活知识”并不擅长。比如你最近一周的代码评审结论、某个模块刚重构完的新结构、某个第三方库刚发现的坑,这些内容如果都写进 AGENTS.md,文件会迅速膨胀到不可维护。
我的做法是把两者结合起来:AGENTS.md 作为骨架,向量检索作为肌肉。
具体落地方式是这样的:
- AGENTS.md 里只写“方针性”内容,比如技术栈选型、架构方向、编码原则。
- 具体到某个模块的当前状态、历史决策记录、近期变更摘要,则放入向量库。
- 调用模型时,固定加载 AGENTS.md,同时根据当前任务语义去向量库检索相关模块的状态信息,拼进上下文。
这个组合的好处在于,模型面对的是“总纲 + 局部现状”的完整上下文,既不会遗忘全局约定,又能感知近期变化。我曾在一次需要评审一个刚重构模块的任务里同时用了这两种方式:AGENTS.md 提供了“该模块必须保持接口兼容”的红线;向量库召回了“重构后缓存策略从本地改为 Redis”的近期决策。模型给出的评审意见明显更有针对性,不再只是泛泛的代码风格检查。
对于个人开发者或者小团队,如果暂时没精力搭向量库,也不用觉得这是短板——先用好 AGENTS.md,就已经能把 80% 的“重复介绍项目”问题解决掉。向量检索是在你感受到“AGENTS.md 记录不过来”的时候,再考虑的下一个阶段。
6. 团队协作中的 AGENTS.md 工作流:评审推进与文件治理
AGENTS.md 虽然是一个文本文件,但当它进入多人协作环境后,就变成一个需要“治理”的资产。我在团队里推行这套机制时,遇到过三类比较典型的问题。
6.1 谁来改?变更流程怎么定?
一个很实际的问题是:AGENTS.md 写好后,A 开发觉得“这个约束太死,影响效率”,B 测试觉得“约束不够,容易踩坑”,双方僵持时谁来定音?
我最终参考了一个比较成熟的方案:把 AGENTS.md 视同接口契约来管理。改动前需要发起一个简单的评审单,写明变更点、受影响模块、可能副作用,至少两名相关开发者确认后合入。虽然流程上多了一步,但它能避免“拍脑袋式”地加一条规则,也能防止某些约定被随意弱化。
实际操作中,我建议直接在代码评审请求的描述里附上变更说明,不搞额外系统。团队本来就在同一个仓库协作,顺手的事。
6.2 如何让模型不“过度遵守”配置?
AGENTS.md 太有效有时候也是问题。有一次模型因为看到“禁止修改已上线的数据库表结构”,在评审一个新增字段的迁移脚本时,给出了“建议回滚”的错误判断——它把“迁移变更”误认为是“危险操作”。
这个问题的解法,不是把负面清单删掉,而是在每个约束后面写上适用范围。比如:
- 禁止修改已上线的数据库表结构(特殊情况:新增扩展字段并利用默认值填充,仍可走迁移流程,但必须附带回滚方案)。这样模型在遇到边界情况时能得到明确指引,而不是机械地执行禁令。调整之后,类似的误判明显变少了。
6.3 文件膨胀怎么办?
如果你用得很认真,AGENTS.md 会随着项目演进不断变长。当它超过三四百行时,对模型的价值反而开始下降。我遇到这个问题后的处理思路是“分层拆文件”:
- 根目录保留一个精简版的 AGENTS.md,只描述项目身份、架构红线、负面清单。
- 详细的操作手册、测试约定、工具配置等,分散到
docs/agents/目录下的子文件,比如docs/agents/frontend.md、docs/agents/testing.md。 - 部分 AI 编程工具支持在 AGENTS.md 里用
import或相对路径引用其他文件,模型在任务相关时才去读取子文件。
在不能通过配置文件自动引用子文件的场景里,我会在最顶部写一个“文件索引”,让模型先看目录,再按需请求对应文件内容。这样既能维持信息密度,又不会把所有内容一股脑塞进上下文。
7. 效果度量与未来方向:不只是“记得住”,更是“用得好”
花了不少篇幅讲配置方法,最后用一节来说说怎么判断这套机制到底有没有用,以及它未来可能演变成什么样。
度量方式上,我不建议拍脑袋感觉“效果变好了”,而是定几个可观察的指标:
- 重复性问题数量:统计过去两周评审对话里,开发者需要向模型重复解释项目背景或者规范的次数。引入 AGENTS.md 后,这个数值应当显著下降。
- 关键约定漏检率:在代码评审任务里,故意藏几个明显的“约定违规模式”,看模型能不能发现。这个指标能直接反映声明式配置是否被模型真正“读到”且“理解”了。
- 上下文 Token 消耗:对比配置前后,完成同类任务的 Token 消耗。如果配置组织合理,它能在不显著增加 Token 的同时,大幅减少对话轮数——因为很多背景不用再临时解释了。
我在用过一段时间后,最明显的一个感受是:AI 编程时不那么“愣头青”了。从前模型像个只知道当前文件的局部受理员,现在更像一个有项目全局观的协作者。当然,它还做不到百分之百稳定,但已经足够把“重复交代背景”的时间省下来,真正聚焦在有难度的设计决策上。
说到未来,我看好两个方向。一个是记忆分层的进一步工程化:AGENTS.md 这类声明式配置好好沉淀成“项目宪法”,向量检索能做得更智能,再加上会话记忆,三者各司其职。另一个是动态配置生成:未来可能有工具根据项目的 commit 历史、代码结构变化,自动建议 AGENTS.md 该更新哪些条目,减少人工维护成本。不过这些都是后话了,眼前最值得做的一件事,就是给你的项目建一份 AGENTS.md,然后用一次真实任务去测试它到底能省多少事。
在我自己动手做这份文件之前,我也觉得“给 AI 写说明书”听起来有点繁琐。但真正用起来之后,我发现它其实是在帮自己整理思路——你强迫自己把以前只存在于口头和脑中的约定写下来,这个动作本身,就已经让项目变得更有结构、更容易交接、也更经得起迭代了。