鱼皮AI导航
鱼皮AI导航
  • 主页
  • 社区
  • AI工具
  • AI知识库
  • AI提示词
  • MCP
  • Skills
  • AI学习资源
  • AI资讯
  • GitHub开源
登录/注册
站长:程序员鱼皮 老鱼简历 商务合作 增值电信业务经营许可证
2026 鱼皮AI导航 | 沪ICP备19026706号-6
6
3
9

深度解析 Claude Code 记忆系统:从源码看 AI 编程助手如何"记住"你的项目

yosoo
yosoo
2026-04-03 15:11
阅读 3179
yosoo
2026-04-03 15:11
阅读 3179

深度解析 Claude Code 记忆系统:从源码看 AI 编程助手如何"记住"你的项目

本文基于 Claude Code v2.1.88 泄露源码及社区分析资料,深入剖析其记忆系统的架构设计与实现细节。如果你正在构建 AI Agent 系统,这套记忆架构非常值得参考。

一、为什么需要记忆系统?

Claude Code 是 Anthropic 官方的 CLI 编程助手。每次启动一个新会话,模型面对的是一个全新的上下文窗口——它不知道你的项目用什么技术栈、你偏好什么代码风格、上次修了什么 bug。

没有记忆系统,你每次都要花几分钟"教育"AI:解释架构、重复约定、描述上下文。这在复杂项目上是巨大的效率损耗和 token 浪费。

Claude Code 的解决方案是一套 三层持久化记忆体系,配合会话内的 上下文压缩机制,让 AI 在跨会话和长会话两个维度上都能高效利用知识。

二、记忆系统全景架构

从源码结构看,Claude Code 的记忆相关代码分布在以下目录:

▼
text
复制代码
src/ ├── memdir/ # Auto Memory 核心(记忆目录管理) │ └── memdir.ts # buildMemoryPrompt / loadMemoryPrompt / 截断逻辑 ├── services/ │ ├── SessionMemory/ # 会话记忆提取(Session Memory) │ │ └── sessionMemory.ts │ └── compact/ # 上下文压缩(三层策略) ├── utils/ │ └── api.ts # CLAUDE.md 注入逻辑(prependUserContext) └── constants/ # System Prompt 各段落定义

整个记忆体系可以概括为 "手动 + 自动 + 会话"三层架构:

▼
text
复制代码
┌─────────────────────────────────────────────────┐ │ Layer 1: CLAUDE.md(手动记忆) │ │ 用户手写的持久化指令,每次会话自动加载 │ │ 注入位置:user context(第一条用户消息前) │ ├─────────────────────────────────────────────────┤ │ Layer 2: Auto Memory(自动记忆) │ │ Claude 自主决定写入的跨会话知识 │ │ 存储位置:~/.claude/projects/<project>/memory/ │ │ 注入位置:system prompt 动态段 │ ├─────────────────────────────────────────────────┤ │ Layer 3: Session Memory(会话记忆) │ │ 当前会话内的上下文管理与压缩 │ │ 机制:autoCompact + snipCompact + contextCollapse│ └─────────────────────────────────────────────────┘

三、Layer 1:CLAUDE.md —— 手动记忆层

3.1 不在 System Prompt 里

这是最大的认知误区。很多人以为 CLAUDE.md 的内容被拼接到 system prompt 中,实际上并非如此。

从源码看,CLAUDE.md 通过 prependUserContext() 函数注入,插入位置是消息列表的最前面,作为一条特殊的 user message:

▼
typescript
复制代码
// src/utils/api.ts(简化) export function prependUserContext(messages, context): Message[] { return [ createUserMessage({ content: `As you answer the user's questions, you can use... ${context.claudeMdContent} ${context.memoryContent} ...` }), ...messages ] }

这意味着 CLAUDE.md 不享受 system prompt 级别的缓存优化。每次会话它作为 user message 的一部分被发送,会消耗实际的输入 token。

3.2 四级作用域

CLAUDE.md 支持四个作用域层级,按优先级从低到高:

层级路径场景
企业级MDM 管控策略注入企业统一管控
用户级~/.claude/CLAUDE.md个人全局偏好
项目级./CLAUDE.md 或 ./.claude/CLAUDE.md团队共享约定(提交到 git)
本地级./CLAUDE.local.md个人项目偏好(gitignore)

项目级的 CLAUDE.md 可以通过 /init 命令自动生成——Claude 会分析你的代码库,提取构建命令、测试指令和项目约定。

3.3 最佳实践

由于 CLAUDE.md 直接消耗 token,写法上需要注意效率:

  • 越短越好:简洁的指令比冗长的描述更容易被模型遵循
  • 结构化:用清晰的分类(构建命令、代码风格、架构约定)组织内容
  • 避免废话:不要写"请帮我"、"你应该"这类无效前缀
  • 可执行:写成可直接执行的命令或可直接遵循的规则

四、Layer 2:Auto Memory —— 自动记忆层(memdir)

这是 Claude Code 记忆系统中最有技术含量的部分,代码位于 src/memdir/memdir.ts。

4.1 核心设计:基于文件的记忆目录

每个项目在 ~/.claude/projects/<project>/memory/ 下有一个专属的记忆目录。目录路径通过 git 仓库路径派生,所以同一仓库的所有 worktree 和子目录共享同一个记忆空间。

▼
text
复制代码
~/.claude/projects/ ├── <project-hash-A>/ │ └── memory/ │ ├── MEMORY.md # 索引文件(入口点) │ ├── debugging.md # 主题文件:调试经验 │ ├── patterns.md # 主题文件:代码模式 │ └── architecture.md # 主题文件:架构笔记 └── <project-hash-B>/ └── memory/ └── MEMORY.md

4.2 MEMORY.md:200 行硬截断的索引文件

源码中定义了明确的截断常量:

▼
typescript
复制代码
// src/memdir/memdir.ts export const ENTRYPOINT_NAME = 'MEMORY.md' export const MAX_ENTRYPOINT_LINES = 200 export const MAX_ENTRYPOINT_BYTES = 25_000 // 25KB

只有 MEMORY.md 的前 200 行或前 25KB 会在会话启动时自动加载。超出部分直接被截断,并且会产生警告提示:

▼
text
复制代码
WARNING: MEMORY.md is 350 lines (limit: 200). Only part of it was loaded. Keep index entries to one line under ~200 chars; move detail into topic files.

这意味着 MEMORY.md 应该被当作索引使用,而不是存放大量细节。每条记忆控制在一行、200 字符以内,详细内容放到独立的 topic 文件中。

4.3 Topic 文件:按需加载

像 debugging.md、patterns.md 这样的主题文件不会在启动时加载。Claude 在会话过程中需要相关信息时,会通过标准的文件读取工具按需读取它们。

这是一个典型的冷热分层设计:

  • 热数据(MEMORY.md 前 200 行)→ 每次启动加载,消耗固定 token
  • 温数据(topic 文件)→ 按需读取,用工具调用触发
  • 冷数据(历史会话)→ 不加载,依赖 Session Memory 提取

4.4 四类记忆分类法

从 buildMemoryLines() 函数的源码注释可以看到,Auto Memory 采用了一个封闭的四类分类体系:

▼
typescript
复制代码
// src/memdir/memdir.ts /** * Constrains memories to a closed four-type taxonomy: * - user: 用户偏好和习惯 * - feedback: 用户的修正和反馈 * - project: 项目特定知识 * - reference: 参考信息 * * Content derivable from current project state (code patterns, * architecture, git history) is explicitly excluded. */

关键设计原则:可以从代码库当前状态推导出来的信息(代码模式、架构、git 历史)被显式排除在记忆之外。这避免了记忆与实际代码之间的不一致——代码变了但记忆没更新的问题。

4.5 记忆写入时机

Claude 并不是每次会话都写记忆。从源码和官方文档看,它的写入策略是:

  1. 用户纠正时:当用户纠正 Claude 的行为("不要用分号"、"我们用 pnpm 不用 npm"),Claude 会主动将这些偏好写入记忆
  2. 有价值的发现时:调试过程中发现的坑、构建系统的特殊配置等
  3. Claude 自主判断:基于"这条信息在未来的对话中是否有用"来决定是否记忆

写入操作在 UI 中会显示 "Writing memory" 提示,用户可以随时编辑或删除这些文件(它们就是普通的 Markdown 文件)。

4.6 记忆注入到 System Prompt

loadMemoryPrompt() 函数负责将记忆内容注入到 system prompt 的动态部分(SYSTEM_PROMPT_DYNAMIC_BOUNDARY 之后):

▼
typescript
复制代码
// src/memdir/memdir.ts(简化) export function buildMemoryPrompt(params: { displayName: string memoryDir: string extraGuidelines?: string[] }): string { const entrypoint = params.memoryDir + ENTRYPOINT_NAME const raw = fs.readFileSync(entrypoint, { encoding: 'utf-8' }) const t = truncateEntrypointContent(raw) // 硬截断 const lines = buildMemoryLines(params.displayName, params.memoryDir, ...) lines.push(`## ${ENTRYPOINT_NAME}`, '', t.content) return lines.join('\n') }

注意这里是同步读取(fs.readFileSync),因为记忆加载发生在 system prompt 组装阶段,需要在 API 调用前完成。

五、Layer 3:Session Memory —— 会话内记忆管理

5.1 Session Memory 提取

src/services/SessionMemory/sessionMemory.ts 实现了从对话过程中自动提取值得记忆的内容。从架构分析中可以看到,它的工作方式是:

▼
typescript
复制代码
// 会话结束或 compact 触发时 shouldExtractMemory() -> runForkedAgent() -> Session Memory 更新

这里用了一个巧妙的设计——fork 出一个子 agent 来做记忆提取,不阻塞主会话的执行流程。

5.2 三层上下文压缩

长会话中上下文会逐渐填满,Claude Code 的 services/compact/ 实现了三层压缩策略:

策略机制触发时机
autoCompact将历史消息总结为摘要上下文接近限制时自动触发
snipCompact修剪冗长的工具输出单次工具输出过大时
contextCollapse折叠旧的消息段落保留关键信息,折叠细节

这套压缩机制确保了即使在超长会话中,关键的上下文信息不会因为窗口限制而丢失。

六、System Prompt 的缓存架构

Claude Code 的 system prompt 不是一整块文本,而是被精心分割为静态段和动态段:

▼
text
复制代码
System Prompt 结构: ┌──────────────────────────────────┐ │ 静态段(可缓存) │ ← Anthropic API prompt caching │ - 角色定义 │ │ - 工具定义(schema) │ │ - 安全规则 │ │ - 基础指令 │ ├──── SYSTEM_PROMPT_DYNAMIC_BOUNDARY ──┤ │ 动态段(每轮重算,破坏缓存) │ ← DANGEROUS_uncached │ - Auto Memory 内容 │ │ - MCP 工具列表 │ │ - 当前项目上下文 │ │ - 功能开关状态 │ └──────────────────────────────────┘

静态段通过 Anthropic API 的 prompt caching 机制可以被缓存复用,大幅降低 token 消耗和延迟。Auto Memory 注入在动态段——这意味着每次记忆内容变化,都会破坏后续的缓存,所以记忆内容要尽量稳定和精简。

七、CLAUDE.md vs Auto Memory:注入位置的差异

这两套机制虽然都提供跨会话记忆,但注入位置完全不同:

维度CLAUDE.mdAuto Memory
注入位置User message(对话开头)System prompt(动态段)
缓存影响不影响 system prompt 缓存变化会破坏缓存
加载方式完整加载(无截断)MEMORY.md 前 200 行
写入者用户手动Claude 自动
版本控制可提交到 git本地存储,不共享
适合内容团队约定、构建命令个人偏好、调试经验

八、记忆系统的设计启示

如果你在构建自己的 AI Agent 记忆系统,Claude Code 的设计有几个值得借鉴的点:

8.1 分层而非全量

不是所有记忆都需要每次加载。热数据(MEMORY.md 索引)自动加载,温数据(topic 文件)按需读取,冷数据(历史会话)通过提取机制保留精华。

8.2 索引 + 详情分离

MEMORY.md 当索引用,详细内容放 topic 文件。这个模式和数据库的"索引-数据"分离思想一致——索引小且快,数据大但不常读。

8.3 排除可推导信息

不记忆可以从代码库当前状态推导出来的内容。这避免了记忆与现实不一致的维护负担。

8.4 记忆是纯文本

所有记忆都是 Markdown 文件,人类可读可编辑。没有私有数据库、没有向量存储、没有嵌入计算。简单可靠。

8.5 硬性截断保护

200 行 / 25KB 的硬截断不是建议,是强制执行的。这种"宁可丢信息也不爆上下文"的设计,在生产系统中非常重要。

九、局限性

当然,这套系统也有明显的局限:

  • 单 Agent 绑定:记忆存储在 ~/.claude/ 下,不能跨工具共享(比如 Cursor 或 OpenCode 无法读取)
  • 无语义检索:topic 文件的查找依赖 Claude 自己的文件读取工具,本质上是 grep 级别的搜索,没有向量相似度匹配
  • 无版本管理:记忆文件没有版本历史,误删除或错误修改无法回退
  • 上下文开销:即使是索引级别的记忆,200 行也是不小的 token 消耗

社区已经有一些项目在尝试解决这些问题,比如 memsearch(跨 Agent 语义记忆)和 memory-mcp(基于 MCP 的记忆服务),有兴趣的可以关注。

十、总结

Claude Code 的记忆系统是一个务实的工程设计——没有花哨的向量数据库,没有复杂的 RAG 管线,就是 Markdown 文件 + 分层加载 + 硬性截断。但这种简单性恰恰是它的优势:可预测、可调试、可人工干预。

对于 AI Agent 开发者来说,Claude Code 的记忆架构提供了一个很好的参考基线:先用最简单的方案解决 80% 的问题,再在必要时引入更复杂的机制。


参考资料:

  • Claude Code 源码教学指南 - 中英双语 20 章教程
  • Claude Code 官方记忆文档
  • liuup/claude-code-analysis - 源码静态分析
  • Claude Code Architecture Breakdown
  • 深入浅出 Claude Code:从源码理解 CLAUDE.md

如果这篇文章对你有帮助,欢迎点赞收藏。关于 AI Agent 架构设计的更多内容,可以关注我后续的分享。

人工智能
Python
AI
算法
6
9
分享
操作
评论
相关内容
0个评论
全部评论
点击登录,快来和大家讨论吧~
表情
图片
🔥热门工具
朱雀AI检测朱雀AI检测
朱雀AI检测助手朱雀AI检测助手
LovartLovart
老鱼简历老鱼简历
WritePass官网WritePass官网
面多多面多多
CursorCursor
星月写作星月写作
零感AI零感AI
墨得问题墨得问题

目录

🔥 热门文章
1
离谱,DeepSeek 崩了 5 小时,大家却喊:梁圣恩情还不完??
450
2
B 站上 DeepSeek 闹鱼灾了,我发起《大肥鱼清除计划》!
410
3
DeepSeek 全新模型发布,性价比最高的一集!
410
4
自己学习ai,直接买cursor 的套餐,还是买gpt 或者claude 的套餐?
370
5
又一个国产版 Codex 神器,也来卷办公了!
340
6
Vibe Coding 实战:从零构建现代专业级 AI 搜索引擎
330
7
day3-如何写出一个高质量的 Skill(组内分享) 高质量 Skill 不是“一个调得很顺的巨型 Prompt”,而是一个可验证、可回归、可维护的能力包。 先定义“什么算好”,再实现“怎么做好”。评估体系先于 Skill 本身成型。 下面用“故障诊断 Markdown 转 YAML”作为例子,但方法是通用的。 --- 一、先想清楚:Skill 到底是什么 一个 Skill 至少包含四部分: 部分 作用 接口 输入什么、输出什么、边界在哪 流程 分几步做,每步的产物是什么 规则 硬约束、经验规则、失败模式 降级策略 不确定时怎么办,而不是硬编一个看似合理的结果 高质量 Skill 的共同点:职责单一、接口清晰、规则可定位、输出可验证。 反例:把几十条经验全塞进一个主 Prompt,改一条规则要重调整个 Prompt,评估时也不知道是哪条规则退化。 --- 二、核心方法:先建评估,再写 Skill 不要先写转换器再补测试。正确顺序是: 1. 定义输出契约:什么算合法、什么算合格; 2. 建金标准集:一小批人工认可“可放行”的样本; 3. 先写评估 Skill:让它在金标准集上跑出基线; 4. 再迭代生成 Skill:每次修改跑同一套评估,无退化且目标维度提升才算正向。 这就是评估驱动开发:评估是 Skill 的单元测试,金标准集是回归锚点。 --- 三、评估 Skill:三层门禁,逐层递进 前一层不过,后一层不跑。每层留可追溯证据。 第 1 层:确定性硬门禁 用解析器、Schema、校验器完成,不消耗模型成本。 · 输出可解析; · 必填字段齐全,类型/枚举合法; · 引用目标存在,无悬空引用、无不可达节点; · 关键路径至少有一条能到达预期出口。 不通过直接打回。 第 2 层:语义断言 用脚本 + 结构遍历检查“逻辑对不对”,仍然保持确定性。 通用检查项: · 覆盖率:源材料里的关键步骤、分支、条件,输出里是否都有对应? · 完整性:每个判断节点是否都有明确出口?有没有死胡同? · 可达性:每条路径是否都能到达预期终点?有没有无出口循环? · 顺序与依赖:有先后依赖的操作,是否保留了顺序?有没有被拍平成无序列表? 例子:故障诊断转换中,检查“每个判断项是否有是/否/异常出口”“每条路径是否能到根因”。 第 3 层:LLM-as-Judge 只处理解析器表达不了的维度:忠实度、完整性、可执行性。 但 Judge 会漂移,不能单独放行,必须建立在第 1、2 层之上。Judge 的 Prompt、rubric、模型版本都要版本化,换模型必须用金标准集重新校准。 通用 Judge 维度: 维度 问什么 忠实度 输出是否忠实源材料意图?有没有自行发明内容? 完整性 关键步骤、条件、证据是否保留?隐式知识有没有被压成空话? 收敛性 输出是否仍指向原目标,而不是发散? 可执行性 下游不依赖源材料能否直接使用? --- 四、金标准集:回归测试的锚点 不需要一开始就标注几百份。用已认可的样本当种子,扩到 15~30 份,覆盖失败模式而非随机抽样: · 完整正例:典型流程; · 边界/异常分支:异常路径、循环、前置失败回退; · 已知易错模式:实际踩过的坑; · 留出集:不参与调优,只用于最终验收,防过拟合。 金标准不需要完美,只需要当前标准下认可可放行。 回归指标:关键路径用 pass^k(k 次全过),稳定性用 pass@k。 --- 五、工程约束:让批量产出可重放 · 幂等:同输入 + 同 Skill 版本 + 同规则 → 输出一致,否则无法判断变好是 Skill 改了还是随机波动; · 隔离不阻断:单份失败进隔离队列,记录失败层和原因,不阻塞其余; · 版本绑定:规则、rubric、金标准集进 Git;每份报告绑定“源版本 + 生成 Skill 版本 + 评估 Skill 版本 + Judge 模型版本”; · 抽样人工复核:Judge 临界样本 + 易错模式,人工抽检结果反过来校准 rubric。 --- 六、Skill 本身怎么写 · SKILL.md 控制篇幅,写清:输入约定、输出契约、分步流程、硬规则、降级策略; · 经验规则放 references/ 或 rules/,按失败模式分类,不要全塞进主 Prompt; · 不确定时标 needs_review: true,不要硬编看似合理的结果; · 迭代由评估报告驱动:报告告诉你哪层挂了、哪类失败模式,你改对应规则文件,而不是漫无目的调 Prompt。 --- 七、落地顺序(不要反过来) 1. 固化输出契约:Schema + 结构约束; 2. 建金标准集:从已认可的 + 最易出错的样本开始; 3. 先写评估 Skill:跑出基线报告; 4. 再迭代生成 Skill:每次修改对比逐项通过率,无退化且目标提升才算正向; 5. 批量运行 + 隔离回放:失败进队列,结束后人工抽检; 6. 评估 Skill 自身版本化:换 Judge 模型必须重新校准。 --- 八、给组员的三条硬要求 1. 不许凭感觉说“变好了”:每次修改必须附评估报告对比,逐项通过率说话。 2. 不许跳过确定性门禁直接看 Judge 分数:前两层挂了,Judge 分数没有意义。 3. 不许把规则堆进主 Prompt:规则按失败模式分文件,评估报告要能定位到具体文件。 --- 一句话收尾 生成 Skill 决定“能不能做”,评估 Skill 决定“敢不敢用”。 先让评估体系站稳,再让生成器迭代。这样交付的不是一堆“看起来还行”的产出,而是一套可证明、可回归、可交接的 Skill 质量体系。
320
8
我的第一个出海产品!7 天 2 万
310
9
WorkBuddy 本地 API 桥 + dsh 插件:把你的 WorkBuddy 额度,变成手边随手可用的模型
310
10
什么是LLM
300