ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

从无状态模型到AGENTS.md:让AI编程助手拥有项目记忆

从无状态模型到AGENTS.md:让AI编程助手拥有项目记忆

这两年做 AI 辅助开发,有一个感受特别深:模型的能力一直在涨,但它在项目里的“记性”始终是那块短板。你用同一个工具,今天聊清楚了模块边界、数据流向、哪些文件不能动,明天重新开一个会话,它又全忘了。你只能一遍遍地把项目结构、构建命令、代码规范贴进上下文,然后眼睁睁看着它在不该改的地方乱动。这个问题的根源,恰恰就藏在“无状态模型”这四个字里。

围绕这个痛点,行业内其实已经走过了两条路:一条是给模型补记忆的 Memory 工程,另一条是近两年才真正火起来的 AGENTS.md 声明式配置。这两种思路不是替代关系,而是一次编程范式的转换——从“无状态模型 + 每次现场沟通”,走向“有状态协作 + 一次性约定”。这篇文章不是纯概念科普,我想把它讲成一段可以落地的演进记录:无状态模型到底卡在哪,Memory 工程补了什么、又漏了什么,AGENTS.md 为什么能补上这块,以及我实际给项目写配置时踩过的坑。适合正在重度使用 AI 编程助手、又受够了反复“调教”的工程师,也适合对 AI 编码工具链有兴趣、想弄明白背后机制的人。文中我会给出一份可以直接抄的配置模板,以及几个容易踩但不有人明说的细节。

1. 无状态模型的本质与 AI 编程的第一性困境

1.1 无状态到底意味着什么:每次对话都是一次“失忆”开机

先说一个最容易被忽略的基本事实:绝大多数 AI 编程工具背后的大语言模型,在 API 层面是“无状态”的。所谓无状态,是指每次请求之间没有任何天然的记忆,模型处理完一次输入、给完一次输出,这段对话就结束了。开发者如果想要让模型“想起”稍早前的内容,唯一的办法是把那些内容重新拼进下一次请求的输入里。

这个机制很像一个极端场景:你面前坐着一个非常聪明、但患有严重短期失忆的实习生,你每说一句话,他都当你是第一次开口。你只能在每次开口时,把前因后果、背景材料全部塞进一张纸上递给他。那张纸就是上下文窗口,内容一多,前面的字就被挤掉了。

理解这一点,才能理解后面所有的问题。所谓“AI 编程助手”,在无状态约束下的本质工作方式,就是“一次性输入 + 一次性输出”。工具本身或许会在产品层面帮你缓存对话历史,但缓存不等于记忆——它只是把你和模型之间发生过的内容再翻出来,重新放进上下文窗口。缓存一断、会话一重启,一切归零。

1.2 失忆现场:AI 编程中最典型的几个崩坏场景

无状态带来的失忆,在真实开发流程里非常具体,我列几个你一定见过的现场:

  • 换会话后失忆。早上你和工具一起梳理了某个老项目的三层架构,约定好“所有数据库访问必须走仓储层”。下午开新会话让它加个功能,它直接绕过仓储层,在控制器里裸写查询。
  • 长对话末尾被人为截断。聊了一个小时,上下文窗口快满了,工具开始“忘了”最开始的架构约束,甚至为了节省 token 自己压缩历史摘要。摘要一压缩,细节丢失。
  • 多文件修改时缺少全局观。让它重构一个函数,它只改了函数本体,不改所有调用方,因为调用关系在之前几轮对话里出现过,但现在已经滑出窗口了。
  • 执行链断裂。你让它跑测试、发现失败、修复、再跑,这一整套动作如果跨了多个会话,它每次都要重新理解“项目怎么跑测试”“当前的失败是什么”。

这些现场的共同点是什么?不是模型能力不足,而是模型根本没有一个跨越时间的稳定记忆载体。能力再强,也架不住每次都是全新的开局。

1.3 提示工程的手动补偿:为什么撑不住

既然无状态是前提,那早期几乎所有团队的做法,就是用提示工程去补偿。典型操作有三种:把项目约定写进系统提示词、在每次会话开头复制一段“项目须知”、或者干脆搞一个巨大的 prompt 模板,让工具每次先读一段自我介绍再开始干活。

这三种做法我全都试过,结论是:短期有效,长期痛苦。第一,上下文窗口是稀缺资源,你把几 KB 的项目约定塞进去,留给真实代码和任务的空间就少了,尤其是处理长文件、大改动的场景,非常吃亏。第二,这种“须知”是人肉维护的,和代码仓库脱节,项目一改,提示词忘了改,工具拿着过时约定反而帮倒忙。第三,每个开发者自己存一份模板,格式五花八门,团队内部根本没有统一口径。

这其实是“无状态模型”时代的一种必然挣扎——你把记忆硬塞进每次对话的输入里,代价高昂,还不可持续。所以行业内开始认真想过一个问题:能不能给模型一个真正的外置大脑?这就是 Memory 工程。

2. Memory 工程:为模型搭一个外置大脑

2.1 Memory 工程的核心命题:把上下文变成可管理资产

Memory 工程的目标很简单:让模型在多个会话、多个任务之间保留并复用信息,而不是每次从零开始。这个概念最初是从对话机器人领域火起来的,后来被引入 AI 编程工具链。它的核心思路是把“对话历史”“项目知识”“用户偏好”这些信息,从易失的上下文窗口里抽出来,放到一个可读写、可检索、可持续更新的存储层。

我习惯把这里的记忆分成两层:短期记忆和长期记忆。短期记忆就是当前会话内来回传递的对话历史和当前任务状态,它生命周期短,但实时性最强。长期记忆则需要跨会话存活,比如一个项目的架构决策、API 约定、目录规范、团队成员的工作习惯。AI 编程真正缺的,主要是长期记忆——它要能在新会话开始时,自动“想起”这个项目是什么、应该怎么干。

2.2 记忆的四种常见载体与取舍

行业内做长期记忆,主流有四种载体,各有各的适用场景:

  • 对话摘要。把每次会话的关键结论自动缩写成摘要,下次会话开始时加载。轻量,但丢失细节,摘要本身就是有损压缩。
  • 记忆文件。用一个或多个文本文件(如项目说明、约定文档)存放关键信息,会话开始时让工具读取。直观、可控,但依赖人工维护。
  • 向量数据库 / RAG 检索。把项目文档、代码注释、历史对话切片做成向量索引,工具根据任务语义自动检索相关内容。自动化程度高,但需要额外基础设施,同时存在检索不精确的问题。
  • 自动记忆模块。部分工具提供了记忆插件,自动记录用户偏好和历史决策,下次自动调用。体验好,但黑盒属性强,你不知道它记住了什么、什么时候会忘。

如果把这些方案并排放在一起,能明显看到一个矛盾:越自动的方案,越不可控;越可控的方案,越依赖人工。向量检索很聪明,但它是猜你要什么,而不是明确告诉你“这个项目就是这样”;对话摘要很方便,但压缩过程中会丢掉棱角;人工记忆文件最可靠,但维护成本全部压在人身上。

2.3 早期 Memory 工程的局限:记忆和代码仓库脱节

我实际用下来,早期的 Memory 工程方案有一个通病:记忆被放在项目之外。你的摘要存在工具的本地配置里,向量库存在数据库或云端,自动记忆模块存在工具自己的存储空间。这些记忆跟代码仓库没有版本关系,项目迭代了,记忆却可能还停留在三个月前。而且它们基本是私有数据,换一台机器、换一个工具、加一个协作同事,记忆就断档了。

更隐蔽的问题是被动性。记忆系统做得再好,它也是在“模型需要时”去查、去读,模型自己并不知道哪些信息是这个项目里不可违背的硬约束。你可以让摘要里写“不允许改用户表结构”,但模型仍然可能忽略——因为在它看来,那只是一条参考信息,不是行为边界。

这些局限让我意识到,光靠“给模型补记忆”是不够的,记忆必须升级成一种项目层面的、对模型有强制力的“约定”。于是 AGENTS.md 这种声明式配置开始进入视野——它不是给模型提供背景知识,而是直接告诉模型:在这个项目里,什么必须做、什么不能做、按什么流程做。

3. AGENTS.md 声明式配置:从每次解释到一次性约定

3.1 AGENTS.md 到底是什么:给智能体看的 README

AGENTS.md 本质上是一个放在项目根目录(或子目录)的 Markdown 文件,里面用结构化、声明式的语言描述这个项目的“智能体行为契约”。当 AI 编程工具进入项目时,会自动读取这个文件,把它当作理解项目、规范自身行为的第一手资料。

你可以把它类比成给智能体看的 README:传统 README 是写给人类开发者看的,介绍项目是什么、怎么跑起来;而 AGENTS.md 是写给 AI 智能体看的,重点不止于此,还包含你在编程协作中希望它遵守的规则和边界。一次声明,之后每次会话都自动生效,不需要你再复制粘贴。

这个思路最大的变化,是把“记忆”从工具的私有存储里解放出来,放进项目的版本控制里。AGENTS.md 成为代码仓库的一部分,跟着代码一起演进、一起审查、一起被所有人分享。记忆从此变成了协作资产,而不是某个人的私有配置。

3.2 它解决的,是提示工程里最无解的隐性知识问题

为什么说 AGENTS.md 补上了记忆工程漏掉的那块?因为它解决的是“隐性知识显性化”的问题。任何项目里都有一堆没人写进文档、但老手默认知道的事情:这个模块虽然叫 payment,但里面核心逻辑是库存锁定;那个脚本只在本地调试用,CI 里绝对不能跑;后端改了接口,前端类型总是人马不停蹄地对齐……

这些知识以前存在于老成员的脑子里,新人靠问、靠踩坑才能积累,AI 工具则靠每次会话里被反复重申才能勉强不犯错。AGENTS.md 给了它们一个标准落点:你把所有想对智能体讲的边界和流程写进去,工具启动时必读、且按此执行。这比任何 RAG 检索都更直接——不需要模型去“猜测”这个项目的规矩,项目自己把规矩说清楚了。

3.3 配置里到底该写什么:核心板块拆解

根据我给多个项目写 AGENTS.md 的经验,一份好配置通常包含六个板块,每个板块对应一类信息:

  • 项目一句话概述。告诉智能体“你在哪个项目里、这个项目是干嘛的”,避免它用通用知识误解代码意图。
  • 技术栈与目录地图。列出主要语言、框架、关键目录职责。这点特别适合 monorepo,能帮工具快速锁定改动范围。
  • 常用命令清单。构建、测试、lint、单测、特定环境的命令要写清楚,而且必须是真实可用的命令,不是“建议参考 package.json”。
  • 代码风格与约束。缩进、命名、组件组织、接口设计约定,越具体越好。
  • 架构边界与禁区。哪些层之间不能直接调用、哪些表不能随便动、哪些文件是生成的不要手动改。这部分最提气,因为它直接阻止了模型干蠢事。
  • 工作流约定。改完代码要不要跑测试、提交前要做哪些检查、遇到 API 变更的第一动作是什么。

实际写的时候,很多人会犯一个毛病:把 AGENTS.md 写成一本代码规范书。其实它应该更像一份“作战简报”——短、准、可执行,每一条都能直接约束行为,而不是表决心的废话。

3.4 和同类配置的对比:为什么“声明式”是范式转换

现在市面上的 AI 编程工具,不少都已支持“项目级规范文件”的机制,有些以工具名命名、有些沿用通用约定,AGENTS.md 是目前被讨论最多的一种开放形式。把它们放在一起看,能更清楚看到趋势:

维度传统 README / 文档工具私有记忆 / 向量检索AGENTS.md 声明式配置
目标读者人类开发者AI 模型(被动获取)AI 智能体(主动读取)
存储位置代码仓库工具本地 / 外部存储代码仓库 / 版本控制
更新方式人工维护自动/半自动人工维护 + 代码评审
强制力无弱(可能不加载)强(启动必读)
跨工具通用是否是(开放性约定)
维护成本中低但不可控中但可控

这张表背后,是一次看待 AI 协作方式的范式转换:以前我们默认模型是“无状态的临时工”,于是每次都得面试式地把规矩讲一遍,记忆工程则是试图给临时工开小灶;而 AGENTS.md 的思路,是把“这个项目怎么干活”直接做成了标准合同,一入职就自动签好。用工程化的语言说,就是把每次对话都要重新博弈的高成本协商,变成了一次低成本、可版本管理的配置协商。这就是“声明式”三个字的真正分量。

4. 实操:为项目编写一份高质量 AGENTS.md

4.1 写之前,先用三个问题盘点项目事实

动手写配置前,先不要打开编辑器,而是先回答三个问题:这个项目是怎么被构建和测试的?这个项目里有哪些“看不见但很重要”的约束?哪些代码我绝对不想让 AI 动?

我通常会在终端里快速收集信息。先用 ls 和 find 摸清目录结构,再看 README 和根目录下的配置文件确认技术栈,翻几眼 package.json、pyproject.toml、go.mod 这类文件拿到命令入口。最关键的一步,是看最近两位数的 git log 提交记录,从中找到那些反复出现的模式:大家改哪些文件、提交前做什么检查、哪块代码一直出问题。

这个过程能帮你把“我认为项目是这样”和“项目实际是这样”对齐。我知道有人会嫌麻烦,但 AGENTS.md 的价值是长尾的,前期盘点做得越真实,后面工具帮你省的时间越多。

4.2 一份可以直接抄的配置模板

下面是我在内部项目里长期使用的精简模板,你可以直接拿过去改。需要注意模板只是骨架,具体内容必须来自你项目的事实,不能照抄。

# AGENTS.md ## 项目概述 这是一个基于 XX 框架的 YY 服务,主要负责提供 ZZ 能力。 代码采用分层架构:接入层 / 业务层 / 数据层,禁止跨层调用。 ## 常用命令 - 安装依赖:npm install - 本地开发:npm run dev - 运行测试:npm test - 类型检查:npx tsc --noEmit - 代码检查:npm run lint ## 目录地图 - src/api:HTTP 接口定义,所有路由入口只允许出现在这里 - src/services:业务逻辑,一个 service 文件只处理一个业务域 - src/repositories:数据访问层,所有数据库操作必须经过这里 - src/generated:生成代码,永远不要手动修改,改完重新生成 ## 代码约束 - 接口返回统一用标准响应格式,错误码定义见 docs/error-codes.md - 数据库表结构变更必须走迁移脚本,禁止直接改历史迁移文件 - 新增第三方依赖前,先查一下是否已有同类依赖 ## 工作流 1. 修改代码后必须运行 `npm run lint`,通过后再提 MR/PR 2. 涉及数据层的变更,必须在提交说明中标注影响的表 3. 如果测试失败,先修复导致失败的代码,再重跑测试

写这份文件的几个要点:每条都不能有歧义,比如“禁止直接改”就比“尽量别改”有效得多;命令必须是实际跑过、验证过的,不能凭感觉写;涉及链接的地方,直接指向仓库内的文档路径,让工具能自己打开。

4.3 怎么验证配置真的生效了

很多人写完 AGENTS.md,就以为万事大吉。我见过最坑的情况是:配置写了一长串,工具根本就没读,而作者浑然不知。所以落地之后,必须做一轮验证。

我的验证套路分三步。第一步,新建会话,故意问工具两个问题:“这个项目怎么运行测试?”“这个项目里哪些目录是不能手动改的?”,看回答内容是否来自你的 AGENTS.md。如果它答得和文件里一致,说明加载链路通了。第二步,给它布置一个轻微“越界”的任务——比如让它在 src/generated 里改一行代码,看它会不会主动拒绝或提示“根据项目约定,此文件不应手动修改”。第三步,有条件的话开工具的执行日志,确认每次会话启动时 AGENTS.md 是否被读取,以及被读取的目录范围。

这三步走完,你对这份配置是“真合同”还是“摆设”就有了确切答案。

4.4 避坑指南:我从实盘里总结的五个反模式

写 AGENTS.md 踩过的坑,远比写的过程多。这里列几个最常见的,给后来人排雷:

  • 把配置写成散文。大段描述性文字对模型的理解帮助有限,声明式配置功夫在结构化、条文化的约束上,每条最好能独立生效。
  • 写过多无效信息。“使用代码质量较高的方式”“优雅地处理错误”这类话等于没说,模型不知道你心里的“优雅”到底是什么。宁可写“错误响应必须包含 code 和 message 两个字段”。
  • 命令没有验证。写测试命令之前自己先跑一遍,确保命令真的存在、真的能跑通。机器人可不会帮你圆场。
  • 混入过期信息。AGENTS.md 不是一次性文件,它跟着项目走。技术栈换了、目录重构了、命令变了,都要同步更新,否则就是给工具喂过期的地图。
  • 试图一文件管所有。单个根目录文件适合中小项目;大型仓库建议根目录只写全局约定,子模块用独立的嵌套配置细分,避免主文件膨胀。

5. 常见问题与排查技巧实录

5.1 配置好像没生效,先检查这四个地方

遇到 AGENTS.md 没生效,先别急着怀疑工具坏。我通常按这个顺序排查:第一,文件位置是否正确——必须是项目根目录,名称大小写要严格符合约定;第二,文件编码是否为 UTF-8,有时候用其他编码会导致识别异常;第三,工具是否真正重启,多数工具只在会话启动时加载配置,改完文件必须开新会话;第四,确认这类配置文件没有被工具的忽略机制排除掉,比如有些只能读特定名称的规范文件。

这一套下来,八成问题都能定位。剩下的要么是工具不支持、要么是加载链路太深,需要去翻工具的文档确认支持范围。

5.2 指令冲突了怎么办:谁能覆盖谁

在项目里同时存在多个规范文件时,冲突不可避免。比如根目录 AGENTS.md 说了“所有路由必须走 api 目录”,但子模块的配置文件里写了“本模块独立路由”,工具听谁的?

我的经验是,约定一个明确的优先级规则,并把规则写进根目录文件的开头。常见做法是:子目录配置优先于根目录配置,因为它更接近具体代码,描述的场景更准确;同一目录下,项目级约定优先于工具私有配置,因为前者被代码评审控制,后者可能存在个人偏好。冲突时不要指望工具自己判断,你必须在文件里明确写出来,让规则本身没有歧义。

5.3 文件越来越长,token 开销变大,怎么收敛

瘦身和落地是同步的工程,不是头痛医头。如果发现 AGENTS.md 越来越长、上下文窗口摄入开销明显,我会做三个动作。第一步,内容分级:把“必须遵守的硬约束”留在 AGENTS.md,把“背景知识、细节指南”挪到 docs 子目录,在文件里只留链接。第二步,压缩表达:能用表格和列表演达的,不要写成句子,两行表格往往能替代八行文字。第三步,动态加载:如果工具支持按目录递归读取,根目录只放全局信息,细分约定下沉到具体模块,这样大多时候工具只读跟手头任务相关的那份,而不是每次都吞下整个仓库的规范。

5.4 团队协作,怎么让规范文件不过期

AGENTS.md 最大的风险不是写不好,而是没人维护。我的做法是把它当成一等公民对待:进代码评审范围,谁动了目录结构谁来同步更新;通过 CI 脚本校验关键命令是否仍然存在于配置文件里;每隔一段时间,专门安排一次“规范对账”,拿真实任务测试配置有没有过时。听起来繁琐,但比每次新人都来问“这个项目怎么跑”要省得多。

另一个值得提的点是把 AGENTS.md 纳入团队 onboarding 流程。新人进项目,第一件事是读这份文件,再让他在工具里开个会话,验证 AI 的回答是否和文件一致。这个动作能同时检验规范和工具链的健康度,一举两得。

6. 个人体会与后续扩展

6.1 用了 AGENTS.md 之后,我对 AI 编程的心态变了

对我来说,AGENTS.md 最大的意义不是让 AI 少犯错,而是把我和 AI 协作的方式,从“每次现场调教”变成了“事先约定好再开工”。以前新会话启动,我总是抱着“这次它会不会又乱来”的警惕;现在只要项目根目录有这份文件,开新会话的焦虑感会低很多,因为我知道初始约束已经就位了。

心态转变也带动了工作方式的变化。以前写代码前要花时间在对话里描述任务背景,现在背景都写在配置文件里,我可以直接把精力投到更具体的业务逻辑上。这个体验,就像从“每天面试一个新实习生”变成“团队里固定有一个熟悉项目规矩的老成员”。

6.2 顺着这个思路,我还在玩两件事

AGENTS.md 只是一个起点。我现在在尝试把它和 Memory 工程的其他手段组合成一套分层记忆:AGENTS.md 负责静态约定,向量检索负责动态知识,会话摘要负责短期上下文。静态约定保证底线,动态检索负责喂料,短期上下文负责临场发挥。三者各管一段,效果比单一手段好用得多。

第二件事,是用脚本自动生成 AGENTS.md 的项目事实部分。我写了一个小工具,扫描项目结构、提取命令入口、解析目录注释,自动生成配置的初稿,人工再补充业务约束。这样既降低了写配置的启动成本,也保证基础信息不过期。后面如果有精力,我甚至想把它接进 CI,每次代码更新都自动 diff 一下配置文件是否过时。

说到底,AI 编程的前沿不只在模型参数里,也在于我们怎么组织人和模型协作的上下文。AGENTS.md 这类声明式配置,用最小的成本,把这个组织过程工程化了。我个人的体会是:别把它当成又一个要维护的文档,把它当成你写给智能体的第一行代码——这行代码写好了,后面所有对话都会顺畅很多。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进