プロバイダードリフト: デフォルトルーティングがLLMコストを膨らませる仕組み
目次
プロンプトキャッシュを有効にして、ヒットカウンターはときどき動くものの、請求額はほとんど変わらない。プロンプトの構造を疑う前に、ダッシュボードが隠している点を見てみましょう。それは、実際にどのアップストリームが各リクエストを処理したのかということです。
マルチプロバイダー型ゲートウェイは、単一のモデルを複数のアップストリームプロバイダーに分散させ、リクエストごとに1つを選びます。プロンプトキャッシュはプロバイダーごと(多くの場合、プロバイダー内のノードごと)に存在します。そのため、2回目の同一リクエストが1回目とは異なるアップストリームに着地すると、プロンプトが1バイトも変わっていなくてもキャッシュミスになります。これがプロバイダードリフトであり、トークン課金モデルでは静かにコストを倍増させます。
ドリフトを引き起こす2つの条件
これはあなたが選んで設定した誤設定ではありません。初期状態のまま使うとこうなるのです。
- デフォルトの自動ルーティング。 リクエストはアップストリームを固定せずにモデルへ送られるため、ゲートウェイが呼び出しごとに1つを選びます。
- デフォルトのプロバイダーソート = “default (balanced)”。 ゲートウェイは1つに固定するのではなく、対象となるアップストリーム間で負荷分散します。
どちらも工場出荷時のデフォルトです。ドリフトを引き起こすために何かを触る必要はありません。むしろ、それを避けるために設定を触る必要があるのです。
同一リクエストを20回送るとどうなるか
私たちは、人気のあるマルチプロバイダー型ゲートウェイの1つに対し、上記のデフォルト設定のまま、同一の約8Kトークンのプレフィックスを連続して20回送信し、毎回アップストリームが報告するプロバイダーとキャッシュのフィールドを取得しました。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回の呼び出しをシングルバックエンド型ゲートウェイ(1モデル、1アップストリーム、負荷分散なし)に対して実行すると、同一のワークロードでヒット率は**19/20(95%)**になります。同じモデル、同じプロンプト、同じ呼び出し回数です。唯一の変数は、ルーティングがドリフトするかどうかだけです。
対照的に、まさに同じマルチプロバイダー型ゲートウェイ上で、GPTクラスのモデルは20回の呼び出しすべてが1つのアップストリーム(A***e)にルーティングされ、19/20ヒットしました。ドリフトは一様ではなく、ゲートウェイがたまたま分散させるモデルに噛みつきます。今回の実行では、それがDeepSeekファミリーのモデルでした。
結論A: 期待していたコスト vs 実際に支払ったコスト
ドリフトするモデルでの呼び出しあたりのコストは、キャッシュの結果によってきれいに分かれました。
| 呼び出しの種類 | 呼び出しあたりの中央コスト |
|---|---|
| キャッシュヒット | ~$0.00015 |
| キャッシュミス | ~$0.00062 |
このモデルでは、ミスはヒットの約4倍のコストがかかります(生の入力トークンで見ると、公表されている差はさらに大きく、およそ50倍です)。これを20回の呼び出しで合計してみましょう。
| シナリオ | ヒット率 | 同一の20回の呼び出しのコスト |
|---|---|---|
| 期待値(キャッシュに到達可能) | 95% | $0.0026 |
| 実際(デフォルトのドリフト) | 20% | $0.0102 |
同じモデル、同じプロンプト、同じ20回のリクエストです。プロバイダードリフトによって実行コストは約3.9倍になりました。キャッシュはずっと「オン」でした。ルーティング層が単に、あなたのトークンのほとんどをミスのレートで課金しただけです。これを、大きく安定したプレフィックスを一日中再生する本番エンドポイントにスケールさせれば、この差はあなたの入力支出の大部分を占めることになります。
結論B: キャッシュがないということはレイテンシの恩恵もないということ
キャッシュはコストのレバーだけではありません。ウォームなプレフィルは最初のトークンをより早く返します。ドリフトによってキャッシュを奪われると、その高速化も失います。私たちは繰り返しの同一呼び出しでtime-to-first-token(TTFT)を測定しました。
GPTクラスのモデル(一貫した1つのアップストリームにルーティング、キャッシュ到達可能):
| 呼び出し | TTFT |
|---|---|
| 1回目(コールド、ミス) | ~1760 ms |
| それ以降(ウォーム、ヒット) | ~1130 ms |
キャッシュにより最初のトークンが約36%高速になり、しかも安定しています。すべてのウォーム呼び出しが狭い帯域に収まります。
DeepSeekファミリーのモデル(デフォルトのドリフト、キャッシュにほとんど到達不可):
- 10回繰り返した呼び出し全体でのキャッシュヒット: 0。
- TTFTは呼び出しごとに約1000 msから約4500 msまで揺れ動き、ときおり空のレスポンスもありました。
ほぼすべてのリクエストが新しいアップストリームになるため、コールドプレフィルのレイテンシのままとなり、応答したプロバイダーの分散をそのまま引き継ぎます。GPTモデルは到達可能なキャッシュから36%のTTFT改善を得ましたが、ドリフトするモデルは何も得られず、しかも最速と最遅の呼び出しの間に4.5倍の開きが生じました。
自分のセットアップを5分で監査する
これらの数字も、誰の数字も信用しないでください。同じ長いプレフィックスを数回送り、2つのフィールドを観察してください。ドメインはハードコードしていません。環境変数で自分のゲートウェイを指定してください。
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)}")
同じモデルに対してアップストリームが複数あれば、それはドリフトです。プロンプトの安定性に比べてヒット率が大きく下回っていれば、あなたに税金を課しているということです。より詳しい方法はDoes Your LLM Gateway Lie About Cache?にあります。
何を確認すべきか
ドリフトの治療法は構造的なものです。各呼び出しを、あなたのプレフィックスを一度も見たことのない新しいアップストリームに負荷分散するのではなく、ある特定のモデルを一貫したバックエンドへルーティングし、次のリクエストでウォームキャッシュに実際に到達できるようにします。ゲートウェイを評価するときは、同じプレフィックスを20回送ってアップストリームの数を数えてください。1つが望ましい状態です。9つは税金です。
公平を期した補足: プロンプトキャッシュはどこでもベストエフォートであり、ディスクキャッシュ型のモデルでは、シングルバックエンドであっても長いアイドル時間が空くとヒット率は依然として低下します。ドリフトを排除しても無限のキャッシュが手に入るわけではありません。ただ、最大かつ最も無駄なミスの原因、つまりあなたが同意した覚えもなく、目にも見えない原因を取り除くのです。
まとめ
「プロンプトキャッシュ対応」と「あなたのキャッシュに到達可能」は別の主張です。1つのモデルを入れ替わり立ち替わりのアップストリームに分散させるゲートウェイは、キャッシュ対応を正直に報告しながら、20%のヒット率、約4倍の請求額、4.5倍揺れる最初のトークンのレイテンシを提供することがあります。注視すべき数字は、キャッシュがうたわれているかどうかではありません。あなたが実測したヒット率と、同一のリクエストがいくつのアップストリームに触れるかです。プローブを実行し、データに結論を出させましょう。
より広範な監査方法についてはDoes Your LLM Gateway Lie About Cache?を、そもそもなぜキャッシュが存在するのかについてはHow KV Cache & TTL Workをご覧ください。
FAQ
これは私の側の誤設定ですか? いいえ。工場出荷時のデフォルト、つまりプロバイダーソートが “default (balanced)” のままの自動ルーティングで発生します。ドリフトを避けるには、その逆ではなく、能動的にアップストリームを固定する必要があります。
1つのアップストリームに固定すれば解決しますか? プロバイダー間のドリフトは取り除けますが、単一のアップストリームでも多くの場合、プレフィックスアフィニティのない複数のレプリカが動いているため、ヒットは依然として行ったり来たりします。固定したと想定するのではなく、固定後に実測してください。
なぜGPTクラスのモデルはドリフトしなかったのですか? 今回の実行では、ゲートウェイがたまたま単一のアップストリームへルーティングしました。ドリフトはモデルごとに異なり、ゲートウェイが対象とする適格なアップストリームをいく