让 Claude Code 跨会话记住你是谁、你偏好什么、项目正在发生什么——这是 Memory 系统的核心目标。它不是简单的聊天记录持久化,而是一个结构化的知识管理系统,通过四种记忆类型、自动提取机制、团队同步等功能,让 AI 真正”理解”你。
导读:为什么需要 Memory? 假设你今天让 Claude Code 帮你重构代码,明天让它继续优化。如果没有 Memory:
Claude 不知道你昨天做了什么
Claude 不知道你的编码风格偏好
Claude 不知道项目正在进行的决策
每次对话都从零开始,这是 AI 编程助手的一个根本性限制。
Claude Code 的 Memory 系统解决了这个问题:让 AI 跨会话积累知识 。
一、四种记忆类型 1.1 类型定义 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ┌─────────────────────────────────────────────────────┐ │ 四种记忆类型 │ ├─────────────────────────────────────────────────────┤ │ │ │ User(用户画像) │ │ └─ 角色、目标、技能水平、偏好 │ │ └─ 示例:"用户是数据科学家,关注日志系统" │ │ │ │ Feedback(行为反馈) │ │ └─ 对 Claude 工作方式的纠正或肯定 │ │ └─ 示例:"集成测试用真实数据库,不用 mock" │ │ │ │ Project(项目动态) │ │ └─ 谁在做什么、为什么、截止日期 │ │ └─ 示例:"3/5 起合并冻结,移动团队发版" │ │ │ │ Reference(外部引用) │ │ └─ 外部系统指针:仪表板、工单系统、Slack 频道 │ │ └─ 示例:"Pipeline bug 在 Linear 'INGEST' 项目" │ │ │ └─────────────────────────────────────────────────────┘
1.2 不存储的内容 Memory 系统有一个核心原则:只记住无法从代码中推断出来的东西 。
记住
不记住
你是数据科学家,关注日志系统
代码架构、文件结构
“不要 mock 数据库”
Git 历史、谁改了什么
周四后冻结非关键合并
已有的 CLAUDE.md 内容
Bug 跟踪在 Linear 的 INGEST 项目
调试方案(修复已在代码里)
二、Memory 存储格式 2.1 文件结构 1 2 3 4 5 6 7 8 9 10 11 12 ~/.claude/ └── projects/ └── {项目路径哈希}/ └── memory/ ← 自动记忆目录 ├── MEMORY.md ← 索引文件 ├── user_role.md ← 用户画像记忆 ├── feedback_testing.md ← 行为反馈记忆 ├── project_freeze.md ← 项目动态记忆 ├── reference_linear.md ← 外部引用记忆 └── team/ ← 团队共享记忆 ├── MEMORY.md └── ...
2.2 记忆文件格式 每个记忆文件使用 YAML frontmatter + Markdown:
1 2 3 4 5 6 7 8 9 10 11 --- name: testing_policy description: 集成测试必须用真实数据库,不能用 mock type: feedback --- **规则:** 集成测试必须连接真实数据库,禁止使用 mock。**Why:** 去年第四季度出现过 mock 测试通过但生产迁移失败的问题。**How to apply:** 所有标记为 integration test 的测试文件都要使用测试数据库连接。
2.3 MEMORY.md 索引文件 MEMORY.md 是索引而不是内容,它始终加载到上下文 中:
1 2 3 4 5 6 # Memory Index - [用户角色 ](user_role.md ) — 数据科学家,关注可观测性/日志- [测试策略 ](feedback_testing.md ) — 集成测试用真实数据库,不 mock- [合并冻结 ](project_freeze.md ) — 2026-03-05 起冻结非关键合并- [Bug 追踪 ](reference_linear.md ) — 流水线 bug 在 Linear INGEST 项目
限制 :最多 200 行或 25KB,超出会被截断。
三、Memory 提取机制 3.1 自动提取流程 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 触发时机:每次模型完成回复(无 tool_use)时 ↓ 守卫检查:主代理?功能门控开启?自动记忆启用? ↓ 频率控制:turnsSinceLastExtraction++ (默认每 1 次) ↓ 互斥检查:主代理自己写了记忆?→ 跳过 ↓ 扫描现有记忆 → 生成清单 ↓ 运行分叉代理(runForkedAgent) - 共享父会话提示词缓存 - 最多 5 个 turn - 限制工具权限 ↓ 写入新记忆文件 + 更新 MEMORY.md ↓ 通知用户:"Memory updated in ..."
3.2 工具权限限制 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 function createAutoMemCanUseTool (memoryDir: string ): CanUseToolFn { return (toolName, input ) => { if (['Read' , 'Grep' , 'Glob' ].includes(toolName)) { return true } if (toolName === 'Bash' && isReadOnlyCommand(input.command)) { return true } if (['Edit' , 'Write' ].includes(toolName)) { return isInsideMemoryDir(input.file_path, memoryDir) } return false } }
3.3 互斥机制 防止重复保存:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function hasMemoryWritesSince ( messages: Message[], sinceUuid: string , ): boolean { for (const msg of messages) { if (msg.uuid === sinceUuid) break if (msg.type === 'assistant' ) { for (const block of msg.content) { if (block.type === 'tool_use' && ['Edit' , 'Write' ].includes(block.name) && isMemoryPath(block.input.file_path)) { return true } } } } return false }
四、Memory 在 Prompt 中的使用 4.1 系统提示词注入 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 async function loadMemoryPrompt ( ): Promise <string | null > { const sections = [] sections.push(`## Types of memory` ) sections.push(...getMemoryTypeDescriptions()) sections.push(`## What NOT to save` ) sections.push(...getWhatNotToSaveList()) sections.push(`## How to save memories` ) sections.push(getSaveInstructions()) sections.push(`## When to access memories` ) sections.push(getAccessGuidelines()) sections.push(`## Before recommending` ) sections.push(getValidationGuidelines()) sections.push(`## MEMORY.md` ) sections.push(await loadMemoryIndex()) return sections.join('\n\n' ) }
4.2 智能检索 每次用户查询时动态选择相关记忆:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 async function findRelevantMemories ( query: string , memoryDir: string , recentTools: string [] = [], ): Promise <RelevantMemory []> { const files = await scanMemoryFiles(memoryDir) const candidates = await Promise .all( files.map(f => parseMemoryFile(f)) ) const selected = await sideQuery({ model: 'claude-sonnet-4-5' , systemPrompt: MEMORY_SELECTOR_PROMPT, messages: [{ role: 'user' , content: query }], context: { candidates, recentTools }, }) return selected.map(s => ({ path: s.path, mtimeMs: s.mtimeMs })) }
Sonnet 选择器提示词 :
1 2 3 4 5 6 7 8 9 10 你是记忆选择器。从候选记忆中选择对处理用户查询有用的记忆。 规则: - 最多选 5 个 - 不确定是否有用就不要选 - 如果提供了最近使用的工具列表,不要选这些工具的使用文档 (但要选择关于这些工具的警告/陷阱/已知问题) 返回格式: - memory_path: 选择原因
4.3 新鲜度警告 1 2 3 4 5 6 7 8 function memoryFreshnessText (mtimeMs: number ): string { const days = memoryAgeDays(mtimeMs) if (days <= 1 ) return '' return `This memory is ${days} days old. Memories are point-in-time observations that may become stale. Verify against current code before asserting as fact.` }
五、团队 Memory 同步 5.1 API 端点 1 2 GET /api/claude_code/team_memory?repo={owner/repo} ← 拉取 PUT /api/claude_code/team_memory?repo={owner/repo} ← 推送
5.2 同步语义
操作
行为
Pull
服务器内容覆盖本地文件(服务器优先)
Push
仅上传内容哈希不同的键(delta 上传)
删除
本地删除不会删除远程(下次 pull 会恢复)
5.3 冲突解决 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 async function pushTeamMemory (state ): Promise <PushResult > { const localFiles = await readLocalMemoryFiles() const localHashes = computeHashes(localFiles) const delta = computeDelta(localHashes, state.serverChecksums) const response = await api.pushTeamMemory(delta) if (response.status === 412 ) { const latest = await api.getTeamMemoryHashes() const newDelta = recomputeDelta(localHashes, latest) return pushTeamMemory({ ...state, serverChecksums: latest }) } return { success: true } }
5.4 安全限制
单文件最大 :250KB
上传体最大 :200KB(分批上传)
秘密扫描 :使用 gitleaks 规则扫描凭证,检测到则跳过该文件
六、AutoDream:后台记忆整合 6.1 触发条件 1 2 3 4 5 6 7 8 9 10 async function shouldTriggerAutoDream ( ): Promise <boolean > { if (hoursSinceLastConsolidation < minHours) return false if (sessionsSinceLastConsolidation < minSessions) return false if (otherProcessConsolidating) return false if (timeSinceLastScan < 10 * 60 * 1000 ) return false return true }
6.2 四阶段流程 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ┌─────────────────────────────────────────────────────┐ │ AutoDream 四阶段流程 │ ├─────────────────────────────────────────────────────┤ │ │ │ Phase 1: 定向(Orientation) │ │ └─ 确定要审查的会话列表 │ │ │ │ Phase 2: 收集(Collection) │ │ └─ 从会话中提取候选记忆 │ │ │ │ Phase 3: 整合(Consolidation) │ │ └─ 合并、去重、更新记忆文件 │ │ │ │ Phase 4: 修剪(Pruning) │ │ └─ 删除过时或重复的记忆 │ │ │ └─────────────────────────────────────────────────────┘
6.3 DreamTask 状态 1 2 3 4 5 6 7 type DreamTaskState = { type : 'dream' phase: 'starting' | 'updating' sessionsReviewing: number filesTouched: string [] turns: DreamTurn[] }
七、关键源文件索引
文件
职责
src/memdir/paths.ts
路径解析,优先级链
src/memdir/memdir.ts
提示词构建,MEMORY.md 截断
src/memdir/memoryScan.ts
扫描目录、解析 frontmatter
src/memdir/memoryTypes.ts
四种记忆类型定义
src/memdir/findRelevantMemories.ts
Sonnet 智能检索
src/services/extractMemories/
自动提取服务
src/services/teamMemorySync/
团队记忆同步
src/services/autoDream/
AutoDream 后台整合
src/utils/frontmatterParser.ts
YAML frontmatter 解析
src/components/memory/
UI 组件
src/commands/memory/
/memory 命令
八、总结 Claude Code 的 Memory 系统体现了几个核心设计原则:
结构化知识 :四种记忆类型,避免信息混淆
自动提取 :后台智能分析对话,提取有价值信息
智能检索 :Sonnet 模型动态选择相关记忆
新鲜度管理 :旧记忆附带警告,使用前需验证
团队同步 :服务器优先语义,支持协作
AutoDream :后台”做梦”整理记忆
这个设计让 AI 真正能够”记住”用户,而不是每次都从零开始。
系列文章导航: