Claude Code
记忆系统技术架构研究

记忆机制 · 存储结构 · 调用机制 · 上下文工程 · 记忆类型分析 · 深层设计洞察 · 对比分析
2026 年 4 月 · 基于 Claude Code 源码的深度技术分析

00背景与研究范围


Claude Code 是 Anthropic 发布的官方命令行编程助手,允许用户通过自然语言与 Claude 模型在终端中协作完成软件工程任务。本报告通过对 Claude Code 开源代码的深度分析,系统性地拆解其记忆系统的架构设计、存储结构、调用机制和上下文工程策略。

研究动机

AI 编程助手的核心挑战之一是跨会话的知识持久化——如何让模型"记住"用户偏好、项目上下文和历史决策。Claude Code 的源码揭示了一套远比其公开文档所描述的更为复杂的记忆体系。通过源码分析,我们可以看到 Anthropic 在记忆管理、上下文优化和成本控制方面的工程实践。

研究范围与声明

本报告基于 Claude Code 开源仓库(2026 年 4 月)的源码级分析。重要发现:源码中实现的大部分智能记忆功能尚未对外部用户开放——它们由运行时 feature flag(tengu_* 系列)或构建时 flag(feature())控制,默认关闭。报告涵盖了所有功能层级,从已发布到实验性功能。

对比分析章节中的 OpenClaw 部分同样基于其 GitHub 最新源码(2026-04-01 克隆)的源码级分析,而非官方文档。

功能成熟度一览

功能状态控制机制
CLAUDE.md 手动记忆文件已发布无门控,所有用户可用
/memory 命令(编辑记忆文件)已发布无门控
/compact 命令(上下文压缩)已发布无门控
Auto Memory 目录结构已发布autoMemoryEnabled 设置,默认开启
后台记忆抽取 (extractMemories)灰度中tengu_passport_quail 默认 false
AI 记忆召回 (findRelevantMemories)灰度中tengu_moth_copse 默认 false
Session Memory(会话笔记)灰度中tengu_session_memory 默认 false
Session Memory Compact灰度中需要两个 flag 同时开启
Auto Dream(记忆整合)灰度中tengu_onyx_plover 默认禁用
Team Memory 同步实验性feature('TEAMMEM') 构建级 flag
/dream 技能实验性feature('KAIROS') 构建级 flag
KAIROS 日志模式实验性feature('KAIROS') 构建级 flag
Agent Memory Snapshot实验性feature('AGENT_MEMORY_SNAPSHOT')
用户当前实际可用的记忆功能仅为 CLAUDE.md 文件编辑和 /compact 命令。源码中实现的后台抽取、AI 召回、Session Memory、Dream 整合、Team Memory 等智能功能均默认关闭。本报告分析的是 Anthropic 正在构建的下一代记忆系统的完整蓝图——从中可以看到记忆架构从手动走向全自动化的迭代方向。

01记忆系统总体架构


Claude Code 实现了一个多层次、基于文件的持久化记忆系统,包含五个独立子系统,在不同作用域和时间尺度上协同运行。整个系统没有数据库依赖——所有记忆都以 Markdown 文件存储在磁盘上,用户可以用任何文本编辑器直接查看和修改。

记忆交互架构

下图展示了五大子系统之间的完整数据流——记忆从何产生、存到哪里、如何召回、如何整合:

Claude Code 记忆交互架构

图中三层结构对应 API 调用容器(Context Window)、持久化子系统、后台进程与压缩。箭头展示记忆的三条生命周期路径:编码(对话内容 → Auto Memory / Session Memory)、检索(持久化子系统 → Context Window)、巩固(Auto Memory → Auto Dream → 整合写回)。

五大子系统

这一设计与人类认知系统高度类似:工作记忆对应当前对话的 Context Window,程序记忆对应 System Prompt 中的行为指令,情景记忆对应 Session Memory 中的事件记录,语义记忆对应 Auto Memory 中的持久化知识,记忆巩固对应 Auto Dream 的定期整合。

子系统作用记忆类型映射持久性
Context Window当前对话的即时上下文,200K token 容量上限工作记忆会话内
CLAUDE.md / System Prompt行为规则与操作指令,静态/动态分层缓存程序记忆永久
Session Memory当前会话的结构化笔记,12K token 模板情景记忆会话级
Auto MemoryAI 自动管理的持久化知识,MEMORY.md 索引 + 主题文件语义记忆永久
Auto Dream后台定期整合记忆文件,24h + 5 sessions 门控记忆巩固周期性

系统交互流程

每次 API 调用时,模型看到的上下文由四层记忆协同构成:

1
System Prompt
行为指令(如何保存、读取、分类记忆),静态段全局缓存
2
User Context
MEMORY.md 索引 + CLAUDE.md 规则,每次 API 调用始终注入
3
对话历史
当前对话 + 压缩后的 Session Memory 摘要
4
当前 Turn 附件
Sonnet 分类器选中的最多 5 个 Auto Memory 主题文件
核心设计思想:MEMORY.md 索引始终可见(低成本目录),主题文件按需召回(高精度),行为指令教模型如何自主管理记忆,会话记忆在压缩时提供连续性。架构图中的三条路径——编码(对话 → Auto Memory / Session Memory)、检索(持久化子系统 → Context Window)、巩固(Auto Dream 定期整合)——构成了记忆系统的完整生命周期,后续章节将逐一展开。

02记忆的存储与索引


本章从两个维度展开记忆系统的基础设施:首先是 src/memdir/ 模块的职责分工和分类法设计——决定"记什么"和"怎么分类";然后是磁盘上的物理布局和路径解析——决定"存在哪"和"怎么找到"。

核心记忆系统位于 src/memdir/ 目录,是整个记忆架构的基础设施层——它定义了记忆文件的格式规范、类型分类法、存储路径解析规则,以及 AI 驱动的召回机制。这一层直接决定了"记什么"和"怎么找"。

入口点与模块职责

文件核心职责
memdir.ts记忆提示构建主入口,loadMemoryPrompt() / buildMemoryLines()
memoryTypes.ts四类型分类法定义 + 排除规则
findRelevantMemories.tsAI 驱动的记忆召回(Sonnet 分类器)
memoryScan.ts扫描 .md 文件读取 frontmatter
memoryAge.ts时效性字符串 + staleness 警告
paths.ts路径解析 + 启用检查

记忆类型分类法

系统定义了一个封闭的四类型体系 (memoryTypes.ts:14-19),这是 Auto Memory 的分类约束——防止低价值信息膨胀记忆库:

类型用途示例
user用户角色、目标、知识、偏好"资深 Go 工程师,React 新手"
feedback用户对工作方式的纠正和确认"测试中不要使用 DB mock"
project进行中的工作、截止日期、决策"3月5日代码冻结"
reference指向外部系统的指针"Pipeline bugs 在 Linear INGEST 项目"

明确排除的内容 (memoryTypes.ts:183-195):代码模式、架构描述、git 历史——这些能从项目当前状态直接派生,存为记忆会快速过时。这一排除规则体现了对语义记忆"只存不可派生知识"的设计哲学。

记忆文件格式

每个记忆是一个独立的 Markdown 文件,带有 YAML frontmatter。description 字段是 AI 召回的关键——Sonnet 分类器依赖它判断相关性:

---
name: user is senior Go engineer
description: Deep Go expertise, new to React — frame frontend explanations in backend analogues
type: user
---

User has 10 years Go experience. First time touching
the React frontend of this repo. Prefer backend
analogies when explaining React concepts.

AI 驱动的记忆召回

核心设计决策:不用关键字匹配或向量搜索,而用 Sonnet 模型作为语义分类器 (findRelevantMemories.ts:39-75)。这一选择使语义记忆的检索完全不依赖 embedding 服务、数据库或 reindex,新增记忆立即可被召回:

1
scanMemoryFiles()
扫描目录所有 .md 文件,读取前 30 行解析 frontmatter
2
formatMemoryManifest()
生成文本清单:[type] filename (date): description
3
sideQuery(Sonnet)
发送清单 + 用户查询,Sonnet 选择最多 5 个相关文件
4
返回 JSON
{ selected_memories: ["file1.md", "file2.md"] },强制 JSON Schema

存储结构决定了 Auto Memory 和 Session Memory 如何在磁盘上持久化。Claude Code 采用了索引-内容分离的两层文件结构——这既是持久化知识的物理载体,也是后续所有召回和上下文注入机制的基础。

磁盘目录结构

~/.claude/
├── CLAUDE.md                        ← 用户级手动规则
├── agent-memory/                    ← Agent 作用域记忆
│   └── <agentType>/
│       ├── MEMORY.md
│       └── *.md
├── session-memory/                  ← 会话笔记
│   └── <session-id>.md
└── projects/
    └── <sanitized-git-root>/
        └── memory/                  ← 自动记忆主目录
            ├── MEMORY.md            ← 索引文件(始终加载)
            ├── user_role.md         ← 主题文件(按需加载)
            ├── feedback_testing.md
            ├── project_deadline.md
            ├── team/                ← 团队共享记忆
            │   └── *.md
            └── logs/                ← KAIROS 日志
                └── YYYY/MM/YYYY-MM-DD.md

路径解析优先级

路径解析遵循三级优先级 (paths.ts:223-235),安全设计排除了恶意仓库通过 projectSettings 重定向记忆路径的攻击向量:

优先级来源安全特性
1CLAUDE_COWORK_MEMORY_PATH_OVERRIDE 环境变量SDK/Cowork 专用
2settings.jsonautoMemoryDirectory仅信任 policy/local/user,排除 projectSettings
3~/.claude/projects/<git-root>/memory/默认计算路径,Git worktree 共享

MEMORY.md 索引层

MEMORY.md 不是记忆本身,而是目录索引——始终加载到 User Context 中,让模型知道有哪些持久化记忆存在。每行约 150 字符,最多 200 行 / 25KB (memdir.ts:35-38)。索引-内容分离在 context window 占用和信息可得性之间取得了精确平衡:

- [Senior Go engineer](user_role.md) — deep Go, new to React
- [No DB mocks in tests](feedback_testing.md) — use real DB after Q3 incident
- [Merge freeze Mar 5](project_deadline.md) — mobile release cut
- [Pipeline bugs in Linear](reference_linear.md) — project "INGEST"

Session Memory 结构化载体

存储在 ~/.claude/session-memory/<session-id>.md,是结构化的 Markdown 模板。它记录的是"当前会话中发生了什么",用于上下文压缩时保持对话连续性:

每 section 最多 2000 token,总计 12000 token。

Agent 记忆的三作用域

Agent 的语义记忆支持三种隔离级别 (agentMemory.ts:52-65):

作用域路径特点
user~/.claude/agent-memory/<type>/跨项目通用
project<cwd>/.claude/agent-memory/<type>/随项目提交到 VCS
local<cwd>/.claude/agent-memory-local/<type>/本地不入库

时效性标注

memoryAge.ts 将时间戳转换为人类可读字符串,因为"模型不擅长日期算术"。超过 1 天的记忆附加 staleness 警告,提醒模型这是时间点上的观察而非当前状态。这种设计防止陈旧的记忆文件被模型当作当前事实引用。

03记忆的检索


调用机制决定了记忆如何在正确的时机进入模型的上下文。Claude Code 设计了四条独立路径:Auto Memory 索引始终可见、主题文件按需召回、Session Memory 在压缩时恢复、System Prompt 注入行为指令。

路径一:MEMORY.md 索引 → 始终加载

context.ts:172 中,getMemoryFiles() 扫描所有记忆文件入口,包括 AutoMem 和 TeamMem 的 MEMORY.md。内容被截断保护后,通过 getClaudeMds() 格式化为字符串,作为 getUserContext().claudeMd 在每次 API 调用时前置注入。这条路径确保模型始终知道有哪些记忆文件可用。

路径二:Auto Memory 主题文件 → AI 驱动的按需召回

这是最核心的召回路径,实现了持久化知识的精确检索。完整数据流如下:

1
query.ts:301 — 每个用户 turn 启动 prefetch
startRelevantMemoryPrefetch(),异步非阻塞
2
attachments.ts:2361 — 提取用户消息 + 门控检查
单词数 > 1、会话总量 < 60KB、abort controller 绑定
3
findRelevantMemories.ts — Sonnet 选择相关文件
scanMemoryFiles() → formatManifest() → sideQuery(Sonnet) → JSON
4
readMemoriesForSurfacing() — 读取完整文件内容
单文件截断保护 + header 附加 staleness 警告
5
query.ts:1604 — 注入消息流
filterDuplicateMemoryAttachments() → createAttachmentMessage()
6
messages.ts:3708 — 渲染为 API 格式
每个文件 → 独立 user message,<system-reminder> 包裹

三层去重机制

层级位置机制
选择器层findRelevantMemoriesalreadySurfaced 集合过滤已展示路径
文件状态层getRelevantMemoryAttachmentsreadFileState 过滤模型已读/写/编辑的文件
消费层query.ts:1604filterDuplicateMemoryAttachments 最终去重

路径三:Session Memory → 上下文压缩时注入

当 auto-compact 触发时,trySessionMemoryCompaction() (sessionMemoryCompact.ts:514) 读取磁盘上的会话记忆文件,截断后格式化为摘要消息,成为压缩后的第一条消息。这让模型在上下文窗口耗尽后仍能保持对"之前发生了什么"的连续感知。

路径四:行为指令 → System Prompt 注入

prompts.ts:495 中,systemPromptSection('memory') 调用 loadMemoryPrompt() 返回记忆行为指令(类型定义、保存规则、访问规则)。这条路径不传递记忆内容,而是教模型如何使用记忆系统——"知道怎么做"而非"知道什么"。

四条路径的协同:行为指令教模型"怎么用记忆",索引让模型"知道有什么",按需召回提供"具体细节",会话记忆在压缩时保持"发生了什么"的连续性。

04记忆的编码与巩固


记忆抽取是将当前对话中的重要信息转化为持久化知识和结构化笔记的过程——对应认知科学中的"记忆编码"和"记忆巩固"。Claude Code 通过后台 Forked Agent 自动完成这一过程。

Forked Agent:共享缓存的分叉架构

所有后台抽取都使用 runForkedAgent 模式——创建主对话的完美分叉,共享 prompt cache 前缀。这是整个系统最精巧的成本优化:分叉 agent 发送与主对话完全相同的 system prompt + tools + 消息前缀,只在末尾追加自己的 prompt,因此 Anthropic API 的 prompt cache 前缀完全匹配,后台工作只为增量部分付费。

extractMemories:自动抽取持久化记忆

extractMemories.ts 在每个查询循环结束时自动触发,将对话中值得记住的信息抽取为 Auto Memory 文件。

Session Memory:结构化会话笔记

sessionMemory.ts 维护当前对话的结构化笔记,是会话级笔记的核心载体。它注册为 post-sampling hook,在模型每次回复后异步运行。触发条件采用双阈值设计:

Session Memory 在上下文工程中发挥关键作用——它是第五章"七级上下文压力缓解策略"中 Session Memory Compact(策略6)的数据来源,无需额外 API 调用即可完成压缩。

autoDream:定期整合

autoDream.ts 定期在后台回顾并整合累积的 Auto Memory 文件,清理冗余、合并相关内容。它使用三级门控控制执行频率:

门控条件作用
时间门控距上次整合 ≥ 24 小时限制整合频率
会话门控上次整合后 ≥ 5 次会话确保有足够新素材
锁门控consolidationLock.ts 文件系统锁防止跨会话并发
记忆编码的完整闭环:对话 → extractMemories → 主题文件;对话 → Session Memory → 结构化笔记;主题文件 → autoDream → 整合后的记忆。三个过程全部在后台自动完成,用户无感。

05上下文工程


前面三章分析了记忆的存储、检索和编码——它们最终都汇入一个共同的容器:context window。本章聚焦这个容器本身的管理——如何在有限的 200K token 空间中装入最大价值的信息,同时最大化 prompt cache 命中率。

System Prompt 的分层构建

prompts.ts:444-577 将 system prompt 构建为有序的字符串数组,分为静态和动态两半,由 SYSTEM_PROMPT_DYNAMIC_BOUNDARY 标记分割。静态段承载不变的行为规则,动态段承载会话级状态:

静态段(可全局缓存)

动态段(会话级状态)

动态段通过 systemPromptSection() 注册并缓存,仅 DANGEROUS_uncachedSystemPromptSection() 每轮重算(会破坏 prompt cache)。

三级 Prompt Cache 架构

splitSysPromptPrefix() (api.ts:310) 将 system prompt 分割为不同缓存作用域的块,这是性能优化的核心:

缓存模式BlockCache Scope含义
Global Cache
(1P 用户)
Attribution Headernull不缓存
CLI Prompt Prefixnull不缓存
Static Content(静态段)global全用户共享
Dynamic Content(动态段)null不缓存
Org Cache
(3P 用户)
Attribution Headernull不缓存
Prompt Prefixorg组织内共享
Everything Elseorg组织内共享

每次 API 调用的消息装配流水线

Context window 的内容由以下 10 步流水线精确装配。每一步都在平衡"保留有价值信息"与"控制 token 总量":

1
getMessagesAfterCompactBoundary()
取压缩边界之后的消息
2
applyToolResultBudget()
旧工具结果的大小预算裁剪
3
History Snip
移除旧消息(实验性)
4
Microcompact
时间触发:清除旧工具结果;缓存触发:cache editing API 删除
5
Context Collapse
折叠历史的压缩投影(实验性)
6
appendSystemContext()
注入 system context(环境信息)
7
Auto-compact check
超阈值 → session memory compact 或 full compact
8
prependUserContext()
CLAUDE.md + git status → <system-reminder> 包裹注入
9
Attachment injection
文件变更、记忆 prefetch、Skill、Plan、MCP 增量等
10
normalizeMessagesForAPI()
过滤/合并/重排消息 → queryModelWithStreaming()

Token 预算与自动压缩阈值

Context window 的容量管理依赖精确的 token 计数和阈值计算:

有效窗口 = contextWindow - 20K(摘要输出预留)
自动压缩阈值 = 有效窗口 - 13K(缓冲区)

对于 200K 窗口:阈值 ≈ 200K - 20K - 13K = 167K tokens

tokenCountWithEstimation() (tokens.ts:226) 是规范方法——找到最后一条有真实 API usage 的 assistant message,从该点向后用粗略估计(~4 字符/token,乘 4/3 安全系数)。

断路器 (autoCompact.ts:70):连续 3 次自动压缩失败后停止重试,防止 API 浪费。

七级上下文压力缓解策略

当 context window 接近容量上限时,系统按介入程度从轻到重依次尝试七种策略。前四种不破坏 prompt cache,后三种需要重建缓存:

#策略做了什么Cache 影响
1Cached Microcompactcache editing API 删除旧工具结果不破坏
2Time-based Microcompact替换旧结果为 "[cleared]"缓存已冷
3Tool Result Budget摘要文本替换大结果缓存友好
4History Snip移除旧消息破坏
5Context Collapse折叠历史投影破坏
6Session Memory Compact用会话笔记替代历史破坏,无额外 API
7Full CompactLLM 生成 9 段摘要破坏 + API 调用

策略 1-2:Microcompact — 工具结果的精确清理

工具结果是 context window 中最大的消耗源。Microcompact 专门针对这一问题,有两条路径:

Cached Microcompact (microCompact.ts:297) 利用 Anthropic 的 cache editing API——一种服务端机制,可以在不失效缓存前缀的前提下修改已缓存的 tool_result 内容。工作原理:

可清理的工具集 (microCompact.ts:41-50):FileRead、Bash(所有 shell 变体)、Grep、Glob、WebSearch、WebFetch、FileEdit、FileWrite。

Time-based Microcompact (microCompact.ts:422) 在不同条件下触发——当距上次 assistant 回复超过 60 分钟(匹配服务端 1 小时的缓存 TTL)时,缓存已经过期,此时用 [Old tool result content cleared] 替换旧结果的实际内容,保留最近 5 个工具结果。由于缓存已冷,内容清理不会造成额外的缓存未命中。

策略 3:Tool Result Budget — 大结果的磁盘持久化

applyToolResultBudget() (toolResultStorage.ts:924) 对每条 API 级 user message 中的 tool_result 施加 200K 字符的聚合预算 (toolLimits.ts:49)。超出预算时:

策略 6-7:Session Memory Compact vs Full Compact

当 token 数超过自动压缩阈值时,autoCompactIfNeeded() (autoCompact.ts:287) 按以下顺序决策:

1
先尝试 Session Memory Compact
如果有现成的 Session Memory 笔记,直接用它替代历史,无需额外 API 调用
2
SM 失败则回退到 Full Compact
调用 LLM(forked agent,共享 prompt cache)生成 9 段摘要

Session Memory Compact 的保留策略 (sessionMemoryCompact.ts:57-61):

参数默认值作用
minTokens10,000至少保留 10K tokens 的近期消息
minTextBlockMessages5至少保留 5 条含文本的消息
maxTokens40,000最多保留 40K tokens(防止保留过多)

lastSummarizedMessageId 向后计算保留范围,同时确保不切断 tool_use/tool_result 配对和 thinking 块。

Full Compact 的 9 段摘要结构

prompt.ts:61-132 定义了压缩摘要的标准模板。摘要前先在 <analysis> 块中进行思考(事后被剥离),确保不遗漏关键信息:

  1. Primary Request and Intent — 用户的显式请求和意图
  2. Key Technical Concepts — 技术概念、框架
  3. Files and Code Sections — 涉及的文件和代码片段(含完整代码段)
  4. Errors and Fixes — 错误和修复(含用户反馈)
  5. Problem Solving — 已解决的问题和进行中的排查
  6. All User Messages — 所有非工具结果的用户消息(关键:用于理解意图变化)
  7. Pending Tasks — 待办任务
  8. Current Work — 压缩前正在做的精确工作(含直接引用)
  9. Optional Next Step — 下一步(必须与最近请求直接相关,避免漂移)

如果压缩请求本身触发 prompt-too-long 错误,系统会自动截断最老的消息组并重试(最多重试数次),而非直接失败 (compact.ts:460-490)。

Post-Compact 恢复

压缩不是从零开始——系统执行一系列恢复操作确保关键上下文不丢失:

Sticky Beta Header Latches — 防止缓存抖动

一个容易被忽视的优化:服务端 prompt cache key 包含 beta headers。如果某个 header 在会话中途翻转(如 auto-mode 关闭),缓存键变化会导致 50-70K tokens 的缓存重建

解决方案 (claude.ts:1405):四个 beta header 使用 sticky-on latch——一旦首次发送就在整个会话中持续发送,仅在 /clear 和 /compact 时重置:

LatchHeader触发条件
afkModeHeaderLatchedAFK_MODE_BETA_HEADER首次进入 auto mode
fastModeHeaderLatchedFAST_MODE_BETA_HEADER首次 fast-mode 请求
cacheEditingHeaderLatchedCACHE_EDITING_BETA_HEADERCached MC 启用
thinkingClearLatchedcontext_management thinking上次回复距今 > 1 小时

06记忆类型分析


认知科学将人类记忆分为四种基本类型:工作记忆、程序记忆、情景记忆和语义记忆。Claude Code 的记忆系统在技术实现上惊人地复现了这一分类体系——不是刻意模仿,而是解决工程问题时的自然收敛。本章将建立从认知科学到技术实现的完整映射。

工作记忆 (Working Memory)

认知科学定义

工作记忆是对信息的临时保持和操作系统,容量有限(Miller 的 7±2 法则),是当前认知活动的"舞台"。它不是简单的短期存储,而是一个主动维护、操作和整合信息的系统。

Claude Code 实现

Context Window 是工作记忆的直接对应物。200K token 的上下文窗口就是"认知舞台"的容量上限,装载着当前对话、工具结果、注入的记忆内容和系统提示。

认知特征技术实现代码位置
容量有限200K token 上下文窗口context.ts:9
主动维护10 步消息装配流水线query.ts:307
信息衰减Microcompact 清除旧工具结果microCompact.ts:253
容量管理七级压力缓解策略autoCompact.ts:72
注意力分配cache breakpoints 标记重要位置claude.ts:588
信息刷新每轮 attachment injection 注入新信息query.ts:1580

最有趣的对应是容量管理策略。人类工作记忆在超载时会选择性遗忘和压缩,Claude Code 的七级策略正是这一过程的工程化实现:从轻量整理(cached microcompact)到深度压缩(full compact),逐步丢弃低价值信息以保留核心上下文。

程序记忆 (Procedural Memory)

认知科学定义

程序记忆是关于"如何做"的隐式知识——骑自行车、弹钢琴、打字。它通过重复练习习得,一旦建立就自动执行,不需要有意识地回忆。

Claude Code 实现

System Prompt + CLAUDE.md + memoryTypes 分类法构成了程序记忆。这些指令告诉模型"如何使用记忆系统"、"如何写代码"、"如何与用户交互"——模型按照这些规则自动行为,不需要在对话中显式引用它们。

认知特征技术实现代码位置
隐式知识System Prompt 中的行为指令prompts.ts:444
自动执行模型按规则行为,无需显式引用静态段(7 个 section)
难以言说用户看不到 system prompt 内容isMeta: true 消息
通过练习习得CLAUDE.md 四层加载:managed → user → project → localclaudemd.ts:790
稳定不变静态段全局缓存,会话间共享cacheScope: 'global'
规则系统memoryTypes 分类法约束什么该记什么不该记memoryTypes.ts:14

CLAUDE.md 的四层加载机制(Managed → User → Project → Local)对应程序记忆的不同来源层级:组织级规范、个人习惯、项目约定、本地覆盖。这些"知道怎么做"的知识被编译进每次 API 调用的系统提示中。

情景记忆 (Episodic Memory)

认知科学定义

情景记忆是关于个人经历的记忆——"上周二我在咖啡厅遇到了张三"。它有明确的时间、地点和情感标记,是自传式的、情境化的。

Claude Code 实现

Session Memory + 会话转录 + autoDream 日志构成了情景记忆。Session Memory 记录"这次对话中发生了什么"——修了哪些 bug、遇到了什么错误、用户给了什么反馈。KAIROS 日志 (logs/YYYY/MM/YYYY-MM-DD.md) 则是日期索引的情景记录。

认知特征技术实现代码位置
时间标记session-id 标识 + mtimeMs 时间戳sessionMemory.ts
情境化Worklog section 记录事件序列12000 token 结构化模板
自传式Errors & Corrections 记录"我犯了什么错"Full Compact 第 4 段
可回忆压缩时注入情景记忆恢复上下文sessionMemoryCompact.ts:514
时间衰减memoryAge staleness 警告memoryAge.ts:33
日期索引KAIROS logs/YYYY/MM/YYYY-MM-DD.mdpaths.ts:246

Full Compact 的 9 段摘要本质上是情景记忆的编码过程——将工作记忆中的事件流压缩为结构化的情景记录,保留时间线、因果关系和关键细节。

语义记忆 (Semantic Memory)

认知科学定义

语义记忆是关于世界知识的记忆——"巴黎是法国的首都"、"水的化学式是 H₂O"。它是去情境化的、概念化的,不依赖于特定的学习经历。

Claude Code 实现

Auto Memory (MEMORY.md + 主题文件) + Team Memory构成了语义记忆。这些记忆存储的是去情境化的事实知识——"用户偏好 TypeScript"、"项目使用 PostgreSQL"、"团队约定不在周五部署"。

认知特征技术实现代码位置
去情境化主题文件存事实,不存事件memoryTypes 四类型约束
概念网络MEMORY.md 索引关联多个主题文件memdir.ts:227
语义组织user/feedback/project/reference 分类memoryTypes.ts:14
持久稳定文件持久化,跨会话可用~/.claude/projects/*/memory/
可共享Team Memory API 双向同步teamMemPaths.ts
语义检索Sonnet AI 分类器按语义选择findRelevantMemories.ts:39

语义记忆的"去情境化"特征在排除规则中体现得最为明显——系统明确排除代码模式、架构、git 历史等与特定代码版本绑定的信息,只保留跨版本有效的抽象知识。

四种记忆类型的交互关系

编码路径:工作记忆 →(extractMemories)→ 语义记忆;工作记忆 →(Session Memory)→ 情景记忆;工作记忆 →(Full Compact)→ 情景记忆

检索路径:语义记忆 →(AI prefetch)→ 工作记忆;情景记忆 →(session memory compact)→ 工作记忆;程序记忆 →(system prompt)→ 工作记忆

巩固路径:语义记忆 →(autoDream)→ 整合后的语义记忆;情景记忆 →(KAIROS /dream)→ 语义记忆

这个交互关系揭示了一个重要模式:工作记忆是所有记忆类型的交汇点。信息从工作记忆流向语义/情景记忆(编码),又从语义/情景记忆流回工作记忆(检索),程序记忆则始终在背景中指导这一切。上下文工程(第六章)本质上就是对这个交汇点的容量管理。

07记忆系统的深层设计洞察


前面七章从功能维度分析了记忆系统的架构和实现。本章从四个横切面——安全、鲁棒性、成本、提示工程——审视同一个系统的深层设计决策。这些洞察揭示了工程实践中"看不见的冰山":用户无感、但决定系统是否可靠运行的关键机制。

8.1 信任边界与安全模型

记忆系统的安全模型基于一个核心假设:信任用户本地磁盘,不信任团队同步内容。个人记忆文件从本地文件系统加载,不做内容 sanitize 就注入 context——因为它们共享用户的信任边界。但团队记忆经由网络同步,必须经过多层防御。

团队记忆的五层路径穿越防御

teamMemPaths.ts:22-64 中的 sanitizePathKey() 防御了五种独立攻击向量:

攻击向量防御机制示例
Null bytes检测并拒绝memory\x00../../etc/passwd
URL 编码遍历解码后检查%2e%2e%2f%2e%2e%2f
Unicode 规范化攻击NFKC 规范化后重检fullwidth ../ → ASCII ../
反斜杠注入替换为正斜杠..\\..\\..
绝对路径逃逸resolve 后验证前缀/etc/passwd

Unicode 规范化防御(PSR M22187 vector 4)的精巧之处在于:path.resolve() 把 fullwidth 字符当作字面字节处理,但下游文件系统层可能将其规范化为 ASCII。系统在 resolve 之前先做 NFKC 规范化,消除这个时间差攻击窗口。

悬空 Symlink 攻击检测

teamMemPaths.ts:109-171 — 攻击者可以创建一个指向 teamDir 外部的 symlink,且目标不存在。writeFile 会跟随链接并在沙箱外创建目标文件。系统用 lstat 区分"真正不存在"和"悬空 symlink",还检测 ELOOP(symlink 循环)。

秘密扫描的反检测设计

secretScanner.ts:44-46 中,Anthropic API key 前缀在运行时拼接:

const ANT_KEY_PFX = ['sk', 'ant', 'api'].join('-')

这是供应链防御——扫描器的源码本身不包含它要检测的模式,避免在构建阶段触发 excluded-strings 检查。秘密在写入时就被拦截(teamMemSecretGuard.ts:15),而非等到团队同步时,确保即使同步禁用也不会泄露。

8.2 故障模式与自愈机制

记忆系统的所有后台进程都设计了优雅降级路径——任何记忆相关的失败都不会中断用户的主对话流。

Extraction Cursor 恢复

如果 lastMemoryMessageUuid 在压缩后从消息列表中消失(被摘要替代),系统回退到全量消息计数而非返回 0(extractMemories.ts:103-108)。返回 0 会导致后续所有抽取被跳过("无新消息"),等于永久禁用该会话的记忆抽取。

错误静默 + 光标不前进

抽取过程中的任何错误都被捕获并记录,从不暴露给用户extractMemories.ts:497-502)。关键的是光标不前进——受影响的消息在下一次抽取时会被重新考虑。

Trailing Run 模式

当新的抽取请求在进行中时到达(extractMemories.ts:297-323):

这种设计确保了并发请求不会导致重复抽取或遗漏。

Session Memory Compact 的 6 级降级链

sessionMemoryCompact.ts:514-629 在六个检查点中任何一个失败都优雅回退到 legacy compact:

1
Feature flags off → return null
2
No session memory file → log tengu_sm_compact_no_session_memory
3
Template-only (empty) → log tengu_sm_compact_empty_template
4
Summarized message ID not found → log tengu_sm_compact_summarized_id_not_found
5
Post-compact tokens exceed threshold → log tengu_sm_compact_threshold_exceeded
6
Any exception → log tengu_sm_compact_error,回退到 Full Compact

LRU 缓存逐出防御

attachments.ts:1709-1724readFileState 是一个 100 条目的 LRU 缓存。在繁忙会话中,早期条目会被逐出。如果没有防御,同一个 CLAUDE.md 在每次 LRU 逐出后会被重新注入 context,导致 prompt 膨胀。系统用一个永不逐出的 loadedNestedMemoryPaths Set 作为回归防护。

8.3 Token 预算的成本经济学

记忆系统的每一层都有精确的 token 预算约束,形成了一个五层预算体系——从单个文件到整个会话,逐层控制记忆对工作记忆(context window)的占用。

预算层级限制位置保护目标
单个记忆文件200 行 或 4KB(取小值)attachments.ts:269-277防止单个大文件挤占其他记忆
每轮注入最多 5 个文件findRelevantMemories.ts:20控制单轮记忆召回量
会话累计60KB 总字节数attachments.ts:288防止长会话中记忆注入失控
Session Memory12,000 tokens(每 section 2,000)SessionMemory/prompts.ts:8-9情景记忆压缩比
CLAUDE.md40,000 字符claudemd.ts:92程序记忆占用上限
MEMORY.md 索引200 行 / 25KBmemdir.ts:35-38语义记忆索引大小

Extraction 的两轮成本优化

后台抽取被限制为最多 5 轮(extractMemories.ts:425-427),提示词指导了一个两轮策略:第 1 轮并行 Read 收集信息,第 2 轮并行 Write 写入记忆。频率节流通过 tengu_bramble_lintel 控制——每 N 个 eligible turn 才执行一次抽取。

Staleness 警告的认知经济学

系统不删除旧记忆(信息损失),而是用约 50 字的 staleness 文本降低其权重(信息保留 + 可靠性校准)。这一设计源于一个特定的观察:带有文件路径引用的陈旧记忆,反而比不带引用的更具误导性——因为 file.ts:42 这样的引用让陈旧声明看起来更权威 (memoryAge.ts:30-31)。

缓存命中率追踪

每次后台抽取完成后,系统计算精确的 prompt cache 命中率并上报(extractMemories.ts:440-452):

hit_rate = cache_read / (input + cache_creation + cache_read) × 100

这个指标直接衡量 forked agent 共享 prompt cache 的实际效果——如果命中率下降,说明某些变更破坏了缓存前缀匹配。

8.4 提示词即代码:Eval 驱动的记忆提示工程

记忆系统中最不可见但影响最大的设计决策发生在提示词层面。源码注释揭示了一个重要事实:记忆行为指令的措辞经过严格的 A/B 评估

"Before recommending" vs "Trusting what you recall"

memoryTypes.ts:240-256 中记录了一个关键评估结果:

Section 标题正文Eval 结果
"Before recommending from memory"(行动暗示)相同3/3 通过
"Trusting what you recall"(抽象描述)相同0/3 通过

相同的正文内容,仅 section 标题不同,导致模型行为从完全失败到完全成功。行动暗示(action cue)——"在做 X 之前"——比抽象描述——"关于 X 的可信度"——有效得多。这揭示了 prompt engineering 的一个深层规律:模型对指令的响应不是基于语义理解,而是基于模式匹配的激活路径

独立 Section 的必要性

同一条指令作为独立 section 存在时 eval 通过率为 3/3,但作为 "When to access" 部分的一个子弹点存在时通过率为 0/2。这说明在长 prompt 中,section 级别的结构化对指令遵循有决定性影响——嵌套在其他内容中的指令容易被模型"淹没"。

排除规则的 Eval 验证

memoryTypes.ts:183-195 中明确排除代码模式、架构描述、git 历史的决策不是拍脑袋做的。注释记录了没有这些排除规则时的失败模式:模型会将 src/auth.ts:42 uses bcrypt 这样的信息存为记忆,但代码重构后这条记忆就变成了危险的过时权威声明。

设计启示

记忆系统的提示词不是"写了就行"的配置文本——它们是经过 eval 验证的代码。标题措辞、section 层级、排除规则的每一个选择都有评估数据支撑。这种"提示词即代码"的工程纪律,是 Claude Code 记忆系统可靠性的隐藏基石。

08与 OpenClaw 记忆系统对比


OpenClaw 是一个开源的多渠道 AI 助手平台,其记忆系统在设计哲学上与 Claude Code 有本质差异。本章基于 OpenClaw 最新源码(2026-04-01 克隆自 GitHub)的源码级分析,通过记忆类型框架进行对比,确保两侧分析深度一致。

数据来源:Claude Code 部分基于本地源码分析(精确到文件:行号);OpenClaw 部分基于 GitHub 最新源码的源码级分析,涵盖 extensions/memory-core/、src/agents/、src/auto-reply/ 等核心模块。

存储结构对比

维度Claude CodeOpenClaw
存储格式纯 Markdown + YAML frontmatterMarkdown 文件 + SQLite 索引数据库(4 表 + 2 虚拟表)
语义记忆MEMORY.md 索引 + 独立主题文件MEMORY.md 单文件 + memory/*.md
情景记忆Session Memory (<session-id>.md)每日笔记 (memory/YYYY-MM-DD.md)
索引方式无索引文件(frontmatter 即元数据)SQLite:chunks 表存嵌入向量,chunks_fts 存 FTS5 全文索引,chunks_vec 存 sqlite-vec ANN 索引 (memory-schema.ts:1-102)
分块策略不分块(整文件加载)400 tokens/chunk,80 tokens 重叠 (memory-search.ts:94-95)
团队共享team/ 子目录 + API 同步无内建团队记忆
Agent 记忆三作用域 (user/project/local)按 agentId 隔离,每个 agent 独立 SQLite 库 (memory-search.ts:132)
重索引安全无需重索引原子化 temp-DB + swap 模式,防止 corruption (manager-sync-ops.ts:1145)

按记忆类型的召回机制对比

记忆类型Claude CodeOpenClaw
工作记忆七级压力缓解策略;prompt cache 三级架构;forked agent 共享缓存auto-compact + session pruning;可插拔 Context Engine 架构 (context-engine/types.ts:104)——compaction、context assembly、ingestion 均可被自定义引擎替换
程序记忆System Prompt 静态/动态分层;CLAUDE.md 四层加载;memoryTypes 分类法AGENTS.md + SOUL.md + TOOLS.md 注入 (system-prompt.ts:184);Memory Recall section 强制 agent 回答前搜索记忆;Skills 平台
情景记忆Session Memory 结构化笔记(12000 token);Full Compact 9段摘要每日笔记 memory/YYYY-MM-DD.md;昨天+今天自动加载;可选的会话转录索引(delta 触发:100KB 或 50 条消息)(manager-sync-ops.ts:435)
语义记忆AI 分类器 (Sonnet) 按需召回;无需 embedding混合搜索:向量(sqlite-vec ANN 或内存 fallback)+ BM25 (FTS5),默认权重 0.7:0.3 (hybrid.ts:127);BM25 评分使用 sigmoid-like 转换 (hybrid.ts:46);需要 embedding provider

记忆写入与编码对比

维度Claude CodeOpenClaw
自动编码Forked Agent 每轮自动抽取(独立后台 agent)压缩前自动 flush——是一个完整 agent turn(非简单提醒),agent 自己决定写什么 (flush-plan.ts:1-139)
编码时机每个 turn 结束(持续)Token 接近阈值时(softThreshold 4000 tokens)或转录超 2MB 时强制触发 (agent-runner-memory.ts:451)
写入规则四类型分类法约束写入内容Flush prompt 约束:只写 memory/YYYY-MM-DD.md,MEMORY.md 为只读;context hash 去重防止重复 flush (memory-flush.ts:118)
记忆巩固autoDream 定期整合(24h + 5会话)无自动整合。Temporal decay 提供软性"遗忘"(默认半衰期 30 天),但不删除或合并文件 (temporal-decay.ts:1)
编码成本Forked agent 共享 prompt cache,几乎免费完整 agent turn,需要额外模型调用
Subagent 记忆Agent Memory 三作用域,可跨会话Subagent 使用 promptMode: "minimal",排除 Memory Recall section (system-prompt.ts:42)

语义记忆检索算法对比

两个系统在语义记忆检索上采用了完全不同的技术路线,值得深入对比:

维度Claude CodeOpenClaw
检索技术AI 分类器(Sonnet sideQuery)混合搜索(向量余弦相似度 + BM25 关键词)
搜索触发每个 user turn 自动 prefetch(系统驱动)Agent 调用 memory_search 工具,但工具描述标记为"Mandatory recall step"——系统提示强制 agent 在回答相关问题前搜索 (tools.ts:24)
向量搜索不使用向量sqlite-vec 硬件加速 ANN 搜索,失败时自动降级为内存 cosine 计算 (manager-search.ts:74)
关键词搜索不使用关键词FTS5 (BM25),支持 unicode61 和 trigram 分词器(CJK 支持),sigmoid-like 评分转换 (hybrid.ts:46)
结果融合Sonnet 直接选择(端到端语义理解)加权线性组合 score = 0.7×vector + 0.3×text (hybrid.ts:127)
多样性控制无(依赖 Sonnet 判断)MMR (Maximal Marginal Relevance),Jaccard 相似度 + CJK bigrams (mmr.ts:1-248)
时间衰减staleness 文本警告(提示性)指数衰减 score × e^(-λ×age),MEMORY.md 等常青文件豁免 (temporal-decay.ts:71)
降级策略无(AI 分类器不依赖外部服务)无 embedding 时自动降级为 FTS-only 模式,提取关键词多路搜索 (manager.ts:462)
配置复杂度零配置可调参数:权重、MMR lambda、temporal decay 半衰期、candidate multiplier 等

Claude Code 更强的地方

OpenClaw 更强的地方

相似之处

09总结


Claude Code 的记忆系统是一个精心设计的、面向长期使用的工程化解决方案。它在技术实现上自然收敛到了认知科学的记忆分类体系——工作记忆、程序记忆、情景记忆和语义记忆四种类型在系统中都有明确的技术对应物和精巧的协同机制。

核心设计原则

原则实现
Cache is king三级缓存架构、static/dynamic 分离、sticky header latches、forked agent 共享前缀
记忆应无感发生后台 forked agent 自动抽取、autoDream 自动整合、prefetch 自动召回
轻索引重内容MEMORY.md 始终加载(200行指针),主题文件按需获取(最多5个)
分层压力缓解从 cache editing(零成本)到 full compact(一次 API 调用),七级递进
工具结果是最大消耗microcompact + tool result budget + maxResultSizeChars 三层控制
压缩不丢失9段结构化摘要 + 文件恢复 + session start hooks 重注入
行为规则分层Managed → User → Project → Local 四层加载 + 类型分类法
一句话总结

Claude Code 的记忆系统优化的是"记忆应该自然发生"——通过完整的四类型记忆体系和自动化的编码/检索/巩固通路,让 AI 助手获得了接近人类认知系统的记忆能力,而用户几乎不需要意识到记忆系统的存在。

与 OpenClaw 的核心差异在于:Claude Code 投资于自动化和缓存优化(让记忆无感运行),OpenClaw 投资于搜索精度和可配置性(让用户控制记忆检索)。两种哲学各有适用场景,但 Claude Code 对记忆类型的完整覆盖——特别是工作记忆的七级管理策略和程序记忆的缓存分层——展现了更成熟的系统性设计。