<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Context Management on AI 輔助維運工程</title>
    <link>https://eeit.github.io/ai-devops-blog/tags/context-management/</link>
    <description>Recent content in Context Management on AI 輔助維運工程</description>
    <generator>Hugo</generator>
    <language>zh-tw</language>
    <copyright>2026 鄧景仁 (Scott Teng) · 授權：CC BY-NC 4.0</copyright>
    <lastBuildDate>Tue, 14 Apr 2026 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://eeit.github.io/ai-devops-blog/tags/context-management/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>四層 Context 壓縮:200K 窗口的真實調度</title>
      <link>https://eeit.github.io/ai-devops-blog/posts/03-context-compression/</link>
      <pubDate>Tue, 14 Apr 2026 00:00:00 +0000</pubDate>
      <guid>https://eeit.github.io/ai-devops-blog/posts/03-context-compression/</guid>
      <source url="https://eeit.github.io/ai-devops-blog/posts/03-context-compression/">AI 輔助維運工程</source>
      <description>拆解 Claude Code 中我覺得比較精巧、也容易被誤解的設計 —— 四層 Context 壓縮管線。搞懂 context 何時被壓縮、如何決定哪一層啟動,以及手動 /compact 該在什麼時機使用。</description><content:encoded><![CDATA[<blockquote>
<p>本文為《AI 輔助維運工程:從 Claude Code 機制到企業落地》系列第 3 篇。前一篇談了 Agent Loop,這一篇會進入<strong>這個系列裡技術密度較高的主題</strong>。如果你之前對「為什麼我的 context 會突然不夠用」、「<code>/compact</code> 到底何時該按」、「Claude 為什麼突然開始忘東西」這些問題感到困惑,這篇會把這些機制一起拆開來看。</p>
</blockquote>
<h2 id="為什麼需要整整一篇寫這件事">為什麼需要整整一篇寫這件事</h2>
<p>前一篇講了 Agent Loop —— 每一輪模型呼叫,都要把<strong>整段對話歷史</strong>送進 API。</p>
<p>這件事在對話短的時候沒人會在意。但當任務開始變長:</p>
<ul>
<li>一個跨 10 個檔案的重構</li>
<li>一次完整的事件排查</li>
<li>一份規格文件從草稿到定稿的對話</li>
</ul>
<p>你會發現一個令人焦慮的現象:<strong>Claude Code 開始回應變慢、帳單變貴、有時候甚至主動告訴你「context 快滿了」</strong>。</p>
<p>根本原因在於 context window 的物理上限。以目前主流的 Claude 模型來說:</p>
<ul>
<li><strong>舊一代模型</strong>(例如 Sonnet 4、Sonnet 4.5):上限 <strong>200K tokens</strong></li>
<li><strong>新一代模型</strong>(Opus 4.6 / 4.7、Sonnet 4.6):上限提升到 <strong>1M tokens</strong>,且自 2026 年 3 月起已 GA 無溢價</li>
</ul>
<p>聽起來 1M 似乎什麼煩惱都沒了?實際沒這麼簡單 —— 稍後會有一節專門談「1M 不是萬靈丹」。這裡先建立一個共識:<strong>不論你用哪一代模型,壓縮管線的設計原理都一樣,只是觸發閾值不同</strong>。</p>
<p>一個五小時的維運任務,搭配幾份被讀進 context 的大型設定檔,即使在 200K 窗口也會消耗得比你想像快。</p>
<p>如果 Claude Code 對這件事不做任何處理,用戶體驗會是這樣:</p>
<blockquote>
<p>使用到 80%:正常
80% → 95%:越來越慢,因為每一輪都在傳巨量 context
95% → 100%:API 開始拒絕,因為超過模型上限
100% 之後:session 直接掛掉,你要從頭來過</p>
</blockquote>
<p><strong>所以 Claude Code 設計了一套系統,在你不察覺的情況下,持續清理 context 空間</strong>。這套系統有四層,每一層用不同策略,對 token 的衝擊從「幾乎零成本」到「呼叫一次 API 做摘要」不等。</p>
<p>這篇文章要做的,就是把這四層攤開來。</p>
<hr>
<h2 id="為什麼不能只用一種壓縮策略">為什麼不能只用一種壓縮策略</h2>
<p>你可能會想:為什麼不直接一招?等 context 滿了再叫模型摘要不就好?</p>
<p>這會有兩個問題。</p>
<p><strong>問題一:摘要本身很貴</strong>。讓模型把 100K tokens 的對話摘成 20K tokens,這個動作就要再花一次 API call,還要花 output token 產生那 20K 摘要。如果每隔幾輪就做一次,光摘要就吃光你的預算。</p>
<p><strong>問題二:過早摘要會丟失資訊</strong>。你不會希望一個還在處理中的子任務被摘成三句話 —— 模型會失去它需要的細節,回應品質直接掉下來。</p>
<p>合理的設計是:<strong>先用最便宜的手段釋放空間,真的不夠了再用昂貴的手段</strong>。這就是四層管線的核心思想。</p>
<hr>
<h2 id="四層管線的全景">四層管線的全景</h2>
<p>在每一輪 Agent Loop 準備呼叫 API 之前,Claude Code 會依序跑過下面這些階段:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"> <span class="err">┌─────────────────────────────────────────────┐</span>
</span></span><span class="line"><span class="cl"> <span class="err">│</span>  <span class="n">Pre</span><span class="o">-</span><span class="n">pipeline</span><span class="p">:</span> <span class="n">Tool</span> <span class="n">Result</span> <span class="n">Budget</span>           <span class="err">│</span>  <span class="err">←</span> <span class="err">過大</span> <span class="k">tool</span> <span class="n">result</span> <span class="err">的預先處理</span>
</span></span><span class="line"><span class="cl"> <span class="err">└─────────────────────────────────────────────┘</span>
</span></span><span class="line"><span class="cl">                      <span class="err">│</span>
</span></span><span class="line"><span class="cl">                      <span class="err">▼</span>
</span></span><span class="line"><span class="cl"> <span class="err">┌─────────────────────────────────────────────┐</span>
</span></span><span class="line"><span class="cl"> <span class="err">│</span>  <span class="n">Layer</span> <span class="mi">1</span><span class="p">:</span> <span class="n">Snip</span> <span class="n">Compact</span>                       <span class="err">│</span>  <span class="err">←</span> <span class="err">零成本修剪</span>
</span></span><span class="line"><span class="cl"> <span class="err">└─────────────────────────────────────────────┘</span>
</span></span><span class="line"><span class="cl">                      <span class="err">│</span>
</span></span><span class="line"><span class="cl">                      <span class="err">▼</span>
</span></span><span class="line"><span class="cl"> <span class="err">┌─────────────────────────────────────────────┐</span>
</span></span><span class="line"><span class="cl"> <span class="err">│</span>  <span class="n">Layer</span> <span class="mi">2</span><span class="p">:</span> <span class="n">Micro</span> <span class="n">Compact</span>                      <span class="err">│</span>  <span class="err">←</span> <span class="k">tool</span> <span class="n">result</span> <span class="err">壓縮</span>
</span></span><span class="line"><span class="cl"> <span class="err">└─────────────────────────────────────────────┘</span>
</span></span><span class="line"><span class="cl">                      <span class="err">│</span>
</span></span><span class="line"><span class="cl">                      <span class="err">▼</span>
</span></span><span class="line"><span class="cl"> <span class="err">┌─────────────────────────────────────────────┐</span>
</span></span><span class="line"><span class="cl"> <span class="err">│</span>  <span class="n">Layer</span> <span class="mi">3</span><span class="p">:</span> <span class="n">Context</span> <span class="n">Collapse</span>                   <span class="err">│</span>  <span class="err">←</span> <span class="err">投射式壓縮</span>
</span></span><span class="line"><span class="cl"> <span class="err">└─────────────────────────────────────────────┘</span>
</span></span><span class="line"><span class="cl">                      <span class="err">│</span>
</span></span><span class="line"><span class="cl">                      <span class="err">▼</span>
</span></span><span class="line"><span class="cl"> <span class="err">┌─────────────────────────────────────────────┐</span>
</span></span><span class="line"><span class="cl"> <span class="err">│</span>  <span class="n">Layer</span> <span class="mi">4</span><span class="p">:</span> <span class="n">Auto</span> <span class="n">Compact</span>                       <span class="err">│</span>  <span class="err">←</span> <span class="n">API</span> <span class="err">摘要</span><span class="p">(</span><span class="err">最貴</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="err">└─────────────────────────────────────────────┘</span>
</span></span><span class="line"><span class="cl">                      <span class="err">│</span>
</span></span><span class="line"><span class="cl">                      <span class="err">▼</span>
</span></span><span class="line"><span class="cl">           <span class="p">[</span><span class="err">送進</span> <span class="n">API</span> <span class="err">呼叫模型</span><span class="p">]</span>
</span></span></code></pre></div><p>每一層都有它啟動的條件、代價、和清出空間的能力。我們一層一層拆。</p>
<hr>
<h2 id="pre-pipelinetool-result-budget">Pre-pipeline:Tool Result Budget</h2>
<p>這一層嚴格來說不是壓縮,是<strong>預防性措施</strong>。</p>
<p>場景:Claude Code 執行了一個 <code>Bash: cat /var/log/nginx/access.log</code>,檔案有 80MB。如果這 80MB 整個塞進 context,後面的管線會瞬間爆炸。</p>
<p>Tool Result Budget 做的事就是在 tool 執行結果進入 context 之前,先判斷它的大小。超過門檻的,會被<strong>內容替換</strong>(content replacement)—— 把原始龐大結果換成一個摘要訊息,原始內容寫入磁碟保留,context 裡只放一個引用。</p>
<p>這個設計很精巧的一點是:<strong>替換狀態跨壓縮持久化</strong>。也就是說,即使後面 Layer 4 做了大摘要,這個「被替換過的 tool result」的記憶不會丟失,模型還是知道「剛才跑了那個指令,結果很大被外存了」。</p>
<p><strong>對你的影響</strong>:你不太需要關心這一層,它自動運作。但知道它存在有一個好處 —— 當你看到 tool result 被標記「truncated」時,那不是 bug,是這個機制在保護你。</p>
<hr>
<h2 id="layer-1snip-compact零成本修剪">Layer 1:Snip Compact(零成本修剪)</h2>
<p>接下來進入壓縮管線的第一層,也是最便宜的一層。</p>
<p>Snip Compact 做的事情可以用一句話概括:<strong>把舊的、明顯可以丟的片段直接刪掉</strong>。</p>
<p>什麼叫「明顯可以丟」?典型的例子:</p>
<ul>
<li>很多輪之前的一個 <code>Bash: ls</code> 指令和它的輸出</li>
<li>已經被後續行為覆蓋的舊檔案讀取結果</li>
<li>使用者已經明確說「這個不用了」的段落</li>
</ul>
<p>這一層的關鍵特徵是 <strong>「零成本」</strong> —— 它不呼叫 API、不做推理、只是按規則把某些 message 從 context 移除。計算開銷幾乎為零,釋放的空間卻可能非常可觀。</p>
<p><strong>類比</strong>:就像你整理辦公桌時,先把明顯沒用的廢紙丟掉,還沒開始動需要判斷的東西。</p>
<p>Snip Compact 在每一輪都會跑,永遠是第一道防線。你幾乎察覺不到它在作用,但它默默為你省了大量空間。</p>
<hr>
<h2 id="layer-2micro-compacttool-result-壓縮">Layer 2:Micro Compact(tool result 壓縮)</h2>
<p>第二層開始有點技巧了。</p>
<p>Micro Compact 聚焦在<strong>處理 tool result</strong>。上一層刪了能直接丟的,但有些 tool result 還有價值 —— 模型可能之後要引用 —— 只是<strong>詳細程度過頭了</strong>。</p>
<p>舉例:你讓 Claude Code 讀了一個 500 行的設定檔,它讀完後做了分析,已經從裡面抽出重點。兩輪之後,完整的 500 行內容還佔著 context。這時候 Micro Compact 會做的事情是:</p>
<p><strong>保留這個 tool result 的「殼」(它的 tool_use_id、它是哪個 tool、執行成功與否),但把詳細的內容替換成一個摘要</strong>。</p>
<p>關鍵設計:Micro Compact 以 <strong>tool_use_id</strong> 為單位運作,不拆解內容、不重組訊息結構。這讓它可以跟其他層安全組合 —— 它的處理不會影響訊息格式的完整性。</p>
<p><strong>相較於 Layer 1</strong>:Layer 1 是「整段丟」,Layer 2 是「保留外層、壓縮內容」。Layer 2 的成本比 Layer 1 高一點(要產生摘要),但保留了可追溯性 —— 模型仍然知道「我剛才讀過某個檔案」。</p>
<hr>
<h2 id="layer-3context-collapse投射式壓縮">Layer 3:Context Collapse(投射式壓縮)</h2>
<p>這一層的設計最巧妙,也最難懂。</p>
<p>一般壓縮的做法是「<strong>修改 context 本身</strong>」—— 刪掉某些東西、取代某些內容。但這有個風險:修改是不可逆的。你丟掉的東西,就真的丟了。</p>
<p>Context Collapse 採用完全不同的思路:<strong>不修改底層的訊息歷史,而是建立一個「投射視圖」</strong>(projective view)。</p>
<p>用一個比喻:</p>
<blockquote>
<p>想像你的對話歷史是一棟三層樓的書櫃,整整齊齊放著所有 message。
傳統壓縮是把某幾本書從書櫃搬走、直接丟掉。
Context Collapse 是<strong>在書櫃前面加一片毛玻璃</strong> —— 書櫃本身沒變,但從外面看,某些書被遮住了,只看得到一個整體的輪廓。</p>
</blockquote>
<p>這個設計的好處是:</p>
<ol>
<li><strong>可還原</strong>:必要時可以把毛玻璃拿掉,完整歷史還在</li>
<li><strong>適合長 session</strong>:即使做了多次 collapse,底層訊息仍然保存</li>
<li><strong>給模型一個「精華版」</strong>:模型看到的是投射後的版本,而不是原始的完整對話</li>
</ol>
<p><strong>Context Collapse 的觸發有兩個門檻</strong>:</p>
<ul>
<li>到達 <strong>90%</strong> 時:開始做 collapse commit(把舊的 message 封存進 collapse log)</li>
<li>到達 <strong>95%</strong> 時:進入 blocking 模式,禁止新的 tool 執行,避免 context 爆炸</li>
</ul>
<p>Context Collapse 是一個<strong>功能開關</strong>(feature flag),不是所有版本的 Claude Code 都預設啟用。如果啟用了,它會取代 Layer 4 的工作(兩者互斥)。</p>
<p><strong>對你的影響</strong>:如果你的版本啟用了這層,你會發現長 session 的品質比舊版本明顯穩定。但如果沒啟用,接下來的 Layer 4 就是最後防線。</p>
<hr>
<h2 id="layer-4auto-compact最重的手段">Layer 4:Auto Compact(最重的手段)</h2>
<p>前三層都還沒能把空間清出來夠用?好,Auto Compact 登場。</p>
<p>這是<strong>最貴、也最強</strong>的一層。它的做法是:</p>
<ol>
<li>開一個<strong>分叉的 agent</strong>(forked agent)</li>
<li>這個 agent 的任務就是:把到目前為止的對話歷史,摘要成一段簡短的文字</li>
<li>把原本的對話歷史替換成這段摘要</li>
<li>繼續跑主 session</li>
</ol>
<p>本質上,這是<strong>花一次 API call 去換 context 空間</strong>。成本高,但效果也最顯著 —— 幾十萬 tokens 可以瞬間被壓成幾千 tokens。</p>
<h3 id="閾值的數學">閾值的數學</h3>
<p>Auto Compact 什麼時候觸發?這有明確的公式:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">effective_window = context_window - 20,000  ← 保留給摘要輸出的空間
</span></span><span class="line"><span class="cl">threshold        = effective_window - 13,000  ← 再留一個緩衝
</span></span></code></pre></div><p>套用到不同的 context window:</p>
<p><strong>200K 窗口(Sonnet 4 / 4.5 等舊一代模型)</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">effective_window = 200,000 - 20,000 = 180,000
</span></span><span class="line"><span class="cl">threshold        = 180,000 - 13,000 = 167,000   ← 約 83.5%
</span></span></code></pre></div><p>意思是:當 context 用到 167K 左右時,Auto Compact 自動觸發。</p>
<p><strong>1M 窗口(Sonnet 4.6、Opus 4.6 / 4.7)</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">effective_window = 1,000,000 - 20,000 = 980,000
</span></span><span class="line"><span class="cl">threshold        = 980,000 - 13,000 = 967,000   ← 約 96.7%
</span></span></code></pre></div><p>也就是說,<strong>1M 模型要撐到 967K 才會觸發 Auto Compact</strong>。實務上大多數 session 根本打不到這個數字,Auto Compact 在 1M 模型上幾乎不會被自動觸發。</p>
<p>為什麼都留 20K 給摘要?因為摘要本身也是 output tokens,也要在 context 裡佔位置。如果不預留,摘要還沒生出來就超標了。這個設計不隨 window 大小變。</p>
<p><strong>要查自己目前的 window 大小,在 Claude Code 裡輸入 <code>/context</code> 指令,它會回傳 <code>Xk/200k</code> 或 <code>Xk/1000k</code> 的格式告訴你</strong>。</p>
<h3 id="互斥規則">互斥規則</h3>
<p>Auto Compact 有幾個情況<strong>不會</strong>觸發,原因都很務實:</p>
<table>
  <thead>
      <tr>
          <th>情境</th>
          <th>為什麼不觸發</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>正在做 <code>/compact</code> 或 session memory 操作</td>
          <td>避免遞迴(本身就是 compact agent)</td>
      </tr>
      <tr>
          <td>Context Collapse 已啟用</td>
          <td>Layer 3 已經在做這件事</td>
      </tr>
      <tr>
          <td>Reactive Compact 模式</td>
          <td>等 API 真的回傳「context 太長」錯誤才處理</td>
      </tr>
      <tr>
          <td>連續失敗超過 3 次</td>
          <td>Circuit breaker,避免無限重試</td>
      </tr>
  </tbody>
</table>
<p>那個 <strong>3 次連續失敗 circuit breaker</strong> 很值得一提 —— 它的存在是因為沒這個機制的時候,曾經有 session 連續失敗 50 多次,浪費了大量 API 呼叫。工程設計常常是這樣:一個看似簡單的保護機制,背後都是血淚史。</p>
<h3 id="session-memory被忽略的精巧設計">Session Memory:被忽略的精巧設計</h3>
<p>Layer 4 有個優先嘗試的輕量版,叫 <strong>Session Memory Compaction</strong>。</p>
<p>相較於「開一個 agent 做全摘要」,Session Memory 更像「<strong>智慧修剪</strong>」—— 它不重新生成內容,而是有策略地挑選哪些 message 保留、哪些捨棄,試圖在<strong>不花一次 API call</strong> 的情況下達到目標。</p>
<p>觸發順序是:<strong>Session Memory 先試 → 失敗才走 full compact</strong>。這又是一個「便宜的先試,貴的最後上」的設計。</p>
<hr>
<h2 id="為什麼這樣排序一個簡單的經濟學">為什麼這樣排序:一個簡單的經濟學</h2>
<p>回頭看這四層,你會發現它們的排列是有嚴格邏輯的:</p>
<table>
  <thead>
      <tr>
          <th>層級</th>
          <th>成本</th>
          <th>空間釋放量</th>
          <th>資訊損失</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Pre-pipeline</td>
          <td>低</td>
          <td>視 tool result 大小</td>
          <td>最小(可還原)</td>
      </tr>
      <tr>
          <td>Layer 1 Snip</td>
          <td>接近零</td>
          <td>小到中</td>
          <td>小(丟的是舊東西)</td>
      </tr>
      <tr>
          <td>Layer 2 Micro</td>
          <td>低</td>
          <td>中</td>
          <td>小(保留摘要)</td>
      </tr>
      <tr>
          <td>Layer 3 Collapse</td>
          <td>中</td>
          <td>大</td>
          <td>最小(投射式)</td>
      </tr>
      <tr>
          <td>Layer 4 Auto</td>
          <td>高</td>
          <td>最大</td>
          <td>中至大(看摘要品質)</td>
      </tr>
  </tbody>
</table>
<p><strong>從成本最低的開始試,能釋放多少算多少;前面的不夠用,才動用更貴的手段</strong>。</p>
<p>這就是這套系統背後的思路:<strong>對我而言,把 context 當成需要主動管理的資源,比交給運氣靈光來得安心一些</strong>。</p>
<hr>
<h2 id="1m-不是萬靈丹你該知道的真相">1M 不是萬靈丹:你該知道的真相</h2>
<p>看到這裡你可能想:「那我只要用 1M 模型,這四層壓縮我幾乎不用管了?」</p>
<p>技術上成立,但<strong>實務上要打一個大問號</strong>。</p>
<h3 id="模型的-recall-能力會隨-context-膨脹衰減">模型的 recall 能力會隨 context 膨脹衰減</h3>
<p>window 變大 ≠ 模型能好好使用全部空間。</p>
<p>Anthropic 公佈的 MRCR(multi-needle retrieval)測試結果:</p>
<table>
  <thead>
      <tr>
          <th>模型</th>
          <th>256K 時的 recall</th>
          <th>1M 時的 recall</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Opus 4.6 / 4.7</td>
          <td>93%</td>
          <td>~76–78%</td>
      </tr>
      <tr>
          <td>Sonnet 4.5(舊款)</td>
          <td>—</td>
          <td>18.5%(不建議用)</td>
      </tr>
      <tr>
          <td>Sonnet 4.6</td>
          <td>未公佈</td>
          <td>未公佈</td>
      </tr>
  </tbody>
</table>
<p>白話翻譯:<strong>你塞越多 context 進去,模型忘記東西的機率越高</strong>。即使技術上 window 能裝,模型的注意力會被稀釋。</p>
<h3 id="實務上多數-session-根本用不到-1m">實務上多數 session 根本用不到 1M</h3>
<p>根據社群的實測觀察,大多數 Claude Code session 峰值落在 <strong>80K–120K tokens</strong>。真正需要用到 500K 以上的場景不多,通常是:</p>
<ul>
<li>跨多個大型 codebase 的全域重構</li>
<li>一次讀入幾十份長篇文件做綜合分析</li>
<li>超長時間的自主 agent 任務(連續跑幾小時)</li>
</ul>
<p>日常維運、除錯、寫規格這類工作,200K 都綽綽有餘。</p>
<h3 id="1m-模型最實際的價值降低-compact-頻率不是撐更久">1M 模型最實際的價值:降低 compact 頻率,不是撐更久</h3>
<p>比較合理的用法不是「把 1M 塞滿」,而是:</p>
<ul>
<li>在 80K–150K 的正常使用範圍內,<strong>讓你不用頻繁擔心壓縮觸發</strong></li>
<li>遇到偶發的大型任務,<strong>不用馬上切 session 或 <code>/compact</code></strong></li>
<li>多一點彈性去讀幾個額外的參考檔案</li>
</ul>
<p>換句話說,1M 是把「context 緊張」這件事推到後景,而不是讓你可以永遠不管它。</p>
<h3 id="如果你在用-pro-方案">如果你在用 Pro 方案</h3>
<p>Max / Team / Enterprise 方案是<strong>自動啟用</strong> 1M。Pro 方案需要手動執行 <code>/extra-usage</code> 才會開啟 —— 這是 Anthropic 有意識的設計,讓付費層級自然區分。</p>
<p>如果你在 Pro 而沒跑過 <code>/extra-usage</code>,你現在用的是 200K,不是 1M。可以用 <code>/context</code> 確認當下狀態。</p>
<h3 id="環境變數可以強制關閉">環境變數可以強制關閉</h3>
<p>少數場景你可能想<strong>強制只用 200K</strong>(例如為了控制成本、或在舊模型間切換時保持一致),可以設:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">CLAUDE_CODE_DISABLE_1M_CONTEXT</span><span class="o">=</span><span class="m">1</span>
</span></span></code></pre></div><p>設了之後,model picker 不會出現 1M 選項。適合團隊統一環境配置時使用。</p>
<hr>
<h2 id="使用者能做什麼主動-vs-被動">使用者能做什麼:主動 vs 被動</h2>
<p>理論講完,來講實務。作為使用者,你不用去控制這四層(它們自動運作),但你<strong>有主動權</strong>在幾個關鍵時刻可以介入。</p>
<h3 id="時機一子任務結束時主動-compact">時機一:子任務結束時,主動 <code>/compact</code></h3>
<p>很多人以為 <code>/compact</code> 只在 context 快滿時才要用。這是我自己一開始也誤解的地方。</p>
<p>更聰明的用法是:<strong>每次完成一個子任務後,主動執行 <code>/compact</code></strong>。</p>
<p>為什麼?因為自動觸發永遠是被動的 —— 要等到真的快滿了才動。而你完成一個子任務時,你最知道:</p>
<ul>
<li>哪些前面的細節可以丟(「已經完成,結果正常」)</li>
<li>哪些需要保留(「這個決策後面還要用」)</li>
<li>下一個子任務需要什麼 context 基礎</li>
</ul>
<p>這時候主動 <code>/compact</code> 並帶上 custom instruction,可能會比自動摘要更貼近你的需求。</p>
<p>範例:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">/compact 重點保留:檔案修改清單、錯誤修正紀錄、未完成的 TODO。
</span></span><span class="line"><span class="cl">可以丟掉:一般探索性的 bash 輸出、已經確認正確的讀檔結果。
</span></span></code></pre></div><h3 id="時機二切-session不要依賴壓縮">時機二:切 session,不要依賴壓縮</h3>
<p>壓縮再強,也比不上「<strong>開新 session</strong>」乾淨。</p>
<p>當你要換一個完全不同的任務(例如從「debug production」切到「寫下週的週報」),最好的做法不是在同一個 session 裡繼續,而是:</p>
<ol>
<li>把當前進度寫進一個檔案(例如 <code>PROJECT_STATUS.md</code>)</li>
<li>結束當前 session</li>
<li>開新的,從頭讀那個檔案作為起點</li>
</ol>
<p>這比指望四層壓縮都要來得乾淨一些。</p>
<h3 id="時機三知道何時該停">時機三:知道何時該停</h3>
<p>有一個啟示來自前面的 3 次失敗 circuit breaker:<strong>如果 Claude Code 開始頻繁觸發 Auto Compact,那是警訊</strong>。</p>
<p>頻繁觸發代表你的任務規模已經超過 session 能舒服處理的範圍。這時候該做的不是「讓它繼續撐」,而是:</p>
<ul>
<li>切分任務(拆成幾個小任務分 session 做)</li>
<li>檢查你的 CLAUDE.md 是不是寫得太長</li>
<li>檢查你是不是讀了一堆其實不需要的檔案進來</li>
</ul>
<p>長 session 的壓力累積是真實存在的。管理 context 的最好方法,是<strong>從一開始就不要讓它膨脹</strong>。</p>
<hr>
<h2 id="幾個容易踩的雷">幾個容易踩的雷</h2>
<h3 id="雷一以為-compact-是魔法按鈕">雷一:以為 <code>/compact</code> 是魔法按鈕</h3>
<p><code>/compact</code> 會丟資訊。即使你寫了 custom instruction,摘要還是會漏細節。該備份的關鍵結論,請寫進檔案。</p>
<h3 id="雷二在重要決策前觸發壓縮">雷二:在重要決策前觸發壓縮</h3>
<p>如果 Claude Code 正在做一個關鍵判斷(例如「要刪哪些檔案」),不要在這時候手動 <code>/compact</code> —— 它可能把剛才的分析摘掉了,決策品質會受影響。等決策完成再壓縮。</p>
<h3 id="雷三盲目追求context-撐越久越好">雷三:盲目追求「context 撐越久越好」</h3>
<p>有些人把「能不能不用壓縮撐完一個 8 小時 session」當成成就。這是誤解。<strong>能把任務切成小塊分段做,每段乾淨結束,才是更好的工程實踐</strong>。</p>
<hr>
<h2 id="一個我自己偏好的心態">一個我自己偏好的心態</h2>
<p>四層壓縮聽起來很複雜,但它主要提醒一個觀念:</p>
<blockquote>
<p><strong>Context 是工程資源,不是取之不盡的倉庫</strong>。</p>
</blockquote>
<p>你用任何工具時都有資源觀念 —— 記憶體、磁碟、網路頻寬都有上限。AI 助理的 context 也一樣,只是它太新,大家還沒建立習慣。</p>
<p>有這個觀念之後,我自己覺得一些選擇變得比較自然:</p>
<ul>
<li>不會寫 10 頁的 CLAUDE.md</li>
<li>不會把整個 codebase 丟進對話</li>
<li>會主動切 session</li>
<li>會在關鍵時刻 <code>/compact</code></li>
<li>會把結論寫進檔案,而不是記在對話裡</li>
</ul>
<p>這些習慣累積起來,我覺得是「比較熟練使用 Claude Code」跟「一直踩雷」之間一個比較明顯的分野。</p>
<hr>
<h2 id="下一篇預告">下一篇預告</h2>
<p>接下來第 4 篇要談另一個常被混淆的主題:<strong>Sub-agent 與 Agent Team</strong>。</p>
<p>這兩個概念一直被工程師當成同一件事,實際上它們解決的是完全不同的問題 —— 一個是「怎麼讓 AI 跑得更快」,另一個是「怎麼讓 AI 聽話、有紀律」。</p>
<p>下一篇我們釐清這個誤會,並示範它們怎麼搭配使用。</p>
<hr>
<h2 id="本篇重點整理">本篇重點整理</h2>
<ul>
<li>Claude Code 的 context 管理不是黑盒,是<strong>一套四層的壓縮管線</strong>,從便宜到昂貴依序嘗試</li>
<li><strong>Pre-pipeline</strong>:處理過大的 tool result,防止污染整個管線</li>
<li><strong>Layer 1 Snip</strong>:零成本修剪,刪掉明顯可丟的舊片段</li>
<li><strong>Layer 2 Micro</strong>:以 tool_use_id 為單位壓縮 tool result,保留外殼丟掉內容</li>
<li><strong>Layer 3 Collapse</strong>:投射式壓縮,建立 view 而不修改底層 —— 最巧妙的一層</li>
<li><strong>Layer 4 Auto Compact</strong>:最貴的手段,用一次 API call 換大量空間;閾值約 window 的 83.5%(200K)或 96.7%(1M)</li>
<li><strong>Session Memory</strong>:Layer 4 會先試的輕量版,不呼叫 API 就能做修剪</li>
<li><strong>1M 不是萬靈丹</strong>:window 變大但模型 recall 能力會衰減,實務多數 session 根本用不到 1M</li>
<li><strong>主動介入時機</strong>:子任務結束時 <code>/compact</code>、切 session 而不硬撐、知道何時該拆任務</li>
<li><strong>核心觀念</strong>:把 context 當工程資源管理,而不是賭運氣</li>
</ul>
<hr>
<p><em>本文作者:鄧景仁 (Scott Teng) | 資訊服務業 infra 工程師,專注於 Azure / Linux / 安全維運。如需討論可聯繫 <a href="mailto:st333117@gmail.com">st333117@gmail.com</a>。</em></p>
<p><em>本系列所有內容為個人學習與實務心得整理,不代表任職機構立場。本文對 Claude Code 內部機制的描述,基於社群對 Claude Code 的公開分析材料與筆者實務觀察,並非 Anthropic 官方文件。具體閾值與行為可能隨版本演進。</em></p>
<hr /><p style="font-size:0.9em;opacity:0.8;margin-top:2em;">本文原刊於 <a href="https://eeit.github.io/ai-devops-blog/posts/03-context-compression/" rel="canonical">https://eeit.github.io/ai-devops-blog/posts/03-context-compression/</a>，作者：鄧景仁 (Scott Teng)。<br />授權條款：<a href="https://creativecommons.org/licenses/by-nc/4.0/deed.zh_TW" rel="license">CC BY-NC 4.0</a> · 禁止商業使用；分享請署名並註明原文 URL。<br />商業授權請聯絡：st333117@gmail.com</p>]]></content:encoded>
    </item>
  </channel>
</rss>
