一、什么是 /compact
/compact 将当前对话历史压缩为一段结构化摘要,释放上下文窗口空间,让长会话可以持续进行。
核心机制:用 LLM 对对话历史生成摘要 → 替换原始消息 → 重新注入系统上下文(CLAUDE.md 等)。
二、关键常量
| 常量 | 值 | 含义 |
|---|---|---|
MAX_OUTPUT_TOKENS_FOR_SUMMARY | 20,000 | 摘要最大输出 token |
AUTOCOMPACT_BUFFER_TOKENS | 13,000 | 自动压缩缓冲区 |
MANUAL_COMPACT_BUFFER_TOKENS | 3,000 | 手动压缩缓冲区 |
MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES | 3 | 熔断器:连续失败 3 次后停止自动压缩 |
POST_COMPACT_MAX_FILES_TO_RESTORE | 5 | 压缩后最多恢复 5 个文件内容 |
POST_COMPACT_TOKEN_BUDGET | 50,000 | 压缩后附件总 token 预算 |
三、三条压缩路径
/compact 命令不是单一实现,而是有三条路径按优先级依次尝试:
路径 1:Session Memory Compact(快速路径)
条件:Session Memory 功能开启 + 无自定义指令 + 存在有效 session memory
原理:
- 不调用 LLM 重新总结
- 找到上次摘要点(
lastSummarizedMessageId),保留最近的消息 - 消息保留策略(默认配置):
minTokens = 10,000 → 至少保留 10K token 的近期消息
minTextBlockMessages = 5 → 至少保留 5 条含文本的消息
maxTokens = 40,000 → 最多保留 40K token- 会保护 tool_use / tool_result 配对完整性(不会拆散一对)
特点:速度最快,不耗额外 token,适合日常自动压缩。
路径 2:Reactive Compact
条件:特定功能标志开启时使用
原理:部分消息压缩,只压缩旧消息,保留最近的对话。分两个方向:
from:从某个切分点到末尾的消息生成摘要up_to:对切分点之前的消息生成摘要
路径 3:Traditional Compact(兜底路径)
条件:前两条路径不可用或失败时使用
原理:对整个对话历史调用 LLM 生成结构化摘要。这是最完整但最慢的路径。
四、摘要生成的 Prompt 结构
Traditional compact 使用的 prompt 要求 LLM 生成 9 个章节的结构化摘要:
<analysis> ← 分析草稿(会被丢弃,不进入最终摘要)
...
</analysis>
<summary> ← 最终摘要(保留)
1. Primary Request and Intent ← 用户所有明确请求
2. Key Technical Concepts ← 涉及的技术/框架
3. Files and Code Sections ← 具体文件和代码片段
4. Errors and Fixes ← 所有错误及修复方式
5. Problem Solving ← 已解决和进行中的问题
6. All User Messages ← 每条用户消息(非工具结果)
7. Pending Tasks ← 待完成的任务
8. Current Work ← 压缩前正在进行的工作
9. Optional Next Step ← 建议的下一步
</summary>
关键安全措施:prompt 前后都有强调 "不要调用任何工具,只输出纯文本",防止 LLM 在压缩过程中执行工具。
五、自动压缩触发机制
5.1 阈值计算
有效上下文窗口 = 模型上下文窗口 - 20,000(摘要输出预留)
自动压缩阈值 = 有效上下文窗口 - 13,000(缓冲区)示例(200K 上下文模型):
有效窗口 = 200,000 - 20,000 = 180,000
自动压缩在 180,000 - 13,000 = 167,000 token 时触发5.2 触发条件
每次查询后检查:
shouldAutoCompact() 依次检查:
✓ 自动压缩是否启用?(环境变量 + 用户配置)
✓ 当前请求来源是否允许?(排除 compact 自身等)
✓ 当前 token 数 ≥ 阈值?
→ 全部满足则触发5.3 熔断器
连续 3 次自动压缩失败后,熔断器打开,停止尝试。成功一次则重置计数。
5.4 环境变量覆盖
CLAUDE_CODE_AUTO_COMPACT_WINDOW=100000 # 覆盖上下文窗口大小
CLAUDE_AUTOCOMPACT_PCT_OVERRIDE=80 # 按百分比触发(0-100)六、压缩后发生什么
6.1 消息替换
原始对话消息被替换为一条 user 消息:
"This session is being continued from a previous conversation.
Here is a summary of the conversation so far:
{摘要内容}
Recent messages are preserved verbatim."6.2 上下文重新注入
压缩后重新加载(完全存活):
- ✅ 所有 CLAUDE.md 文件(从磁盘重新读取)
- ✅ .claude/rules/*.md
- ✅ @include 引用的文件
- ✅ Auto memory(MEMORY.md)
- ✅ 激活的 skill 内容
6.3 文件内容恢复
压缩后会尝试恢复关键文件内容:
- 最多恢复 5 个文件
- 总 token 预算 50,000
- 单文件最多 5,000 token
- Skill 文件预算 25,000 token
6.4 缓存清理
runPostCompactCleanup() 清理以下缓存:
- 用户上下文缓存
- Memory 文件缓存(触发重新加载)
- 系统提示词缓存
- 权限审批缓存
- 会话消息缓存
6.5 Hook 触发
PreCompact → 压缩前触发(matcher: "manual" 或 "auto")
PostCompact → 压缩后触发(stdin 包含摘要内容)
SessionStart → 压缩后也会触发(等同于新会话开始)七、手动 vs 自动压缩对比
| 特性 | 手动 /compact | 自动压缩 |
|---|---|---|
| 触发方式 | 用户输入 /compact | token 超过阈值时自动 |
| 自定义指令 | 支持 /compact 保留 xxx 信息 | 不支持 |
| 缓冲区 | 3,000 token | 13,000 token |
| Session Memory 路径 | 有自定义指令时跳过 | 优先使用 |
| 熔断器 | 无 | 连续 3 次失败后停止 |
八、使用指南
8.1 基本用法
# 直接压缩(无自定义指令)
/compact
# 带自定义指令(告诉 LLM 压缩时保留什么)
/compact 保留所有关于数据库迁移的讨论细节
/compact Keep all code snippets and file paths8.2 什么时候手动 /compact
- 上下文快满时 — 看到黄色/红色进度条
- 话题转换时 — 从 A 功能切到 B 功能前先压缩
- Claude 开始"忘记"早期指令时 — 上下文过长导致注意力稀释
- 长时间调试结束后 — 大量试错信息可以压缩掉
8.3 什么时候不需要手动 /compact
- 对话刚开始 — 消息太少,会报 "Not enough messages to compact"
- 自动压缩已经在工作 — 默认开启,通常不需要手动干预
- 关键代码还在讨论中 — 压缩可能丢失细节,先完成当前任务再压缩
8.4 自定义指令的最佳实践
# ✅ 好的自定义指令 — 具体、有重点
/compact 保留:1) 所有修改过的文件路径 2) 数据库 schema 变更 3) 当前未完成的 TODO
# ✅ 好的自定义指令 — 保护关键上下文
/compact Preserve the API endpoint mapping and all error handling patterns we discussed
# ❌ 不好的 — 太笼统
/compact 保留所有内容8.5 配合 Hook 使用
压缩前提醒保留重点
{
"hooks": {
"PreCompact": [{
"hooks": [{
"type": "command",
"command": "echo '{\"systemMessage\": \"⚠️ 即将压缩对话,关键信息请确认已记录到 CLAUDE.md\"}'"
}]
}]
}
}压缩后记录摘要
{
"hooks": {
"PostCompact": [{
"hooks": [{
"type": "command",
"command": "jq -r '.summary // empty' >> .claude/compact-log.txt"
}]
}]
}
}8.6 长会话生存策略
核心原则:CLAUDE.md 是持久文件,不要把会话临时信息往里塞,否则会快速膨胀超过 200 行上限。
信息保留应分层处理:
| 信息类型 | 保留方式 | 示例 |
|---|---|---|
| 长期架构决策 | 写入 CLAUDE.md / rules | "API 统一用 RESTful,不用 GraphQL" |
| 会话学到的 pattern | 依赖 Auto Memory(自动) | Claude 自行判断是否记录到 ~/.claude/projects/<project>/memory/ |
| 本次压缩需保留的上下文 | /compact 保留xxx 自定义指令 | /compact 保留当前数据库迁移的进度和方案 |
| 调试过程、试错记录 | 不需要保留,压缩释放空间 | 反复 debug 的堆栈信息 |
具体策略:
- 只把真正长期有效的决策写入 CLAUDE.md — 如编码规范、架构选型,而非会话临时状态
- 会话临时上下文用
/compact自定义指令保留 — 只影响本次压缩摘要,不污染持久文件 - 信任 Auto Memory — Claude 会自动将有价值的 pattern 写入
MEMORY.md,无需手动干预 - 阶段性任务完成后主动 /compact — 清理无用上下文
- 话题切换前压缩 —
/compact 保留当前进度,然后开始新话题
8.7 常见问题排查
| 问题 | 原因 | 解决 |
|---|---|---|
| "Not enough messages to compact" | 消息太少 | 继续对话,积累更多消息 |
| "Conversation too long" | 单条消息/对话已超长 | 按 Esc 两次回退几条消息再试 |
| 压缩后丢失关键信息 | 摘要未覆盖到 | 使用自定义指令指定保留内容 |
| 压缩后行为改变 | CLAUDE.md 冲突或模糊 | 检查 /memory,确认指令文件加载正确 |
| 自动压缩不触发 | 熔断器打开或功能禁用 | 检查环境变量,手动 /compact 重置 |
九、核心源码文件索引
| 文件 | 职责 |
|---|---|
src/commands/compact/compact.ts | 命令入口,路由三条路径 |
src/services/compact/compact.ts | 核心压缩逻辑(流式处理、重试、附件恢复) |
src/services/compact/sessionMemoryCompact.ts | Session Memory 快速压缩路径 |
src/services/compact/autoCompact.ts | 自动压缩触发、阈值计算、熔断器 |
src/services/compact/prompt.ts | 三种 prompt 变体 + 格式化函数 |
src/services/compact/postCompactCleanup.ts | 压缩后缓存清理 |
十、一句话总结
/compact有三条路径(Session Memory → Reactive → Traditional),自动压缩在约 83% 上下文使用率时触发。CLAUDE.md 完整存活压缩(从磁盘重新读取),对话记忆被结构化摘要替代。长期决策写入 CLAUDE.md/rules,会话临时上下文用/compact 保留xxx自定义指令保留,日常 pattern 交给 Auto Memory 自动记录——不要把临时信息塞进 CLAUDE.md 导致膨胀。