新开一个会话,Agent 却知道项目的测试命令、代码风格、哪些目录不能碰——这不是模型「记住」了上次聊天,而是外部文件和加载逻辑在起作用。本文拆解 Claude Code 的记忆分层:规则与经验各放哪里、记忆如何与上下文协同、以及记忆越积越多之后怎么治理。

为什么记忆必须外置

先明确一个前提:LLM 在两次请求之间不保存任何状态。每轮调用时,客户端把系统提示、历史对话、工具结果和新问题拼在一起发给模型;下一轮还能「想起来」,只是应用层又把相关内容带了回来。

普通聊天不太暴露这个问题,Agent 场景就不一样了:读文件、跑命令、调工具,每一步都在消耗上下文,窗口很快被临时材料占满,长期规则反而淹没其中。所以跨会话的知识必须外置成文件,并回答四个问题:什么值得长期保存?存到哪里、谁看得见?启动时加载多少、任务中怎么补?过期或冲突的记忆如何发现和清理?

规则与经验:两类记忆的分工

Claude Code 的长期上下文先分两类:人写给 Agent 的规则和 Agent 自己攒下的经验。

机制 谁写 适合存什么 加载方式
CLAUDE.md 人 稳定规则、项目约定、协作流程 每次会话加载
.claude/rules/ 人 只在某类文件或目录下生效的条件规则 读取匹配文件时按需加载
Auto Memory Agent 工作中发现的偏好、命令、排坑经验 启动时加载索引,正文按需读

规则文件:确定性与可审查

CLAUDE.md 是会话开始前的工作说明书:编码规范、常用命令、目录约束、不要碰的区域。它按层级组织——组织级、用户级(~/.claude/CLAUDE.md)、项目级、本地级、子目录级。范围越大的越先加载,各层是叠加关系而非覆盖;子目录级文件要等读到对应目录的文件时才补进来。几点要注意:

  • CLAUDE.md 以 user message 形式注入,本质是提示而非强制约束;真正要硬拦的行为(禁止危险命令、提交前跑检查)应交给 Hooks、权限配置或 CI。
  • 每份文件建议控制在 200 行以内,写得太长模型反而只记住一部分。
  • @path/to/file 引入外部文件不会省 Token——被引用的内容照样在启动时展开进上下文。

只在特定路径下才有意义的规则(比如前端规则只在 src/**/*.tsx 生效),适合放进 .claude/rules/ 并通过 frontmatter 里的 paths 控制触发范围,避免每次会话都背着无关规则。

---
paths:
- "src/**/*.{ts,tsx}"
---

# TypeScript 规则

- API 入参必须做校验。
- 测试优先复用已有 fixture。

Auto Memory:经验的索引式存储

Auto Memory 记录 Agent 在工作中发现的构建命令、调试经验、用户偏好和反复出现的坑。它按 Git 仓库存储在 ~/.claude/projects/<project>/memory/,目录里 MEMORY.md 是入口索引,细节放在各自的 topic file 中。会话启动时只加载索引的前 200 行或 25KB,哪个先到就停;需要细节时再打开对应文件。/memory 可以查看和编辑。

这个结构和 Skills 的渐进式披露是同一思路:先让模型知道「有什么」,别把「全部内容」一次性塞进窗口。想关掉它,可以在配置里设 "autoMemoryEnabled": false 或设置对应的环境变量。

多代理场景下还有 Subagent Memory:记忆主体换成某个子代理,按 user、project、local 三种 scope 存到不同的 agent-memory 目录,用来沉淀专用 worker(如只负责数据库迁移的代理)的长期经验。注意它和 Agent Teams 不是一回事——后者解决多个会话之间的任务分工与通信,不等于共享长期记忆。

记忆与上下文的协同

记忆系统的设计核心是和上下文窗口打配合,而不是替代它:

  1. 索引常驻,正文按需:索引文件短小、每轮加载;具体经验在任务相关时才读入。索引别写成小作文,只负责告诉 Agent「有哪些记忆、该打开哪个文件」。
  2. 只记源码推不出来的东西:用户偏好、项目特有约定、某次技术决策的原因、踩过的坑,值得记;目录结构、函数签名、依赖版本、提交历史,都能从仓库直接查到,重复记录只会抬高固定开销。
  3. 读回记忆要分信任等级:用户长期偏好可以优先采用,但本轮明确指令永远优先级更高;历史决策原因只能参考,它解释的是当时为什么这么选;文件路径、模块位置这类会变的事实只能当线索,用之前必须回到当前代码库核对——「按记忆找方向,按现状做决定」。

记忆膨胀的治理

一条记忆写进去,成本就不只是几十个 Token:它每轮都可能被加载,还需要被复查、更新或删除;没人管时,Agent 可能拿着过期前提继续做决定。「记错」比「忘记」更糟糕。

治理从写入端开始。写入前先问三个问题:下次做决定会不会用到?是不是用户明确确认过(而非 Agent 自己猜的)?过期了有没有人能发现?答不上来就让它留在当前会话。真正写入时也别只记一句结论,至少带上原因和适用范围:

---
type: feedback
created_at: 2026-06-17
updated_at: 2026-06-17
---

# 集成测试连接真实 MySQL

涉及数据库行为的集成测试连接真实 MySQL,不用 H2 内存库替代。

原因:曾有用例在 H2 上通过,上线后因事务与 SQL 方言差异出问题。

适用范围:纯参数校验、分支逻辑可用轻量替代;涉及事务、索引、并发必须回 MySQL。

只写「别用 H2」,Agent 容易机械执行;补上原因和边界,它遇到边缘场景才有机会做对取舍。时间表达也要落成绝对日期——「月底前别动订单模块」应写成「2026-06-30 前不修改订单模块」,否则隔几天再读就失了效。

运维侧的配套动作:记忆变更走 review;按季度审计过期条目;密钥、凭证这类敏感信息永不写入;定期用 /memory 看看实际记了什么。

至于向量检索类方案(如 memsearch 这类外置记忆库),适合多工具、多成员、长周期共享记忆的团队,代价是索引、嵌入模型、权限都要有人维护。记忆只有几十条时,文件索引完全够用,别为了用而用。

小结

  1. 模型不保存跨会话状态,记忆 = 外部文件 + 加载规则;规则(CLAUDE.md、.claude/rules/)由人维护求确定性,经验(Auto Memory)由 Agent 记录但需人审查。
  2. 记忆与上下文协同的要点是索引常驻、正文按需、只记源码推不出的内容;读回时区分信任等级,可变事实先核对再用。
  3. 治理的核心是克制写入:写清原因、边界和绝对时间,定期审计清理,敏感信息绝不入库。
  4. 规模没到之前,Markdown 文件索引胜过向量库;让 Agent「记住一切」没有意义,更可靠的是让它知道下一步该去哪里核对。