章节导航 第 9 章 / 共 23 章
Context 管理与记忆系统
四种内存类型、三种运行模式、AI 智能检索、上下文压缩策略、会话恢复机制——Claude Code 如何管理有限的注意力
9.1 有限注意力的管理艺术
模型的上下文窗口是有限的。当前这一代模型(Opus、Sonnet 5、Fable 5.1)的窗口是 1M token——本章初稿沿用的 200K 已经过时,Fable 5.1 自 v2.1.257 起成为默认 Fable 模型,官方对它的描述是”1M context, 50 per Mtok with $0.25/Mtok cache reads”。即便如此,在一个长时间的编码会话中,消息历史、工具结果、文件内容仍然会把窗口填满。Context 管理的本质是在有限的注意力中放入最相关的信息。
⚠️ 数字更正说明:本章此前写”即使 Claude 支持 200K token 的上下文”。该数字对应的是更早一代模型。截至 2026-09(v2.1.267),官方 changelog 有三处独立佐证 1M 窗口:v2.1.247 把 Sonnet 5 的默认 auto-compact 窗口改为其完整 1M 上下文(约 967K 处压缩,此前约 934K);v2.1.257 新增 Fable 5.1 并注明 1M 上下文;v2.1.260 改进 1M 上下文模型的 auto-compact,称 Opus 与 Fable 会话改为在 1M 上限前不久压缩。另 v2.1.251 还修了一条”切换到 Opus 1M 以获得 5 倍上下文”的提示在模型本身已是 1M 时仍然出现的 bug。
世代已经再往前挪了一格。 上面的佐证链锚在 2026 年 9 月上旬那一代模型上;同一条 changelog 在 9 月下旬又换代两次:v2.1.280(2026-09-22)新增 Claude Opus 5.5(claude-opus-5-5)并使其成为默认 Opus 模型——1M 上下文、$4/$20 per Mtok、cache reads $0.20/Mtok;v2.1.284(2026-09-28)新增 Claude Sonnet 5.5(claude-sonnet-5-5)并使其成为 Anthropic API 上的默认 Sonnet 模型——同样是 1M 上下文、$2/$10 per Mtok。窗口大小没变,变的是这套数字所锚定的模型名:读者若按 Opus / Sonnet 5 去查定价页,会落到 5.5 之前的那张表。
窗口从 200K 到 1M 并没有让本章失效,而是改变了瓶颈的位置:对话历史不再是最先撑满窗口的部分,工具结果(9.6 节第 1 层,现可调至 128K 字符、落盘上限 1 GB)与工具定义(见下文 Workflow 案例)才是。这也解释了为什么 2026 年 8-9 月的优化集中在工具侧而非摘要侧——如果只盯对话历史,会误判下一阶段的优化方向。
但”窗口有多大”是模型 × 通道的函数,不只是模型名的函数(v2.1.285,2026-09-29)。 上面把 1M 当作当前这一代模型的既定事实,这条补的是反向限定。官方 changelog 逐字:
Changed sessions behind a custom
ANTHROPIC_BASE_URLto use the 1M context window of models that have one (Opus 4.7+, Sonnet 5+, Fable); run/autocompact 200kif your gateway stops at 200K
两层读法。其一,官方的措辞是 “Changed … to use”,即改之前,走自定义网关的会话并未取 1M——同一代模型、同一份代码,在不同通道上窗口可以不同。其二,官方给的兜底动作不是换模型,而是手动把 auto-compact 窗口下调到 200k(/autocompact 200k),这等于承认在网关场景下窗口可能确实只落在 200K。
所以上面那句”窗口从 200K 到 1M 改变了瓶颈的位置”要补一个前提:在你实际使用的通道上,这个 1M 确实成立。同理,9.6 那张口径对照表里的 967K,也是”某个模型在某个通道上的默认窗口”,而不是一个跨通道常量。(与 Ch00 阅读提醒第 8 条、6.10 节的通道限定同源。)
Claude Code 的 Context 管理分为三个层面:
- 短期记忆:当前会话的消息历史
- 中期记忆:CLAUDE.md 和项目配置(每次会话加载)
- 长期记忆:跨会话持久化的记忆文件(memory 目录)
9.2 四种内存类型
Claude Code 的记忆系统通过四种类型化记忆存储不同场景的信息,每种类型有明确的定义和使用规则:
| 类型 | 作用域 | 描述 | 保存时机 | 使用方式 |
|---|---|---|---|---|
| user | 始终私有 | 用户角色、目标、职责 | 了解用户详细信息时 | 根据用户画像定制回答 |
| feedback | 默认私有 | 工作方式指引(避免什么/保持什么) | 用户纠正或确认方法时 | 指导未来行为,避免重复 |
| project | 项目知识 | 当前工作、目标、事件 | 了解谁在做什么、为什么 | 理解请求背景 |
| reference | 通常团队 | 外部系统信息位置指针 | 了解外部资源及其用途时 | 引用外部系统时查找 |
每个记忆文件采用 Markdown 格式 + Frontmatter 元数据:
---
name: user_role
description: 用户是资深前端工程师,后端初学者
type: user
---
具体内容...
一个关键的设计决策:明确禁止保存可从代码推导的信息——代码模式、架构、文件路径、Git 历史、调试方案、CLAUDE.md 中已有内容。这避免了记忆系统变成项目状态的冗余副本。
源码引用:内存类型定义于 memoryTypes.ts,核心逻辑位于 memdir.ts。
9.3 三种运行模式
记忆系统支持三种运行模式,覆盖从个人到团队的不同场景:
| 模式 | 激活方式 | 存储位置 | 同步 | 适用场景 |
|---|---|---|---|---|
| Auto Memory | 默认启用 | ~/.claude/projects/<slug>/memory/ | 无 | 个人项目记忆 |
| TEAMMEM | Feature Flag + GitHub 仓库 | <autoMemPath>/team/ | 支持 | 团队协作共享 |
| KAIROS | Feature Flag + 助手模式 | <autoMemPath>/logs/YYYY/MM/ | 无 | 长期会话日志 |
Auto Memory 是基础模式——基于文件的行式内存系统,通过 MEMORY.md 索引文件组织记忆。
⚠️ “默认启用”有边界,而且这个边界是不对称的(v2.1.285,2026-09-29)。 官方 changelog 逐字:“Changed /memory so that Auto-memory can no longer be turned on from a background session or from a session one of Claude Code’s own tools started; turning it off there still works”。即:在后台会话里、或在由 Claude Code 自己的工具启动的会话里,Auto-memory 不能开启,但可以关闭。上表”默认启用”描述的是前台会话的默认状态,不是一个在任何上下文里都能双向切换的开关。这与第 8 章”后台与并发路径上的可靠性事实”是同一条线——后台路径上的能力集与前台并不相同,凡是把某个能力当作无条件的默认值的表述,都要先问它在哪条路径上成立。
TEAMMEM 在 Auto Memory 基础上增加团队目录,支持跨成员记忆同步。同步采用 ETag 乐观锁 避免冲突:
- 推送前检查内容哈希
- 只上传内容变化的文件(增量上传)
- 遇到 412 冲突时刷新服务器校验和并重试(最多 2 次)
- 上传前自动扫描敏感信息(使用 Gitleaks 规则)
KAIROS 是最有趣的模式——仅追加的每日日志范式。日志按日期组织(logs/YYYY/MM/YYYY-MM-DD.md),不重写、不重组。夜间进程将日志蒸馏为 MEMORY.md 和主题文件。KAIROS 还集成了 BriefTool(快速速记)和 PushNotificationTool(推送通知)。
三者的优先级关系:KAIROS > TEAMMEM > Auto Memory。KAIROS 和 TEAMMEM 互斥。
源码引用:三种模式的实现参见 memdir.ts#L327-370,KAIROS 路径管理参见 paths.ts#L246-251,团队同步参见 teamMemorySync/index.ts。
9.4 AutoDream:后台记忆整合机制
2026 年引入的 AutoDream(内部代号 “Dream: Memory Consolidation”)是 Claude Code 的后台记忆整合系统,模拟人类 REM 睡眠的记忆巩固过程。
核心概念与触发条件
AutoDream 在以下条件满足时自动触发:
- 时间触发:每 24 小时(防止过于频繁的整合)
- 会话阈值:5+ 次有效会话后(确保有足够的新记忆)
- 后台执行:用户不活跃时自动启动,不干扰当前工作
四阶段整合流程
扫描阶段
├── 递归扫描所有记忆文件(memory/ 目录)
├── 按修改时间排序,识别新记忆
└── 统计各类记忆的数量和大小
↓
去重阶段
├── 语义相似度检测(避免重复内容)
├── 时间窗口合并(同一主题的连续记忆)
└── 冲突解决(相同键的不同值)
↓
蒸馏阶段
├── 用 Claude 模型生成结构化摘要
├── 写入 MEMORY.md 索引文件
└── 创建主题文件(topic_*.md)
↓
清理阶段
├── 删除过时条目(超过保留期限)
├── 压缩历史文件(减少存储占用)
└── 更新元数据统计
与 KAIROS 的关系
AutoDream 和 KAIROS 都是记忆整合机制,但定位不同:
- AutoDream:Auto Memory 模式下的默认机制,自动化程度高
- KAIROS:需要显式启用的高级模式,提供更精细的控制
AutoDream 实现了”仅追加 + 定期蒸馏”范式的自动化,将记忆维护从手动操作变为系统级服务。
源码引用:AutoDream 实现参见 autoDream.ts,记忆整合策略参见 memoryConsolidation.ts。
9.4.1 开源方案对比:TencentDB Agent Memory
腾讯云开源的 TencentDB Agent Memory 提供了与 Claude Code 三模式截然不同的记忆架构,核心特性包括:
- Context Offloading:将不活跃上下文卸载到外部存储(TencentDB),按需加载,而非 Claude Code 的文件系统存储
- Mermaid Task Canvas:用 Mermaid 图表可视化任务执行进度和依赖关系,Claude Code 目前没有等价的记忆可视化方案
- 多级缓存:热/温/冷三级上下文缓存策略,基于访问频率自动迁移
| 维度 | Claude Code 三模式 | TencentDB Agent Memory |
|---|---|---|
| 存储方式 | 文件系统(Markdown 文件) | 外部数据库(TencentDB) |
| 加载策略 | AI 驱动相关性检索(前 200 文件) | 三级缓存 + 按需加载 |
| 可视化 | 无(纯文本索引 MEMORY.md) | Mermaid Task Canvas 图表 |
| 上下文卸载 | KAIROS 仅追加日志 + 蒸馏 | 主动卸载不活跃上下文到外部存储 |
| 团队协作 | TEAMMEM + GitHub 同步 | 数据库级共享 |
| 记忆类型 | 四类型化(user/feedback/project/reference) | 按温度分级(热/温/冷) |
两种方案的设计哲学差异显著:Claude Code 选择文件系统 + AI 检索——对开发者透明,可用 git 追踪,但受限于文件系统的查询能力;TencentDB 选择数据库 + 缓存——查询灵活,支持可视化,但引入了外部依赖。Mermaid Task Canvas 是值得关注的创新——它将记忆从”可搜索的文本”升级为”可导航的图谱”,解决了 Agent 记忆的可解释性问题。
9.6 CLAUDE.md:项目的自我描述
CLAUDE.md 是 Claude Code 的一个独特设计——它是一个放在项目根目录的 Markdown 文件,告诉 Claude Code 关于这个项目的一切:编码规范、架构约定、常用命令、禁忌事项。
它的作用类似于人类新成员入职时阅读的”项目 Wiki”,但格式针对 AI 优化——简洁、结构化、可操作。
getClaudeMds 函数负责把多源记忆文件组装成上下文字符串。它根据文件类型生成不同的语义描述:
// getClaudeMds 的语义标签生成(简化)
const description =
file.type === 'Project'
? ' (project instructions, checked into the codebase)'
: file.type === 'Local'
? " (user's private project instructions, not checked in)"
: file.type === 'TeamMem'
? ' (shared team memory, synced across the organization)'
: file.type === 'AutoMem'
? " (user's auto-memory, persists across conversations)"
: " (user's private global instructions for all projects)";
TEAMMEM 类型的记忆还被包裹在 XML 标签 <team-memory-content source="shared"> 中——这给模型一个明确的信号:这些内容来自团队共享,而不是用户个人设置。
CLAUDE.md 的加载策略值得注意:
- Plan Agent 设置了
omitClaudeMd: true——不预加载,需要时自己 FileRead - 其他代理默认加载
- SDK 模式下可以通过环境变量覆盖加载路径
- 入口点文件有截断限制:最多 200 行 / 25,000 字节
源码引用:CLAUDE.md 加载逻辑参见 claudemd.ts。
9.5 AI 智能记忆检索
当记忆文件数量增多后,不能把所有记忆都塞进上下文。Claude Code 使用 AI 驱动的相关性检索 来选择最相关的记忆:
findRelevantMemories(query)
├── scanMemoryFiles()
│ ├── 递归读取 memory/ 下所有 .md 文件(排除 MEMORY.md)
│ ├── 并行读取每个文件前 30 行(解析 Frontmatter)
│ ├── 按修改时间倒序排序
│ └── 返回前 200 个文件头信息
│
├── 过滤已处理的文件(alreadySurfaced 集合)
│
└── selectRelevantMemories()
├── 使用 Sonnet 模型评估相关性
├── 最多返回 5 个相关文件
└── 遵循选择规则:
- 只选明确有用的,不确定不选
- 避免关键词误判
- 排除最近用过的工具文档(减少噪音)
- 允许返回空列表
两个关键限制保证了性能:
| 限制 | 值 | 作用 |
|---|---|---|
MAX_MEMORY_FILES | 200 | 最大扫描文件数 |
FRONTMATTER_MAX_LINES | 30 | 每个文件读取的行数上限 |
上面两个数字都出在检索侧。加载侧另有一个与 MAX_MEMORY_FILES 同名不同义的 200:MEMORY.md 的前 200 行,或前 25KB,先到为准会在每次对话开始时加载,超出部分不加载;写入后 Claude Code 会按这两个限制度量该文件,接近上限时提醒缩短,超限时写入仍然成功,但会返回错误要求重写索引——因为超出部分在下次加载时会被丢掉。⚠️ 两个”200”必须分清:MAX_MEMORY_FILES=200 是文件数,MEMORY.md 的 200 是行数,而 25KB 是与行数并列的第二个上限、按先到者触发。
扫描策略的一个优化细节:readFileInRange 内部执行 stat 操作获取修改时间,避免了先 stat 再读取的二次系统调用。
源码引用:记忆扫描参见 memoryScan.ts,智能检索参见 findRelevantMemories.ts。
9.6 上下文压缩:五层级联管线
Claude Code 的上下文压缩不是单一机制,而是五层级联管线,每层有不同的触发条件和处理策略。在深入实现细节之前,先引入 Context-ReAct 论文提出的上下文管理五原子操作,为实践提供理论框架:
| 原子操作 | 语义 | Claude Code 五层管线映射 |
|---|---|---|
| Skip | 跳过不相关上下文 | Tool Result Budget(预算过滤无关工具结果) |
| Compress | 压缩冗余上下文 | Reactive/Forced compact(摘要生成) |
| Rollback | 回滚到之前的上下文状态 | ❌ 未实现——当前管线不可逆 |
| Snippet | 提取关键片段 | Snip(截断保留首尾) |
| Delete | 删除过期上下文 | Micro-compact(移除最旧消息) |
值得注意的是 Rollback 操作的缺失。Claude Code 的五层管线是单向的——压缩一旦执行,原始上下文无法恢复。PreCompact Hook 允许用户在压缩前保存关键信息(见下方),但这不是真正的回滚——它只是将信息转移到外部存储,而非恢复对话历史的原始状态。这一缺失是否是设计缺陷?在大多数场景下,单向压缩足够:如果压缩导致信息丢失,Agent 可以通过重新读取文件恢复。但在复杂调试场景中,压缩前的中间推理链可能无法重建——此时 Rollback 能力可能是有价值的。
📌 辨析:
/rewind不是上下文 Rollback。Claude Code 确实提供了/rewind与--rewind-files,但它们恢复的是磁盘上的文件内容(检查点备份),不是对话历史。两者名字相近而对象不同:Rollback 回滚的是”模型看到了什么”,/rewind回滚的是”文件变成了什么”。把/rewind当作上表 Rollback 行的实现证据是典型的”机制对但描述错”——上下文级回滚仍然缺失。顺带一提,v2.1.260 修了
/rewind自身的两个问题:检查点备份文件缺失时仍报成功,以及/rewind会残留被回退轮次的文件读取跟踪(导致「File unchanged since last read」桩与外部编辑后整文件重新注入)。这类 bug 说明文件级检查点本身也有状态一致性问题,与上下文管理是两套独立机制。
Tool Result Budget(工具结果预算)
├── 限制单个工具结果的大小(防止一个工具占用过多 Token)
├── 触发条件:工具结果超过预设阈值
├── 处理策略:截断或摘要
├── 【可调】v2.1.261 起 bashOutputMaxChars / taskOutputMaxChars 可上调至 128K 字符;
│ 超出部分落盘,v2.1.265 起落盘结果有 1 GB 上限,会话内预览会说明文件被截断
↓
Micro-compact(微压缩)
├── 小规模上下文修剪(不需要完整摘要)
├── 触发条件:Token 接近但未到临界值
├── 处理策略:移除最旧的 10-20% 消息
↓
Snip(截断)
├── 截断过长的工具结果(保持核心信息)
├── 触发条件:单个工具结果过长
├── 处理策略:保留开头和结尾,截断中间部分
↓
Reactive compact(响应式压缩)
├── 接近限制时触发摘要生成
├── 触发条件:Token 用量达到 80% 限制
├── 处理策略:生成对话历史摘要,插入 compact_boundary
↓
Forced compact(强制压缩)
├── 硬限制强制压缩
├── 触发条件:Token 用量达到 95% 限制
├── 处理策略:激进压缩,可能丢失部分上下文
第 1 层是五层里唯一用户可直接调节的一层。其余四层的阈值由实现决定,只有 Tool Result Budget 暴露了参数:v2.1.261 新增 bashOutputMaxChars 与 taskOutputMaxChars,控制命令与后台任务输出在内联返回给 Claude 之前的字符上限,可上调至 128K 字符,超出部分改为存文件;v2.1.265 又给落盘的工具结果加了 1 GB 上限,且会话内预览会说明文件被截断过。这也意味着”工具结果多大算大”在 2026 年 9 月之后是一个可配置项,而不是固定常数。
一个必须避开的口径混淆。官方 changelog 给出的 auto-compact 数字与上面管线里的 80% / 95% 不是同一件事:
| 数字 | 出处 | 含义 |
|---|---|---|
| 约 967K(此前约 934K) | v2.1.247 | Sonnet 5 的 auto-compact 窗口:改为完整 1M 上下文后,1M 窗口上的会话在此处自动压缩 |
| ”在 1M 上限前不久” | v2.1.260 | Opus 与 Fable 的 1M 上下文会话的 auto-compact 行为;超大上下文的 recovery compaction 不再在 10 分钟处超时 |
| 80% / 95% | 本书 9.6 | 响应式压缩 / 强制压缩的触发阈值 |
967K/1M 约等于 96.7%,与本书的 95% 数值接近但口径不同:前者是模型上下文窗口意义上的触发点,后者是管线内部的阈值比例。读者若把 967K 直接当成”95% 阈值 = 967K”,在 200K 窗口下会算出完全错误的绝对值。建议把 80% / 95% 理解为按剩余余量表述的相对阈值,不与官方 auto-compact 绝对值互相换算。
第三个维度:那两个官方数字都不是会话级常量(v2.1.288 / v2.1.296)。 上表是按口径把 967K 与 80%/95% 分开;2026 年 10 月的两条再按执行单元拆了一层:
- 按模型保存(v2.1.288,2026-10-02):官方 changelog 逐字 “Changed
/autocompactto save the auto-compact window per model, so each model keeps its own setting when you switch”——切换模型时,每个模型各自保留自己的设置。 - 按节点覆盖(v2.1.296,2026-10-09):
autoCompactWindow进入子代理 frontmatter 与--agents定义,“so a subagent can auto-compact earlier than the main conversation’s window”——子代理可以比主会话更早压缩。
因此 967K 的准确身份是”某个模型上的默认窗口”,而不是”这个会话的压缩点”;同一棵会话树里,主会话与子代理可以在不同的点压缩。⚠️ 它与 6.2 节的 promptCacheTtl / subagentPromptCacheTtl(v2.1.243)属于同一条”按执行单元细分”的线,但缓存 TTL 与压缩窗口是两个不同的旋钮,改一个不等于改另一个,不要互相换算。(与 4.6 节”阈值不再是’一个会话一个数’,而是二维的”同源。)
2026 年 9 月下旬到 10 月中旬共有四条新行为,形态上都不在这五层之内。 五层是”逐层加深”,下面四条是另外四种形态——前三条出自 9 月,第四条出自 10 月中旬,且性质与前三条差别最大,故在三条之后单独展开:
- 递归重入(v2.1.284):修掉了”压缩之后仍然报 Prompt is too long”。压完的请求若仍超长,Claude Code 会再压一轮,并保留更少的近期对话。这不是第六层,而是同一条管线跑第二遍——五层模型里没有”压两次”这个位置。
- 压缩自己也会失败(v2.1.282):摘要请求被拒时压缩会失败;现在改为在回退模型上重试。它把压缩从一个必然成功的步骤,变成一个有失败路径、需要兜底的步骤。
- 触发阈值本身会算错(v2.1.273):context meter 与 auto-compact 把 advisor-tool turns 按约两倍真实上下文体积计数,导致 auto-compact 在真实窗口约一半处就触发。
第三条值得单独说一句:它把上面那张口径对照表又拆成了两个此前混在一起的问题——阈值定在多少与阈值算得对不对。本章此前默认计量是准的、只需讨论取值;v2.1.273 说明计量本身也可能是 bug 的来源,而这类 bug 的表现是”压缩来得莫名其妙地早”。
-
空闲压缩(v2.1.299,2026-10-14):终端里一个 200K+ token 的会话空闲约 54 分钟后被压缩,赶在它一小时 prompt cache 过期之前,使下一条消息不必把整段会话重新处理一遍。官方 changelog 逐字:
Added idle compaction in the terminal: a 200K+ token conversation left idle for about 54 minutes is compacted before its one-hour prompt cache expires, so your next message doesn’t reprocess it all
Added
CLAUDE_CODE_IDLE_COMPACT_MIN_TOKENSto change idle compaction’s 200K-token minimum;"idleCompaction": falsein settings.json turns it off. Both need v2.1.290 or later可调两项:
CLAUDE_CODE_IDLE_COMPACT_MIN_TOKENS改 200K 门槛;settings.json里"idleCompaction": false关闭(官方注明两项都需 v2.1.290 或之后)。v2.1.302(2026-10-16) 起/config新增 Idle compaction 行,且空闲压缩后的提示会说明怎么关掉它。
第四条与前三条的区别,比前三条之间的区别更大,有两点必须分开记:
- 触发条件不是 token 用量,是空闲时长——五层管线的”触发条件”一栏至此全部是 token 维度,这是第一条例外。
- 动机不是”上下文快满了”,是”缓存快过期了”——压缩第一次被用来保住缓存(让下一条消息不必重新处理整段会话),而不是释放窗口。
由此得到一条本章此前没有的读法:看到”压缩发生了”,不能默认推断”上下文不够了”,也可能是”缓存要过期了”。这与 9.9 的 TokenPilot 论点(“前缀稳定性 > 单次压缩量”)动机同源但方向相反——TokenPilot 说的是”别让前缀变”,空闲压缩说的是”赶在缓存失效前主动压掉”。
⚠️ 两条官方未说明,写入时不推广:① 54 分钟是否随 promptCacheTtl 变化(官方只写在”1 小时 cache”语境下,本书按默认 1 小时 TTL 下的取值理解,不推广到改过 TTL 的配置);② “Both need v2.1.290 or later” 是指这两个开关从该版本起可用,还是指空闲压缩功能本身自该版本就在(v2.1.299 才公告)——两种读法对本书记述的影响不同。(与 4.6 节”第六个触发源:空闲压缩”同源,两处表述一致。)
还有一个本节此前从未问过的问题:压缩由谁执行(v2.1.301,2026-10-15)。 本节讲触发与策略,9.7 讲恢复流程,两者都默认”压缩由当前会话的模型执行”。官方 changelog 逐字:
Improved switching to a model with a smaller context window: a conversation too long for the new model is now summarized by the previous model first
切换到上下文窗口更小的模型时,过长的对话会先由切换前的那个模型总结一遍。三点:
- 这是本节第四种触发源(前三种:token 阈值、空闲时长、递归重入),而它的触发源是用户操作——换模型。
- 它第一次让”执行压缩的模型”与”之后运行会话的模型”不是同一个。本章此前默认二者同一,这条说明压缩是有执行者选择的独立模型调用。
- ⚠️ 官方未说明这次摘要是否走
PreCompacthook、是否留下compact_boundary、是否计入/cost,不得推断。
把它与上面第四条并读,可以得到一个更一般的结论:压缩不是一个事件,而是一次有触发源、有执行者、有目的的调用。触发源至少有四种(容量、空闲、用户操作、递归重入),执行者在换模型场景下与会话模型分离,目的在空闲压缩场景下是保缓存而非腾空间。(与 6.4 节”切换模型的第二重后果”、4.6 节”第三个触发源:容量收缩”同源,三处表述一致。)
PreCompact Hook:用户干预压缩过程
系统支持 PreCompact Hook,允许用户在压缩触发前注入自定义逻辑:
// 用户可注册的钩子示例
registerPreCompactHook((messages) => {
// 在压缩前自动保存关键上下文到 CLAUDE.md
saveCriticalContextToClaudeMd(messages);
// 或将重要对话片段写入外部存储
exportImportantConversations(messages);
return messages; // 返回修改后的消息数组
});
压缩后的技能恢复策略
压缩完成后,系统采用智能恢复策略:
- POST_COMPACT_MAX_FILES_TO_RESTORE=5:最多重新加载 5 个关键文件
- 不重新注入 skill_listing:节省约 4K tokens(避免重复加载技能列表)
- 保持工具状态:已加载的工具保持可用状态
“不重新注入 skill_listing”是本书唯一一处量化 skill 上下文成本的地方,而它只在压缩时发生一次。v2.1.261 新增的 /skill-doctor 把这变成常态能力:它显示哪些已加载的 skill 从未被使用、以及它们各自占用多少上下文,用于裁剪。方向正好相反——不是省,而是查谁在浪费。
同一问题的另一个实例是工具定义。v2.1.248 把 Workflow 工具的提示占用从约 5.7K token 降到约 1K(降幅 82%),手法是把脚本编写参考移到 bundled 的 workflow-authoring skill。这与第 10 章 10.3.1 节”MCP Tool Search 懒加载”(工具定义 134K→5K)是同一个模式:把静态参考文档从常驻的提示前缀里拆出去,改成按需加载。9.6 节的五层管线处理的是对话历史的膨胀,而这两例说明上下文还有相当一部分来自工具与技能的定义本身。
附带一条观测成本的变化:v2.1.261 起 /context 的 token 计数在 token-counting API 不可用时改用本地估算,不再额外发小模型请求——这也从侧面说明”量一下上下文有多大”本身曾经是有成本的。
源码引用:五层压缩管线参见 compactPipeline.ts,PreCompact Hook 参见 preCompactHooks.ts。
压缩策略谱系:摘要 vs 不透明压缩 vs 逐字压缩
Claude Code 的五层级联管线本质上属于逐字压缩(Verbatim Compaction)范式——保留原始文本,仅删除冗余部分。2026 年 MorphLLM 发布的基准测试将 AI Agent 上下文管理策略划分为三种范式,并提供了量化对比:
| 策略 | 机制 | 优点 | 缺点 | 实测影响 |
|---|---|---|---|---|
| LLM Summarization | 用 LLM 生成对话摘要替代原文 | 语义保留较好,压缩比高 | 丢失细节,不可审计 | JetBrains 数据:导致 13-15% 更长的 Agent 轨迹(摘要丢失细节 → Agent 需重新获取信息) |
| Opaque Compression | 外部模型压缩 Token | 节省空间,对 Agent 透明 | 不可审计,压缩质量不可控 | 压缩质量依赖外部模型能力 |
| Verbatim Compaction | 保留原始文本,仅删除冗余 | 可审计,信息损失最小 | 压缩比受限 | MorphLLM 推荐,Factory.ai/JetBrains 验证 |
| RL-based Compaction | 训练阶段联合优化任务执行+压缩生成 | 模型学会在压缩后仍能完成任务,非推理时猜测 | 需要训练基础设施,无法用于 API-only 部署 | CompactionRL: SWE-bench Verified +7.0pp, Terminal-Bench 2.0 +3.1pp(2026-07,GLM-4.5-Air/4.7-Flash) |
Claude Code 选择逐字压缩的工程合理性在于:编码 Agent 对上下文细节高度敏感——一个变量名、一行错误日志的丢失可能导致完全不同的代码修改行为。摘要策略的 13-15% 轨迹延长在编码场景中可能意味着额外的文件读取、错误尝试和用户纠正,综合成本远超压缩节省的 Token。同时,逐字压缩保持了可审计性——用户和开发者可以追溯压缩后的文本到原始对话,这对信任建立至关重要。
逐字保留 vs 模型摘要,第一次有了轻量模型上的对照实验(transparent-compact,arXiv:2610.20116)。 上表给 Verbatim Compaction 的”实测影响”栏写的是”MorphLLM 推荐,Factory.ai/JetBrains 验证”,支撑它的负面数据(LLM Summarization 导致 13-15% 轨迹延长)出自 JetBrains——两者不是同一组实验。2026 年 10 月出现了一项把它们做成直接对照的工作:Maximising Transparency in Context Compaction Improves Retention of Facts and Commitments for Lightweight Coding Agents(Felix Woolford,[v1] 2026-10-14,单一作者预印本),为开源 Pi 编码 agent 设计了确定性压缩方法 transparent-compact:保证上下文中的用户与助手散文不被模型或算法改动,并显式标注哪些地方被裁掉了。对照是 Pi 默认的模型摘要压缩,以及 pi-vcc(手法相近但不逐字保留散文);基准跑在四个不同性能水平的模型上,重点放在本地消费级硬件能跑的轻量模型(重点是 Qwen3.8-27B)。
结果:在承诺(用户设定、只存在于对话中的规则)与事实回忆两类探针上持平或优于两个对照;优势集中在避免”自信的瞎编”——把没回忆起来的信息当成已知断言出去。即便用前沿模型,优势仍在但更小。
它把上面那段论证推进了一格:此前”编码 Agent 对上下文细节敏感”只是一条场景论证,这条给出了随模型能力变化的梯度——轻量模型没有余力去”绕过压缩丢掉的东西”,因此逐字保留的收益随模型变弱而变大。⚠️ 限定:单一作者预印本,未同行评议,benchmark 为自建探针集;不得与本章已有的 JetBrains 13-15% 混为同一出处。
第三个衡量维度:压完之后,哪些条目可信(SJC,arXiv:2610.20927)。 上表比较的是压缩率与信息损失,9.6.3 的预印本问的是”何时压缩 / 压缩成什么”。还有一个维度此前没人量:留下来的这段里,哪些是事实、哪些是压缩器自己写的推理。
Prune the Summary, Not the History: Source-Judged Compaction for Long-Horizon Agents(Guanghui Min、Chen Chen,[v1] 2026-10-14)的核心观察是:压缩提示会要求”决策与下一步”,于是每份摘要都混入了两类内容——环境确立的事实,与压缩器自己写的推理;此后 agent 无法区分二者。对一个广泛使用的一文中结构化压缩器的分析显示,83% 的失败运行可追溯到某个执行具体摘要条目的动作,而这些条目多数没有环境输出支持。
方案 SJC 是一个免训练的后处理步骤:逐条给摘要条目打”是否在环境输出或上一份摘要中有来源”的分,剔除无源条目;既不改 agent 也不改压缩器,每次压缩只多一次廉价的判定请求。判定器 Jev 是非生成式决策模型,用校准概率而非文本回答”有没有来源”。在 AppWorld 与 OfficeBench、两个 agent 模型上,跨运行可靠性比底层压缩器提升 2.1%–8.9%,且不增加 agent 的 token 用量。
与本章的接口:9.6 已有”Rollback 缺失”(原始上下文回不来)与”逐字压缩可审计”两条,SJC 补的是第三条——冗余不等于可信。这给 9.9 那句”宁可保留更多冗余信息也不破坏前缀”加了一个此前没有的反对理由:摘要里的推理性条目本身就是污染源,保留更多文本并不必然减少幻觉,区分”来自环境”与”来自压缩器”是另一件独立的工作。
⚠️ 两处限定:预印本未同行评议;83% 的分母是失败运行数——论文逐字写的是 “83% of failed runs trace back to an action that carries out a specific summary entry”,不得写成”83% 的运行失败”。
Attention Matching:基于注意力模式的 KV Cache 压缩
2026 年 MIT 发表的 Attention Matching 论文提供了另一种压缩思路——不修改对话文本,而是压缩 KV Cache 本身。核心方法:
- Attention Pattern 分析:追踪模型对每对 KV 向量的注意力权重分布
- 关键 Token 识别:保留高注意力权重的 KV 对,淘汰低权重的
- 50x 压缩:在几乎无损的前提下实现 50 倍 KV Cache 压缩
这与 MorphLLM 三种策略的本质区别在于:
| 压缩方法 | 压缩对象 | 信息损失 | 压缩比 | 可审计性 |
|---|---|---|---|---|
| LLM Summarization | 对话文本 | 高(语义摘要替代原文) | 高 | 低(摘要不可逆) |
| Verbatim Compaction | 对话文本 | 低(仅删减冗余) | 中 | 高(可追溯原文) |
| Attention Matching | KV Cache | 极低(保留高注意力 Token) | 50x | 中(Token 级可解释) |
Attention Matching 的 50x 压缩比远超文本级压缩的效果上限,且信息损失极低——因为它直接利用了模型自身的注意力模式来判断哪些 Token 对当前推理最重要。这暗示了一种可能性:Claude Code 的五层级联管线(文本级压缩)未来可能受益于在 KV Cache 层面进行二级压缩——文本级压缩处理用户可感知的上下文管理,KV Cache 级压缩处理模型内部的注意力优化。
Focus Agent:注意力引导的主动上下文选择
Focus Agent 论文提供了另一种主动压缩思路——不压缩已有上下文,而是在 Agent 循环中动态过滤不相关上下文:
- 训练一个轻量级 focus classifier,判断每段上下文与当前任务的相关性
- 在每轮 Agent 循环开始时,用 classifier 评估所有上下文段的相关性
- 过滤掉低相关性的上下文段,仅保留高相关性的进入模型
Focus Agent 实测实现 22.7% token 削减,与 Claude Code 的 Active Context Compression(arXiv 2601.07190)形成互补:
| 维度 | Active Context Compression | Focus Agent |
|---|---|---|
| 压缩时机 | 上下文溢出时被动压缩 | 每轮循环主动过滤 |
| 决策主体 | LLM 自主决定压缩策略 | 独立 classifier 判断相关性 |
| 信息损失 | 可能丢失(摘要/截断) | 低(仅过滤不相关段) |
| 额外开销 | 无(LLM 自身完成) | classifier 推理开销 |
| 工程可行性 | 已在 Claude Code 实现 | 需额外训练 classifier |
Focus Agent 的工程可行性在于 classifier 的轻量级——不需要完整 LLM,一个小型分类模型即可。但引入额外模型的维护成本和延迟是否值得 22.7% 的 token 削减,取决于使用场景的 token 成本敏感度。
9.6.1 CompressKV:语义检索头驱动的极致压缩
Attention Matching 的 50x 压缩比已经是 KV Cache 层面的优秀结果,但 2026 年 6 月的 CompressKV 将这一思路推到了更极致的边界:
| 维度 | Attention Matching | CompressKV |
|---|---|---|
| 压缩比 | 50x | ~33x(3% KV 守住 97% 性能) |
| 决策信号 | 整体注意力权重 | Semantic Retrieval Heads(专门负责语义检索的 attention head) |
| LongBench QA 性能 | 接近完整 | 97%(仅 3% KV) |
| Needle-in-a-Haystack | — | 90% 准确率(0.7% 容量) |
CompressKV 的关键洞察是:Transformer 的不同 attention head 分工不均——存在专门的”语义检索头”(Semantic Retrieval Heads),其 attention score 能精准定位上下文中对当前生成任务有价值的关键 Token。仅用这几组 head 的 score 决定保留策略,就能实现比整体注意力模式更精准的压缩。
同期工作:STAR-KV 和 R-KV 从不同路径探索 KV Cache 压缩上界——STAR-KV 关注时空局部性,R-KV 关注鲁棒性。三者构成 2026 年 KV Cache 压缩的三条竞争路径。
工程落地的两大瓶颈
CompressKV/Attention Matching 类方法在算法层面已足够优秀,但尚未在 Claude Code 等生产 Agent 中部署——瓶颈从”算法效果”转移到了工程落地:
- FlashAttention 内核不暴露 attention score。FlashAttention 出于性能考虑将 attention 计算融合在 GPU kernel 内部,外部代码无法读取中间 attention 分数。CompressKV 的决策依赖 score 访问——要么修改推理引擎(破坏 FlashAttention 的性能优势),要么用慢速的非融合实现(损失 2-3 倍速度)。
- Paged Attention 的 block 粒度导致内存碎片。vLLM 的 Paged Attention 将 KV Cache 切分为固定大小的 block(如 16 tokens/block),按需分配。CompressKV 选出的”高注意力 Token”在物理上不连续——eviction 释放单个 token 后,整个 block 不能归还给内存池,实际可释放的内存远低于理论压缩比。paged attention 的 block 粒度与细粒度 Token 选择是根本性的工程不匹配。
这两大瓶颈解释了为什么 KV Cache 压缩算法论文数量快速增长(2026 H1 仅 CompressKV/STAR-KV/R-KV 三篇同期工作),但生产部署案例稀少。Claude Code 当前采用 Anthropic API 内置的 Prompt Caching(应用层前缀缓存)而非 Token 级 KV Cache 压缩——因为 Prompt Caching 不需要修改推理引擎,是当前 API 抽象层下唯一可行的”开发者可控”优化点。
三层 KV Cache 优化栈
yage.ai 在 2026-06 的研究提出,KV Cache 优化应被视为一个三层栈:
| 层级 | 创新方向 | 当前状态 | Claude Code 应用 |
|---|---|---|---|
| 压缩层 | CompressKV/STAR-KV/R-KV 等算法 | 学术前沿,部署门槛高 | ❌ 未部署 |
| 路由层 | 多副本部署 + 负载均衡优化 | 工业成熟 | ✅ 多副本部署 |
| API 层 | Prompt Caching | 工业成熟 | ✅ 已实现(核心优化点) |
核心论点:压缩算法已足够好,当前瓶颈在”工程落地”和”API 抽象”。Claude Code 的 Prompt Caching 在这个三层栈中处于最末层——它是开发者唯一直接可控的层,但优化空间被 API 抽象层限制。未来的 KV Cache 优化突破将依赖推理引擎的 API 演进(如 FlashAttention 暴露 score 接口、paged attention 支持细粒度 eviction),而非单纯的算法创新。
第三条路径:区域感知淘汰。MemDecay(arXiv:2607.10582,2026-07-12)发现,不同语义区域的 token 注意力半衰期相差一个数量级——system token 半衰期 148-189 步,scratchpad token 仅 14-16 步。这提供了一种绕过 FlashAttention score 访问限制的思路——不依赖单个 token 的 attention score,而是利用 token 所属的语义区域(system prompt / tool output / reasoning / scratchpad)作为淘汰决策的代理信号。Claude Code 的静态/动态分离(6.2 节)天然为此提供了区域标注——静态段 token 应获得最低衰减速率,动态段 token 可接受较高衰减。在所有设置中,MemDecay 保持 system-region 事实完整(全缓存精度),而无区域感知的基线方法无法保留超过 13/24。
9.6.2 Latent Briefing:跨 Agent 记忆共享的 KV Cache 路径
9.4.1 节的 TencentDB Agent Memory 提供了多 Agent 记忆共享的存储层方案(数据库 + 缓存),第 8.5 节的 ForkSubagent 提供了上下文克隆路径。2026 年 4 月 Ramp Labs 提出的 Latent Briefing 则开辟了第三条路径——直接在 KV Cache 层面实现多 Agent 间的记忆共享。
核心机制:
- Worker 模型生成 token 时,分析其注意力模式
- 识别哪些 KV Cache 条目对当前任务最重要
- 在表征层面丢弃其余条目,得到压缩后的”Latent Briefing”
- 将 Latent Briefing 注入到下游 Agent 的 KV Cache
性能数据:
- Worker 模型 token 消耗降低 65%
- 压缩延迟仅 ~1.7s(比 LLM 摘要快 10-30 倍)
- 任务自适应:不同查询对同一 context 的压缩结果不同
三种跨 Agent 记忆方案对比:
| 方案 | 实现层 | 适用场景 | 性能特征 |
|---|---|---|---|
| TencentDB Agent Memory | 存储层(数据库+缓存) | 跨进程/跨机器持久化记忆 | 高延迟但持久化 |
| ForkSubagent 上下文克隆 | 上下文层(消息历史) | 子 Agent 完整继承父上下文 | 高 token 消耗但完整 |
| Latent Briefing | KV Cache 层(表征压缩) | Worker Agent 高频共享记忆 | 极低延迟 + 任务自适应 |
Latent Briefing 与 Claude Code ForkSubagent(8.5 节)的技术互补性体现在:ForkSubagent 克隆父 Agent 的完整历史,子 Agent 需要重复携带所有父上下文;Latent Briefing 在 Worker Agent 场景下,子 Agent 只需接收压缩后的”记忆简报”而非完整历史——token 消耗降低 65%。这两种模式可以组合使用:父 Agent Fork 出多个 Worker Agent 时,对实时性要求高的 Worker 使用 Latent Briefing 接收压缩记忆,对需要完整上下文的 Worker 使用 ForkSubagent 克隆。
Ramp Labs 的 Latent Briefing 与 9.6.1 节的 CompressKV 构成KV Cache 优化的两翼——CompressKV 关注单 Agent 内的 Cache 压缩(3% KV 守住 97% 性能),Latent Briefing 关注多 Agent 间的 Cache 共享(65% token 节省)。两者共同预示了 KV Cache 从”单 Agent 内部状态”升级为”多 Agent 通信基础设施”的演进方向。
9.6.3 2026-07 KV Cache 淘汰三路径
9.6 节覆盖的五层级联管线(LLM Summarization / Opaque / Verbatim / Attention Matching / CompressKV)都基于”当前注意力分数”或”语义检索头”做淘汰决策。2026 年 7 月,三条新路径在”决策信号”维度上实现范式升级——不再问”哪些 token 被注意过”,而是问”哪些 token 会被需要”:
| 路径 | 代表工作 | 决策信号 | 关键数据 | 与 Claude Code 的工程关系 |
|---|---|---|---|---|
| 训练时压缩 | CompactionRL(2026-07-03) | RL 训练联合优化任务+压缩 | SWE-bench Verified +7.0pp, Terminal-Bench 2.0 +3.1pp | 挑战”压缩是推理时补丁”的根本假设;对 API-only 用户(Claude Code 绝大多数用户)当前不可行 |
| 未来注意力预测 | KVpop(arXiv:2607.05061,2026-07-06) | delayed memory scorer 预测未来需求 | 88% 压缩比下保留 97-100% 性能(Qwen3-4B) | 9.6.1 节两大工程瓶颈(FlashAttention 不暴露 score、paged attention 内存碎片)同样阻碍此路径 |
| 区域感知淘汰 | MemDecay(arXiv:2607.10582,2026-07-12) | 语义区域注意力半衰期差异 | system token 半衰期 10x 于 scratchpad;全缓存精度保护关键区域 | 6.2 节静态/动态分离天然提供区域标注——语义区域 = 缓存策略维度 |
这三条路径不互斥,但代表根本不同的工程哲学:CompactionRL 将压缩移入训练阶段,KVpop 将决策从看过去升级到预测未来,MemDecay 将决策从token 粒度上移到语义区域粒度。对 Claude Code 的五层级联管线,最可操作的启示来自 MemDecay——利用 6.2 节的静态/动态分离实现区域感知的差异化淘汰,是唯一不依赖推理引擎改造即可在应用层开始探索的路径。
2026 年 9 月下旬又有五篇新预印本落在这两条轴上,四篇问”何时压缩 / 压缩成什么”,一篇正面把裁剪的失效边界写成正式议题:
| 工作 | 提交日 | 切入点 |
|---|---|---|
| StateComp: Learning When to Compress History in Long Horizon Agents(arXiv:2609.27298) | 2026-09-23 | 把”何时压缩”本身学成一个可训练策略 |
| Memory Control Signals Emerge Before Action in Long Horizon Agents(arXiv:2609.27286) | 2026-09-23 | 长程 agent 中记忆控制信号先于动作出现 |
| Stable Geometry with Divergent Task Evidence for Efficient Long-Horizon Agent Compression(arXiv:2609.27332) | 2026-09-23 | 任务证据发散时保持压缩后表示的几何稳定 |
| Compact-Memory LLM Agents via Online Max-Member Clustering and Atom-Aware Packing(arXiv:2609.04915) | 2026-09-04 | 在线最大成员聚类 + 原子感知打包 |
| Protocol-Preserving Context Trimming for Agentic Workflows: Benefits, Failure Regimes, and Budget Guardrails(arXiv:2609.16461) | 2026-09-15 | 保协议的上下文裁剪,标题即点明失效区间与预算护栏 |
最后一篇与 9.6 的逐字压缩 vs LLM 摘要谱系直接相接,也是本轮唯一一篇把”什么时候不该裁”写成正式议题的——9.6 此前讨论的一直是”怎么裁得更多”。⚠️ 三项 2026-09-23 的工作同日提交、第一作者同为 Wang Mingxuan、同为 9 位作者,属同一研究组的一次系列投稿,只能算一条线索,不能当作三项互相独立的佐证;五篇均为 6–25 天内的新预印本,未经同行评议。
第四条路:不改摘要,而是在摘要之后补一段学到的表征(REMORY,arXiv:2610.11287)。 上面三路径与五篇预印本的共同动作都是改摘要本身——换触发时机、换决策信号、换表示。REMORY: Learning Residual Memory for Context Compaction([v1] 2026-10-08,[v2] 2026-10-11)动的是另一处:在摘要之外追加一段有界的 soft memory tokens,由网络根据”历史 + 摘要”生成,帮助冻结的 LLM 逼近”有完整历史时的续写”——论文把它比作序列维度上的残差连接。
它与本章是直接对话而非平行工作:论文引言把 Claude Code 与 Codex CLI 的 /compact 作为”当前主流做法”的参照(HTML 全文逐字:“popular coding agents such as Claude Code and Codex CLI provide /compact to free context space”),并指出输入长度呈锯齿状——随交互增长、在压缩处骤降。
关键数字:在 SummHay 上用全上下文 5.2% 的输入位置逼近全上下文的联合分数。论文正文给了这组绝对数——原始上下文平均 96,872 个位置、仅摘要 1,393 个、摘要加记忆 5,024 个,后者即 5,024 / 96,872 ≈ 5.2%。在 BrowseComp 与 Terminal-Bench 2.1 上,Qwen3.8-27B 与 GLM-5.3-Flash 有稳定增益,且重复工具输出与工具错误显著减少。
⚠️ 三处限定:① 预印本 v2,未同行评议;② 5.2% 是”追加之后总长度占原始上下文位置的比例”,不是压缩率——不得反写成”压缩了 94.8%“;③ 实测的 harness 是 Codex CLI,不是 Claude Code(论文逐字:“Each within-actor comparison holds weights, the Codex CLI harness, prompts, tools, decoding, budgets, and compaction policy fixed”)。Claude Code 在论文里是参照对象,不是实验平台,两者不能混。
它与 9.9 的 TokenPilot 是互补而非竞争:TokenPilot 优化的是”别让前缀变”,REMORY 优化的是”变完之后补回什么”。本章此前只有前者。
9.7 会话恢复
Claude Code 支持通过 --resume 参数恢复之前的会话。这依赖于持续的会话持久化——每条消息都被写入 transcript 文件。
恢复流程:
- 读取上一次会话的 transcript
- 重建消息历史
- 如果有
compact_boundary,只加载边界之后的消息 - 继续对话
一个关键的工程细节:用户消息在进入主循环之前就被持久化(见第 4 章)。这确保了即使 API 调用期间进程被杀死,transcript 中至少有用户的最后一条消息——--resume 可以从这个点恢复。
恢复动作的入口本身曾是一个注入面(v2.1.299,2026-10-14)。 上面讲恢复流程与持久化顺序,未涉及恢复命令自身的安全。官方 changelog 逐字:
Changed the resume command printed at exit: it names the session by its ID and no longer by its name, so that nothing in a session name can run when the line is pasted
退出时打印的那条 resume 命令,此前以会话名寻址,现在改用会话 ID。两层教学点。其一,恢复动作的入口曾经是一个命令注入面:会话名里的内容可能在你把这一行粘贴进终端时被当作命令执行——这是本章唯一一处与命令注入直接相关的官方事实。其二,官方的修法是改寻址方式(用 ID 而不是名字),不是过滤会话名里的字符——把不可信输入排除出可执行的上下文,而不是试图净化它。这个取舍在第 7 章的允许型规则与第 8 章的派生识别里都出现过,值得单独记住。
顺带一句:同版本还改了 worktree 会话的 resume 打印——长 flag 放不下时改用 -w 与 -r,都放不下则在上方行说明该去哪里执行。恢复入口的细节不止于安全。
9.9 设计启示
学术分类体系定位
根据 arXiv 2603.07670《Memory for Autonomous LLM Agents》综述,AI Agent 记忆系统可从三个维度分类:
| 维度 | 分类 | Claude Code 实现 |
|---|---|---|
| 形式 | 参数化/非参数化 | 非参数化(文件系统存储) |
| 功能 | 工作/事件/语义/程序记忆 | 混合(user=语义/feedback=程序/project=事件/reference=语义) |
| 动态 | 写入/管理/读取 | 显式写入 + AI 驱动检索读取 |
与主流框架对比
Claude Code 在记忆系统设计空间中的定位:
- vs Mem0(向量检索):Claude Code 使用 AI 驱动相关性检索而非向量相似度
- vs Letta(分层认知):Claude Code 采用类型化记忆而非严格分层架构
- vs LangMem(知识图谱):Claude Code 保持简单文件结构,避免复杂图数据库
核心设计原则
-
类型化记忆优于大杂烩。user/feedback/project/reference 的分类决定了访问策略和生命周期。
-
AI 检索 + 硬限制 = 可控系统。最多 200 个文件、最多返回 5 个相关记忆——这些限制确保系统不会成为性能瓶颈。
-
压缩是必需品,不是优化。在长会话中,不压缩就会超出上下文限制,导致 API 调用失败。
上面第 3 条还应带一个任务类型的边界。2026 年 10 月出现了一条方向相反的证据:Scaling Discovery Requires Forgetting(arXiv:2610.20563,[v1] 2026-10-14,11 位作者,第一作者 Shangyin Tan)发现,研究型 agent 无论”单 agent 跑更久""多 agent 并行”还是”让并行 agent 共享候选”,最终都会遇到平台期——每个 agent 锚定在自己的历史尝试上,改动越来越小,此后追加预算几乎不再带来改进。解法是周期性丢弃搜索状态:删掉每个 agent 的 session 与候选历史,从当前最优候选重启。在启发式编程、kernel 优化、模型训练四类任务上,同样预算下比并行 agent 高至多 15%、比单 agent 高至多 39%。
第 3 条讲的是”不压缩会失败”,这条讲的是”压得太少也会失败”——两者不矛盾,但要分清任务类型:在上下文必须延续的场景(编码调试、长会话协作),历史即证据,本章 9.6 的整套框架依然成立;在开放式发现类任务里,保留历史本身可能就是平台期的成因。论文的总结是”允许 agent 记住什么,与给它多少算力同等重要”。⚠️ 限定:预印本([v1] 2026-10-14),未同行评议;四类任务均属可自动评分的发现类任务,不得推广到编码调试这类”历史即证据”的场景。
-
持久化先于执行是会话恢复的基础。没有预先写入的 transcript,就没有恢复能力。
-
仅追加 + 定期蒸馏是可持续的知识管理模式。AutoDream 和 KAIROS 都体现了这一范式。
2026 年记忆系统发展趋势
记忆系统正从附属功能发展为独立工程学科。六大主流框架(Mem0、Letta、LangMem、Zep、AgentCore、CrewAI Memory)代表了不同的设计范式。Claude Code 的设计选择体现了在简单性、可控性和 AI 原生性之间的平衡。
上下文压缩的前沿方向
Claude Code 的五层压缩管线是被动触发式——当 Token 用量达到 80%/95% 阈值时才执行压缩。2026 年的两项前沿研究提出了不同的范式:
被动 vs 主动压缩:Active Context Compression(ACC, arXiv:2601.07190)提出 Agent 应在工作过程中主动决定保留什么、丢弃什么,而非等到上下文快满时才压缩。ACC 的核心观察是”Context Bloat”——交互历史持续增长导致计算成本线性增加,被动压缩无法及时应对。Claude Code 的被动管线与 ACC 的主动模式可以互补:Agent 主动丢弃明确不再需要的历史(如已完成的子任务上下文),被动压缩作为兜底机制处理剩余的上下文膨胀。
有损 vs 无损修剪:Contextual Memory Virtualisation(CMV, arXiv:2602.22402)提出用 DAG(有向无环图) 管理会话状态,实现”类 Git 的工作流”管理对话记忆。关键创新是结构化无损修剪——当会话达到上下文限制时,不是有损压缩,而是通过 DAG 版本控制保留完整结构信息,仅从当前视图”隐藏”不活跃的分支。这与 Claude Code 的 Reactive/Forced compact(有损摘要)形成范式对比。
两种思路的互补可能性:Agent 主动压缩(丢弃确定无用的历史)+ DAG 无损修剪(保留结构、隐藏不活跃分支)+ 被动兜底压缩(处理极端情况)。这种分层架构可能在未来的编码 Agent 中实现更精细的上下文管理。
第三种视角:TokenPilot 的”前缀稳定性优先”。Claude Code 的五层压缩管线是被动触发式(80%/95% 阈值),9.6 节的主动/被动讨论关注”何时压缩”和”压缩什么”。浙江大学 ZJUNLP 的 TokenPilot(arXiv:2606.17016)提出了一种根本不同的视角——将压缩从”节省 Token”问题升级为”缓存命中率优化”问题:
核心操作不再是”压缩什么”,而是”如何组织才能让前缀不变”。
Claude Code 的 Prompt Caching(6.2 节)的核心价值不在”省了多少 Token”,而在”跨轮次缓存命中率”——每 1% 的缓存命中率提升直接转化为等比例的成本降低,在长会话 Agent 中效果远超一次性 Token 削减。TokenPilot 的 Ingestion-Aware Compaction 通过主动维护前缀稳定性(PinchBench 成本降低 61%、Claw-Eval 降低 87%),印证了”前缀稳定性 > 单次压缩量”的设计哲学。
这一视角对 9.6 节五层级联管线的启示是:
- 被动触发的问题不仅是”延迟压缩”——更根本的是它破坏了跨轮次缓存结构。即使压缩后的总 token 数更少,但前缀变化导致后续轮次的缓存完全失效
- 主动维护前缀稳定是更高级的优化目标——它需要”全局长线思维”而非”单轮局部最优”。在长会话 Agent 中,这意味着宁可保留更多冗余信息也不破坏前缀——这与 MorphLLM 的”逐字压缩保留原文”思想不谋而合
- TokenPilot 印证了 Claude Code 静态/动态分离(6.2 节)的设计正确性——边界分离的本质就是”维护前缀不变”,TokenPilot 的工程化实现在更细粒度上验证了这一方向
这一视角也将 6.2 节的 Prompt Caching 讨论与 9.6 节的压缩管线讨论统一起来——两者都是”缓存命中率优化”的不同层次:Prompt Caching 在 API 层(应用层前缀缓存),TokenPilot 在上下文层(Ingestion-Aware Compaction),五层级联管线在对话历史层(80%/95% 阈值被动压缩)。Claude Code 的工程选择是接受被动压缩的延迟性,但通过静态/动态分离和 Prompt Caching 弥补缓存命中率损失——这是一个务实的工程平衡。
如何验收上面这套论点。此前”前缀稳定性 > 单次压缩量”更像一条设计哲学,因为本书没有给出测量手段。这一点在 2026 年 8-9 月被补上了:
- v2.1.251:
/cost新增每会话 prompt-cache 行,报命中率、miss 数、重新缓存的 token 数、warm/cold 指示;同时提供prompt_cache对象供 status line 脚本使用。 - v2.1.260:
/cost与 status line 的prompt_cache字段新增缓存未命中的可能原因(如工具定义或 system prompt 变了、空闲超过 TTL)。这一项把”命中率掉了”从观察推进到归因。 - v2.1.243:新增
promptCacheTtl与subagentPromptCacheTtl设置,让 API-key 与云厂商用户可以分开配置——主会话保持 1 小时缓存、子 Agent 保持 5 分钟(与 8.3 节的experimental.cacheTtl是同一机制的两个入口)。 - v2.1.275:补上了此前无法归因的一类 miss——恢复出来的记忆文件,其 age note 在一次压缩或
--resume之后会在请求之间发生变动,从而打掉 prompt cache。同版本还修了响应里偶发出现游离</ccmemory>结束标签的问题。
一条被漏掉的机制前提。 上面四项都是测量手段,但”前缀为什么会稳定”这件事本章此前从未交代:Claude Code 在会话的第一个请求上构建系统提示并把它记录进 session,之后(含 --resume / --continue)都复用这份记录,直到会话被压缩为止。这才是 9.9 整套论证得以成立的机制——没有它,“前缀稳定”只是运气。传 --system-prompt-snapshot off 才改为每个请求重建(v2.1.257 引入该 flag)。官方还给了三个版本门:v2.1.265 之前,传任意一个 system prompt flag 也会顺带把记录关掉;v2.1.268 之前,不拉取 feature flag 的会话(Amazon Bedrock、Google Cloud 的 Agent Platform、Microsoft Foundry)每次请求都重建,此时该 flag 无效;以 --bare 或 CLAUDE_CODE_SIMPLE=1 启动的 bare 模式下记录保持关闭,除非显式传 on。
这条实现事实顺手解释了一个常见困惑:改了 --append-system-prompt 之后行为往往不变——因为复用的是会话开头那份记录,新提示要等会话被压缩之后才生效,或者显式传 --system-prompt-snapshot off 立刻生效。
分离还可以自己声明。 6.2 节的静态/动态分离此前只有”量出来”这一侧。v2.1.275 起,在自定义系统提示里放一行仅含 __SYSTEM_PROMPT_DYNAMIC_BOUNDARY__ 的行,Claude Code 会在该行处切分并删掉该行,上半部分保持缓存、下半部分每次变化。官方注明该切分只在部分配置下生效(见 Agent SDK 的 “Cache the static part of a custom prompt”)。至此,“分离做得对不对可以量出来”才有了对应的”我可以自己划分界线”。
有了这三项,“前缀稳定性”就从设计哲学变成了可验收指标:先读 /cost 的命中率建立基线,改动提示构造后复测,若命中率下降则由 v2.1.260 的原因字段定位是工具定义、system prompt 还是 TTL 过期。这与 6.2 节的静态/动态分离设计形成闭环——分离做得对不对,现在可以量出来。