本文為《AI 輔助維運工程:從 Claude Code 機制到企業落地》系列第 3 篇。前一篇談了 Agent Loop,這一篇會進入這個系列裡技術密度較高的主題。如果你之前對「為什麼我的 context 會突然不夠用」、「/compact 到底何時該按」、「Claude 為什麼突然開始忘東西」這些問題感到困惑,這篇會把這些機制一起拆開來看。

為什麼需要整整一篇寫這件事

前一篇講了 Agent Loop —— 每一輪模型呼叫,都要把整段對話歷史送進 API。

這件事在對話短的時候沒人會在意。但當任務開始變長:

  • 一個跨 10 個檔案的重構
  • 一次完整的事件排查
  • 一份規格文件從草稿到定稿的對話

你會發現一個令人焦慮的現象:Claude Code 開始回應變慢、帳單變貴、有時候甚至主動告訴你「context 快滿了」

根本原因在於 context window 的物理上限。以目前主流的 Claude 模型來說:

  • 舊一代模型(例如 Sonnet 4、Sonnet 4.5):上限 200K tokens
  • 新一代模型(Opus 4.6 / 4.7、Sonnet 4.6):上限提升到 1M tokens,且自 2026 年 3 月起已 GA 無溢價

聽起來 1M 似乎什麼煩惱都沒了?實際沒這麼簡單 —— 稍後會有一節專門談「1M 不是萬靈丹」。這裡先建立一個共識:不論你用哪一代模型,壓縮管線的設計原理都一樣,只是觸發閾值不同

一個五小時的維運任務,搭配幾份被讀進 context 的大型設定檔,即使在 200K 窗口也會消耗得比你想像快。

如果 Claude Code 對這件事不做任何處理,用戶體驗會是這樣:

使用到 80%:正常 80% → 95%:越來越慢,因為每一輪都在傳巨量 context 95% → 100%:API 開始拒絕,因為超過模型上限 100% 之後:session 直接掛掉,你要從頭來過

所以 Claude Code 設計了一套系統,在你不察覺的情況下,持續清理 context 空間。這套系統有四層,每一層用不同策略,對 token 的衝擊從「幾乎零成本」到「呼叫一次 API 做摘要」不等。

這篇文章要做的,就是把這四層攤開來。


為什麼不能只用一種壓縮策略

你可能會想:為什麼不直接一招?等 context 滿了再叫模型摘要不就好?

這會有兩個問題。

問題一:摘要本身很貴。讓模型把 100K tokens 的對話摘成 20K tokens,這個動作就要再花一次 API call,還要花 output token 產生那 20K 摘要。如果每隔幾輪就做一次,光摘要就吃光你的預算。

問題二:過早摘要會丟失資訊。你不會希望一個還在處理中的子任務被摘成三句話 —— 模型會失去它需要的細節,回應品質直接掉下來。

合理的設計是:先用最便宜的手段釋放空間,真的不夠了再用昂貴的手段。這就是四層管線的核心思想。


四層管線的全景

在每一輪 Agent Loop 準備呼叫 API 之前,Claude Code 會依序跑過下面這些階段:

 ┌─────────────────────────────────────────────┐
   Pre-pipeline: Tool Result Budget              過大 tool result 的預先處理
 └─────────────────────────────────────────────┘
                      
                      
 ┌─────────────────────────────────────────────┐
   Layer 1: Snip Compact                          零成本修剪
 └─────────────────────────────────────────────┘
                      
                      
 ┌─────────────────────────────────────────────┐
   Layer 2: Micro Compact                         tool result 壓縮
 └─────────────────────────────────────────────┘
                      
                      
 ┌─────────────────────────────────────────────┐
   Layer 3: Context Collapse                      投射式壓縮
 └─────────────────────────────────────────────┘
                      
                      
 ┌─────────────────────────────────────────────┐
   Layer 4: Auto Compact                          API 摘要(最貴)
 └─────────────────────────────────────────────┘
                      
                      
           [送進 API 呼叫模型]

每一層都有它啟動的條件、代價、和清出空間的能力。我們一層一層拆。


Pre-pipeline:Tool Result Budget

這一層嚴格來說不是壓縮,是預防性措施

場景:Claude Code 執行了一個 Bash: cat /var/log/nginx/access.log,檔案有 80MB。如果這 80MB 整個塞進 context,後面的管線會瞬間爆炸。

Tool Result Budget 做的事就是在 tool 執行結果進入 context 之前,先判斷它的大小。超過門檻的,會被內容替換(content replacement)—— 把原始龐大結果換成一個摘要訊息,原始內容寫入磁碟保留,context 裡只放一個引用。

這個設計很精巧的一點是:替換狀態跨壓縮持久化。也就是說,即使後面 Layer 4 做了大摘要,這個「被替換過的 tool result」的記憶不會丟失,模型還是知道「剛才跑了那個指令,結果很大被外存了」。

對你的影響:你不太需要關心這一層,它自動運作。但知道它存在有一個好處 —— 當你看到 tool result 被標記「truncated」時,那不是 bug,是這個機制在保護你。


Layer 1:Snip Compact(零成本修剪)

接下來進入壓縮管線的第一層,也是最便宜的一層。

Snip Compact 做的事情可以用一句話概括:把舊的、明顯可以丟的片段直接刪掉

什麼叫「明顯可以丟」?典型的例子:

  • 很多輪之前的一個 Bash: ls 指令和它的輸出
  • 已經被後續行為覆蓋的舊檔案讀取結果
  • 使用者已經明確說「這個不用了」的段落

這一層的關鍵特徵是 「零成本」 —— 它不呼叫 API、不做推理、只是按規則把某些 message 從 context 移除。計算開銷幾乎為零,釋放的空間卻可能非常可觀。

類比:就像你整理辦公桌時,先把明顯沒用的廢紙丟掉,還沒開始動需要判斷的東西。

Snip Compact 在每一輪都會跑,永遠是第一道防線。你幾乎察覺不到它在作用,但它默默為你省了大量空間。


Layer 2:Micro Compact(tool result 壓縮)

第二層開始有點技巧了。

Micro Compact 聚焦在處理 tool result。上一層刪了能直接丟的,但有些 tool result 還有價值 —— 模型可能之後要引用 —— 只是詳細程度過頭了

舉例:你讓 Claude Code 讀了一個 500 行的設定檔,它讀完後做了分析,已經從裡面抽出重點。兩輪之後,完整的 500 行內容還佔著 context。這時候 Micro Compact 會做的事情是:

保留這個 tool result 的「殼」(它的 tool_use_id、它是哪個 tool、執行成功與否),但把詳細的內容替換成一個摘要

關鍵設計:Micro Compact 以 tool_use_id 為單位運作,不拆解內容、不重組訊息結構。這讓它可以跟其他層安全組合 —— 它的處理不會影響訊息格式的完整性。

相較於 Layer 1:Layer 1 是「整段丟」,Layer 2 是「保留外層、壓縮內容」。Layer 2 的成本比 Layer 1 高一點(要產生摘要),但保留了可追溯性 —— 模型仍然知道「我剛才讀過某個檔案」。


Layer 3:Context Collapse(投射式壓縮)

這一層的設計最巧妙,也最難懂。

一般壓縮的做法是「修改 context 本身」—— 刪掉某些東西、取代某些內容。但這有個風險:修改是不可逆的。你丟掉的東西,就真的丟了。

Context Collapse 採用完全不同的思路:不修改底層的訊息歷史,而是建立一個「投射視圖」(projective view)。

用一個比喻:

想像你的對話歷史是一棟三層樓的書櫃,整整齊齊放著所有 message。 傳統壓縮是把某幾本書從書櫃搬走、直接丟掉。 Context Collapse 是在書櫃前面加一片毛玻璃 —— 書櫃本身沒變,但從外面看,某些書被遮住了,只看得到一個整體的輪廓。

這個設計的好處是:

  1. 可還原:必要時可以把毛玻璃拿掉,完整歷史還在
  2. 適合長 session:即使做了多次 collapse,底層訊息仍然保存
  3. 給模型一個「精華版」:模型看到的是投射後的版本,而不是原始的完整對話

Context Collapse 的觸發有兩個門檻:

  • 到達 90% 時:開始做 collapse commit(把舊的 message 封存進 collapse log)
  • 到達 95% 時:進入 blocking 模式,禁止新的 tool 執行,避免 context 爆炸

Context Collapse 是一個功能開關(feature flag),不是所有版本的 Claude Code 都預設啟用。如果啟用了,它會取代 Layer 4 的工作(兩者互斥)。

對你的影響:如果你的版本啟用了這層,你會發現長 session 的品質比舊版本明顯穩定。但如果沒啟用,接下來的 Layer 4 就是最後防線。


Layer 4:Auto Compact(最重的手段)

前三層都還沒能把空間清出來夠用?好,Auto Compact 登場。

這是最貴、也最強的一層。它的做法是:

  1. 開一個分叉的 agent(forked agent)
  2. 這個 agent 的任務就是:把到目前為止的對話歷史,摘要成一段簡短的文字
  3. 把原本的對話歷史替換成這段摘要
  4. 繼續跑主 session

本質上,這是花一次 API call 去換 context 空間。成本高,但效果也最顯著 —— 幾十萬 tokens 可以瞬間被壓成幾千 tokens。

閾值的數學

Auto Compact 什麼時候觸發?這有明確的公式:

effective_window = context_window - 20,000  ← 保留給摘要輸出的空間
threshold        = effective_window - 13,000  ← 再留一個緩衝

套用到不同的 context window:

200K 窗口(Sonnet 4 / 4.5 等舊一代模型):

effective_window = 200,000 - 20,000 = 180,000
threshold        = 180,000 - 13,000 = 167,000   ← 約 83.5%

意思是:當 context 用到 167K 左右時,Auto Compact 自動觸發。

1M 窗口(Sonnet 4.6、Opus 4.6 / 4.7):

effective_window = 1,000,000 - 20,000 = 980,000
threshold        = 980,000 - 13,000 = 967,000   ← 約 96.7%

也就是說,1M 模型要撐到 967K 才會觸發 Auto Compact。實務上大多數 session 根本打不到這個數字,Auto Compact 在 1M 模型上幾乎不會被自動觸發。

為什麼都留 20K 給摘要?因為摘要本身也是 output tokens,也要在 context 裡佔位置。如果不預留,摘要還沒生出來就超標了。這個設計不隨 window 大小變。

要查自己目前的 window 大小,在 Claude Code 裡輸入 /context 指令,它會回傳 Xk/200kXk/1000k 的格式告訴你

互斥規則

Auto Compact 有幾個情況不會觸發,原因都很務實:

情境為什麼不觸發
正在做 /compact 或 session memory 操作避免遞迴(本身就是 compact agent)
Context Collapse 已啟用Layer 3 已經在做這件事
Reactive Compact 模式等 API 真的回傳「context 太長」錯誤才處理
連續失敗超過 3 次Circuit breaker,避免無限重試

那個 3 次連續失敗 circuit breaker 很值得一提 —— 它的存在是因為沒這個機制的時候,曾經有 session 連續失敗 50 多次,浪費了大量 API 呼叫。工程設計常常是這樣:一個看似簡單的保護機制,背後都是血淚史。

Session Memory:被忽略的精巧設計

Layer 4 有個優先嘗試的輕量版,叫 Session Memory Compaction

相較於「開一個 agent 做全摘要」,Session Memory 更像「智慧修剪」—— 它不重新生成內容,而是有策略地挑選哪些 message 保留、哪些捨棄,試圖在不花一次 API call 的情況下達到目標。

觸發順序是:Session Memory 先試 → 失敗才走 full compact。這又是一個「便宜的先試,貴的最後上」的設計。


為什麼這樣排序:一個簡單的經濟學

回頭看這四層,你會發現它們的排列是有嚴格邏輯的:

層級成本空間釋放量資訊損失
Pre-pipeline視 tool result 大小最小(可還原)
Layer 1 Snip接近零小到中小(丟的是舊東西)
Layer 2 Micro小(保留摘要)
Layer 3 Collapse最小(投射式)
Layer 4 Auto最大中至大(看摘要品質)

從成本最低的開始試,能釋放多少算多少;前面的不夠用,才動用更貴的手段

這就是這套系統背後的思路:對我而言,把 context 當成需要主動管理的資源,比交給運氣靈光來得安心一些


1M 不是萬靈丹:你該知道的真相

看到這裡你可能想:「那我只要用 1M 模型,這四層壓縮我幾乎不用管了?」

技術上成立,但實務上要打一個大問號

模型的 recall 能力會隨 context 膨脹衰減

window 變大 ≠ 模型能好好使用全部空間。

Anthropic 公佈的 MRCR(multi-needle retrieval)測試結果:

模型256K 時的 recall1M 時的 recall
Opus 4.6 / 4.793%~76–78%
Sonnet 4.5(舊款)18.5%(不建議用)
Sonnet 4.6未公佈未公佈

白話翻譯:你塞越多 context 進去,模型忘記東西的機率越高。即使技術上 window 能裝,模型的注意力會被稀釋。

實務上多數 session 根本用不到 1M

根據社群的實測觀察,大多數 Claude Code session 峰值落在 80K–120K tokens。真正需要用到 500K 以上的場景不多,通常是:

  • 跨多個大型 codebase 的全域重構
  • 一次讀入幾十份長篇文件做綜合分析
  • 超長時間的自主 agent 任務(連續跑幾小時)

日常維運、除錯、寫規格這類工作,200K 都綽綽有餘。

1M 模型最實際的價值:降低 compact 頻率,不是撐更久

比較合理的用法不是「把 1M 塞滿」,而是:

  • 在 80K–150K 的正常使用範圍內,讓你不用頻繁擔心壓縮觸發
  • 遇到偶發的大型任務,不用馬上切 session 或 /compact
  • 多一點彈性去讀幾個額外的參考檔案

換句話說,1M 是把「context 緊張」這件事推到後景,而不是讓你可以永遠不管它。

如果你在用 Pro 方案

Max / Team / Enterprise 方案是自動啟用 1M。Pro 方案需要手動執行 /extra-usage 才會開啟 —— 這是 Anthropic 有意識的設計,讓付費層級自然區分。

如果你在 Pro 而沒跑過 /extra-usage,你現在用的是 200K,不是 1M。可以用 /context 確認當下狀態。

環境變數可以強制關閉

少數場景你可能想強制只用 200K(例如為了控制成本、或在舊模型間切換時保持一致),可以設:

export CLAUDE_CODE_DISABLE_1M_CONTEXT=1

設了之後,model picker 不會出現 1M 選項。適合團隊統一環境配置時使用。


使用者能做什麼:主動 vs 被動

理論講完,來講實務。作為使用者,你不用去控制這四層(它們自動運作),但你有主動權在幾個關鍵時刻可以介入。

時機一:子任務結束時,主動 /compact

很多人以為 /compact 只在 context 快滿時才要用。這是我自己一開始也誤解的地方。

更聰明的用法是:每次完成一個子任務後,主動執行 /compact

為什麼?因為自動觸發永遠是被動的 —— 要等到真的快滿了才動。而你完成一個子任務時,你最知道:

  • 哪些前面的細節可以丟(「已經完成,結果正常」)
  • 哪些需要保留(「這個決策後面還要用」)
  • 下一個子任務需要什麼 context 基礎

這時候主動 /compact 並帶上 custom instruction,可能會比自動摘要更貼近你的需求。

範例:

/compact 重點保留:檔案修改清單、錯誤修正紀錄、未完成的 TODO。
可以丟掉:一般探索性的 bash 輸出、已經確認正確的讀檔結果。

時機二:切 session,不要依賴壓縮

壓縮再強,也比不上「開新 session」乾淨。

當你要換一個完全不同的任務(例如從「debug production」切到「寫下週的週報」),最好的做法不是在同一個 session 裡繼續,而是:

  1. 把當前進度寫進一個檔案(例如 PROJECT_STATUS.md)
  2. 結束當前 session
  3. 開新的,從頭讀那個檔案作為起點

這比指望四層壓縮都要來得乾淨一些。

時機三:知道何時該停

有一個啟示來自前面的 3 次失敗 circuit breaker:如果 Claude Code 開始頻繁觸發 Auto Compact,那是警訊

頻繁觸發代表你的任務規模已經超過 session 能舒服處理的範圍。這時候該做的不是「讓它繼續撐」,而是:

  • 切分任務(拆成幾個小任務分 session 做)
  • 檢查你的 CLAUDE.md 是不是寫得太長
  • 檢查你是不是讀了一堆其實不需要的檔案進來

長 session 的壓力累積是真實存在的。管理 context 的最好方法,是從一開始就不要讓它膨脹


幾個容易踩的雷

雷一:以為 /compact 是魔法按鈕

/compact 會丟資訊。即使你寫了 custom instruction,摘要還是會漏細節。該備份的關鍵結論,請寫進檔案。

雷二:在重要決策前觸發壓縮

如果 Claude Code 正在做一個關鍵判斷(例如「要刪哪些檔案」),不要在這時候手動 /compact —— 它可能把剛才的分析摘掉了,決策品質會受影響。等決策完成再壓縮。

雷三:盲目追求「context 撐越久越好」

有些人把「能不能不用壓縮撐完一個 8 小時 session」當成成就。這是誤解。能把任務切成小塊分段做,每段乾淨結束,才是更好的工程實踐


一個我自己偏好的心態

四層壓縮聽起來很複雜,但它主要提醒一個觀念:

Context 是工程資源,不是取之不盡的倉庫

你用任何工具時都有資源觀念 —— 記憶體、磁碟、網路頻寬都有上限。AI 助理的 context 也一樣,只是它太新,大家還沒建立習慣。

有這個觀念之後,我自己覺得一些選擇變得比較自然:

  • 不會寫 10 頁的 CLAUDE.md
  • 不會把整個 codebase 丟進對話
  • 會主動切 session
  • 會在關鍵時刻 /compact
  • 會把結論寫進檔案,而不是記在對話裡

這些習慣累積起來,我覺得是「比較熟練使用 Claude Code」跟「一直踩雷」之間一個比較明顯的分野。


下一篇預告

接下來第 4 篇要談另一個常被混淆的主題:Sub-agent 與 Agent Team

這兩個概念一直被工程師當成同一件事,實際上它們解決的是完全不同的問題 —— 一個是「怎麼讓 AI 跑得更快」,另一個是「怎麼讓 AI 聽話、有紀律」。

下一篇我們釐清這個誤會,並示範它們怎麼搭配使用。


本篇重點整理

  • Claude Code 的 context 管理不是黑盒,是一套四層的壓縮管線,從便宜到昂貴依序嘗試
  • Pre-pipeline:處理過大的 tool result,防止污染整個管線
  • Layer 1 Snip:零成本修剪,刪掉明顯可丟的舊片段
  • Layer 2 Micro:以 tool_use_id 為單位壓縮 tool result,保留外殼丟掉內容
  • Layer 3 Collapse:投射式壓縮,建立 view 而不修改底層 —— 最巧妙的一層
  • Layer 4 Auto Compact:最貴的手段,用一次 API call 換大量空間;閾值約 window 的 83.5%(200K)或 96.7%(1M)
  • Session Memory:Layer 4 會先試的輕量版,不呼叫 API 就能做修剪
  • 1M 不是萬靈丹:window 變大但模型 recall 能力會衰減,實務多數 session 根本用不到 1M
  • 主動介入時機:子任務結束時 /compact、切 session 而不硬撐、知道何時該拆任務
  • 核心觀念:把 context 當工程資源管理,而不是賭運氣

本文作者:鄧景仁 (Scott Teng) | 資訊服務業 infra 工程師,專注於 Azure / Linux / 安全維運。如需討論可聯繫 st333117@gmail.com

本系列所有內容為個人學習與實務心得整理,不代表任職機構立場。本文對 Claude Code 內部機制的描述,基於社群對 Claude Code 的公開分析材料與筆者實務觀察,並非 Anthropic 官方文件。具體閾值與行為可能隨版本演進。