~/blog/tool-definition-tax-17k-context-economics

改裝 2080 Ti 22G · part 6

[趣味競賽 進階 #6] 工具定義稅:還沒開口,就先吃掉 17K token——而且每次重算都重來一遍

cat --toc

TL;DR

我數了家裡那個 AI 助理(雛羽,改裝 2080 Ti 上的 Qwen3.6-27B 模型)每次回話前要付的「入場費」:還沒開始處理我輸入的文字,就已經佔掉約 23K token,其中 17,434 個(實測)只是 39 個工具的使用說明書——約 73%。一般模型這筆只算一次、之後重用;但這顆是 hybrid 模型,算好的快取沒法重用,一沒命中就整段重算,而一個對話回合常用 6~16 次工具,這 17K 等於一回合被重收十幾次。結論:問題不是工具太多,是這筆「打底開銷」太貴;砍工具不是解法,像技能那樣「用到才載」才是。

白話導讀:AI 助理開口前要先付一筆「入場費」

你進一家店,還沒點東西,先收你一筆入場費——這就是我家那個 AI 助理每次回話前的處境。

它能做很多事:排程、委派任務、開終端機、搜尋、操作看板……每一項能力,背後都是一個「工具」。而模型要知道某個工具怎麼用,你就得在每次請求裡,把那份工具的使用說明書(寫著工具叫什麼、要哪些參數、每個參數什麼意思)一起塞給它讀。

我掛了 39 個工具。把這 39 份說明書加起來,約 17,434 個 token(token 是模型的計算單位,粗略想成「幾個字」)——這是它「還沒開始處理我打的任何一個字」之前,就已經吃掉的開銷。再加上系統提示,整個「空回合的打底開銷」大概 23K token 起跳。

如果這是一般的模型,這筆錢只付一次:第一回合讀進去後就存起來(快取),之後每回合直接重用。問題是我這顆是 hybrid 模型(一種把注意力和記憶結構混在一起的新架構),它沒辦法重用那塊快取——只要快取一沒命中,它就把整段(包含那 17K 工具說明書)從頭重讀一遍。於是一次性的「入場費」,變成每次重算都要再付一遍的「稅」。

這篇講的就是這筆稅:它從哪來、為什麼這麼貴、以及為什麼正確的解法不是砍工具


前言:上一篇把重算的記憶存了起來,這篇來看「被重算的」到底是什麼

上一篇(#5,把對話記憶 KV cache 存硬碟那篇)講的是:這個 hybrid 模型只要快取一沒命中,就把整段從頭重算,害你等第一個字等很久;解法是把算好的記憶存到硬碟,下次直接讀存檔、不要重算。那篇證明了一件事:重算很貴,貴到值得存起來。

那篇講的是「怎麼讓它別重算」。這篇換個角度,從帳本切進去問:既然每次沒命中都得把整段重算,那這段裡到底裝了什麼、哪一塊最貴?

答案有點出乎意料:最大那塊不是我的對話、不是系統提示,是工具的使用說明書。

先把方法講在前頭,免得被當成精算:下面所有 token 數,都是「字數 ÷ 4」的估計——我抓了一份真實送進模型的完整內容,把工具那一欄的字數除以 4。模型自己算 token 的方式會有點出入,但大方向很清楚。當數量級看,別當小數點後幾位的精算看。

拆帳:工具佔了七成

先把帳攤開。我抓的這份請求快照,是 2026-06-21 晚上一次真實請求送進模型那一刻的完整內容(紀錄)。拆開數:

項目token(估計)佔比
工具說明書(39 個工具)~17,434~73%
系統提示(已含技能目錄)~6,263~26%
空回合打底開銷 合計~23.7K

⚠️ 一個要講精確的細節:這份快照的系統提示是一整塊 25,052 字(約 6,263 token),而且它已經把技能目錄包在裡面了。所以別把「系統提示 6,263」「技能 3,700」當兩筆相加——技能目錄是住在系統提示那塊裡面的。乾淨、站得住腳的數字就兩個:工具 = 17,434 token系統提示(含技能)= 6,263 token,合計約 23.7K

這筆開銷跑不掉。我翻了整份紀錄,這個模型在真實對話裡見過最精瘦的一回合,也吃了 18,427 token。那是一個「使用者只丟極短一句、系統那塊也壓到最小」的回合——它還是吃了 18K,光工具說明書就約 17.4K,等於這個最瘦回合裡九成以上(約 94%)都是工具說明書。換句話說:就算我一個字都不打、把其他能砍的都砍到最小,這個模型也得先讀完那 17K 的工具說明書。(上表那個 ~23.7K 是這份快照當下的數字——系統那塊會隨對話狀態和載入的技能浮動,所以「最瘦回合 18,427」比「快照 23.7K」更小,並不矛盾:兩個都指向同一件事——工具說明書是壓死人的那塊。)

空回合打底開銷的解剖:整個約 23.7K token 裡,工具說明書獨佔約 17.4K(73%),系統提示+技能目錄約 6.3K(26%)。使用者一個字都還沒打,這筆帳就已經掛在那。

最肥的幾份說明書

那 39 份說明書不是均分的,有幾份特別肥。從同一份快照實測,前 12 名:

工具token(估計)
cronjob1,802
delegate_task1,734
terminal1,349
session_search1,268
kanban_create1,077
skill_manage1,036
kanban_complete846
execute_code676
memory544
patch482
search_files446
send_message412

光最肥的兩個(cronjob + delegate_task)就約 3,500 token——比很多人整段對話還長。而且這每一份,都得逐回合重新讀給模型聽(下面解釋為什麼)。

順帶一個誠實的小校正:這幾個數字跟我之前筆記裡記的(cronjob 1,791、delegate_task 1,732…)差個位數——那是因為這次重抓重算,字數抓得比上次完整一點點。方向、排名一模一樣,我用這次實測的數。

為什麼這變成「每回合」的稅(整篇的重點)

這裡是核心,也是最容易被當成「廢話,不就開銷嗎」而略過的地方。

  • 在一般的模型上:這 17K 工具說明書擺在最前面,第一回合讀進去後就被存起來(快取),之後每一回合都直接重用。只付一次,後面幾乎免費。
  • 在我這顆 hybrid 模型上:它的架構(混合注意力 + 一種叫 Mamba/SSM 的記憶結構)沒辦法重用開頭那段的快取。只要快取一沒命中,它就被迫把整段從頭重算——這 17K 工具說明書,跟著一起重算。

這不是我猜的。這正是上一篇(disk-KV 那篇)裡那行 llama.cpp 的系統紀錄:

slot update_slots: forcing full prompt re-processing due to lack of cache data
  (likely due to SWA or hybrid/recurrent memory, ...)

這也不是我自己腦補,來源就在這:

  • PR #13194("kv-cache : add SWA support",已合併):講的是 SWA(滑動視窗注意力)為什麼不能重用快取——視窗一滑動,開頭的資訊就遺失了。上面那行紀錄把 SWA 跟 hybrid 並列,SWA 那半出自這裡。
  • Issue #22746("Eval bug: Qwen 3.6 27B forcing full prompt re-processing due to lack of cache data",狀態 還開著(Open)):這條正中我這顆——Qwen 3.6 27B(就是我在跑的同一顆),貼的紀錄一字不差就是上面那行:它檢查完所有存檔都對不上、把 15 個失效存檔全清掉、然後把整段 53,564 個 token 從頭重算。好幾種量化版本(Q3_K_M / Q4_K_M / IQ4_XS…)都中。
  • Issue #20225("Eval bug: Qwen 3.5 Full prompt re-processing on every conversation turn",狀態 已關閉(Closed)):上一代同家族的佐證——Qwen 3.5 每個對話回合都被迫整段重算,有人回報一個 15K token 的對話每回合要等約 8 分鐘,而不是幾秒。(⚠️ 它標題寫「3.5」、狀態 Closed;真正打中 3.6 的是上面那條還開著的 #22746,別把 3.5 那條的 Closed 讀成「3.6 也修好了」。)

這個限制一碰上那 17K,稅就跑出來了。一個對話回合裡,助理常要連續用好幾個工具——做一步、看結果、再做一步,每一步都是一次新請求、內容又長一點。我數了真實紀錄:單一對話回合裡用工具的次數,通常介於 6 到 16 次,還飆到過 30、34。如果這當中有 9 次快取沒命中,那就是這 17K 工具說明書,在一個回合裡被重算了 9 次。

至於重算一次要多久?冷重算大約每秒 360-624 個 token,17,434 個 token 換算下來,光把工具說明書重讀一遍,每次沒命中就要花約 28 到 48 秒

同一份 17K 工具說明書,在兩種模型上的命運。一般模型:讀一次 → 存起來 → 之後每回合免費重用,是一條水平線。hybrid 模型:每次快取沒命中都把這 17K 從頭重算一次,變成一根又一根重複的柱子——同樣的說明書,被重讀了 N 遍。這就是「一次性成本」變成「每回合稅」的全貌。

先講清楚:這稅是「一陣一陣」的,不是每回合都 16 倍

免得你帶錯結論:「一回合重算 16 次」是最壞情況,不是常態。

大多數回合其實不用重算——快取還在、對話接得上(命中率 98-100%),工具說明書不用重讀,幾乎不付這筆錢。真正會爆的,是少數快取突然失效的回合:對話跳掉、或模型剛當掉重開、把記憶體裡的快取清空了。所以這筆稅是一陣一陣的——平常很安靜,集中在那幾個「失效回合」一次炸開。

所以別讀成「每回合都重算 16 次」。真實的樣子是:大多數回合幾乎不繳稅,少數失效回合一次繳一大筆。但因為這種回合「等第一個字」的時間又長又痛(上一篇那種冷重算動輒幾十秒、長對話飆到幾分鐘),這筆「陣發稅」對體感的傷害,遠比它的平均值看起來嚴重。

正確的解法不是砍工具

看到「73% 是工具」,直覺是「那砍掉一半工具不就好了」。錯。

那 39 個工具——排程、委派、終端機、搜尋、看板、技能管理……——幾乎每個都有存在的理由。砍掉就是把助理的能力砍掉。為了省這筆開銷把助理弄笨,本末倒置。

真正的解法,其實這套系統裡早就有一套可以抄:技能(skills)的做法:

  • 平常只放一份技能的「名字清單」(很小一塊),不放完整內容。
  • 完整的技能說明,等模型真的決定要用、發起呼叫那一刻才載進來

如果工具也照這個模式——第一次用到某個工具時才載它的說明書,而不是 39 份全部先塞好——那筆 17K 的打底開銷就會少一大半。模型平常只要知道「我有哪些工具可用」(一份名字清單),要用時再去查細節。

這個直覺,跟前傳那台老卡的教訓是同一個。GTX 970 系列那篇 RAG 客服 我刻意不裝一堆笨重的套件(沒有 torch、沒有向量資料庫、不碰 LangChain)——能省則省。在 2080 Ti 上,咬人的「肥肉」換成了工具說明書,但解法是同一個本能:只載你真的會用到的東西。

另一條路,是把上游那個「快取不能重用」的限制修好,讓這 17K 像一般模型那樣只存一次。但那是 llama.cpp 上游要處理的事,不是我在家裡改幾行就能解的。兩條路——「工具用到才載」或「修好快取重用」——都比直接砍功能合理。

收尾:這是「開銷帳」的問題,不是工具的問題

把這篇講成一句話:

助理的瓶頸常常不在「它聰不聰明」,而在「它每次思考前要先付多少入場費」。 那份 17K 的工具說明書,在一顆會重用快取的一般模型上是一次性投資;在一顆不會重用的 hybrid 模型上,變成每次失效都要再付一遍的稅。同一份說明書,放在不同的快取架構上,帳算出來天差地遠。

最反直覺的是:你以為的成本(模型多大、跑多快)都不是這裡的主角。真正咬人的,是那段你根本沒在看、每次快取一失效就默默被重算一遍的開頭內容。盯著「吐字速度」看,你永遠不會發現這筆錢正在流走。

至於這塊值得被存起來的開頭內容到底該存哪(記憶體裡自動但會蒸發,還是硬碟撐得住重開)——上一篇 disk-KV 已經回答了。這篇補的是另一半:在那塊被反覆重算的東西裡,最肥、最該先處理的,就是這 17K 工具說明書。

誠實聲明(醜話講在前頭)

  • token 數是「字數 ÷ 4」估計,不是模型精算。數量級和排名確定,精確值有 ±。
  • 系統提示和技能目錄是重疊的:那份快照的系統提示已經包含技能目錄,所以別把 17,434(工具)+ 6,263(系統)+ 技能 三筆相加。乾淨的帳是:工具 17,434 + 系統(含技能)6,263 ≈ 23.7K。
  • 「重算 16 次」是最壞情況:大多數回合(命中 98-100%)幾乎不繳稅,所以這稅是一陣一陣的、集中在失效回合,不是每回合 16 倍。
  • 「一回合 6-16 次工具」是某段紀錄的實測分佈,飆到過 30/34,不同時段會變。
  • 39 個工具是這顆雛羽的設定,其他助理掛的工具數不一定一樣。
  • 冷重算每秒 360-624 token 是先前的紀錄數字,「每次失效 28-48 秒」是用它換算的數量級,不是逐次計時。

我能放心給你的就是這些:一份真實請求快照拆出來的工具帳(這次重新實測)、整份紀錄撈出來的最短回合與工具次數分佈、加上兩條解釋「為什麼 hybrid 不能重用快取」的上游 GitHub 來源。當一個「開銷帳」的案例讀,不當精算報表讀。


同系列其他篇:

前傳:

常見問題

什麼是「工具定義稅」?為什麼是稅、不是一次性成本?
AI 助理能用的每一個工具,都得在每次請求裡附一份「使用說明書」(寫著工具叫什麼、要哪些參數),模型才知道怎麼用。我家這個模型掛了 39 個工具,光這些說明書就約 17,434 個 token(模型的計算單位,本次實測)。在一般的模型上,這 17K 擺在最前面,第一次讀進去就被存起來(快取)、之後每回合重用——只付一次。但我這顆是 hybrid 模型(新架構),沒辦法重用那塊快取,只要快取一沒命中,就得把整段從頭重讀一次——這 17K 就跟著重算。於是「一次性成本」變成「每次重算都要再付一遍的稅」。
那把工具砍掉不就好了?
別這樣解。那 39 個工具(排程、委派、終端機、搜尋、看板、技能管理…)幾乎每個都有用,砍掉就是把助理變笨。真正的解法是「用到才載」——這正是技能(skills)功能已經在做的事:平常只放一份技能的「名字清單」(很小),完整內容等真的要用時才載進來。如果工具也這樣設計(第一次用到才載說明書,而不是 39 份全部先塞好),這筆打底開銷就會少一大半。另一條路是把上游那個「快取不能重用」的限制修好。兩條都比砍功能好。
這些 token 數字是精確的嗎?
是估計值,方法我講清楚:我抓了一份真實的請求快照(送進模型那一刻的完整內容),把工具那一欄的字數除以 4 當估計。模型自己算 token 的方式會有點出入,但大方向很清楚——工具說明書就是這筆開銷的絕大多數。另外從紀錄裡撈到,這個模型在真實對話裡見過最精瘦的一回合也吃了 18,427 token,光工具就約 17.4K,等於一個「什麼都還沒講」的回合,九成以上都是工具說明書。

接著讀

不想錯過新文章?

訂閱我確保不漏接!

隨時一鍵退訂。