一文拆解Claude Code中上下文壓縮機(jī)制
一次真實的編碼會話,token 總量可能輕松沖到 400K 甚至更高——可模型的上下文窗口只有 200K。Claude Code 是怎么把"無限增長的對話"塞進(jìn)"固定大小的窗口",還能一路保持思路連貫的?
答案不是"撐滿了就總結(jié)一下"這么簡單。它背后是一條 5 級漸進(jìn)式壓縮流水線:最便宜、最無損的手段先上,最貴、最有損的手段壓到最后才用。本文做一次源碼級拆解。
文章內(nèi)容:
- Claude Code 用 5 層手段管理上下文,核心哲學(xué)是漸進(jìn)式壓縮:cheapest first, heaviest last。
- 前 4 層(工具結(jié)果落盤、歷史裁剪、微壓縮、上下文折疊)幾乎零成本、且基本無損/可回滾。
- 只有最后一層 AutoCompact 會真正調(diào)用一次 LLM 做摘要——這一層才是"有損不可逆"的,而絕大多數(shù)對話根本走不到這里。
- "有損不可逆"的根本局限,靠兩件事兜底:跨會話的記憶系統(tǒng)(CLAUDE.md / auto memory)+ 完整保留原始對話的 transcript。
- 整條壓縮流水線位于源碼
src/services/compact/,約 3,960 行 TypeScript / 5 個文件。
適合誰讀:用 Claude Code 但好奇它"內(nèi)部怎么轉(zhuǎn)"的開發(fā)者;做 Agent / LLM 應(yīng)用、需要自己設(shè)計上下文工程的工程師。

一、先理解問題:窗口有限,對話無限
把上下文窗口想象成模型的工作臺面。對一個 200K token 的模型來說,這塊臺面在你發(fā)第一條消息之前就已經(jīng)被占掉一部分了:
- 系統(tǒng)提示詞 + 工具定義:約 20–25K token,是雷打不動的固定開銷。
- 系統(tǒng)提醒(system reminders) :每輪再加 200–2,000 token,視情況而定。
- 剩下大約 175K token 才是"對話歷史"能用的空間。
問題在于:歷史會無限增長,窗口卻不會。你讀一個 3,000 行的文件、跑幾條 grep、讓它改幾輪代碼——每次工具調(diào)用都往臺面上堆 2K–8K token。不處理的話,遲早撐爆。
更微妙的是:撐爆之前,質(zhì)量就已經(jīng)開始下滑了。這和電腦內(nèi)存很像——你可以把內(nèi)存用到 95%,但最后那點空間會被換頁、GC、系統(tǒng)開銷吃掉,程序反而卡死。LLM 同理:那塊"空著"的上下文不是浪費(fèi),它是模型"思考"的地方。窗口越滿,模型用來規(guī)劃、權(quán)衡、評估代碼改動的余地就越小。
所以 Claude Code 的目標(biāo)不是"用滿",而是在臺面變亂的過程中持續(xù)清理,始終給推理留出余量。

二、核心設(shè)計哲學(xué):漸進(jìn)式壓縮
整條流水線只有一句話原則:最便宜的手段先上,最重的手段最后用。 (cheapest first, heaviest last)
每往下一層,要么消耗更多算力,要么丟掉更多細(xì)節(jié)。于是系統(tǒng)能做到:"能用零成本手段解決的,絕不動用花錢又有損的 LLM 摘要。" 實測結(jié)論也印證了這一點:絕大多數(shù)對話根本走不到最后一層。
下面是完整的 5 級全景。
- 消息歷史持續(xù)增長
- L1 · 工具結(jié)果預(yù)算單塊 >50K 字符 → 落盤 + 2KB 預(yù)覽成本:零 · 可恢復(fù)
- L2 · 歷史裁剪 Snip回收陳舊的對話腳手架成本:零
- L3 · 微壓縮 MicroCompact回收舊工具輸出 · 時間型/緩存型雙路徑成本:零 API 調(diào)用
- L4 · 上下文折疊 Context Collapse~90% 觸發(fā) · 投影式折疊 · 可回滾成本:零 · 非破壞性
- L5 · 自動壓縮 AutoCompact分叉子 Agent 生成 LLM 摘要成本:一次 API 調(diào)用 · 不可逆
- 組裝最終 API 請求
三、逐層拆解
L1 · 工具結(jié)果預(yù)算(Tool Result Budget)
問題:某個工具一次就吐出一個巨大的內(nèi)容塊——比如讀了個幾 MB 的文件、跑了條刷屏的命令。
做法:當(dāng)單個工具結(jié)果超過閾值(DEFAULT_MAX_RESULT_SIZE_CHARS,約 50,000 字符)時,Claude Code 不會粗暴截斷,而是把完整輸出落盤,只在上下文里留一個約 2KB 的預(yù)覽:
<persisted-output> Output too large (2.3 MB). Full output saved to: /tmp/.claude/session-xxx/tool-results/toolu_abc123.txt Preview (first 2.0 KB): [前 2000 字節(jié)內(nèi)容] ... </persisted-output>
為什么是"落盤"而不是"截斷"? 截斷意味著永久丟失——萬一 bug 恰好藏在第 500 行呢?落盤后,模型如果后續(xù)真需要那段內(nèi)容,可以用 Read 工具從磁盤把完整文件取回來。2KB 預(yù)覽則剛好夠它判斷"要不要去取"。
這是對很多筆記里"Snip 就是直接截斷"說法的修正:第一層的本質(zhì)是可恢復(fù)的落盤,而不是丟棄。這恰恰呼應(yīng)了整套系統(tǒng)"盡量不做不可逆操作"的取向。
L2 · 歷史裁剪(History Snip)
可以把這一層理解成對話腳手架的垃圾回收。會話里那些重復(fù)的 assistant 包裝、冗余的記賬信息、早就不影響下一步?jīng)Q策的舊片段,會在更重的壓縮啟動之前先被裁掉。它同樣是零成本,且只動"明顯沒用"的部分。
L3 · 微壓縮(MicroCompact)—— 回收舊工具輸出
這是最關(guān)鍵、也最精妙的一層。一句話定性:
MicroCompact 不是"總結(jié)歷史",而是"對舊工具輸出做垃圾回收"。

它專門清理哪些東西
微壓縮只回收"舊工具調(diào)用返回的大塊原始內(nèi)容",因為這些內(nèi)容有個共同點——丟了還能再拿回來:
| 工具類型 | 為什么適合清理 |
|---|---|
| Read | 文件之后可以重新讀取 |
| Bash / Shell | 舊日志通常很大,而且可能已經(jīng)過時 |
| Grep | 搜索結(jié)果可以重新生成 |
| Glob | 文件列表可以重新掃描 |
| WebSearch / WebFetch | 網(wǎng)頁內(nèi)容可以重新獲取 |
| Edit / Write | 修改結(jié)果通常已經(jīng)落到文件系統(tǒng)里 |
兩條互斥的路徑:時間型 vs 緩存型
微壓縮內(nèi)部分兩條路,互斥,按場景擇一:
microcompactMessages()
|
+-------------+--------------+
| |
長時間未交互? 緩存仍然有效?
| |
是 是
| |
Time-based Microcompact Cached Microcompact
(直接改本地消息內(nèi)容) (改用 cache_edits)
| |
冷緩存場景 熱緩存場景
| 對比項 | Time-based Microcompact | Cached Microcompact |
|---|---|---|
| 使用場景 | 長時間沒繼續(xù)對話,緩存大概率已過期 | 對話持續(xù)進(jìn)行,緩存仍然有效 |
| 是否修改本地消息 | 修改 | 不修改 |
| 如何刪除內(nèi)容 | 把舊結(jié)果替換為固定占位符 | 給 API 發(fā)送 cache_edits |
| 是否保留提示緩存 | 不需要(緩存已經(jīng)冷了) | 盡量保留緩存前綴 |
| 觸發(fā)依據(jù) | 時間間隔 | 工具數(shù)量閾值 |
| 優(yōu)先級 | 最高,觸發(fā)后直接返回 | 時間路徑未觸發(fā)時才執(zhí)行 |
Cached 路徑的巧思:它不改本地消息,而是給服務(wù)端發(fā)一條 cache_edits 指令,讓服務(wù)端在原緩存塊里"就地標(biāo)記刪除" ,從而不破壞寶貴的緩存前綴:
已有緩存: A B C D E F G
↓ 發(fā)送 cache_edits:基于原緩存,把 C 標(biāo)記為刪除
有效視圖: A B D E F G
類比:把它想成數(shù)據(jù)庫里的視圖(View) ——底層的消息數(shù)組(表)原封不動,但每次 API 請求看到的是一個被過濾、被精簡后的"投影"。
一個容易踩坑的追問:cache 里到底還在不在?
Q:微壓縮后,被標(biāo)記刪除的舊工具結(jié)果,cache 里還緩存著嗎?
A:會暫時同時存在于"服務(wù)端原始緩存塊"和"本地消息歷史"里,但在模型當(dāng)前使用的有效緩存視圖中已被排除,不再占用上下文。一句話——cache 里仍包含它,但模型有效上下文不包含它。
| 所在位置 | 是否還在 |
|---|---|
Claude Code 本地 messages | 還在 |
| 本地會話記錄 / transcript | 通常還在 |
| 服務(wù)端原始緩存塊 | 很可能暫時還在,直到 TTL 過期 |
| 模型當(dāng)前有效上下文 | 不在 |
| 后續(xù)請求的有效 token 統(tǒng)計 | 不再計入活動上下文 |
L4 · 上下文折疊(Context Collapse)—— 增量、可回滾
如果前幾層還不夠,進(jìn)入折疊層。它的定位和"自動壓縮"有本質(zhì)區(qū)別:
Context Collapse 是持續(xù)、增量式的上下文管理;AutoCompact 是達(dá)到閾值后對整段會話的一次集中式重寫。
折疊層最大的優(yōu)點是非破壞性、可回滾:原始消息從不刪除,生成的摘要存放在一個獨立的 collapse store,由 projectView() 在請求時把摘要"疊加"到原始消息之上。換句話說,模型看到的是折疊后的視圖,但底層數(shù)據(jù)還在——需要時能還原。
它大約在 ~90% 利用率開始提交(commit), ~95% 進(jìn)入更強(qiáng)的阻塞式處理。和自動壓縮的完整對比:
| 對比項 | Context Collapse | AutoCompact(自動壓縮) |
|---|---|---|
| 工作方式 | 持續(xù)、增量式管理 | 達(dá)到閾值后一次性執(zhí)行 |
| 處理粒度 | 更細(xì),逐步提交可保留信息 | 更粗,把舊上下文整體摘要化 |
| 觸發(fā)階段 | 約 90% 開始 commit,95% 進(jìn)入阻塞處理 | 有效窗口剩約 13K token 時觸發(fā) |
| 是否調(diào)用模型 | 通常由獨立 context agent 整理、提交 | 會調(diào)用模型生成摘要 |
| 對原消息的影響 | 維護(hù)獨立的 committed log,逐步折疊活動上下文 | 直接用"摘要 + 保留的近期消息"替換舊消息 |
| 中斷程度 | 偏增量、后臺式整理 | 類似一次 stop-the-world 壓縮 |
| 信息保留 | 傾向保存更細(xì)粒度的結(jié)構(gòu)化信息 | 主要依賴摘要質(zhì)量 |
| 能否與自動壓縮并存 | — | 開啟 Collapse 后,主動 AutoCompact 被禁用 |
一句話記住差異:
- AutoCompact:以"對話段落"為壓縮單位 → "上下文快滿了,把過去整體總結(jié)一次。"
- Context Collapse:以"事實、決定、狀態(tài)、產(chǎn)物"為提交單位 → "在上下文變滿的過程中,持續(xù)把有價值的信息提交出去,再逐步折疊已處理的活動上下文。"
L5 · 自動壓縮(AutoCompact)—— 唯一真正"有損"的一層
走到這里,才會真的調(diào)用一次 LLM 做摘要。這也是幻燈片上"有損不可逆"畫框的那一層。
觸發(fā)與閾值(以 200K 窗口為例)
- 保留約 20,000 token 給"寫摘要"本身用;
- 保留約 13,000 token 作為緩沖——所以當(dāng)有效窗口只剩約 13K 時觸發(fā);
- 另有 3,000 token 的手動壓縮緩沖:只剩這么多時,新請求會被阻塞,提示你手動
/compact。

調(diào)用鏈:一張圖看懂"該不該壓、怎么壓"
用戶發(fā)一條消息
│
▼
主對話循環(huán)(query loop,?? 推斷)
│
▼
autoCompactIfNeeded(messages, ...) ← 總指揮
│
▼
先查熔斷器:連續(xù)失敗 ≥ 3 次? ──是──? 直接放棄(防死循環(huán))
│否
▼
shouldAutoCompact(...) ← 只負(fù)責(zé)判斷「該不該」
│ 一連串"直接返回 false"的守衛(wèi)(遞歸 / 實驗開關(guān) / 功能未開)
│ 都過了 → 數(shù) token → calculateTokenWarningState → 返回 true/false
▼
返回 false → 不壓,結(jié)束
返回 true → 繼續(xù):
│
▼
trySessionMemoryCompaction(...) ← ① 優(yōu)先用「會話記憶」壓
│ 成功 → 清理 + 返回 wasCompacted:true
│ 失敗 / 不可用 ↓
▼
compactConversation(...) ← ② 退而用傳統(tǒng) LLM 摘要
│ 成功 → 清理 + consecutiveFailures:0 + 返回
└ 拋錯 → 失敗次數(shù) +1 + 返回 wasCompacted:false
幾個值得注意的設(shè)計:
- 熔斷器(circuit breaker) :連續(xù)失敗 3 次就停止再試,避免在異常情況下反復(fù)燒錢、卡死。
- 會話記憶優(yōu)先:在真正花錢做完整摘要之前,先嘗試用后臺預(yù)先攢好的"會話記憶"來壓——能省掉那次昂貴的模型調(diào)用。
- 摘要的提示詞強(qiáng)制保留三類信息:完成了什么、當(dāng)前狀態(tài)、做過的關(guān)鍵決策。壓縮后
messages只剩一條,但 Agent 知道"之前發(fā)生過什么",能接著干活。
還有一層"兜底中的兜底":反應(yīng)式壓縮(Reactive Compact)
再周密的估算也有失手的時候——某個工具結(jié)果意外巨大、多個系統(tǒng)提醒同時注入、token 估算偏低……一旦 API 直接返回 413(Prompt Too Long) ,Reactive Compact 會立刻觸發(fā):只保留最后 4 條消息、其余全部摘要,然后重試。一個 hasAttemptedReactiveCompact 守衛(wèi)保證它只嘗試一次,不會陷入重試死循環(huán);若一次仍不夠,錯誤才上拋給用戶。
這一層的哲學(xué)很值得玩味:與其追求完美的 token 計數(shù),不如接受估算的不精確,并提供一條穩(wěn)健的恢復(fù)路徑。
以及:手動 / Agent 主動壓縮
除了自動觸發(fā),壓縮也能被主動調(diào)用:你隨時可以 /compact(還能附帶指令,比如"重點保留認(rèn)證相關(guān)的工作");Agent 自己也可能在即將切換到一個完全不同的任務(wù)時,主動 compact 清空當(dāng)前上下文,為新任務(wù)騰地方。
四、那個繞不開的問題:有損不可逆,怎么破?
回到最初的靈魂拷問。先把結(jié)論說清楚:這條流水線里,前四層基本都是無損或可回滾的——落盤可 Read 回來、折疊可還原、微壓縮只是"視圖"過濾。真正不可逆的,只有第 5 層那次 LLM 摘要。 系統(tǒng)的全部努力,就是讓對話盡量止步于前幾層,把"有損摘要"壓到最少發(fā)生。
但只要它會發(fā)生,信息論上就一定有損耗。Claude Code 用兩件事來兜底這條根本局限:
- 跨會話的記憶系統(tǒng):壓縮管的是"當(dāng)前會話的臺面整潔度",而
CLAUDE.md/ auto memory 管的是"跨會話的長期知識"。每個會話從干凈上下文開始,記憶文件在開頭被讀入;auto memory 還能讓 Claude 根據(jù)你的糾正自動記筆記。兩者配合,Agent 既不被當(dāng)前對話淹沒,又不丟失重要的長期信息。 - 完整的原始檔案(transcript) :
.transcripts/里保存了壓縮前的全部原始對話。它是事后取證 / 回溯用的備份——Agent 平時不會主動去翻,但只要你需要,一切都在。
五、一個少有人提的隱患:注入指令會"穿透"壓縮
這是整套設(shè)計里一個容易被忽視、卻很值得警惕的點:壓縮流水線對所有內(nèi)容一視同仁。
摘要器(summarizer)會用同一條流水線處理"用戶指令"和"工具結(jié)果"。如果攻擊者在某個項目文件里埋了惡意指令,而模型恰好讀了那個文件——這些指令會一起被卷進(jìn)摘要,在壓縮后與正常上下文再也無法區(qū)分。那個讓摘要質(zhì)量很高的 <analysis> 草稿區(qū),也會忠實地把注入指令一并保留下來。流水線里沒有一個環(huán)節(jié)去區(qū)分"這是用戶說的"還是"這是模型讀到的文件里寫的"。
換句話說:prompt injection 不僅能影響當(dāng)前回答,還可能"固化"進(jìn)被壓縮后的長期上下文里。 做 Agent 安全的同學(xué),這是個值得單獨深挖的攻擊面。
六、寫在最后:從這套設(shè)計能學(xué)到什么
拋開 Claude Code 本身,這套壓縮流水線其實是一份很好的上下文工程范本:
- 分層降級,便宜的先上。 不要一上來就動用最貴、最有損的手段;先窮盡零成本、可恢復(fù)的清理。
- 能可逆就別不可逆。 落盤而非截斷、折疊而非刪除、視圖過濾而非物理移除——把"不可逆操作"壓到最后、最少。
- 接受不完美,但準(zhǔn)備好恢復(fù)路徑。 與其追求完美的 token 估算,不如做好 413 兜底。這是工程上的成熟,而非妥協(xié)。
- 結(jié)構(gòu)化地保留關(guān)鍵信息。 摘要強(qiáng)制保留"做了什么 / 當(dāng)前狀態(tài) / 關(guān)鍵決策",而不是自由發(fā)揮——固定模板能顯著降低"丟掉要緊細(xì)節(jié)"的概率。
- 壓縮 ≠ 記憶。 會話內(nèi)的整潔度和跨會話的長期知識,是兩套互補(bǔ)的系統(tǒng),別用一個去硬扛另一個的活。
想自己摸一遍?在真實會話里跑一次 /context,對照本文的閾值,看看 system prompt、tools、memory、messages 和那塊 autocompact 緩沖各占多少 token——把"理論"和"實測"對上號,比只讀源碼更有體感。
附:技術(shù)坐標(biāo)與說明
- 壓縮流水線源碼位于
src/services/compact/,約 3,960 行 TypeScript,橫跨 5 個文件。 - 關(guān)鍵函數(shù):
autoCompactIfNeeded/shouldAutoCompact/calculateTokenWarningState/trySessionMemoryCompaction/compactConversation/microcompactMessages/projectView。

以上就是一文拆解Claude Code中上下文壓縮機(jī)制的詳細(xì)內(nèi)容,更多關(guān)于claude code上下文壓縮的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章

Claude Code上下文智能監(jiān)控與自動處理完整指南
使用Claude Code進(jìn)行大型項目開發(fā)時,你一定遇到過這些問題:質(zhì)量下降,重復(fù)工作,強(qiáng)制中斷等,這不是Claude變笨了,而是上下文窗口被填滿了,所以本文給大家介紹了Claude C2026-06-18
Claude Code對接DeepSeek的完整使用教程(2026 最新版)
Claude Code 是 Anthropic 推出的終端級 AI 編程代理,本教程為大家詳細(xì)介紹了如何使用ClaudeCode對接DeepSeek,涵蓋安裝Node.js、ClaudeCode及配置DeepSeek模型的全流程,幫2026-06-26
Claude Code 接入 ClaudeAPI.com 教程:CC Switch 一鍵配置 API
這段文章詳細(xì)介紹了使用Claude API的工具時如ClaudeCode、Cline和Cursor時,開發(fā)者常遇到的API配置問題,以及如何通過ClaudeAPI.com提供的CCSwitch工具快速解決這些問題,感興2026-06-26
Claude Code配置本地Ollama模型或別的模型(Deepseek等)的實踐指南
本文詳細(xì)介紹了如何使用Claude Code Router將Ollama或DeepSeek等非Anthropic模型接入Claude Code,包括安裝、配置步驟及常見問題排查,通過協(xié)議轉(zhuǎn)換網(wǎng)關(guān),需要的朋友可以參考2026-06-26
VSCode+ClaudeCode+Deepseek的配置與聯(lián)動搭建
,本文詳細(xì)介紹了在VSCode中配置ClaudeCode插件并集成Deepseek AI模型的方法,該方案實現(xiàn)了編輯器與AI助手的無縫協(xié)同,適用于開發(fā)調(diào)試、文檔編寫等場景,感興趣的可以了解一下2026-06-26
Claude Code Skill的入門與進(jìn)階實踐指南
這段文章詳細(xì)介紹了如何使用Claude的Skill功能來自動化重復(fù)任務(wù),通過創(chuàng)建“任務(wù)說明書”來固定常用規(guī)則,減少重復(fù)溝通,提高工作效率,文章覆蓋了Skill的基本概念、應(yīng)用場景、2026-06-25
這篇文章主要為大家介紹了Claude Code CLI不同場景案例實操指南,涵蓋Python數(shù)據(jù)處理、JavaScript網(wǎng)頁交互、Java學(xué)生信息管理及Go語言HTTP接口開發(fā),提供全流程支持,降低開發(fā)2026-06-24
本文揭示了Claude Code工具的核心配置機(jī)制,指出其使用體驗主要取決于.claude/目錄下的配置文件而非模型本身,文章詳細(xì)解析了用戶級和項目級兩個.claude/目錄的結(jié)構(gòu)差異與作2026-06-24









