OpenRouterのProvider Routingとは:同じモデルIDでも品質が変わる理由
OpenRouterで同じモデルIDを指定しても、実際にリクエストを処理する提供元は毎回同じとは限りません。 1つのモデルIDの裏に、量子化方式もコンテキスト長も稼働率も違う複数のエンドポイントがぶら下がっているからです。
そしてデフォルトの振り分けは価格の逆二乗で重み付けされます。何も指定しないと、安い——多くの場合は強く量子化された——エンドポイントにトラフィックが偏ります。「同じモデルなのに出力の質が安定しない」という体験の多くは、これが原因です。
この記事では、Provider Routingの仕組み、制御に使うパラメータ、そして実際に踏みやすい落とし穴を整理します。
1つのモデルIDに複数のエンドポイント
あるモデルが何社から提供されているかは、エンドポイント一覧のAPIで確認できます。
curl -s https://openrouter.ai/api/v1/models/<author>/<slug>/endpoints \
-H "Authorization: Bearer $OPENROUTER_API_KEY"
返ってくる各エンドポイントは、次の点でばらつきます。
- 価格 — 同じモデルでも提供元によって数倍の差がつくことがあります
- 量子化 — fp16 / fp8 / fp4 など。精度と価格はここで交換されています
- コンテキスト長 — 公称100万トークンのモデルを、実際には10万トークン程度で提供している例があります
- 稼働率 — 90%を切るエンドポイントも珍しくありません
- 対応機能 — 画像入力やツール呼び出しに対応していないエンドポイントもあります
つまり「モデルを選ぶ」だけでは、品質は決まりません。
デフォルトの振り分けは価格の逆二乗
OpenRouterのドキュメントは、デフォルトの負荷分散をこう説明しています。
Provider A is 9x more likely to be first routed to Provider A than Provider C because (1 / 3^2 = 1/9) (inverse square of the price).
価格が3倍のエンドポイントは、選ばれる確率が 1/9 になる、という重み付けです。安いほうに強く寄りますが、ゼロにはなりません。3倍高いエンドポイントにも約9分の1のリクエストが流れます。
これは「だいたい安いところに行く」という話ではなく、トラフィックが確率的に分散されるということです。同じプロンプトを10回投げると、別々のエンドポイントが応答している可能性があります。出力の揺れが説明できないときは、まずここを疑ってください。
制御に使うパラメータ
リクエストの provider オブジェクトで制御します。主なフィールドは次のとおりです。
| フィールド | 型 | 既定値 | 用途 |
|---|---|---|---|
only | string[] | — | 許可する提供元のスラッグ(許可リスト) |
ignore | string[] | — | 除外する提供元 |
order | string[] | — | 優先順位を明示 |
allow_fallbacks | boolean | true | 指定外へのフォールバックを許すか |
sort | string | object | — | 価格・スループットなどでの並べ替え |
max_price | object | — | 100万トークンあたりの価格上限 |
quantizations | string[] | — | 許可する量子化方式 |
data_collection | "allow" | "deny" | "allow" | 学習に使う可能性のある提供元を許すか |
require_parameters | boolean | false | 指定パラメータに対応した提供元のみ使う |
モデルIDに :nitro を付けるとスループット順、:floor を付けると価格順のショートカットになります。
{
"model": "z-ai/glm-5.2",
"messages": [{"role": "user", "content": "..."}],
"provider": {
"only": ["z-ai", "fireworks", "together"],
"max_price": { "prompt": 1.5, "completion": 4.5 },
"quantizations": ["fp16", "bf16", "fp8"]
}
}
実運用で踏む落とし穴
ここからは、私たちがゲートウェイを運用するなかで実際に踏んだものです。FastMetalは有料モデルの一部をOpenRouter経由で提供しているため、この設定は日常的に触っています。
1. 価格上限だけで絞ると、安かろう悪かろうに寄る
最初にやりがちなのが「max_price だけ設定する」です。ところが価格上限は下から切るので、残るのは安いエンドポイントばかりになります。
実際にあった例では、あるモデルの価格上限が許可していた4つのエンドポイントがすべてfp4量子化で、そのうち1つは公称100万トークンのモデルを約9.6万トークンのコンテキストで提供し、別の1つは稼働率が85%を下回っていました。同時に、そのモデルを開発したラボ自身のエンドポイントと、品質で評判のホストは、価格上限から外れていました。
許可リスト(only)が主、価格上限が従です。信頼できる提供元を先に列挙し、そのうえで上限をかけてください。順序が逆だと、価格だけを見て割引タイヤを選ぶことになります。
2. スラッグは表示名と違い、間違えても無言で無視される
only に書くのはスラッグで、UIの表示名ではありません。ここがずれていてもエラーは出ません。許可リストは設定されているように見えて、実際には何も制約していない状態になります。
| 表示名 | 正しいスラッグ |
|---|---|
| DeepInfra | deepinfra(deep-infra ではない) |
| Amazon Bedrock | amazon-bedrock |
google-vertex |
スラッグはエンドポイント一覧APIの tag の接頭辞(例:novita/fp8 → novita)で確認できます。設定後は必ず実際に呼び出して、意図した提供元に届いているか確かめてください。
3. 価格上限が低すぎると、404で全滅する
max_price を厳しくしすぎて、条件を満たすエンドポイントがゼロになると、リクエストは通りません。No endpoints found that satisfy the max price というエラーになります。これは節約ではなく障害です。
厄介なのは、上流の価格が上がったときに、設定を変えていないのに突然そうなる点です。ある提供元がコンテキスト長ごとに複数の価格帯を持っているケースもあり、公開されている最安値が通常のリクエストで到達できるとは限りません。
価格上限は理屈ではなく実測で決めてください。 価格帯を安いほうから順に試し、実際にルーティングが通る最も安い水準を採用するのが確実です。
4. 一時的なエラーと構造的な不達を混同しない
Provider returned error は多くの場合、単なる混雑です。同じ組み合わせがリトライで成功することはよくあります。これを理由に提供元を除外リストへ入れると、良い提供元を無駄に失います。
一方で、アカウントのデータポリシー設定によって構造的に到達できないエンドポイントも存在します。この2つは区別してください。前者は放っておけば直り、後者は永久に直りません。
5. 機能の対応可否は自分で確かめる
「このモデルは画像入力に対応している」という一般的な情報が、そのエンドポイントで成り立つとは限りません。モデル自体は対応していても、OpenRouter上で画像入力を提供しているエンドポイントが1つもない、という状況は実際にあります。カタログで画像対応をうたう前に、実際に画像を1枚投げて確認するのが唯一確実な方法です。
FastMetalではどうしているか
上に書いた作業は、利用者一人ひとりがやるには重すぎます。FastMetalでは、OpenRouter経由で提供する有料モデルについて、提供元の許可リストと価格上限を設定したうえでカタログに載せています。信頼できる提供元(モデルを開発したラボ自身、および実績のあるホスト)を優先し、価格上限は実測で決めています。
利用者から見えるのは、円建ての単価とモデルIDだけです。
from openai import OpenAI
client = OpenAI(
api_key="<FASTMETAL_API_KEY>",
base_url="https://api.fastmetal.ai/v1",
)
resp = client.chat.completions.create(
model="glm-5.2",
max_tokens=500,
messages=[{"role": "user", "content": "量子化が出力品質に与える影響を説明して"}],
)
print(resp.choices[0].message.content)
もちろん、自分で細かく制御したいなら、OpenRouterを直接使って provider を書くほうが自由度は高くなります。どちらが正しいという話ではなく、その運用を自分で持つかどうかの選択です。
よくある質問
Q. 同じモデルIDなのに出力の質が違うのはなぜですか? 1つのモデルIDの裏に複数の提供元があり、量子化方式やコンテキスト長が異なるためです。デフォルトでは価格の逆二乗で重み付けして振り分けられるので、リクエストごとに別のエンドポイントが応答することがあります。
Q. 量子化されたエンドポイントを避けるには?
provider.quantizations で許可する方式を明示するか、provider.only で信頼できる提供元だけに絞ります。価格上限だけで制御すると、逆に量子化されたエンドポイントに寄ります。
Q. provider.only を設定したのに効いていないようです。
スラッグが間違っている可能性が高いです。表示名とスラッグは異なり、誤ったスラッグはエラーにならず無視されます。エンドポイント一覧APIで正しい値を確認してください。
Q. FastMetal経由でもProvider Routingを指定できますか? 提供元の許可リストと価格上限は、FastMetal側でモデルごとに設定しています。利用者はモデルIDを指定するだけで、そのルーティング方針が適用されます。
まとめ
OpenRouterのProvider Routingは、1つのモデルIDの裏で複数の提供元に価格の逆二乗で重み付けしてリクエストを振り分ける仕組みです。何も指定しなければ安く量子化されたエンドポイントに寄るため、品質を求めるなら許可リストを主、価格上限を従として設定するのが実務的な結論です。
スラッグの間違いは無言で無視され、価格上限の締めすぎは404を招きます。どちらも設定した直後に実際のリクエストで確認するしかありません。
この運用を自分で持ちたくない場合は、設定済みのカタログとしてFastMetalのモデル一覧を使う選択肢もあります。料金は料金ページ、OpenRouterとの違いは比較ページをご覧ください。