深入浅出 Claude Code(二):从源码解构 MEMORY.md,重塑你的上下文注入链路
- 内容介绍
- 文章标签
- 相关推荐
新一期来啦: 大多数人写 CLAUDE.md 的方式是:随便写几条规则,感觉效果不明显,然后放弃。 你不知道这些文字在 Claude 眼里长什么样、被放在哪里、和其他指令的优先级关系是什么。 今天我来带各位佬友们剖析一下 claudecode 的底层逻辑 全网统一小恐龙头像,在别的地方看到的家人们点点赞 1. CLAUDE.md 不在 System Prompt 里 这是最大的认知误…
上一篇我们重写了 CLAUDE.md,但这只是表层。今天这篇,我们将顺着代码的调用栈,扒开 Claude Code 的记忆系统,看看你的指令在底层究竟被赋予了什么级别的权重。
你让 Claude Code "记住"的东西,下次对话它可能完全不记得。或者记得,但不照做。
其实不是功能坏了——是你不清楚这些 memory 在系统里是怎么流动的。存在哪、怎么加载、权重多高、什么格式才有效,搞清楚这条链路,memory 才能真正起作用。

1. Memory 存在哪
所有 memory 文件存储在本地文件系统,按项目隔离:
~/.claude/projects/{sanitized-project-path}/memory/
├── MEMORY.md ← 索引文件
├── user_profile.md ← topic 文件
├── feedback_no_summary.md
├── project_deadline.md
└── reference_linear.md
{sanitized-project-path} 是你项目根目录的路径哈希。不同项目的 memory 互不干扰。

这些就是普通的 markdown 文件,你可以直接用编辑器打开改。
2. 它怎么被加载到模型的
这是整篇最关键的一点。
Claude Code 的输入结构分两层:system prompt 和 user message。Memory 和 CLAUDE.md 分别在这两层里:
System Prompt(优先级更高):
位置 1-9:静态指令(身份、工具使用规范、语气等)
位置 10:会话指导
位置 11:★ Memory 系统指令 + MEMORY.md 索引内容
位置 12-18:环境信息、MCP 指令等
User Message(优先级更低):
第一条:★ CLAUDE.md 内容(包在 <system-reminder> 里,带降权提示)
第二条:你的第一句话
后续:对话历史
两个关键差异:
Memory 在 system prompt 里,没有降权。 模型被直接告知"你有一个持久化的记忆系统,直接用"。
CLAUDE.md 在 user message 里,带降权。 注入时附带一句 this context may or may not be relevant to your tasks,显式告诉模型这些内容可能不相关。
同一条指令,放在 memory 里比放在 CLAUDE.md 里更容易被遵守。这不是玄学,是注入位置和降权声明的直接影响。
3. MEMORY.md 是索引,不是记事本
很多人往 MEMORY.md 里堆大段内容。问题是它有硬截断:
MAX_ENTRYPOINT_LINES = 200 // 超过 200 行,后面的直接丢弃
MAX_ENTRYPOINT_BYTES = 25_000 // 超过 25KB,在最近的换行处截断
截断后末尾追加一条警告,超出部分永久丢失(本次加载)。
MEMORY.md 的正确用法是当索引——每条一行,指向 topic 文件:
- [用户画像](user_profile.md) — 高级 Go 开发者,偏好简洁代码
- [不要总结](feedback_no_summary.md) — 回答结束不要总结做了什么
- [发布冻结](project_release_freeze.md) — 4月3日前不合并非关键 PR
每行控制在 150 字符以内。详细内容写在各自的 topic 文件里——topic 文件没有行数限制。
system prompt 中只注入 MEMORY.md 的内容和 Memory 系统的使用指令。topic 文件只在模型主动用 Read 工具读取时才会被看到。所以 MEMORY.md 索引条目的描述要写得足够清晰——模型根据这一行描述来判断要不要去读 topic 文件。
4. 四种类型:按对行为的影响排序
Memory 文件用 frontmatter 声明类型。四种类型中,对 Claude 行为影响最大的排在前面:
feedback(行为修正)—— 影响最大
“你做错了 X,以后这样做"或"你做对了 Y,继续保持”。
源码对 feedback 的特别说明:
Record from failure AND success: if you only save corrections, you will avoid past mistakes but drift away from approaches the user has already validated, and may grow overly cautious.
只记纠正不记确认,模型会越来越保守。好的 feedback 两种都要记。
格式要求三行结构——规则、原因、适用场景:
---
name: no-extra-changes
description: 只改用户要求的部分,不要顺便改其他代码
type: feedback
---
只改用户要求改的部分。不要加注释、加类型标注、重构周围代码。
**Why:** 之前"顺手"改动多次引入新问题,用户需要精确控制变更范围。
**How to apply:** 所有代码修改操作。
为什么要 Why 和 How to apply?源码注释说得很直白:
Include why so you can judge edge cases later.
没有 Why,模型只会机械执行规则。有了 Why,遇到边缘情况模型能自己判断该不该打破规则。
user(用户画像)—— 影响中等
关于你是谁的信息。模型据此调整沟通方式。
---
name: user-profile
description: 高级 Go 开发者,新接触 React,偏好简洁
type: user
---
用户是高级 Go 开发者,10 年经验。刚开始接触项目的 React 前端部分。
偏好简洁代码,不喜欢过度抽象。用中文交流。
project(项目背景)—— 影响中等
不能从代码和 git 历史推导出来的项目信息。
---
name: release-freeze
description: 4月3日起冻结非关键合并,移动端切 release 分支
type: project
---
4月3日起冻结非关键 merge,移动端团队切 release 分支。
**Why:** 移动端发版需要稳定的代码基线。
**How to apply:** 4月3日后不建议合并非关键 PR。
注意一个源码里的要求:相对日期必须转为绝对日期。“周四"要写成"2026-04-03”——memory 跨会话,下周再看"周四"就不知道指哪天了。
reference(外部指针)—— 影响最小
指向外部系统的指针,告诉模型哪里能找到信息。
---
name: bug-tracker
description: pipeline bug 在 Linear 的 INGEST 项目追踪
type: reference
---
Pipeline 相关的 bug 在 Linear 项目 "INGEST" 中追踪。
5. 什么不该存
源码里硬编码了一个排除清单:
✗ 代码模式、架构、文件路径 —— 读代码就能知道
✗ Git 历史、谁改了什么 —— git log / git blame 是权威来源
✗ 调试方案和修复步骤 —— 修复已经在代码里
✗ CLAUDE.md 里已经有的 —— 重复无意义
✗ 临时任务进度、当前对话上下文 —— 用 task 系统,不是 memory
还有一条值得单独说:
If they ask you to save a PR list or activity summary, ask what was surprising or non-obvious about it — that is the part worth keeping.
即使你说"记住这个 PR 列表",模型应该追问"这里面什么是让你意外的?"——保存那个意外的部分,而不是一整个列表。能从 git log 还原的信息不值得占 memory 的空间。
6. 陈旧机制:老 memory 会被警告
模型读取 memory 文件时,系统会根据文件修改时间附加陈旧提醒(memdir/memoryAge.ts):
今天 / 昨天 → 无警告
2 天以上 → "This memory is N days old. Memories are point-in-time
observations, not live state — verify against current
code before asserting as fact."
源码还规定了一条验证规则:
如果 memory 里提到了某个文件路径 → 先检查文件是否还存在
如果 memory 里提到了某个函数名 → 先 grep 确认
"memory 说 X 存在" ≠ "X 现在存在"
所以 memory 里不要写"函数 handleAuth 在 main.go 第 42 行"——文件一改就过时。写"项目用中间件模式处理认证,入口在 main.go"这种不依赖行号的描述。
7. 你没说"记住",它也会自动存
除了你主动说"记住这个",Claude Code 还有一个后台提取机制。
模型完成回答后,如果满足以下条件,会自动启动一个后台 agent 扫描对话内容、提取值得保存的信息:
1.本轮主 agent 没有手动写过 memory
2.extractMemories feature flag 启用
3.auto memory 开启
所以你的 memory 目录里可能有你没主动要求保存的文件——那是后台 agent 提取的。
8. Compact 后 Memory 重新加载
执行 /compact 或 /clear 时,Memory 的缓存会被完全清除:
function runPostCompactCleanup(): void {
resetGetMemoryFilesCache('compact') // Memory 文件缓存清除
clearSystemPromptSections() // 包括 memory section
}
下一轮对话时 MEMORY.md 被重新读取。
这意味着:如果你在对话中途手动编辑了 memory 文件(比如用编辑器加了一条 feedback),执行 /compact 后修改立即生效。不需要重启。
9. Memory 和 CLAUDE.md 怎么配合
不要重复——源码明确禁止把 CLAUDE.md 里已有的内容存到 memory。
正确的配合方式:
CLAUDE.md 存规则,Memory 存对规则的强化和例外。
比如 CLAUDE.md 写了"commit message 用中文",但模型老是忘。不要在 memory 里再写一遍"commit message 用中文"。写一条 feedback:
---
name: enforce-chinese-commit
description: 强调 commit message 必须中文,之前多次忘记
type: feedback
---
CLAUDE.md 中的"commit message 用中文"规则必须严格遵守。
**Why:** 之前多次输出英文 commit message,用户每次都要手动改。
**How to apply:** 每次 git commit 前检查 message 是否为中文。
用 feedback 来加强 CLAUDE.md 的权重,而不是重复内容。feedback 在 system prompt 里(高权重),CLAUDE.md 在 user message 里(低权重),两层叠加比写两遍同一句话有效得多。
10. 安全边界
Memory 目录路径不能通过项目级 settings.json 设置:
// SECURITY: projectSettings is intentionally excluded — a malicious repo
// could otherwise set autoMemoryDirectory: "~/.ssh" and gain silent
// write access to sensitive directories
防止恶意仓库把 memory 目录指向 ~/.ssh 然后让 AI 往里写文件。只有用户级和管理员级配置可以改路径。
但 memory 文件的内容没有任何校验——你写什么进去就注入什么到 system prompt。这是设计意图:文件在你本地磁盘上,你有完全控制权。
网友解答:--【壹】--:
已学习,棒棒哒
--【贰】--:
学习学习
--【叁】--:
感谢各位支持
--【肆】--:
感谢分享,前来学习
--【伍】--:
ok,就当下期预告
--【陆】--:
wo03ne?
--【柒】--:
前排学习,感谢佬
--【捌】--:
学习学习
--【玖】--:
学习学习
--【拾】--:
学习一波,加个书签
--【拾壹】--:
前排学习
--【拾贰】--:
学习学习
--【拾叁】--:
type一共有几种类型?
--【拾肆】--:
不错,看完了,第三章呢
--【拾伍】--:
写subagent,agent协作
--【拾陆】--:
向大佬学习
--【拾柒】--:
假装学会了
--【拾捌】--:
点个赞,有时间好好看一下
--【拾玖】--:
第三章不知道写什么了
新一期来啦: 大多数人写 CLAUDE.md 的方式是:随便写几条规则,感觉效果不明显,然后放弃。 你不知道这些文字在 Claude 眼里长什么样、被放在哪里、和其他指令的优先级关系是什么。 今天我来带各位佬友们剖析一下 claudecode 的底层逻辑 全网统一小恐龙头像,在别的地方看到的家人们点点赞 1. CLAUDE.md 不在 System Prompt 里 这是最大的认知误…
上一篇我们重写了 CLAUDE.md,但这只是表层。今天这篇,我们将顺着代码的调用栈,扒开 Claude Code 的记忆系统,看看你的指令在底层究竟被赋予了什么级别的权重。
你让 Claude Code "记住"的东西,下次对话它可能完全不记得。或者记得,但不照做。
其实不是功能坏了——是你不清楚这些 memory 在系统里是怎么流动的。存在哪、怎么加载、权重多高、什么格式才有效,搞清楚这条链路,memory 才能真正起作用。

1. Memory 存在哪
所有 memory 文件存储在本地文件系统,按项目隔离:
~/.claude/projects/{sanitized-project-path}/memory/
├── MEMORY.md ← 索引文件
├── user_profile.md ← topic 文件
├── feedback_no_summary.md
├── project_deadline.md
└── reference_linear.md
{sanitized-project-path} 是你项目根目录的路径哈希。不同项目的 memory 互不干扰。

这些就是普通的 markdown 文件,你可以直接用编辑器打开改。
2. 它怎么被加载到模型的
这是整篇最关键的一点。
Claude Code 的输入结构分两层:system prompt 和 user message。Memory 和 CLAUDE.md 分别在这两层里:
System Prompt(优先级更高):
位置 1-9:静态指令(身份、工具使用规范、语气等)
位置 10:会话指导
位置 11:★ Memory 系统指令 + MEMORY.md 索引内容
位置 12-18:环境信息、MCP 指令等
User Message(优先级更低):
第一条:★ CLAUDE.md 内容(包在 <system-reminder> 里,带降权提示)
第二条:你的第一句话
后续:对话历史
两个关键差异:
Memory 在 system prompt 里,没有降权。 模型被直接告知"你有一个持久化的记忆系统,直接用"。
CLAUDE.md 在 user message 里,带降权。 注入时附带一句 this context may or may not be relevant to your tasks,显式告诉模型这些内容可能不相关。
同一条指令,放在 memory 里比放在 CLAUDE.md 里更容易被遵守。这不是玄学,是注入位置和降权声明的直接影响。
3. MEMORY.md 是索引,不是记事本
很多人往 MEMORY.md 里堆大段内容。问题是它有硬截断:
MAX_ENTRYPOINT_LINES = 200 // 超过 200 行,后面的直接丢弃
MAX_ENTRYPOINT_BYTES = 25_000 // 超过 25KB,在最近的换行处截断
截断后末尾追加一条警告,超出部分永久丢失(本次加载)。
MEMORY.md 的正确用法是当索引——每条一行,指向 topic 文件:
- [用户画像](user_profile.md) — 高级 Go 开发者,偏好简洁代码
- [不要总结](feedback_no_summary.md) — 回答结束不要总结做了什么
- [发布冻结](project_release_freeze.md) — 4月3日前不合并非关键 PR
每行控制在 150 字符以内。详细内容写在各自的 topic 文件里——topic 文件没有行数限制。
system prompt 中只注入 MEMORY.md 的内容和 Memory 系统的使用指令。topic 文件只在模型主动用 Read 工具读取时才会被看到。所以 MEMORY.md 索引条目的描述要写得足够清晰——模型根据这一行描述来判断要不要去读 topic 文件。
4. 四种类型:按对行为的影响排序
Memory 文件用 frontmatter 声明类型。四种类型中,对 Claude 行为影响最大的排在前面:
feedback(行为修正)—— 影响最大
“你做错了 X,以后这样做"或"你做对了 Y,继续保持”。
源码对 feedback 的特别说明:
Record from failure AND success: if you only save corrections, you will avoid past mistakes but drift away from approaches the user has already validated, and may grow overly cautious.
只记纠正不记确认,模型会越来越保守。好的 feedback 两种都要记。
格式要求三行结构——规则、原因、适用场景:
---
name: no-extra-changes
description: 只改用户要求的部分,不要顺便改其他代码
type: feedback
---
只改用户要求改的部分。不要加注释、加类型标注、重构周围代码。
**Why:** 之前"顺手"改动多次引入新问题,用户需要精确控制变更范围。
**How to apply:** 所有代码修改操作。
为什么要 Why 和 How to apply?源码注释说得很直白:
Include why so you can judge edge cases later.
没有 Why,模型只会机械执行规则。有了 Why,遇到边缘情况模型能自己判断该不该打破规则。
user(用户画像)—— 影响中等
关于你是谁的信息。模型据此调整沟通方式。
---
name: user-profile
description: 高级 Go 开发者,新接触 React,偏好简洁
type: user
---
用户是高级 Go 开发者,10 年经验。刚开始接触项目的 React 前端部分。
偏好简洁代码,不喜欢过度抽象。用中文交流。
project(项目背景)—— 影响中等
不能从代码和 git 历史推导出来的项目信息。
---
name: release-freeze
description: 4月3日起冻结非关键合并,移动端切 release 分支
type: project
---
4月3日起冻结非关键 merge,移动端团队切 release 分支。
**Why:** 移动端发版需要稳定的代码基线。
**How to apply:** 4月3日后不建议合并非关键 PR。
注意一个源码里的要求:相对日期必须转为绝对日期。“周四"要写成"2026-04-03”——memory 跨会话,下周再看"周四"就不知道指哪天了。
reference(外部指针)—— 影响最小
指向外部系统的指针,告诉模型哪里能找到信息。
---
name: bug-tracker
description: pipeline bug 在 Linear 的 INGEST 项目追踪
type: reference
---
Pipeline 相关的 bug 在 Linear 项目 "INGEST" 中追踪。
5. 什么不该存
源码里硬编码了一个排除清单:
✗ 代码模式、架构、文件路径 —— 读代码就能知道
✗ Git 历史、谁改了什么 —— git log / git blame 是权威来源
✗ 调试方案和修复步骤 —— 修复已经在代码里
✗ CLAUDE.md 里已经有的 —— 重复无意义
✗ 临时任务进度、当前对话上下文 —— 用 task 系统,不是 memory
还有一条值得单独说:
If they ask you to save a PR list or activity summary, ask what was surprising or non-obvious about it — that is the part worth keeping.
即使你说"记住这个 PR 列表",模型应该追问"这里面什么是让你意外的?"——保存那个意外的部分,而不是一整个列表。能从 git log 还原的信息不值得占 memory 的空间。
6. 陈旧机制:老 memory 会被警告
模型读取 memory 文件时,系统会根据文件修改时间附加陈旧提醒(memdir/memoryAge.ts):
今天 / 昨天 → 无警告
2 天以上 → "This memory is N days old. Memories are point-in-time
observations, not live state — verify against current
code before asserting as fact."
源码还规定了一条验证规则:
如果 memory 里提到了某个文件路径 → 先检查文件是否还存在
如果 memory 里提到了某个函数名 → 先 grep 确认
"memory 说 X 存在" ≠ "X 现在存在"
所以 memory 里不要写"函数 handleAuth 在 main.go 第 42 行"——文件一改就过时。写"项目用中间件模式处理认证,入口在 main.go"这种不依赖行号的描述。
7. 你没说"记住",它也会自动存
除了你主动说"记住这个",Claude Code 还有一个后台提取机制。
模型完成回答后,如果满足以下条件,会自动启动一个后台 agent 扫描对话内容、提取值得保存的信息:
1.本轮主 agent 没有手动写过 memory
2.extractMemories feature flag 启用
3.auto memory 开启
所以你的 memory 目录里可能有你没主动要求保存的文件——那是后台 agent 提取的。
8. Compact 后 Memory 重新加载
执行 /compact 或 /clear 时,Memory 的缓存会被完全清除:
function runPostCompactCleanup(): void {
resetGetMemoryFilesCache('compact') // Memory 文件缓存清除
clearSystemPromptSections() // 包括 memory section
}
下一轮对话时 MEMORY.md 被重新读取。
这意味着:如果你在对话中途手动编辑了 memory 文件(比如用编辑器加了一条 feedback),执行 /compact 后修改立即生效。不需要重启。
9. Memory 和 CLAUDE.md 怎么配合
不要重复——源码明确禁止把 CLAUDE.md 里已有的内容存到 memory。
正确的配合方式:
CLAUDE.md 存规则,Memory 存对规则的强化和例外。
比如 CLAUDE.md 写了"commit message 用中文",但模型老是忘。不要在 memory 里再写一遍"commit message 用中文"。写一条 feedback:
---
name: enforce-chinese-commit
description: 强调 commit message 必须中文,之前多次忘记
type: feedback
---
CLAUDE.md 中的"commit message 用中文"规则必须严格遵守。
**Why:** 之前多次输出英文 commit message,用户每次都要手动改。
**How to apply:** 每次 git commit 前检查 message 是否为中文。
用 feedback 来加强 CLAUDE.md 的权重,而不是重复内容。feedback 在 system prompt 里(高权重),CLAUDE.md 在 user message 里(低权重),两层叠加比写两遍同一句话有效得多。
10. 安全边界
Memory 目录路径不能通过项目级 settings.json 设置:
// SECURITY: projectSettings is intentionally excluded — a malicious repo
// could otherwise set autoMemoryDirectory: "~/.ssh" and gain silent
// write access to sensitive directories
防止恶意仓库把 memory 目录指向 ~/.ssh 然后让 AI 往里写文件。只有用户级和管理员级配置可以改路径。
但 memory 文件的内容没有任何校验——你写什么进去就注入什么到 system prompt。这是设计意图:文件在你本地磁盘上,你有完全控制权。
网友解答:--【壹】--:
已学习,棒棒哒
--【贰】--:
学习学习
--【叁】--:
感谢各位支持
--【肆】--:
感谢分享,前来学习
--【伍】--:
ok,就当下期预告
--【陆】--:
wo03ne?
--【柒】--:
前排学习,感谢佬
--【捌】--:
学习学习
--【玖】--:
学习学习
--【拾】--:
学习一波,加个书签
--【拾壹】--:
前排学习
--【拾贰】--:
学习学习
--【拾叁】--:
type一共有几种类型?
--【拾肆】--:
不错,看完了,第三章呢
--【拾伍】--:
写subagent,agent协作
--【拾陆】--:
向大佬学习
--【拾柒】--:
假装学会了
--【拾捌】--:
点个赞,有时间好好看一下
--【拾玖】--:
第三章不知道写什么了
