用 Markdown 构建 Agent 记忆:透明、可审计、零迁移成本的轻量方案
前面我们聊了很多向量库、知识图谱和复杂的记忆框架,你可能会问:有没有更轻量的 Agent 记忆存储方案?
为什么 Markdown 能作为 Agent 记忆
Markdown 在本质上是一种人和 Agent 都能直接读写的“显式长期记忆”。它不依赖数据库,不需要向量引擎,也不用配置复杂的检索管线。
它的核心优势在于透明、可审查、可版本化、低成本:
- 透明可审计:任何时候打开文件,都能看到 Agent 记住了什么、写入了什么,零黑箱。
- 持久化:文件直接保存在磁盘上,不依赖进程存活。崩溃、重启、换机器,记忆依然完整。
- 版本控制:记忆可以提交到 Git,随时回滚、分支、进行 Code Review,协作得心应手。
- 零迁移成本:标准格式,无供应商锁定。切换模型或框架,只需迁移文件即可。
- 成本极低:本地存储几乎不产生费用,而向量数据库却可能显著推高成本。
Manus 把文件系统视作结构化的外部记忆;Claude Code 则把 CLAUDE.md 和 Auto Memory 做到了明确的产品化;OpenClaw 等 Agent 项目和社区实践中,也频频出现类似的文件化记忆思路。它们共同说明了一个事实:在很多 Agent 场景中,文件系统 + Markdown 已经是一个足够扎实的长期记忆方案。
Claude Code 的 CLAUDE.md 机制
Claude Code 的记忆系统采用双轨制:CLAUDE.md(人工编写) 和 Auto Memory(自动积累)。

CLAUDE.md:该写什么、不该写什么
CLAUDE.md 本质上是一份给 AI 新人看的 onboarding 文档。写得不好还不如不写——一份臃肿的 CLAUDE.md 会让真正重要的规则淹没在噪音中。
该写的内容:
- 技术栈和版本信息:框架版本差异往往是 AI 犯错的源头。不标注 Spring Boot 版本,它更容易生成训练数据中更常见的版本用法。
- 常用命令:构建、测试、lint、启动——全部放在代码块中。代码块里的命令 Claude 倾向于原样执行,而写在自然语言里的命令,它可能按自己的理解去改写。
- 架构决策及背后原因:光写规则不够,写清楚“为什么”能让 Claude 举一反三。例如“不要直接写 SQL,用 QueryWrapper”——补充上“因为 SQL 审计系统依赖 Wrapper 解析来记录操作日志”之后,Claude 在其他需要生成查询的地方也会自觉使用 Wrapper。
- 团队约定和项目特有坑点:提交信息格式、分支命名规范、环境变量依赖。这些 Claude 从代码里读不了,但一个新人入职必然会问。
不该写的内容:
- 代码风格规则(交给格式化工具即可)
- 语言或框架的默认行为(像现代 Python 中用 f-string 这种事写下来纯属噪音)
- 大段参考文档(给链接就够了,Claude 需要时会自己去读)
一句话判断标准:逐行过一遍
CLAUDE.md,每一条规则都问自己——“如果没有这行,Claude 最近是不是真的犯过这个错”。如果答案是“好像没犯过”,那行就可以删掉。
怎么写才能让 Claude 真正遵守
规则要具体可验证。“注意代码可读性”没法验证;“函数名以动词开头、单个函数不超过 40 行”则是可以验证的。规则写得越具体,Claude 遵守的概率就越高。
禁令要搭配替代方案。只是说“不要做 X”会让 Claude 在相关场景中卡住。更好的方式是“不要做 X,遇到这种情况应该做 Y”。实战示例:
# 依赖注入
- 不要使用 @Autowired 字段注入
- 使用构造器注入,配合 Lombok 的 @RequiredArgsConstructor
- 参考示例:UserController.java 中的写法
善用标记词但别滥用。如果某条规则 Claude 反复违反,加上 IMPORTANT: 或 YOU MUST: 可以引起它的注意。但这招不能经常用——到处标“重要”的文件,等于哪里都不重要。
工程提示:如果 Claude 反复忽略某条规则,不要急着加感叹号。更可能是文件太长,规则被其他内容稀释了。解决方案是精简文件,而不是加强语气。
标题用常规名字。使用 Commands、Structure、Conventions、Testing 这类 README 里常见的标题。Claude 训练数据里有大量标准结构的 README,它对“这个标题下面通常写什么”有稳定的认知。
CLAUDE.md 文件的层级结构
| 层级 | 位置 | 作用范围 | 适用场景 |
|---|---|---|---|
| 组织级 | 系统目录(如 /etc/claude-code/CLAUDE.md) |
所有用户 | 公司编码规范、安全策略,任何设置都无法排除 |
| 用户级 | ~/.claude/CLAUDE.md |
个人所有项目 | 代码风格偏好、个人工具习惯 |
| 项目级 | ./CLAUDE.md 或 ./.claude/CLAUDE.md |
团队共享 | 项目架构、编码标准、工作流,提交至 Git |
| 本地级 | ./CLAUDE.local.md |
个人当前项目 | 沙箱 URL、测试数据偏好,加入 .gitignore |
文件加载遵循目录树向上查找规则——从当前工作目录逐级向上,同一目录中 CLAUDE.local.md 追加在 CLAUDE.md 之后,越靠近工作目录的规则优先级越高。
CLAUDE.md 不适合存什么:
- 大段日志和完整对话记录
- 敏感密钥、Token、账号信息
- 高频变化的运行时数据
- 可以实时查询的动态信息
分层管理:项目大了怎么组织
一个人开发,一份 CLAUDE.md 就够用。项目变大、团队介入后,就需要分层:
# `CLAUDE.md`(项目根目录)
## Project
Spring Boot 3.2 + MyBatis-Plus + MySQL 8.0 的订单管理服务。
## Commands
- 构建:`mvn clean package`
- 测试:`mvn test`
## Rules
- API 约定:@docs/api-conventions.md
- 数据库规范:@docs/database-rules.md
用 @path/to/file 引用外部文件。注意:@ 引用会把整个文件内容嵌入上下文,如果被引用文件很大,每个会话启动时都会消耗一大块指令预算。大文件改为自然语言引用——“架构细节参见 docs/architecture.md”,Claude 需要时会自己读取。
对于更细粒度的控制,可以用 .claude/rules/ 目录组织 path-scoped 规则:
---
paths:
- "src/main/java/**/controller/**/*.java"
---
# Controller 规范
- 统一用 Result<T> 包装返回值
- 所有接口必须添加 Swagger 注解
这样编辑 Controller 时只加载 Controller 的规则,编辑 Service 时只加载 Service 的规则。
Auto Memory(自动积累):Claude 根据对话自动写入的笔记,包括调试模式、代码习惯、工作流偏好等。它存储在 ~/.claude/projects/<project>/memory/ 目录下,MEMORY.md 是入口文件,详细笔记组织在子文件中。
注意:Auto Memory 需要 Claude Code v2.1.59 及以上版本,默认开启,可以通过 /memory 或 autoMemoryEnabled 配置关闭。
Markdown 记忆的层级设计
一个完整的 Markdown 记忆体系通常包含多个层级:
- 用户级记忆:存放个人偏好和长期习惯,位置在
~/.claude/CLAUDE.md。比如你偏好 2-space 缩进、习惯先写测试再写代码、不喜欢用 emoji。 - 项目级记忆:存放项目规范、技术栈、目录结构,位于仓库根目录的
CLAUDE.md。团队成员共享,通过 Git 同步。 - 子目录级记忆:存放局部模块的专属规则,在子目录下的
CLAUDE.md。比如backend/中的 API 设计规范、docs/中的写作风格要求。 - 团队共享记忆:需要提交到仓库的共同约定。包括项目级的
CLAUDE.md和.claude/rules/目录下可版本化的规则文件。 - 私有记忆:不应提交的个人工作流。像
CLAUDE.local.md这类文件要加入.gitignore,只留在本地。
Markdown 记忆和传统长期记忆的差异

Markdown 记忆和传统长期记忆的适用边界
并非所有场景都适合 Markdown,也并非所有场景都适合向量库。关键在于理解各自的适用边界:
| 维度 | Markdown 记忆 | 向量库记忆 | RAG 知识库 | 数据库型框架(Mem0等) |
|---|---|---|---|---|
| 检索精度 | 中等(依赖人工组织) | 高(语义相似度) | 高(语义检索) | 高(混合策略) |
| 调试体验 | 极佳 :直接读写文件 | 中等:需向量查询工具 | 中等:需检索日志 | 复杂:需理解框架逻辑 |
| 部署成本 | 极低 :只需文件读写 | 高:需维护向量服务 | 高:需 RAG pipeline | 高:需框架运行时 |
| 版本控制 | 原生集成 Git | 需额外同步机制 | 需额外同步机制 | 需额外同步机制 |
| 迁移成本 | 零 :复制文件即可 | 高:锁定专有格式 | 高:锁定 pipeline | 极高:绑定框架 |
| 适用场景 | 偏好、约定、踩坑记录 | 多样化记忆检索 | 共享知识查询 | 复杂多源记忆管理 |
Markdown 的局限性也很明确:当你需要从海量非结构化文本中检索特定片段时,人工组织的 Markdown 会变成瓶颈。此时向量库的语义检索能力依然不可替代。
反过来,当你的记忆需求是“记住这个项目的编码规范”、“记住用户的报告偏好”这类明确、可结构化的信息时,Markdown 的简洁和可维护性完胜复杂系统。
Markdown 记忆的维护策略
这里以 CLAUDE.md 为例。
CLAUDE.md 不是写完就一劳永逸。项目不断演进,规则也会过时。
- 添加规则要慢:一条新规则只有在 Claude 确实犯过一个错误,并且这条规则能防止同类错误再次出现时,才值得记录进去。为还没发生的事预设规则,往往只是在浪费空间。
- 删规则要果断:如果某条规则已经存在很久,但删掉后 Claude 的行为并没有变化,那就说明这条规则从一开始就没真正起作用——Claude 本来就会那么做。果断移除,把空间留给真正需要的规则。
- 错误驱动的持续进化:每次纠正 Claude 的错误后,追加一句“更新
CLAUDE.md,保证下次不再犯”。积累几次同类错误后总结为一条精炼的规则,避免文件快速膨胀。
两个预警信号:
- 信号一:Claude 为已写入文件的规则频频道歉(比如“抱歉,我刚才忽略了 XX 规则”)。这说明这条规则的措辞有问题——可以换成更直接的表述。
- 信号二:同一条规则在不同会话中反复被违反。这通常不是措辞问题,而是整份文件太长,规则被稀释了。解决办法不是改措辞,而是压缩整份文件。
两个实用的维护习惯:
- 对话式审查:每隔几周,挑几条
CLAUDE.md里的规则问 Claude:“如果我删掉这条规则,你会改变行为吗?”如果它说不会,那这条规则或许就可以删掉了。 - 用
/init但别直接照搬:自动生成的CLAUDE.md是个不错的起点,但里面可能有不准确的描述。按照原则逐条审查,删除冗余,补充缺失。
Git 做版本追踪 + Code Review:每一次重要记忆更新都 commit,遇到问题可以回滚,code review 能追溯修改原因。涉及团队共享内容的修改,尽量走 PR 流程。