第一章:Claude Code 记忆系统——架构总览与四种记忆类型
本文深入解析了Agent开发中记忆管理的核心挑战与解决方案,重点介绍了Claude Code记忆系统的架构设计与四种记忆类型。文章指出Agent无状态的本质特性导致长期协作中的关键上下文丢失问题,提出了"只保存不可推导信息"的核心原则。系统通过五大子系统协同工作,包括自动记忆、CLAUDE.md文件、后台抽取代理等,并严格定义了user、feedback、project、ref
第一章:Agent 开发中的记忆管理——架构总览与四种记忆类型
第一章: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 辅助召回)。
接下来我们通过源码深入每个设计决策。
二、系统架构总览
记忆系统由五个子系统协同工作:
| 子系统 | 职责 | 生命周期 |
|---|---|---|
自动记忆 (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_SECTION(memdir/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 行号,但代码早已改变,却因为引用看起来"有来源"而显得更权威——这反而比没有引用更危险。
六、章节小结
| 设计决策 | 原因 |
|---|---|
| 闭合类型集合(4种) | 防止记忆系统退化为无差别日志 |
| 不保存可推导信息 | 避免与代码/git 产生过期的冗余副本 |
| feedback 记录成功案例 | 防止模型在已验证路径上过度谨慎 |
| 陈旧记忆需验证 | 防止"有来源的错误"比无来源更危险 |
更多推荐



所有评论(0)