擋掉 diff,為甚麼還沒省到額度?一次 Agent SDK 修法的代價
繞過 C26 的收集條件可以改變檔案追蹤,但不能直接證明額度改善。這次歷史 workaround 的教訓,在於你為了修狀態,究竟改掉了哪些證據。
這篇的段落(5)
我曾經為了擋掉 Agent SDK 重複注入的檔案 diff,直接改它要讀回的 JSONL 對話紀錄。
做法看起來很有效率:既然狀態重建只認某幾種工具紀錄,那就改掉收集條件,讓它建不出那份追蹤資料。
但後來的成本追查提醒了我兩件事。擋掉 diff,沒有自動換來快取改善;而我原先寫的「不影響對話內容或理解」,也說得太滿。刪掉歷史 Write 的內容,就是改掉了一部分歷史。
這篇說明當時為甚麼會這樣修,以及你要付出的代價。
版本:Claude Code v2.1.71,以及當時逐輪重新呼叫並 resume 的 SDK 用法。
C26是那份 minified 程式裡的函數名,不是穩定 API。
為甚麼在對話裡 Read,下一輪仍可能重送?
因為我當時的下一輪會重新還原狀態,上輪記憶體裡更新過的資料不一定繼續沿用。
在 CLI 持續互動時,Read 能更新當下的檔案追蹤。但我的 SDK 程式每次重新呼叫、resume,都會從保存的工具歷史再建一次 readFileState。因此,這輪補讀有效,不代表下輪重建後仍有相同狀態。
原文把這件事概括成「Agent SDK 每輪都會丟掉狀態」。現在應該說清楚,我追到的是那個版本、那條呼叫路徑;SDK 也有持續輸入的多輪方式,不能只靠產品名稱判斷生命週期。
C26 當時用哪些工具紀錄建表?
依當時的逆向紀錄,它收集符合條件的 Read 與 Write。
| 工具紀錄 | 收集條件 |
|---|---|
| Read | input.offset === undefined && input.limit === undefined |
| Write | input.file_path && input.content |
| Edit | 那段收集邏輯未處理 |
這裡有個容易混淆的地方:讀取「從第一行開始」,和工具輸入裡「明確存在 offset: 1」,在程式判斷上可以不同。模型或呼叫端實際有沒有送這個欄位,要看紀錄,不能因為工具預設從第一行開始,就說它幾乎永遠不會進表。
我當時想到的 workaround,就是讓歷史紀錄不再符合這兩個條件:替缺少 offset 的 Read 補上 offset: 1,再移除 Write 的 content。
這改的是重建函數的輸入,沒有修正重建函數本身。就像把清單上的資料拿掉,後面的程式當然不會再按同一份資料追蹤;但清單同時也少了原本保存的東西。
刪掉 Write content,會失去甚麼?
會失去那次寫入的完整內容,後來的對話與查核可能受影響。
JSONL 裡的 tool_use 記錄了模型當時要求工具做的事。移除 Write.input.content 後,歷史不再完整描述那次操作。
例如後續想比較「第一次寫了哪個版本」與「目前檔案差在哪裡」,如果當時寫入內容已刪,就不能只靠那筆歷史還原。模型接續時是否受影響,則取決於它還看得到哪些其他資訊,不能預先保證完全沒差。
補 Read 的欄位也改動了歷史工具呼叫。即使讀取範圍在某個版本等效,仍應承認這是為了影響還原邏輯而改寫紀錄。
另外,執行中的程序可能仍在追加 JSONL。若另一段程式同時整份讀入、改完再寫回,就有覆蓋新紀錄的風險。備份能保留先前副本,不能代替對寫入時機與還原結果的確認。
因此我不再把原來那段直接修改原檔的 TypeScript,當成今天可直接採用的整合範例。它缺少完整性、同時寫入與接續結果的驗證,也依賴內部儲存格式與路徑規則。
那次修法到底解決了多少?
它針對部分追蹤紀錄的收集條件,沒有證明整體成本已改善。
原來的想法有三段,需要各自成立:
- 改寫歷史後,重建出的追蹤資料是否真的改變?
- 追蹤資料改變後,要消除的那種 diff 是否真的不再送出?
- 同樣工作量下,輸入、快取與整體消耗是否改善?
第一段就算成立,也不能跳過後兩段。其他內部來源仍可能提供檔案或動態資訊;少一種 diff,也可能還留著另一個破壞快取前綴的來源。
後續實驗裡,大量建立快取的情況仍在,紀錄的讀取比例只有約 15–25%。該表沒有把 sanitizer 的獨立開關完整列出,所以不能反過來精算這段程式單獨有多少效益。它能否定的是當初那個太快的宣告:做到繞過一段收集邏輯,還不能說原本的額度問題修好了。
相關問題可接著看〈我逆向了 Claude Code v2.1.71,找到 token 消耗暴增的根因〉。
相關問題可接著看〈Claude Code 實戰:我怎麼用 AI 寫完一整個網站〉。
若要把本文的判準用在自己的工作,可參考課程與工程手冊的適用範圍。
現在要怎麼判斷這類 workaround 值不值得留?
把省下的用量,和改動歷史造成的損失放在一起看。
如果同一問題能用官方支援的 session 生命週期或持續輸入方式處理,先比較那條路。2026-10-29 的 官方 SDK 文件建議使用 query() 的 AsyncIterable<SDKUserMessage> 維持多輪,或用 options.resume 接續已保存的 session;當年的 V2 已移除,不能再視為現行替代方案。
若你在維護鎖定舊版本的系統,必須研究類似修法,最低限度也要能回答:原始紀錄是否完整保留、實驗期間誰會寫入、是否確實少送目標內容,以及接續後能否正確完成原任務。沒有這些證據,只看到「程式沒報錯」還不夠。
當初我動手,是因為問題已經影響實際工作,等不下去。這個動機保留,對效果的判斷則要跟著證據更新。
接著看〈Agent SDK 每句吃 2–3% 額度:我怎麼從失敗修法追到快取問題〉,裡面放了後續比較。它能幫你看出,一次修法消掉症狀之後,還有哪些問題沒有一起消失。
