離開座位一小時,回來那句話要重讀整段對話嗎?拆開 Claude Code 的 idle compaction
中午離開一個多小時,回到那個從早上聊到現在的 session,照設定文件的說法,對話裡可能已經多了一行 Compacted while idle, before the prompt cache expired。你什麼都沒按,它趁你不在,把整段對話壓成了一份摘要。
它急著在你回來之前動手,理由寫在官方的 costs 頁:「your first message after a break longer than the cache lifetime misses the cache and reprocesses your full context.」休息時間超過快取壽命,回來的第一則訊息就會錯過快取,把整段 context 重新處理一次。同一段接著寫,訂閱方案內的快取壽命是一小時,改用 usage credits 之後降為五分鐘,API key 與雲端供應商預設五分鐘。
要是沒有它,一早上的對話,換來一句「好,繼續」整段重算。
這個功能叫 idle compaction。設定文件的描述是:對一段你已經離開的長對話,在 prompt cache 過期前不久先把它壓縮掉,你下一則訊息送出去的就是摘要,不是整段對話。
它是哪一版加的,兩份官方原文說法不同,我只能並陳。CHANGELOG 把它列在 ## 2.1.299 區塊的 Added 底下(2.1.299 上 npm 的時間是 2026 年 10 月 14 日 UTC),可是同一條寫的是「Both need v2.1.290 or later」;設定文件也寫「The key requires Claude Code v2.1.290 or later」(2.1.290 上 npm 是 2026 年 10 月 5 日 UTC)。CHANGELOG 從 2.1.290 到 2.1.296 的各區塊(中間沒有 2.1.297、2.1.298 這兩個版本號)都沒有出現 idle compaction,至於 2.1.290 的程式本身有沒有這個功能,我沒有查證。寫這篇時(10 月 16 日)本機 claude --version 回的是 2.1.301 (Claude Code)。
「快過期前先壓縮」聽起來像個貼心小功能。可是它挑的時間點,是被快取的運作方式逼出來的,而且要過五道關卡,任何一道沒過,它就安靜地不發生。
快取只認開頭
prompt caching 頁講快取怎麼比對,寫得很短:API 拿每個請求的開頭(文件叫它 prefix)去跟最近處理過的內容比對,「The match is exact, so a change anywhere in the prefix recomputes everything after it. There is no per-file or per-segment caching.」
比對是逐字的,前綴裡任何一處變了,後面全部重算。沒有「這個檔案還在快取裡」這種按檔案或按段落的快取。
想像你把一疊三百頁的講義寄放在影印店櫃台。下次去,只要你遞過去的稿子從第一頁開始跟寄放的那疊一模一樣,店員就直接從那疊接著印,只收新增頁數的錢。可是櫃台有規矩,一小時沒人來拿,那疊就清掉。你晚了五分鐘到,店員手上什麼都沒有,三百頁從第一頁重新掃描。
對話就是那疊講義。每一次你送出訊息,前面整段歷史都是前綴,快取暖著的時候只付新增的那一點;快取清掉了,前綴整段變回沒快取的輸入。
壓縮也得把整疊讀一遍
那回來先 /compact 一下不就好了?
不行。壓縮自己也是一個請求。要產生摘要,模型得先讀過整段歷史。prompt caching 頁寫得很明白:「After a break longer than the cache lifetime, there is no cache left to read, so the summarization request reprocesses the full history as uncached input. This is why /compact costs the most when you resume an old session.」
快取過期之後才壓縮,摘要請求一樣要把全部歷史當成沒快取的輸入讀一遍。所以回到一個舊 session 時跑 /compact,正好是它最貴的時候。
快取還暖著的時候,情況整個反過來:「While the cache is warm, that request reads your prefix from the cache, so a mid-session /compact costs a fraction of what the context size suggests and spends most of its time generating the summary.」同一個摘要請求,前綴可以從快取讀,費用只有 context 大小看起來那樣的一小部分,時間多半花在生成摘要本身。
把兩句擺在一起,idle compaction 的設計就說得通了。壓縮這個動作的成本,幾乎全看快取當下是暖是冷。等你回來再壓,一定是冷的;要壓得便宜,只能在你還沒回來、快取還沒清掉的那幾分鐘裡由它自己動手。設定文件寫的時間是閒置「about 54 minutes」,對照一小時的快取壽命,落在過期前不久。為什麼是 54 而不是 50 或 58,文件沒有解釋,我也不知道。
回到影印店:店員在清櫃台前最後幾分鐘,趁那疊講義還在手邊,把它濃縮成一頁摘要留給你。你回來遞過去的,就是那一頁。
壓縮本身也有代價。prompt caching 頁說,壓縮會用摘要取代你的訊息歷史,依設計會讓對話那一層的快取失效。摘要留下什麼、丟掉什麼,設定文件指向 context-window 頁的 what-survives-compaction 一段,那段原文我沒有讀到,所以這篇不判斷壓完之後少了哪些細節。
五道關卡,少一道就不發生
設定文件列了預設啟用的條件,原文用的是「meets all of these conditions」,五項全中才算。我把每一項跟「什麼情況會讓它過不了」排在一起:
| 條件(文件原文) | 過不了的情況 | 對應的官方文件 |
|---|---|---|
| Session:interactive terminal session | 非互動執行,例如 -p 或 SDK |
settings-reference#idlecompaction |
| Prompt cache:one-hour prompt cache TTL | 主對話不是一小時 TTL | 同上、prompt-caching#which-ttl-each-request-gets |
| Feature flags:Claude Code can fetch feature flags from Anthropic | 設了 DISABLE_GROWTHBOOK、DISABLE_TELEMETRY、DO_NOT_TRACK、CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC;或用 Amazon Bedrock、Microsoft Foundry 等第三方供應商(除非嵌入的主機平台設了 CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST);或 Claude apps gateway session |
env-vars#features-that-need-feature-flag-fetching |
| Size:context 達到門檻,預設 200,000 | 對話還沒長到門檻 | settings-reference |
| Idle time:距上一個請求約 54 分鐘,且電腦當下醒著 | 閒置時間不夠,或電腦睡著了 | settings-reference |
第二道關卡,哪些情況預設是一小時,prompt caching 頁有一張表:
| Request bucket | Claude subscription, within plan usage | Usage credits, API key, or cloud provider |
|---|---|---|
| Main conversation | One hour | Five minutes |
| Everything else | Five minutes, except the server-controlled helper requests, which get one hour | Five minutes |
主對話的 TTL 也可以自己選,用 promptCacheTtl 設定或 CLAUDE_CODE_PROMPT_CACHE_TTL 環境變數,值只吃 5m 或 1h,文件寫兩者都需要 v2.1.242 以上。
五道裡面我覺得最容易踩到的是第三道,因為它跟 idle compaction 本身一點關係都沒有。如果你為了隱私或公司政策,在 shell 設定檔裡放過 DO_NOT_TRACK 或 DISABLE_TELEMETRY,要知道這兩個變數在 env-vars 表裡都寫著會一併關掉 feature flag 的抓取(每個變數設成哪些值才會關,文件說看各自那一列)。env-vars 頁有一段專門列「抓不到 flag 就用不了」的功能,清單最後一項就是在終端閒置時、一小時快取過期前不久壓縮長對話。你沒有碰過任何 compaction 設定,它就已經不在了,畫面上也不會有任何提示。
還有一個跟版本有關的小坑。同一頁寫,安裝之後、或升級到新增某個功能的版本之後的第一個 session,靠 flag 開啟的功能可能缺席;那個 session 抓到 flag 存在本機之後,下一個 session 才會有。剛升級完當天下午就等著看它出現,可能會落空。
第五道的「電腦當下醒著」也值得多看一眼。筆電闔上去吃飯,到第 54 分鐘時機器在睡覺,條件就沒成立。
兩個開關,三條關掉的路
要關掉它,設定文件給的是一個布林鍵,Scope 寫 Any file,預設 true:
1 | { |
門檻用環境變數調。env-vars 表寫 CLAUDE_CODE_IDLE_COMPACT_MIN_TOKENS 只吃正整數,其他值一律忽略,低於 100000 的會被抬到 100000,那是最低門檻。設定文件的範例是放進 settings.json 的 env:
1 | { |
這個範例旁邊,文件只附了一句理由:「At the default, a conversation on a 200K context window auto-compacts before it reaches 200,000 tokens. This example lowers the threshold to 150,000 so that those conversations qualify」。在預設值下,200K context window 的對話在到達 200,000 tokens 之前就已經先 auto-compact 了,這個範例把門檻降到 150,000,讓這類對話也符合條件。我沒有實測過這個門檻的效果,這句就照原文放著,不往下延伸。
真正要小心的是關掉它的路其實有三條,副作用不一樣:
| 做法 | 關掉 idle compaction | 一起關掉 auto-compact | 手動 /compact |
|---|---|---|---|
"idleCompaction": false |
是 | 否 | 照常可用 |
"autoCompactEnabled": false |
是 | 是 | 照常可用 |
DISABLE_AUTO_COMPACT=1 |
是 | 是 | 照常可用 |
DISABLE_AUTO_COMPACT 在 env-vars 表裡還寫著會覆蓋 autoCompactEnabled 設定。如果你只是不想要閒置時被壓縮,用第一條;後兩條會把「context 快滿時自動壓縮」一起拿掉,那是另一個機制,8 月那篇〈壓縮完那條規則為什麼沒回來〉講的就是它。
舊版本這邊有一條文件寫明的死路:idleCompaction 這個鍵在 v2.1.290 以前會被直接忽略,寫了也沒用,文件給的替代方式是關掉 autoCompactEnabled,代價是 auto-compact 一起沒了。
它到底有沒有發生過
除了回來時那行 Compacted while idle, before the prompt cache expired,costs 頁的 /usage 也看得到痕跡。文件給的 Prompt cache 那一行範例長這樣:
1 | Prompt cache (main): 14 requests · 91% of input tokens from cache · 2 misses (last 6m 10s ago, 310.2k tokens re-cached) · 1 expected rebuild (compaction or tool-result clearing) · warm (1h TTL, last activity 40s ago) |
裡面的 expected rebuild 就是 Claude Code 自己剛重寫過對話(壓縮或清掉舊的 tool result)造成的那種快取未命中,文件說它會另外計成 expected rebuild。整條 Prompt cache 行需要 v2.1.251 以上,未命中的可能原因說明則要 v2.1.260 以上。行尾括號裡的 1h TTL,也看得出主對話現在用的是哪一種 TTL。
想確認主對話拿到哪種 TTL,prompt caching 頁另外給了一個方法:跑 claude -p "hello" --output-format json,看結果裡的 usage.cache_creation,一小時的快取寫入記在 ephemeral_1h_input_tokens,五分鐘的記在 ephemeral_5m_input_tokens。這個指令我沒有執行過,欄位名稱照文件抄。
其實這篇從頭到尾都只讀了文件。我沒讓任何對話真的閒置 54 分鐘,沒看過那行 Compacted while idle 的實際畫面,也沒量過門檻變數的效果;Claude Code 本身我只跑過 claude --version。
我會怎麼設
預設開著,不動它。它要的條件很窄,真的觸發時,省掉的正是最貴的那一次整段重算;要付的代價是回來面對一份摘要,而那份摘要留下什麼,我前面說了,還沒讀到原文。
對話很少長到 200,000 tokens 的人,它預設根本輪不到,這整篇知道就好。
回來後少掉的細節如果對你的工作很要命,例如一早上累積的除錯線索,就用 "idleCompaction": false 單獨關它,別動 autoCompactEnabled。
環境裡有 DO_NOT_TRACK 或 DISABLE_TELEMETRY 的話,先去 env-vars 頁看那一列,確認你設的值會不會關掉 flag 抓取。這件事比任何門檻調整都優先。
趁暖做重寫
拆完這個功能,我比較在意的是它背後那條規則:任何會改寫對話前綴的動作,成本都看快取當下是暖是冷。
手動 /compact 也是一樣。文件已經說了,session 中途、快取還暖時壓,只付一小部分;隔了一段比快取壽命還長的時間回來才壓,最貴。所以如果你知道自己要離開一陣子,又確定這段對話之後要壓縮,在離開前壓會比回來後壓便宜。idle compaction 只是把這件事自動化,而且只在那五道關卡全過時才替你做。
快取活多久、怎麼選、帳單怎麼算,8 月那篇〈prompt cache 到底存在哪、活多久?〉拆過;哪些動作會讓快取整段失效,在〈中途改的 CLAUDE.md 這個 session 不算〉;手動壓縮什麼時候該按,7 月那篇〈Claude Code 的 /compact〉。
原文來源:Claude Code Docs:Settings reference(idleCompaction、Change the idle compaction threshold、autoCompactEnabled)、Claude Code Docs:Environment variables(CLAUDE_CODE_IDLE_COMPACT_MIN_TOKENS、DISABLE_AUTO_COMPACT、Features that need feature-flag fetching)、Claude Code Docs:Prompt caching、Claude Code Docs:Costs,皆以 2026 年 10 月 16 日讀取的版本為準;Claude Code CHANGELOG(2.1.299 區塊);版本上架時間取自 npm view @anthropic-ai/claude-code time(2026 年 10 月 16 日查詢)。
















