llm-routing
LLM ルーティング:測定されたベンチマーク、そしてそれが主張するルーター
コストを意識した LLM ルーティングサービス(LangGraph + MCP)、およびそのポリシーを決定する 417 タスクのベンチマーク。
正解したことを検証できる最も安いモデルで回答し、検証が失敗した場合のみエスカレーションします。それが単に最高のモデルに料金を払うよりも優れているかどうかは意見の問題ではありません。選択するモデルに依存し、このリポジトリはそれを実際の3つのラダーで測定します。
結論を一言で:トップのラングが本当に優れており、検証が安価な場合はカスケードを使用します。価格比のしきい値では3つのラダーすべてを正しく処理できません。 同梱のルーターは、コミットされた測定値からラダーごとにその判定を計算し、データがないラダーには回答を拒否します。
実行されるもの | LangGraph ステートマシン — |
ポリシーを決定するもの | 417 タスク(MBPP+ コード、MATH-500 レベル5)、9 ポリシー、3 つの価格ラダー、すべて実モデルで測定:コスト品質フロンティア、正確な McNemar、ペアブートストラップ。 |
構築に使用 | Python 3.10–3.13 · LangGraph · MCP · Anthropic + DeepSeek API · pytest(268 テスト)· GitHub Actions。研究コアは純粋な標準ライブラリ — 依存関係がベンチマーク数値を変更することはできません。 |
証拠 | 5,075 件の実モデル応答、コミット済み。$8.51 支出。すべての図と表はオフラインで、API キーなしで $0.00 で再生成されます。 |
クイックスタート
pip install -e ".[agent]"
python -m llm_routing.build_taskset
python -m router_agent.cli --demo # real model output, no API key, $0.00アカウントもキーもお金も不要:応答は一度購入してコミットされているため、ルーターはシミュレーションではなく実際のモデル出力を再生します。
python scripts/demo.py は、3つの標準的なトレースを出力します — 安いラングで勝利するカスケード、2回支払うカスケード、検証が正確で無料のコードケース。その最初のもの:
1. The cascade's win - verified at the cheap rung
--------------------------------------------------------------------------
query: Let f(x) = x^3 - 3x + 1. Find the sum of the squares of all real roots. [...]
classify domain=math, start=cheap, verifier=self_consistency
answer cheap (deepseek-v4-flash) answered
verify self_consistency -> ACCEPT, confidence=1.00
finalize done: verified
answered by deepseek-v4-flash
verified True (self_consistency)
cost $0.000315 backend $0.000000これら4行は、以下に示すグラフのウォークスルーです。このグラフは router_agent/graph.py から解析され、描画されるのではありません — エスカレーションエッジは answer にループバックし、そのループがこれをルーターではなくカスケードにしているのです。
DeepSeek からの3つの独立したドローがすべて正しい答えを出したため、カスケードは受け入れ、Opus 5 を呼び出しませんでした — トップラングに直接ルーティングするよりもおよそ 27倍安価 です。検証が失敗すると、カスケードはエスカレーションし、両方のラングに支払います。そのトレードが価値があるかどうかは、このリポジトリの残りの部分で測定されます。
発見
単に常に最高のモデルに支払うこととの事前登録比較。ペアアウトカムに対する正確な McNemar、ラダーごとに n=209 の保留タスク。
ladder | rungs | cascade | always-expensive | Δ acc | p | Δ cost/task |
| v4-flash → Opus 5 | 95.7% | 92.3% | +3.3% | 0.039 | −$0.00307 |
| Haiku 4.5 → Sonnet 5 → Opus 5 | 96.7% | 92.3% | +4.3% | 0.012 | +$0.00097 |
| v4-flash → v4-pro | 86.6% | 83.7% | +2.9% | 0.070 | −$0.00000 |
wide では、カスケードはより正確で、かつ4倍安価です。claude では、精度をプレミアムで購入します — 安いラングが Haiku で、数学の半分がそこから5つのサンプルを引き出す場合、検証は無料ではありません。ラダーが符号を決定するため、以下のルーターはそれを仮定するのではなく読み取ります。
さらに3つの結果。それぞれの数値と注意点は docs/RESULTS.md にあります:
予測ルーティングはコインフリップに勝てない — 6回の比較のうち6回。 LLM-as-router も RouteLLM の事前学習済み BERT も、どのラダーでもコスト整合ランダムヌルに勝てません。一方、カスケードはすべてのラダーで両方に勝ちます。違いは決定がいつ行われるかです:予測ルーターは試行を見る前にコミットし、カスケードは検証後に決定します。 → 6つの比較、およびその背後にあるフロンティア AUC
精度はルーターが実際に何をしたかを隠します。 2つのポリシーが同じ精度に到達する方法は、正しい10タスクをエスカレーションするか、すべてをエスカレーションするかです。
always_expensiveは27のレスキューを購入するために201タスクをエスカレーションし、回答を改善できないエスカレーションに $0.71 を費やします。cascadeはそれらのレスキューのうち24を取得し、$0.084 を無駄にします。 → ポリシーごとのスコアカードすべてのポリシーは点ではなく曲線です。 ここにある各ルーターには、精度とお金を交換するノブがあります。したがって、それぞれ1つの設定で2つを比較すると、ノブを設定した人が勝者を選べます。
frontier.pyは各ノブを全範囲にわたってスイープし、結果の曲線を比較します。 → フロンティア、および価格比がそれを決定しない理由
それぞれに figures/ の図があり、各チャートが主張することと、それが runs/ のどのアーティファクトから描かれたかをリストしています。
ベンチマークは独自の結論を出荷する
テーブルで終わるベンチマークは、読者にそれを適用することを任せます。これは関数で終わります。findings.ratio_verdict(ladder) はそのラダーのコミットされたフロンティアを読み取り、そのラダーの判定を返します。同じクエリ、2つのラダー、反対の答え:
$ llm-router --estimate "prove that sqrt(2) is irrational" --ladder wide
recommended policy cascade (measured on the wide ladder)
cascade vs always-best, at matched accuracy -83.1%
$ llm-router --estimate "prove that sqrt(2) is irrational" --ladder claude
recommended policy route (measured on the claude ladder)
cascade vs always-best, at matched accuracy +11.7%その反転が発見であり、ルーターはそれを仮定するのではなく読み取ります — そしてデータがないラダーには辞退します。CLI、MCP の explain_routing ツール、RouterConfig のデフォルトはすべて同じ関数を呼び出すため、ベンチマークが測定したものを変更すると、ルーターが推奨するものも変更されます。時代遅れになる定数はありません — 以前はありましたが、その3つの判定のうち2つは逆でした。
レイアウト
llm_routing/ the experiment — 16 modules, standard library only
router_agent/ the product — LangGraph cascade + MCP server
cache/ 5,075 real model responses — what makes replay free
runs/ every derived artefact: results, frontiers, scorecards
data/ docs/ figures/ scripts/ tests/ archive/2つの半分は、1つのモデルクライアント、1つの価格テーブル、1つの応答キャッシュを共有します。これにより、ルーターからのドル数値がテーブルのドル数値と同じ意味を持つようになります。矢印は一方向にのみ流れます — router_agent は llm_routing をインポートし、その逆はありません — そして CI には、その状態を維持することだけを目的としたジョブがあります。モジュールごと:docs/ARCHITECTURE.md。
MCP クライアントから使用する
ルーターは MCP サーバーです:5つのツール(route_query、resume_routing、estimate_cost、compare_policies、explain_routing)、routing:// の下の4つの読み取り専用リソース、およびポリシーの選択をクライアントに案内する1つのプロンプト。
.mcp.json がコミットされているため、pip install -e ".[agent,mcp]" だけで Claude Code がサーバーを認識します。Claude Desktop や他のクライアントの場合も、同じブロックを手動で登録します:
{
"mcpServers": {
"llm-routing": {
"command": "python",
"args": ["-m", "router_agent.mcp_server"],
"env": {"ROUTER_LADDER": "wide", "ROUTER_MODE": "replay",
"ROUTER_K": "3", "ROUTER_AGREEMENT": "1.0"}
}
}
}ROUTER_MODE=replay は安全な登録です:サーバーはコミットされた応答から回答し、お金を使うことはできません。ただし、実際に支払われたプロンプトのみを提供します。それ以外は、捏造された回答ではなく、構造化された no_cached_response として返されます。ROUTER_K=3 は、これらの応答が購入されたパラメータに一致するように固定されています。デフォルトの5は、誰も購入していないサンプルをキャッシュに要求します。ROUTER_MODE=real とキーを使用すると、任意のクエリを提供し、それらに請求します。
エスカレーションの承認
デフォルトでは未設定。ROUTER_APPROVAL_USD を追加すると、それより高価なエスカレーションは支出する代わりにグラフを一時停止します:route_query は stop_reason: awaiting_approval と thread_id、およびモデルと価格を指定する interrupted ペイロードを返し、resume_routing は人間の回答を運びます。
"env": {"ROUTER_LADDER": "wide", "ROUTER_MODE": "replay",
"ROUTER_K": "3", "ROUTER_AGREEMENT": "1.0",
"ROUTER_APPROVAL_USD": "0.001"}承認はエスカレーションごとです — escalate ノードは通過時にそれをクリアします — したがって、3ラングのラダーは2回要求し、クライアントは stop_reason が別のものになるまで再開する必要があります。チェックポイントはサーバープロセス内の InMemorySaver であるため、両方の呼び出しが同じ実行中のサーバーに到達する必要があります:呼び出しごとに1つを生成するクライアント(scripts/mcp_call.py を含む)は、前のクライアントが一時停止したものを再開できません。存在しない thread_id は、LangGraph 内部からの KeyError ではなく no_suspended_run として返されます。
サーフェス全体を一度に見る
python scripts/demo_mcp.py実際の stdio クライアントセッションを介したサーバーのスクリプト化されたウォークスルー — それが宣伝するものと、それ自身の呼び出しのどれが支出するか、リソース、ラダーフリップ、無料のプロジェクション、ルーティングされた回答、および両方の方法で回答された承認ループ。キーなし、支出なし;最後に、クエリが本番環境でいくらかかったか、実際にアカウントから出た金額を出力します。
2つのサーバーを起動します。その理由は ROUTER_K の要点です:自己整合性サンプルはサンプルインデックスごとにキャッシュされるため、k は応答が購入された条件に起動時に固定されます — 安いラングで検証するクエリでは k=3、4番目のドローが不一致でエスカレーションをトリガーするクエリでは k=4。demo.py はルーターが何をするかを示します;これはサーバーが何をするかを示します。
ターミナルから駆動する
scripts/mcp_call.py はワンショット MCP クライアントです — サーバーを起動し、ハンドシェイクを行い、1つのツールを呼び出して結果を出力します:
python scripts/mcp_call.py --listpython scripts/mcp_call.py explain_routing ladder=widepython scripts/mcp_call.py --resource routing://findings/probeJSON-RPC を手動でパイプしても機能せず、失敗は静かです:サーバーは stdin EOF をシャットダウンとして受け取り、キューをドレインせずに終了するため、echo '...' | python -m router_agent.mcp_server は initialize 応答を出力し、ツール呼び出しをドロップして 0 で終了します。クライアントはパイプを開いたままにします。
実際のお金を使うには、モードを指定します — これは本物の DeepSeek 呼び出しで、MCP を介してルーティングおよび価格設定されています:
ROUTER_MODE=real ROUTER_LADDER=deepseek ROUTER_K=3 ROUTER_AGREEMENT=1.0 python scripts/mcp_call.py route_query query="What is 17 * 23? Give the final answer in \boxed{}." domain=math answered by deepseek-v4-flash (cheap)
verified True via self_consistency
cost $0.000068 backend $0.000068
classify domain=math, start=cheap, verifier=self_consistency
answer cheap (deepseek-v4-flash) answered
verify self_consistency -> ACCEPT, confidence=1.003つの HTTP 呼び出し — 1つの貪欲な回答と、それ自体に対してチェックするための2つの追加 — が安いラングで全会一致で受け入れられたため、v4-pro は触れられませんでした。2回目に実行すると、backend_cost_usd は $0.00 で、cost_usd は変更されません:応答は途中でキャッシュされました。これは、ベンチマークが5,075件を無料で再生できるのと同じメカニズムです。2つの数値は意図的に分離されています — 1つは本番環境での提供コスト、もう1つはアカウントから出た金額です。
提供されたクエリが購入するものは cache/serving.<ladder>.jsonl に保存され、ベンチマークの cache/raw_calls.<ladder>.jsonl には保存されません。両方とも実際の有料応答を保持しますが、証拠となるのは1つだけです:ベンチマークのファイルは、公開されたすべてのテーブルが計算される閉じたセットであり、任意のクエリをそれに追加すると、応答数と以下に引用する総支出が移動します。提供は依然としてベンチマークキャッシュを読み取り、それが --demo を無料にします。
検証
python scripts/check_mcp_server.py2つのフェーズがあり、重要なのは2つ目です。ツールをインプロセスで列挙して呼び出し、その後サーバーをサブプロセスとして起動して、手動でJSON-RPCを送信します。なぜならstdioでは、stdoutがプロトコルであり、ツールの下にある単一の迷いprintがフレームを破壊する一方で、すべてのインプロセステストは依然として成功するからです。これは仮説ではありません。response_cacheは、route_queryだけが到達するコードパス上で、stdoutに古いキーについて警告を出しました。そのため、サーバーはツールを完璧に列挙した後、最初の実際の呼び出しに対して壊れた回答を返しました。
すべてを再現する
リプレイモードは、公開された分析をコミット済みのレスポンスに対して再実行します。キーもネットワークも不要で、費用は$0.00です。
ROUTER_MODE=replay python scripts/run_all_ladders.py --ladders wide # ~30 min3つすべてで--ladders wideを外してください。約75分かかります。公開された数値は、すべての派生アーティファクトを削除した後に、まさにその方法で生成されました。バックエンドに到達した呼び出しは0件、シミュレートされた行は0件、そして再生成されたすべてのファイルはコミット済みのものとバイト単位で同一でした。
リプレイは何もインストールする必要がありません。純粋な標準ライブラリのみで、オフライン、数値に至るまでバイト決定的です。そしてこれがデフォルトなので、上記のコマンドのどれもモードを指定していません。リアルモードはキーが必要で、費用がかかります。3つ目のモードmockがあり、これはテストスイート用にレスポンスを偽造しますが、すべての分析モジュールはこのモードでの実行を拒否します。3つすべてのモードと、すべての分析エントリポイント、データを購入する順序は、docs/METHOD.mdにあります。
ドキュメント
ファイル | 読むべきタイミング |
平易な言葉での説明が欲しい場合。ルーティングの知識は不要です — ここから始めてください | |
すべての調査結果と、その数値とコストが欲しい場合 | |
手法が欲しい場合: タスクセット、これらのデータセットを選んだ理由、ラダー、ポリシー、検証器、劣化実験、実際に実行する方法、そしてこのプロジェクトが自分自身で見つけたバグ | |
ベンチマークとサービング層がモジュールごとにどのように連携するかを知りたい場合 | |
主張の限界を知りたい場合 |
主張の限界と、ここでの新規性
表紙に埋もれずに明記されています: シグナルを生成する検証器は、出荷される検証器ではありません。 コード部分はMBPP+が提供するテストを実行して採点されますが、デプロイされたルーターにはそれらはありません。
そのギャップは指摘されるだけでなく価格設定されており、それを価格設定することがこのリポジトリが文献に追加するものです。FrugalGPT (2305.05176)はカスケードのベースラインであり、それとAutoMixは検証器を所与のものとしています。Dekoninckら (2410.10347)は、品質推定器の精度がこれが機能するかどうかを決める要因であると特定していますが、合成ノイズを注入してテストしています。ここではsweep_degraded.pyが代わりに、客観的に採点されたタスクにおいて、実際の検証器を制御された量だけ劣化させ、ドメイン、モデル、プロンプト、採点者を固定します。つまり、プロキシ検証器を出荷することは、未知への一歩ではなく、測定された曲線に沿った移動なのです。
他のすべての限界はdocs/LIMITATIONS.mdに一度だけ記載され、それを解決する方法も示されています。完全な参考文献はdocs/METHOD.mdにあります。
ライセンス
MIT — LICENSEを参照してください。
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Hosted MCP server for LLM cost estimation, model comparison, and budget-aware routing.
Agent Cost Allocator MCP — multi-tenant LLM cost attribution for chargeback billing. Companion to
AI Reasoning Cache & Consensus Layer with 11 MCP tools via Streamable HTTP.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/APantov/llm-routing-comparison'
If you have feedback or need assistance with the MCP directory API, please join our Discord server