第一章:Claude Code 记忆系统——架构总览与四种记忆类型

系列说明:本系列基于 Claude Code CLI 真实源码,逐章深入剖析其记忆系统设计。本章涵盖:Agent 开发中记忆管理的核心挑战、五大子系统架构、四种记忆类型的语义设计与源码实现。


一、Agent 开发中,记忆管理为什么如此重要?

构建 AI Agent 时,开发者很快会遇到一个根本性问题:Agent 是无状态的

每次会话重新开始,Agent 不记得上一次交流发生了什么——用户说过的偏好、项目踩过的坑、已经确认的技术决策,全部归零。对于一次性任务,这无关紧要;但对于长期协作型 Agent,这是一个致命缺陷。

以 Claude Code 为例,作为一个陪伴开发者日常工作的编程助手,它需要跨会话记住:

类别 例子 如果遗忘的代价
用户画像 “这位开发者是 Go 老手,React 新手” 每次都用初学者视角解释,浪费时间
工作约束 “禁止在测试里 mock 数据库,上季度出过事故” 反复犯同一个错误,降低信任
项目背景 “这次重构是法务合规要求,不是技术债” 给出错误的优先级建议
外部资源 “Pipeline bug 追踪在 Linear 项目 INGEST” 每次都要重新询问资源位置

这类知识有一个共同特点:无法从代码库、Git 历史或文档中自动推导。它们属于人与 Agent 协作过程中沉淀的隐性上下文,必须被主动捕获、持久存储、按需召回

这正是 Agent 记忆管理要解决的核心问题。

1.1 Agent 记忆管理的三个核心挑战

挑战一:什么值得记?

并非所有信息都该进入记忆。代码结构可以 grep,变更历史可以 git log,项目规范写在 README 里——这些都不需要额外记忆。真正该记的是不可推导的上下文:用户的个人背景、协作中形成的约定、只活在对话里的项目决策。

过度记忆和遗忘一样危险——低密度的信息噪声会稀释真正重要的上下文。

挑战二:什么时候写入?

用户不会主动说"记住这个"。有价值的上下文往往在普通对话中自然流露——用户纠正了一个错误、随口提了项目背景、分享了技术偏好。Agent 需要能自动识别这类隐性知识并保存,而不依赖用户的主动指令。

挑战三:如何按需召回?

记忆库随时间积累会变得庞大。把所有记忆全部注入每次对话的上下文,token 消耗不可接受;完全不注入则形同虚设。Agent 需要在每次对话时智能判断哪些记忆与当前查询相关,只召回真正有用的部分。

1.2 Claude Code 的解答

Claude Code 用一套基于文件的持久记忆系统回答了上述三个挑战:

  • 写什么:定义四种严格类型(user/feedback/project/reference),明确排除可推导信息
  • 何时写:主代理主动写 + 后台抽取代理自动从对话中提取
  • 如何召回:用另一个 Sonnet 实例做语义相关性判断,按需注入最相关的记忆

这套设计的特点是:简单(Markdown 文件)、透明(人类可读、可 Git 管理)、智能(AI 辅助召回)。

接下来我们通过源码深入每个设计决策。


二、系统架构总览

记忆系统由五个子系统协同工作:

主动保存

用户对话

主代理 Main Agent

记忆写入?

自动记忆 memdir/

后台抽取代理 extractMemories/

CLAUDE.md 系统

会话记忆 SessionMemory/

代理记忆 AgentTool/agentMemory

~/.claude/projects//memory/

CLAUDE.md 四层文件

~/.claude/session-memory/.md

子系统 职责 生命周期
自动记忆 (memdir/) 跨会话的持久个人/团队记忆 永久保存
CLAUDE.md 系统 (utils/claudemd.ts) 静态项目/用户指令文件 手动维护
后台抽取代理 (services/extractMemories/) 对话结束后自动提取记忆 每轮对话结束触发
会话记忆 (services/SessionMemory/) 当前会话的实时滚动摘要 会话内有效
代理记忆 (tools/AgentTool/agentMemory.ts) 子代理的专属记忆空间 按 scope 决定

本章及后续章节重点聚焦自动记忆子系统,它是整个记忆架构的核心。


三、记忆类型系统:四种类型,闭合分类

3.1 类型定义

源文件:memdir/memoryTypes.ts

export const MEMORY_TYPES = [
  'user',
  'feedback',
  'project',
  'reference',
] as const

export type MemoryType = (typeof MEMORY_TYPES)[number]

这是一个 TypeScript const assertion 构成的闭合类型集合

注释里的设计意图很明确[^1]:

“Memories are constrained to four types capturing context NOT derivable from the current project state. Code patterns, architecture, git history, and file structure are derivable (via grep/git/CLAUDE.md) and should NOT be saved as memories.”

核心设计原则只保存无法从代码/Git 历史推导出来的信息

3.2 类型解析函数

export function parseMemoryType(raw: unknown): MemoryType | undefined {
  if (typeof raw !== 'string') return undefined
  return MEMORY_TYPES.find(t => t === raw)
}

这个函数处理了两种降级场景:

  • 遗留文件(没有 type: 字段)→ 返回 undefined,继续工作
  • 未知类型值→ 优雅降级,不抛错

3.3 四种类型详解

user — 用户画像记忆
属性
团队模式 scope 始终 private(个人信息不共享)
保存时机 了解到用户的角色、背景、偏好、知识
使用时机 工作应根据用户视角定制时

源码中的示例对话

user: I've been writing Go for ten years but this is my first time touching 
      the React side of this repo
assistant: [saves user memory: deep Go expertise, new to React and this 
           project's frontend — frame frontend explanations in terms of 
           backend analogues]
feedback — 工作方式指导
属性
团队模式 scope 默认 private;仅当是项目级约定时才 team
保存时机 用户纠正做法 确认了某种非显而易见的做法
使用时机 指导后续工作风格,避免重复犯错

重要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.”

正文结构要求

规则本身

**Why:** 用户给出的原因(通常是一次事故或强烈偏好)

**How to apply:** 何时/何处生效
project — 项目背景记忆
属性
团队模式 scope 强烈建议 team(所有贡献者都应知道)
保存时机 了解到谁在做什么、为什么、截止日期是什么
使用时机 理解请求背后的细节和约束

时间处理细节:保存时必须将相对日期转换为绝对日期——“下周四” → “2026-04-15”,否则记忆随时间推移会失去解释意义。

reference — 外部系统指针
属性
团队模式 scope 通常 team
保存时机 了解到外部资源(Linear、Grafana、Slack 等)的位置
使用时机 用户引用外部系统时

示例

user: check the Linear project "INGEST" if you want context on these tickets
assistant: [saves reference memory: pipeline bugs are tracked in Linear project "INGEST"]

四、什么不该保存?

源码专门定义了 WHAT_NOT_TO_SAVE_SECTIONmemdir/memoryTypes.ts),作为系统提示的一部分注入给模型。我们直接看源码:

// memdir/memoryTypes.ts 第 183-195 行

/**
 * `## What NOT to save in memory` section. Identical across both modes.
 */
export const WHAT_NOT_TO_SAVE_SECTION: readonly string[] = [
  '## What NOT to save in memory',
  '',
  '- Code patterns, conventions, architecture, file paths, or project structure — these can be derived by reading the current project state.',
  '- Git history, recent changes, or who-changed-what — `git log` / `git blame` are authoritative.',
  '- Debugging solutions or fix recipes — the fix is in the code; the commit message has the context.',
  '- Anything already documented in CLAUDE.md files.',
  '- Ephemeral task details: in-progress work, temporary state, current conversation context.',
  '',
  // H2: explicit-save gate. Eval-validated (memory-prompt-iteration case 3,
  // 0/2 → 3/3): prevents "save this week's PR list" → activity-log noise.
  'These exclusions apply even when the user explicitly asks you to save. 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.',
]

这个数组会被直接 join('\n') 拼入系统提示,最终模型收到的是这段文字:

## What NOT to save in memory

- Code patterns, conventions, architecture, file paths, or project structure — these can be derived by reading the current project state.
- Git history, recent changes, or who-changed-what — `git log` / `git blame` are authoritative.
- Debugging solutions or fix recipes — the fix is in the code; the commit message has the context.
- Anything already documented in CLAUDE.md files.
- Ephemeral task details: in-progress work, temporary state, current conversation context.

These exclusions apply even when the user explicitly asks you to save. 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.

注意源码中的注释 // H2: explicit-save gate. Eval-validated (memory-prompt-iteration case 3, 0/2 → 3/3)——这说明最后一句话是经过 eval 测试验证有效果的提示词改进:在加入这句之前,模型会无差别接受用户"保存 PR 列表"的指令(测试通过率 0/2),加入后通过率提升到 3/3。这是提示词工程中"小改动大效果"的典型案例。

即使用户主动要求保存 PR 列表这类活动日志,也应该追问"其中有什么出乎意料的内容?"——把值得长期记忆的部分提炼出来,而不是无差别存储。


五、陈旧记忆的处理

记忆会随时间变得不准确。源码在 memdir/memoryTypes.ts 定义了 TRUSTING_RECALL_SECTION,该段文字会被注入系统提示:

## Before recommending from memory

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.
- If the user is about to act on your recommendation, verify first.

"The memory says X exists" is not the same as "X exists now."

这段提示针对的是一个具体的失败模式:模型引用了记忆中的 file:line 行号,但代码早已改变,却因为引用看起来"有来源"而显得更权威——这反而比没有引用更危险。


六、章节小结

记忆类型

user

用户画像

始终 private

知识/角色/偏好

feedback

工作方式指导

正/负向均记录

含 Why/How to apply

project

项目背景

优先 team

绝对日期

reference

外部系统指针

通常 team

Linear/Grafana/Slack

设计决策 原因
闭合类型集合(4种) 防止记忆系统退化为无差别日志
不保存可推导信息 避免与代码/git 产生过期的冗余副本
feedback 记录成功案例 防止模型在已验证路径上过度谨慎
陈旧记忆需验证 防止"有来源的错误"比无来源更危险

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐