所属专题簇:记忆与上下文算法深挖
建议前读:21. 记忆系统:CLAUDE.md、Session Memory 与 Agent Memory
建议后读:19. 上下文压缩与历史治理 或 16. 会话持久化与恢复机制
Claude Code 什么时候决定“该写 session memory 了”,以及它如何避免后台抽取把主会话搞乱?
Session Memory 不是随手记录,而是一套带阈值、停顿点判定和防重入控制的后台调度机制;它把“什么时候值得记”和“什么时候安全地记”分开处理。
这一章聚焦 SessionMemory 的调度算法、并发控制和运行时不变量,而不是只解释“它会生成一个 markdown 文件”。
- Session Memory 的触发有硬阈值,不是每轮都写。
- token 增长是硬前提,tool call 数和自然停顿点是协同条件。
- Claude Code 明确防止重复 extraction、超时卡死和会话推进期间的状态踩踏。
- 主调度逻辑:src/services/SessionMemory/sessionMemory.ts
- 阈值与状态工具:src/services/SessionMemory/sessionMemoryUtils.ts
- 更新 prompt:src/services/SessionMemory/prompts.ts
flowchart TD
A["新一轮 messages"] --> B["tokenCountWithEstimation"]
B --> C{"已初始化?"}
C -- 否 --> D{"达到 init token threshold?"}
D -- 否 --> Z["不抽取"]
D -- 是 --> E["markSessionMemoryInitialized"]
C -- 是 --> F{"达到 update token threshold?"}
E --> F
F -- 否 --> Z
F -- 是 --> G["count tool calls since last memory"]
G --> H{"tool call threshold 达标?"}
H -- 是 --> I["触发 extraction"]
H -- 否 --> J{"最后一轮无 tool calls?"}
J -- 否 --> Z
J -- 是 --> I
I --> K["markExtractionStarted"]
K --> L["forked subagent 更新 notes"]
L --> M["recordExtractionTokenCount / setLastSummarizedMessageId / markExtractionCompleted"]
src/services/SessionMemory/sessionMemory.ts 里的 shouldExtractMemory() 很清楚:
- 首先检查初始化阈值
minimumMessageTokensToInit - 初始化后,再检查更新阈值
minimumTokensBetweenUpdate - 然后再看从
lastMemoryMessageUuid以来的 tool call 数 - 最后结合“最后一轮 assistant turn 是否还有 tool calls”
也就是说,tool call 数不是独立触发器,token 增长阈值才是硬前提。
同一函数里还有一个非常重要的分支:
- 如果 token threshold 已满足
- 即使 tool call threshold 没达到
- 只要最后一轮没有 tool calls,也可以触发 extraction
这说明 Anthropic 希望在“自然停顿点”更新 session memory,而不是死等工具调用计数凑够。
src/services/SessionMemory/sessionMemoryUtils.ts 中有几组关键状态:
lastSummarizedMessageIdextractionStartedAttokensAtLastExtractionsessionMemoryInitialized
这已经不是单纯“跑一个后台任务”,而是明确的 extraction 状态机。
同一文件里 waitForSessionMemoryExtraction() 有两层保护:
- 最长等待
EXTRACTION_WAIT_TIMEOUT_MS = 15000 - 如果 extraction age 超过
EXTRACTION_STALE_THRESHOLD_MS = 60000,直接视为 stale,不再等待
这说明 Claude Code 已经预设了“后台 extraction 可能挂住或过久”,因此主会话不能无限阻塞。
src/services/SessionMemory/prompts.ts 强调:
- 只允许使用 Edit tool
- 保持既有 section/header 结构不变
- 当前状态必须始终更新
- 过长 section 和总 token 超预算时必须主动压缩
这说明 Session Memory 不是开放式笔记,而是受模板和预算约束的结构化笔记。
这一层至少有 4 个不变量:
- 不在 token 增长不足时频繁 extraction
- 不在最后一轮仍处于 tool call 中途时贸然 extraction
- 同一时刻最多有一个 extraction 被视为有效进行中
- extraction 不能无限阻塞主流程
如果没有这些限制,Session Memory 很容易退化成:
- 高频无意义抽取
- 在工具调用半途中记录不稳定状态
- 并发 background 任务互相覆盖 notes
- 主会话在等待 memory 任务时卡住
Claude Code 这一套门槛,就是在防这些失败模式。
- Session Memory 的难点不是“怎么写笔记”,而是“何时安全地写笔记”。
- Anthropic 把 token 增长、tool call 密度和自然停顿点组合成调度条件。
- 它还有显式的 stale timeout 和 extraction in-progress 管理,不是朴素后台任务。