Claude Code 的记忆系统是一个分层架构,通过文件持久化存储实现跨对话上下文保持。系统包含三个核心组件:项目记忆(memdir)、会话记忆(Session Memory)和后台记忆提取(extractMemories),它们协同工作让 AI 能够”记住”用户偏好、项目上下文和长期知识。
系统架构概览
flowchart TB
subgraph "User Layer 用户层"
U[用户消息]
end
subgraph "Memory System 记忆系统"
subgraph "Project Memory 项目记忆"
M[memdir.ts]
MT[memoryTypes.ts]
MS[memoryScan.ts]
FR[findRelevantMemories.ts]
end
subgraph "Session Memory 会话记忆"
SM[sessionMemory.ts]
SU[sessionMemoryUtils.ts]
SP[prompts.ts]
end
subgraph "Extract Memories 记忆提取"
EM[extractMemories.ts]
EP[extractMemories/prompts.ts]
end
subgraph "Team Memory 团队记忆"
TM[teamMemorySync]
TP[teamMemPaths.ts]
end
end
subgraph "Storage Layer 存储层"
FS[(文件系统)]
API[(API Server)]
end
U --> M
U --> SM
M --> MT
M --> MS
M --> FR
SM --> SU
SM --> SP
EM --> EP
EM --> MS
TM --> TP
M --> FS
SM --> FS
EM --> FS
TM --> API
TM --> FS
记忆系统的数据流遵循以下原则:MEMORY.md 作为每次对话的入口索引被完整加载,而具体的记忆内容文件通过 Sonnet 侧查询智能召回。MEMORY.md 本身仅包含索引指针,不存储实际记忆内容。
核心存储架构
源码路径:src/memdir/paths.ts、src/memdir/memdir.ts
目录布局与路径解析
~/.claude/projects/<sanitized-git-root>/memory/
├── MEMORY.md ← 入口索引(每次对话加载)
├── user_role.md ← 用户记忆
├── feedback_testing.md ← 反馈记忆
├── project_mobile_release.md ← 项目记忆
├── reference_linear_ingest.md ← 参考记忆
├── private/ ← 私有记忆目录(TEAMMEM模式)
│ ├── MEMORY.md
│ └── ...
└── team/ ← 团队记忆目录(TEAMMEM模式)
├── MEMORY.md
└── ...
路径解析遵循优先级链:CLAUDE_COWORK_MEMORY_PATH_OVERRIDE 环境变量(SDK 覆盖)→ autoMemoryDirectory 设置(仅限 policySettings/localSettings/userSettings,故意排除 projectSettings 防止安全风险)→ 默认路径。
关键安全约束:validateMemoryPath() 拒绝相对路径、Windows 驱动器根、UNC 网络路径和包含空字节的路径。~/ 展开也有限制,防止 ~/.ssh 等敏感目录被意外匹配。
MEMORY.md 索引机制
src/memdir/memdir.ts:35-38
export const ENTRYPOINT_NAME = 'MEMORY.md'
export const MAX_ENTRYPOINT_LINES = 200
export const MAX_ENTRYPOINT_BYTES = 25_000
索引采用双重上限保护:200 行 AND 25KB。超过任一限制都会被 truncateEntrypointContent() 截断并追加警告。这种设计针对两种失败模式:p97 的索引文件用 200 行就能覆盖(行数限制),但 p100 观测到 197KB/200 行的异常条目(字节限制兜底)。
索引格式简洁:每条记忆一行,150 字符以内。MEMORY.md 本身没有 frontmatter,它只是一个链接列表。
四类型分类法
源码路径:src/memdir/memoryTypes.ts
记忆被约束为封闭的四类型系统,每种类型有明确的语义边界和保存时机:
| 类型 | 作用域 | 存储内容 | 典型触发场景 |
|---|---|---|---|
| user | 始终私有 | 用户角色、技术背景、偏好 | “我是数据科学家”、”写了十年 Go” |
| feedback | 默认私有,例外时团队 | 用户对 AI 行为的纠正和确认 | “别 mock 数据库”、”对,就是这样” |
| project | 强烈推荐团队 | 非代码可推导的项目上下文 | “合并冻结周四开始”、”合规驱动 auth 重写” |
| reference | 通常团队 | 外部系统指针 | “pipeline bugs 在 Linear INGEST” |
反馈类型的双通道捕获
feedback 类型的保存指令特别强调:既要从失败中记录,也要从成功中记录。如果只保存纠正,AI 会避免过去错误但会逐渐偏离已被用户验证的方法。确认比纠正更难捕捉,但同等重要——它防止 AI 行为随时间漂移。
记忆的严格排除规则
系统明确禁止保存可从当前项目状态推导的信息:
- 代码模式、架构、文件路径——可实时读取
- Git 历史、最近变更——
git log/git blame更权威 - 调试方案或修复配方——代码和 commit message 已有
- CLAUDE.md 中已记录的内容
- 临时状态和当前对话上下文
这些排除规则即使在用户明确要求保存时也适用。如果用户要求保存本周 PR 列表,系统会引导用户提取其中出乎意料或非显而易见的部分。
智能召回机制
源码路径:src/memdir/findRelevantMemories.ts、src/memdir/memoryScan.ts
召回流程
sequenceDiagram
participant U as 用户消息
participant FR as findRelevantMemories
participant MS as scanMemoryFiles
participant SQ as selectRelevantMemories
participant S as Sonnet侧查询
U->>FR: findRelevantMemories(query, memoryDir)
FR->>MS: scanMemoryFiles() — 扫描所有.md文件
MS-->>FR: MemoryHeader[] (filename, description, type)
FR->>SQ: selectRelevantMemories(query, headers)
SQ->>S: sideQuery() — 轻量Sonnet调用
S-->>SQ: selected_memories: string[]
SQ-->>FR: string[]
FR-->>U: RelevantMemory[] (path, mtimeMs)
核心是 selectRelevantMemories() 函数,它通过 sideQuery() 调用轻量级 Sonnet 模型(非主模型)进行相关性筛选:
// findRelevantMemories.ts:98-121
const result = await sideQuery({
model: getDefaultSonnetModel(), // 用 Sonnet 做筛选
system: SELECT_MEMORIES_SYSTEM_PROMPT,
messages: [{
role: 'user',
content: `Query: ${query}\n\nAvailable memories:\n${manifest}${toolsSection}`
}],
max_tokens: 256,
output_format: { type: 'json_schema', schema: { ... } },
})
近期工具去噪
当 AI 正在使用某工具时,召回该工具的使用文档是噪音(对话中已有工作上下文)。recentTools 参数让召回系统跳过这些记忆,但保留关于这些工具的警告、陷阱或已知问题——这正是使用时最关键的信息。
已展示去重
alreadySurfaced 参数过滤之前轮次已展示过的文件路径,让 Sonnet 的 5 槽预算花在新的候选上。
会话记忆(Session Memory)
源码路径:src/services/SessionMemory/sessionMemory.ts
会话记忆自动维护一个 Markdown 文件,记录当前对话的关键信息。它通过forked 子 agent 在后台周期性提取,不打断主对话流程。
触发阈值
会话记忆的提取遵循三个阈值条件:
| 阈值类型 | 默认值 | 说明 |
|---|---|---|
minimumMessageTokensToInit |
10,000 | 初始化最小上下文 tokens |
minimumTokensBetweenUpdate |
5,000 | 两次更新间最小上下文增长 |
toolCallsBetweenUpdates |
3 | 两次更新间最小工具调用数 |
提取触发条件:token 阈值必须满足 +(tool call 阈值满足 或 上一轮无工具调用)。无工具调用条件确保在自然对话间隙提取。
文件结构模板
会话记忆使用结构化模板:
# Session Title
_5-10词描述性标题,信息密集_
# Current State
_当前活跃工作内容?未完成的待办?下一步?_
# Task specification
_用户要求构建什么?设计决策?_
# Files and Functions
_重要文件?它们包含什么?为什么相关?_
# Workflow
_常用 bash 命令及其顺序?如何解读输出?_
# Errors & Corrections
_遇到的错误及修复方法。用户纠正了什么?_
# Learnings
_什么效果好?什么不好?要避免什么?_
# Key results
_用户请求的具体输出(表格、答案等)_
与上下文压缩的集成
源码路径:src/services/compact/sessionMemoryCompact.ts
当上下文压缩发生时,sessionMemoryCompact.ts 负责保留会话记忆中的关键信息。它会识别哪些消息包含会话记忆内容,并在压缩边界处添加特殊标记,确保压缩后的消息序列仍然包含必要的会话记忆引用。
后台记忆提取(extractMemories)
源码路径:src/services/extractMemories/extractMemories.ts
后台记忆提取在每个完整查询循环结束时运行(当模型产生无工具调用的最终响应时),通过 handleStopHooks 触发。它使用 forked agent 模式——主对话的完美分叉,共享父级的 prompt cache。
与主 Agent 的协同
主 Agent 的 system prompt 始终有完整的保存指令。当主 Agent 自己写入了记忆时,后台 agent 会跳过那段范围(hasMemoryWritesSince 检查)。两者互斥:主 Agent 写则后台跳过,主 Agent 不写则后台捕获遗漏。
工具权限限制
后台 agent 的工具权限受到严格限制:
- 允许:Read/Grep/Glob(无限制)、只读 Bash 命令
- 限制:Edit/Write 仅限
auto-memory目录内 - 禁止:Bash
rm、目录外文件操作
// extractMemories.ts:137-170
export function createAutoMemCanUseTool(memoryDir: string): CanUseToolFn {
return async (tool: Tool, input: Record<string, unknown>) => {
// 允许 Read/Grep/Glob 无限制
if (tool.name === FILE_READ_TOOL_NAME ||
tool.name === GREP_TOOL_NAME ||
tool.name === GLOB_TOOL_NAME) {
return { behavior: 'allow' }
}
// 允许只读 Bash
if (tool.name === BASH_TOOL_NAME) {
if (parsed.success && tool.isReadOnly(parsed.data)) {
return { behavior: 'allow' }
}
return denyAutoMemTool(tool, ...)
}
// Edit/Write 仅限 memoryDir
// ...
}
}
团队记忆同步
源码路径:src/services/teamMemorySync/index.ts
团队记忆在 Git repo 范围内共享(通过 git remote hash 标识),所有认证组织成员可访问。
API 契约
GET /api/claude_code/team_memory?repo={owner/repo} → TeamMemoryData(含 entryChecksums)
GET /api/claude_code/team_memory?repo={owner/repo}&view=hashes → 仅 metadata + entryChecksums
PUT /api/claude_code/team_memory?repo={owner/repo} → 上传 entries(upsert 语义)
同步语义
- 拉取:服务器内容覆盖本地文件(服务器胜出)
- 推送:仅上传内容 hash 与
serverChecksums不同的条目(增量上传) - 删除不传播:删除本地文件不会从服务器移除,下次拉取会恢复
敏感信息防护
团队记忆同步包含密钥扫描机制(secretScanner.ts)。在上传前扫描记忆内容,拒绝包含潜在敏感信息(如 API 密钥、凭证模式)的文件。
记忆注入链路
源码路径:src/memdir/memdir.ts → src/context.ts
loadMemoryPrompt() 是记忆注入的入口,每会话调用一次(通过 systemPromptSection('memory', ...) 缓存):
// memdir.ts:419-507
export async function loadMemoryPrompt(): Promise<string | null> {
const skipIndex = getFeatureValue_CACHED_MAY_BE_STALE('tengu_moth_copse', false)
// KAIROS 日志模式优先
if (feature('KAIROS') && autoEnabled && getKairosActive()) {
return buildAssistantDailyLogPrompt(skipIndex)
}
// TEAMMEM 组合模式
if (feature('TEAMMEM') && teamMemPaths!.isTeamMemoryEnabled()) {
return teamMemPrompts!.buildCombinedMemoryPrompt(extraGuidelines, skipIndex)
}
// 纯自动记忆
if (autoEnabled) {
return buildMemoryLines('auto memory', autoDir, extraGuidelines, skipIndex).join('\n')
}
return null
}
注入时机:context.ts 中 getSystemContext() 调用时,记忆 Prompt 作为 system prompt 的一个 section 被组装。MEMORY.md 的实际内容作为 user context message 注入(而非 system prompt),这样可以利用 Prompt Cache 的 prefix 共享。
记忆漂移防御
源码路径:src/memdir/memoryTypes.ts(TRUSTING_RECALL_SECTION)
记忆可能过期。系统设置专门的 “Before recommending from memory” section:
A memory that names a specific function, file, or flag is a claim that it existed when the memory was written. It may have been renamed, removed, or never merged. Before recommending it:
- If the memory names a file path: check the file exists.
- If the memory names a function or flag: grep for it.
这个 section 的标题经过 A/B 测试验证:”Before recommending from memory”(行动导向)比 “Trusting what you recall”(抽象描述)效果好。
CLI 命令
源码路径:src/commands/memory/memory.tsx
/memory 命令打开记忆文件选择器:
// memory.tsx
export const call: LocalJSXCommandCall = async onDone => {
clearMemoryFileCaches()
await getMemoryFiles()
return <MemoryCommand onDone={onDone} />
}
使用 $EDITOR 或 $VISUAL 环境变量配置的编辑器打开选中的记忆文件。
配置与 Feature Gates
| 功能 | Feature Flag | 配置项 |
|---|---|---|
| 自动记忆 | tengu_passport_quail |
isExtractModeActive() |
| Team Memory | feature('TEAMMEM') |
tengu_herring_clock |
| KAIROS 日志 | feature('KAIROS') |
getKairosActive() |
| 搜索历史上下文 | tengu_coral_fern |
buildSearchingPastContextSection() |
| 跳过 MEMORY.md 索引 | tengu_moth_copse |
skipIndex 参数 |
| 记忆形状遥测 | feature('MEMORY_SHAPE_TELEMETRY') |
logMemoryRecallShape() |
关键设计原则
- 文件即存储:无数据库、无向量存储,只有 Markdown 文件
- 封闭类型系统:四种记忆类型覆盖所有不可推导的上下文
- 双重召回:入口索引全量加载 + 智能筛选按需召回
- 主从协同:主 Agent 和后台 Agent 互斥,不重复工作
- 增量同步:团队记忆使用 SHA256 hash 比较实现增量上传
- 安全优先:路径验证、敏感信息扫描、工具权限限制多层防护
相关文档
相关条目
- 19-agent-xie-diao-mo-shi
- 21-zi-ding-yi-agents
- 多智能体与记忆机制