compaction 沒壞。壞的是你的 recovery 設計
我看那篇 bug report,第一個反應不是「context 太大了」,而是 recovery path 從一開始就修不到真正的問題。
log 很清楚。messages=0、historyTextChars=0、promptChars=10,但 systemPromptChars=34549。接著 preflight 算出 estimatedPromptTokens=10698,再扣掉 reserveTokens=32960 之後,promptBudgetBeforeReserve 只剩 8000,所以它在模型還沒動之前就先判定 overflow。
然後 compaction 出場,看到的是另一個世界。它只看到 transcript 沒有真實對話,於是回 no real conversation messages。reset token snapshot,再重試一次。preflight 當然還是拿到同一個 system prompt、同一組 reserve token,於是再 overflow 一次。這不是 recovery,這只是把同一個死結重播一遍。
以前做過 queue worker 和 retry pipeline,這種 pattern 很危險。只要 admission check 跟 recovery mechanism 看的是不同 invariant,系統就會一直很努力地失敗。表面上像有自癒,實際上只是用更漂亮的方式卡死。
真正該修的有兩個。
第一,preflight 要知道自己要求的 recovery 是否可行。如果 overflow 幾乎都來自 system prompt 或 provider reserve,而不是 conversation transcript,就不該丟給 compaction。因為 compaction 根本沒有材料可以壓。
第二,budget 的責任邊界要一致。你可以把 system prompt 算進 context pressure,也可以把 reserve token 設得很保守,但 admission、compaction、retry 三段至少要共享同一套判斷。現在這個 case 最麻煩的地方,不是它算錯,是每一段都各自算對,拼起來卻不能前進。
很多人看到這種 loop,直覺會去調大 context window 或把 reserveTokensFloor 往上拉。我不會先做這個。那只是把爆點往後挪,不是把 failure mode 消掉。production 真正在意的是 determinism。能不能在進 recovery 前就明確知道「這次救不回來,直接 fail fast」;能不能把錯誤訊息講成「system prompt 過大,不是對話過長」。這兩件事比多撐 2 千 token 有價值得多。
說穿了,compaction 本身沒壞。壞的是你把一個 static prompt overflow,交給一個只會處理 conversation transcript 的機制。這種鍋再重試十次,結果也不會變。
作者:鍵盤工人