供應商漂移:預設路由如何推高 LLM 成本
你啟用了 prompt cache,命中計數偶爾會增加,帳單卻幾乎沒變。先別怪 prompt 結構,看看儀表板沒有顯示的資訊:每次請求實際由哪個上游處理。
多供應商閘道會把同一個模型分散到多家上游供應商,並為每次請求選擇其中一家。Prompt cache 由各供應商獨立管理,而且通常連同一家供應商的不同節點也不共用。因此,第二個完全相同的請求若被送到不同上游,即使 prompt 一個 byte 都沒變,仍會 cache miss。這就是「供應商漂移」(provider drift)。在按 token 計費的模型上,它會悄悄把成本放大。
TL;DR
- 使用原廠預設路由時,某個多供應商閘道將 20 次相同呼叫分散到 9 個上游,prompt cache 只命中 4/20。
- 單一後端閘道處理相同工作負載時,命中率為 19/20;供應商漂移讓這輪測試的成本增加約 3.9 倍($0.0102 對 $0.0026)。
- 在實測的 DeepSeek 系列模型上,cache miss 的成本約為命中的 4 倍(每次呼叫的中位數為 $0.00062 對 $0.00015)。
- 漂移情況因模型而異:同一個閘道將某個 GPT 級模型的 20 次呼叫全數送往同一上游,命中率為 19/20。
觸發漂移的兩個條件
這不是你自行選擇的錯誤設定,而是開箱即用的預設行為:
- 預設自動路由。 請求送往模型時沒有固定上游,因此閘道會為每次呼叫選擇上游。
- 預設供應商排序為「default (balanced)」。 閘道會在符合條件的上游之間做負載平衡,而不是固定使用其中一個。
兩者都是原廠預設值。你不必改任何設定就會遇到漂移;反而必須調整設定才能避開。
20 次相同請求實際會發生什麼
我們在上述預設設定下,連續 20 次將完全相同、約 8K token 的前綴送到一個常見的多供應商閘道,並要求每次回傳上游自己提供的供應商與快取欄位。某個使用磁碟快取的 DeepSeek 系列模型結果如下:
- 這 20 次呼叫由 9 個不同上游處理:
N***a、S***w、M***h、D***a、A***L、P***l、S***e、V***e、A***d。 - 快取命中率:4/20(20%)。 只有請求剛好落到先前已快取該前綴的上游時,才會命中。
將同樣的 20 次呼叫送到單一後端閘道(一個模型、一個上游、不做負載平衡),相同工作負載的命中率是 19/20(95%)。模型、prompt、呼叫次數都一樣,唯一變因是路由是否漂移。
作為對照,在同一個多供應商閘道上,某個 GPT 級模型的 20 次呼叫全數被送到同一個上游(A***e),命中率為 19/20。漂移並非平均發生;哪個模型被閘道分散,就會影響哪個模型。這輪測試中,受影響的是 DeepSeek 系列模型。
結論 A:預期成本與實際支出
在發生漂移的模型上,每次呼叫的成本會依快取結果明顯分成兩組:
| 呼叫類型 | 每次呼叫成本中位數 |
|---|---|
| cache hit | ~$0.00015 |
| cache miss | ~$0.00062 |
在這個模型上,miss 的成本約為 hit 的 4 倍(若只看原始輸入 token,官方公布的價差更大,約為 50 倍)。再把 20 次呼叫加總:
| 情境 | 命中率 | 20 次相同呼叫的成本 |
|---|---|---|
| 預期(可存取快取) | 95% | $0.0026 |
| 實際(預設漂移) | 20% | $0.0102 |
相同模型、相同 prompt、同樣 20 次請求。供應商漂移讓這輪測試的成本增加了約 3.9 倍。快取從頭到尾都是「開啟」狀態;只是路由層讓大部分 token 都按 miss 費率計價。若正式環境的 endpoint 整天反覆使用大型且穩定的前綴,這個差額會占輸入成本的大多數。
結論 B:沒有命中快取,也沒有延遲優勢
快取不只能降低成本。預熱過的 prefill 也能更快回傳第一個 token。漂移讓請求無法命中快取時,這項加速也會消失。我們針對重複的相同呼叫測量了首 token 延遲(time-to-first-token,TTFT):
GPT 級模型(固定路由到同一上游,可存取快取):
| 呼叫 | TTFT |
|---|---|
| 第 1 次(冷快取、miss) | ~1760 ms |
| 後續呼叫(已預熱、hit) | ~1130 ms |
快取讓第一個 token 約快 36%,而且表現穩定:每次預熱後的呼叫都落在很小的區間內。
DeepSeek 系列模型(預設漂移,幾乎無法存取快取):
- 連續重複呼叫 10 次,快取命中次數為 0。
- 每次呼叫的 TTFT 在 ~1000 ms 到 ~4500 ms 之間波動,偶爾還會收到空回應。
幾乎每次請求都被送到新的上游,因此延遲始終停留在冷快取 prefill 水準,還得承受各供應商本身的差異。GPT 模型因為能存取快取,TTFT 改善了 36%;發生漂移的模型不但完全沒有改善,最快與最慢呼叫之間還相差 4.5 倍。
五分鐘檢查自己的設定
不要直接相信這些數據,也不要直接相信任何人的數據。把同一段長前綴送出多次,觀察兩個欄位即可。程式碼沒有寫死任何網域,透過環境變數指向你自己的閘道。
import os, uuid
from openai import OpenAI
client = OpenAI(api_key=os.environ["GW_KEY"], base_url=os.environ["GW_BASE"])
SYS = f"[probe {uuid.uuid4().hex}]\n\n" + ("You are a support assistant. " * 300)
seen, hits = {}, 0
for i in range(20):
r = client.chat.completions.create(
model=os.environ["GW_MODEL"], max_tokens=16,
messages=[{"role": "system", "content": SYS},
{"role": "user", "content": f"q{i}"}],
extra_body={"usage": {"include": True}})
d = r.model_dump()
det = r.usage.prompt_tokens_details
cached = (getattr(det, "cached_tokens", 0) or 0) if det else 0
seen[d.get("provider")] = seen.get(d.get("provider"), 0) + 1 # populated when exposed
hits += 1 if cached else 0
print(f"hit rate {hits}/20; upstreams seen: {len(seen)}")
同一模型出現多個上游,就代表發生了漂移。若命中率遠低於 prompt 的穩定程度,漂移正在增加你的成本。完整測試方法請參考你的 LLM 閘道是否謊報快取?。
應該檢查什麼
解決漂移要從路由結構著手:將指定模型固定路由到同一個後端,讓下一個請求能實際存取已預熱的快取,而不是把每次呼叫負載平衡到從未看過該前綴的新上游。評估閘道時,將同一段前綴送出 20 次,再計算上游數量。你要的是一個。九個就代表額外成本。
不過,所有 prompt cache 都是 best-effort。對使用磁碟快取的模型而言,即使只有單一後端,閒置時間拉長後,命中率仍會下降。消除漂移不代表你會得到永不過期的快取。它只是移除最大、最浪費的 miss 來源,而且這項成本並非你主動選擇,也無法直接看見。
結語
「支援 prompt cache」與「你的請求能存取快取」是兩回事。某個閘道可以如實宣稱支援快取,卻因為把同一模型分散到輪替的上游,最後只提供 20% 的命中率、約 4 倍的帳單,以及最高相差 4.5 倍的首 token 延遲。真正該觀察的不是閘道是否宣稱支援快取,而是實測命中率,以及相同請求實際碰到多少個上游。執行測試,讓數據回答。
完整的檢查方法請參考你的 LLM 閘道是否謊報快取?;若想了解快取存在的原因,請參考KV Cache 與 TTL 的運作方式。
常見問題
這是我這邊的設定錯誤嗎? 不是。原廠預設值就會發生:使用自動路由,且供應商排序維持「default (balanced)」。要避免漂移,必須主動固定上游,而不是相反。
固定單一上游就能解決嗎? 這會消除跨供應商漂移,但單一上游通常仍會執行多個 replica,而且不一定有前綴親和性,因此命中狀態仍可能反覆變化。固定上游後仍應實際測量,不要直接假設問題已解決。
為什麼 GPT 級模型沒有發生漂移? 這輪測試中,閘道剛好將它路由到單一上游。漂移因模型而異,取決於閘道會在多少個符合條件的上游之間做負載平衡,並非所有模型都一樣。
成本差距真的約為 4 倍嗎? 以我們實測的每次呼叫總成本來看,miss 約為 hit 的 4 倍;若按這類模型官方公布的原始輸入 token 價格計算,hit 與 miss 的差距更接近 50 倍。不論採用哪種算法,把原本預期的 hit 變成 miss,都是成本最高的部分。
我應該監控哪一項指標? 持續監控各模型的快取命中率,同時追蹤每個模型使用過的不同上游數量。命中率下降或上游數量增加,都代表實際 token 成本已經上升。