Compact时,大模型干了什么?
当你在Claude Code中敲下
/compact的那一刻,大模型究竟做了什么?为什么压缩后还能"记得"之前的事?
什么是Compact
用过Claude Code的人应该都遇到过这个场景:对话进行到一半,系统提示上下文窗口即将耗尽。这时候你需要做个选择------要么开个新会话从头来过,要么用/compact压缩当前对话。
Compact的本质是用"记忆"替代"录像" 。
想象你在开一个两小时的会议。会议结束后,你不会把录音逐字逐句发给没参加的人,而是写一份会议纪要:讨论了什么、决定了什么、下一步做什么。Compact做的就是这件事------把完整的对话历史压缩成一份"会议纪要"。
#mermaid-svg-wqRmiHNK8W9EoHUV{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-wqRmiHNK8W9EoHUV .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-wqRmiHNK8W9EoHUV .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-wqRmiHNK8W9EoHUV .error-icon{fill:#552222;}#mermaid-svg-wqRmiHNK8W9EoHUV .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-wqRmiHNK8W9EoHUV .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-wqRmiHNK8W9EoHUV .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-wqRmiHNK8W9EoHUV .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-wqRmiHNK8W9EoHUV .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-wqRmiHNK8W9EoHUV .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-wqRmiHNK8W9EoHUV .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-wqRmiHNK8W9EoHUV .marker{fill:#333333;stroke:#333333;}#mermaid-svg-wqRmiHNK8W9EoHUV .marker.cross{stroke:#333333;}#mermaid-svg-wqRmiHNK8W9EoHUV svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-wqRmiHNK8W9EoHUV p{margin:0;}#mermaid-svg-wqRmiHNK8W9EoHUV .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-wqRmiHNK8W9EoHUV .cluster-label text{fill:#333;}#mermaid-svg-wqRmiHNK8W9EoHUV .cluster-label span{color:#333;}#mermaid-svg-wqRmiHNK8W9EoHUV .cluster-label span p{background-color:transparent;}#mermaid-svg-wqRmiHNK8W9EoHUV .label text,#mermaid-svg-wqRmiHNK8W9EoHUV span{fill:#333;color:#333;}#mermaid-svg-wqRmiHNK8W9EoHUV .node rect,#mermaid-svg-wqRmiHNK8W9EoHUV .node circle,#mermaid-svg-wqRmiHNK8W9EoHUV .node ellipse,#mermaid-svg-wqRmiHNK8W9EoHUV .node polygon,#mermaid-svg-wqRmiHNK8W9EoHUV .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-wqRmiHNK8W9EoHUV .rough-node .label text,#mermaid-svg-wqRmiHNK8W9EoHUV .node .label text,#mermaid-svg-wqRmiHNK8W9EoHUV .image-shape .label,#mermaid-svg-wqRmiHNK8W9EoHUV .icon-shape .label{text-anchor:middle;}#mermaid-svg-wqRmiHNK8W9EoHUV .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-wqRmiHNK8W9EoHUV .rough-node .label,#mermaid-svg-wqRmiHNK8W9EoHUV .node .label,#mermaid-svg-wqRmiHNK8W9EoHUV .image-shape .label,#mermaid-svg-wqRmiHNK8W9EoHUV .icon-shape .label{text-align:center;}#mermaid-svg-wqRmiHNK8W9EoHUV .node.clickable{cursor:pointer;}#mermaid-svg-wqRmiHNK8W9EoHUV .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-wqRmiHNK8W9EoHUV .arrowheadPath{fill:#333333;}#mermaid-svg-wqRmiHNK8W9EoHUV .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-wqRmiHNK8W9EoHUV .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-wqRmiHNK8W9EoHUV .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-wqRmiHNK8W9EoHUV .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-wqRmiHNK8W9EoHUV .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-wqRmiHNK8W9EoHUV .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-wqRmiHNK8W9EoHUV .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-wqRmiHNK8W9EoHUV .cluster text{fill:#333;}#mermaid-svg-wqRmiHNK8W9EoHUV .cluster span{color:#333;}#mermaid-svg-wqRmiHNK8W9EoHUV div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-wqRmiHNK8W9EoHUV .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-wqRmiHNK8W9EoHUV rect.text{fill:none;stroke-width:0;}#mermaid-svg-wqRmiHNK8W9EoHUV .icon-shape,#mermaid-svg-wqRmiHNK8W9EoHUV .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-wqRmiHNK8W9EoHUV .icon-shape p,#mermaid-svg-wqRmiHNK8W9EoHUV .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-wqRmiHNK8W9EoHUV .icon-shape .label rect,#mermaid-svg-wqRmiHNK8W9EoHUV .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-wqRmiHNK8W9EoHUV .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-wqRmiHNK8W9EoHUV .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-wqRmiHNK8W9EoHUV :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 完整对话历史
数十万tokens
大模型阅读理解
识别关键信息
过滤冗余内容
生成压缩摘要
几千tokens
用摘要替代原始历史
为什么需要这样做?因为大模型的上下文窗口是有限的。
Claude的上下文窗口是200K tokens,听起来很多。但一个复杂的编程任务------多轮对话、代码修改、工具调用------很快就会填满。一旦溢出,要么无法继续,要么丢失之前的上下文。
Compact时,大模型做了什么
三个步骤
Step 1: 识别关键信息
大模型会扫描整个对话历史,找出哪些是"必须记住"的:
- 做了什么决策(比如"用JWT认证而不是Session")
- 完成了哪些任务(比如"登录模块已实现")
- 当前进度(比如"正在调试权限模块")
- 遇到的问题(比如"bcrypt版本不兼容")
Step 2: 过滤冗余
然后把那些"知道也行,不知道也行"的内容丢掉:
- 重复的确认对话("好的"、"明白了"、"继续")
- 失败的尝试和调试过程
- 无关的闲聊
- 中间过程的细节
Step 3: 生成结构化摘要
最后用自然语言把关键信息组织成一份摘要:
保留:
✅ 任务目标
✅ 关键决策
✅ 最终结果
✅ 未完成工作
丢弃:
❌ 试探过程
❌ 错误路径
❌ 礼貌用语
❌ 重复内容
压缩过程可视化
#mermaid-svg-ZzajPZSOwTEMPY0x{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ZzajPZSOwTEMPY0x .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ZzajPZSOwTEMPY0x .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ZzajPZSOwTEMPY0x .error-icon{fill:#552222;}#mermaid-svg-ZzajPZSOwTEMPY0x .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ZzajPZSOwTEMPY0x .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ZzajPZSOwTEMPY0x .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ZzajPZSOwTEMPY0x .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ZzajPZSOwTEMPY0x .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ZzajPZSOwTEMPY0x .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ZzajPZSOwTEMPY0x .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ZzajPZSOwTEMPY0x .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ZzajPZSOwTEMPY0x .marker.cross{stroke:#333333;}#mermaid-svg-ZzajPZSOwTEMPY0x svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ZzajPZSOwTEMPY0x p{margin:0;}#mermaid-svg-ZzajPZSOwTEMPY0x .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ZzajPZSOwTEMPY0x .cluster-label text{fill:#333;}#mermaid-svg-ZzajPZSOwTEMPY0x .cluster-label span{color:#333;}#mermaid-svg-ZzajPZSOwTEMPY0x .cluster-label span p{background-color:transparent;}#mermaid-svg-ZzajPZSOwTEMPY0x .label text,#mermaid-svg-ZzajPZSOwTEMPY0x span{fill:#333;color:#333;}#mermaid-svg-ZzajPZSOwTEMPY0x .node rect,#mermaid-svg-ZzajPZSOwTEMPY0x .node circle,#mermaid-svg-ZzajPZSOwTEMPY0x .node ellipse,#mermaid-svg-ZzajPZSOwTEMPY0x .node polygon,#mermaid-svg-ZzajPZSOwTEMPY0x .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ZzajPZSOwTEMPY0x .rough-node .label text,#mermaid-svg-ZzajPZSOwTEMPY0x .node .label text,#mermaid-svg-ZzajPZSOwTEMPY0x .image-shape .label,#mermaid-svg-ZzajPZSOwTEMPY0x .icon-shape .label{text-anchor:middle;}#mermaid-svg-ZzajPZSOwTEMPY0x .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ZzajPZSOwTEMPY0x .rough-node .label,#mermaid-svg-ZzajPZSOwTEMPY0x .node .label,#mermaid-svg-ZzajPZSOwTEMPY0x .image-shape .label,#mermaid-svg-ZzajPZSOwTEMPY0x .icon-shape .label{text-align:center;}#mermaid-svg-ZzajPZSOwTEMPY0x .node.clickable{cursor:pointer;}#mermaid-svg-ZzajPZSOwTEMPY0x .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ZzajPZSOwTEMPY0x .arrowheadPath{fill:#333333;}#mermaid-svg-ZzajPZSOwTEMPY0x .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ZzajPZSOwTEMPY0x .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ZzajPZSOwTEMPY0x .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZzajPZSOwTEMPY0x .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ZzajPZSOwTEMPY0x .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZzajPZSOwTEMPY0x .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ZzajPZSOwTEMPY0x .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ZzajPZSOwTEMPY0x .cluster text{fill:#333;}#mermaid-svg-ZzajPZSOwTEMPY0x .cluster span{color:#333;}#mermaid-svg-ZzajPZSOwTEMPY0x div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ZzajPZSOwTEMPY0x .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ZzajPZSOwTEMPY0x rect.text{fill:none;stroke-width:0;}#mermaid-svg-ZzajPZSOwTEMPY0x .icon-shape,#mermaid-svg-ZzajPZSOwTEMPY0x .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZzajPZSOwTEMPY0x .icon-shape p,#mermaid-svg-ZzajPZSOwTEMPY0x .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ZzajPZSOwTEMPY0x .icon-shape .label rect,#mermaid-svg-ZzajPZSOwTEMPY0x .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZzajPZSOwTEMPY0x .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ZzajPZSOwTEMPY0x .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ZzajPZSOwTEMPY0x :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Compact后
原始对话
大模型理解
大模型理解
大模型理解
大模型理解
大模型理解
大模型理解
大模型理解
大模型理解
大模型理解
大模型理解
大模型理解
大模型理解
大模型理解
大模型理解
大模型理解
大模型理解
大模型理解
大模型理解
大模型理解
大模型理解
大模型理解
大模型理解
大模型理解
大模型理解
大模型理解
大模型理解
大模型理解
大模型理解
用户: 帮我写登录
AI: 创建接口...
用户: 有bug
AI: 调试过程...
用户: 还是不对
AI: 换方案...
用户: 可以了
任务: 登录功能
状态: 已完成
方案: JWT+bcrypt
下一步: 权限模块
一个具体例子
原始对话(1000+ tokens):
用户:帮我写一个登录功能
Claude:好的,我来创建一个登录接口...(500字代码)
用户:这里有个bug,密码验证不通过
Claude:让我看看...(调试过程300字)
用户:还是不对
Claude:我换个方案,用bcrypt重新实现...(新方案400字)
用户:可以了,接下来做权限管理
Compact后(100 tokens):
任务:实现登录功能
状态:✅ 已完成
方案:使用JWT + bcrypt密码加密
关键文件:auth/login.js, auth/middleware.js
注意:bcrypt版本需>=5.0
下一步:权限管理模块
从1000 tokens压到100 tokens,但关键信息一个没少。
技术原理深度解析
Compact看起来简单,但背后有几种不同的技术路线。先看一个整体对比:
| 技术路线 | 压缩比 | 是否需要训练 | 适用场景 | 代表方法 |
|---|---|---|---|---|
| 摘要式压缩 | 2-5x | 否 | 对话历史压缩 | Claude Code compact |
| Token级压缩 | 2-20x | 否 | Prompt压缩 | LLMLingua |
| KV Cache压缩 | 2-10x | 否 | 推理效率优化 | H₂O, StreamingLLM |
| 学习式压缩 | 10-100x | 是 | 高压缩比需求 | Gisting, AutoCompressor |
Claude Code的compact功能主要采用摘要式压缩,这也是目前对话类应用最常用的方式。
摘要式压缩(Claude Code采用)
这是最直观的方式------让大模型自己读一遍对话,然后写个摘要。
原始对话 → 大模型理解 → 生成自然语言摘要 → 用摘要替代原对话
优点是语义完整、可读性好,缺点是压缩比有限(通常2-5倍),而且大模型可能会遗漏它"觉得不重要"但实际上你需要的信息。
注:压缩比数据来自微软研究院的LLMLingua论文(Jiang et al., 2023),实际效果取决于文本类型和压缩策略。
Token级压缩(LLMLingua)
微软研究团队提出的方法。思路是:不是每个token都同等重要,有些词删掉也不影响理解。
怎么判断哪些token重要?用困惑度(Perplexity) 。
PPL(x)=exp(−1t∑i=1tlogP(xi∣x<i)) PPL(x) = \exp\left(-\frac{1}{t}\sum_{i=1}^{t}\log P(x_i|x_{<i})\right) PPL(x)=exp(−t1i=1∑tlogP(xi∣x<i))
这个公式的直觉是:
- 低困惑度 → 模型很容易预测这个词 → 信息量低 → 可以删
- 高困惑度 → 模型难以预测 → 信息量高 → 需要保留
举个例子:
原文:The cat sat on the mat
困惑度分布:[低, 高, 中, 低, 低, 高]
"the"、"on"、"the" 这些词模型很容易预测,删掉不影响理解
"cat"、"mat" 是关键信息,必须保留
LLMLingua的压缩流程分三步:
- 段落级压缩:用小模型计算每段的困惑度,分配压缩预算
- 句子级压缩:在保留的段落中,进一步筛选句子
- Token级压缩:删除低信息量的token
压缩比可以达到2-20倍,而且不需要训练,即插即用。
KV Cache压缩
这是更底层的优化。Transformer模型在推理时会缓存Key-Value对(KV Cache),上下文越长,缓存越大。
几种主要方法:
| 方法 | 思路 | 特点 |
|---|---|---|
| H₂O | 只保留注意力得分高的token | 适合长文本 |
| StreamingLLM | 保留"注意力锚点" | 支持无限长度推理 |
| SnapKV | 基于注意力模式聚类选择 | 2024年新方法 |
这些方法主要用在模型推理层面,对用户透明,Claude Code的compact应该是基于摘要式压缩实现的。
学习式压缩
还有一类方法是训练模型专门做压缩:
- Gisting:训练模型用几个特殊的"gist token"来表示一段长prompt
- AutoCompressor:把上下文压缩成可复用的summary vectors
- ICAE:用自编码器把长上下文压缩成紧凑表示
这些方法压缩比更高,但需要额外训练,目前还没大规模应用。
最佳实践
什么时候Compact
| 场景 | 建议 | 原因 |
|---|---|---|
| Token使用率 > 70% | ✅ 好时机 | 预留空间完成任务 |
| 完成阶段性任务后 | ✅ 好时机 | 前文已完成使命 |
| 正在调试复杂问题 | ❌ 不好 | 可能丢失关键上下文 |
| 多轮工具调用中间 | ❌ 不好 | 工具结果可能被压缩掉 |
让Compact更有效
技巧1:指定Focus Topic
/compact focus on the authentication module changes
告诉大模型"这部分最重要",它会在压缩时重点保留相关信息。
技巧2:Compact前先总结
在压缩之前,先让大模型把当前进度写入文件:
"把当前进度写入 progress.md,然后compact"
这样即使压缩丢了细节,文件里还有完整记录。
技巧3:关键信息持久化
不要依赖对话历史保存重要信息。三备份策略:
- 对话历史(会被compact)
- 文件系统(持久化)
- CLAUDE.md(项目级记忆)
技巧4:分阶段Compact
阶段1完成 → compact → 阶段2开始 → compact → ...
每个阶段的上下文相对独立,压缩时损失的信息更少。
局限与应对
Compact不是完美的。压缩是有损的,有些东西会丢。
信息损失
- 细节会丢失:具体的错误信息、某个参数的精确值
- 代码片段被概括:"实现了一个登录接口",但具体代码没了
- 上下文关联减弱:之前讨论的某个边界情况可能被压缩掉
应对策略
写下来,而不是说出来
关键信息一定要写入文件,而不是只在对话里提一句。对话会被压缩,文件不会。
用CLAUDE.md存储项目规范
把技术栈选择、架构决策、编码规范写进CLAUDE.md,这些信息会在每个会话开始时自动加载,不受compact影响。
Compact前检查
在压缩之前,问自己:如果现在所有对话历史都没了,我还能继续工作吗?如果答案是否,先把重要的东西写下来。
未来展望
2025年的趋势
混合压缩
把不同压缩方法组合起来。比如用KV Cache压缩处理推理效率,用摘要压缩处理对话历史,用检索压缩处理长文档。
硬件感知压缩
针对特定硬件优化压缩策略。比如在支持稀疏注意力的GPU上,可以用更激进的Token剪枝。
主动记忆管理
从"被动压缩"到"主动管理"。MemGPT这类系统已经在做分层记忆------重要信息放长期记忆,临时信息放短期记忆,自动在不同层级之间迁移。
从Compact到记忆系统
Compact本质上是一种"事后补救"------对话太长了,不得不压缩。未来可能会变成"事前规划"------从一开始就设计好哪些信息该保留、哪些该丢弃。
这就像人的记忆系统:你不会记住昨天午饭吃了什么(短期记忆自动丢弃),但你会记住家人的生日(长期记忆主动存储)。大模型的记忆系统也会朝这个方向发展。
写在最后
Compact看起来只是一个简单的命令,但背后涉及摘要生成、信息检索、注意力机制等多个AI技术领域。下次当你敲下/compact的时候,可以想象一下大模型正在做"会议纪要"------它在判断什么是重要的,什么是冗余的,然后用几百个token概括你几万token的对话。
这既是大模型的能力,也是它的局限。它能做到"理解",但无法做到"完美记忆"。所以,重要的东西,还是写下来吧。