プロンプト単位で LLM を自動ルーティングする — OrcaRouter Adaptive Named Router の Mundane/Hard プール設計【実践】
この記事で作るもの
- プロンプトの難易度に応じてモデルを自動で振り分けるOrcaRouterの Adaptive Named Router
- 定型処理を低コストなオープンモデルへ、高度な推論をフロンティアモデルへ寄せる Gated モードの Mundane / Hard プール設計
- 「振り分けが意図どおりか」を 監査ログとレスポンスヘッダーで検証し、チューニングするループ
使うのは OrcaRouter です。ダッシュボードでのルーター作成から、自社トラフィックに合わせたプール設計、本番投入前の検証まで、手を動かしながら通しで構築します。
はじめに
プロンプト単位ルーティングで本番 LLM コストが 約 40% 下がるかどうかは、ほぼ一点に集約されます。Mundane(定型)と Hard(高度)のプールをどう切るか、です。
「とりあえず全部フロンティアモデル」をやめて、難易度ごとにモデルを振り分けると、品質を保ったまま支出を削れます。約 40% という数字は、定型プロンプト比率を 65%、定型処理は OSS で約 1/15 のコスト、粗削減額から 33% を保守的に控除した前提での試算です(出典:OrcaRouter ピッチデック「経済性」。月 $10,000 規模なら年 約 $47,700、回収 1 日未満の例)。実際の削減幅は各社のプロンプト分布によって変わり、コード生成中心で 20〜30%、抽出・RAG 中心で 50% 超が目安になります。
問題は、この「振り分け」を if/else で自前実装すると、新しいモデルが出るたびに対応表が陳腐化することです。本記事では、振り分けロジックを OrcaRouter の Adaptive Named Router に寄せたうえで、プールの切り方そのものを設計・検証していきます。ここが、削減幅を決める実務上の勘所です。
なお OrcaRouter は、Continuum AI(米国)が開発し、FlashLabs(日本)が日本独占で提供する適応型推論ゲートウェイです。
対象読者
- LLM のモデル選定をアプリのハードコードから切り離したい開発者
- 社内・顧客向けに LLM 基盤を設計する SIer / プラットフォームエンジニア
- コストとルーティング判断を可視化・統制したい SRE / 運用担当
動作環境
- Python 3.10+(サンプルは Python。Node.js ほか OpenAI 互換 SDK でも同様です)
-
openaiパッケージ(pip install openai) - OrcaRouter アカウント(後述。クレジットカード不要・無料で始められます)
前提(30 秒の復習)
本記事は、OrcaRouter への接続(base_url の差し替え)が済んでいる前提で進めます。未接続の場合は、まず次の 1 行差し替えだけ済ませてください。複数プロバイダーを 1 エンドポイントに束ねる全体像は、別記事『複数の LLM プロバイダーを統一するゲートウェイの実装』で詳しく扱っています。
from openai import OpenAI
import os
client = OpenAI(
base_url="https://api.orcarouter.ai/v1", # ← OrcaRouter 経由にする 1 行
api_key=os.environ["ORCAROUTER_API_KEY"], # sk-orca-... を環境変数に
)
アカウントと API キーは OrcaRouter 登録ページ(500 万無料クレジト付き、クレジットカード不要) から 60 秒で発行できます。
1. なぜ「プール設計」が成否を分けるのか
Adaptive Named Router は 2 つの層で動きます。この役割分担を理解すると、どこを自分で設計すべきかがはっきりします。
- プールの境界(どのプロンプトを mundane/hard とみなし、各プールにどのモデルを入れるか)は、あなたが設計します。 ここが削減幅を決めます。
- プールの「中」でどのモデルを選ぶかは、LinUCB 文脈バンディットが本番トラフィックの結果から自動で最適化します。 ここは運用とともに勝手に賢くなります。
ありがちな失敗は 2 つです。
- 全部を Hard Pool に寄せる → 定型処理にもフロンティア価格を払い続け、削減がほぼ出ない
- 積極的に Mundane へ寄せすぎる → 本来 hard な処理が安いモデルに落ち、品質が劣化する
つまりプール設計は、コストと品質のトレードオフを構造で決める作業です。以降はこの境界を、自社トラフィックに合わせて設計・検証していきます。
2. Step 1:自社トラフィックの難易度分布を見積もる
プールを設計する前に、「自社のプロンプトは mundane と hard がどれくらいの比率か」を把握します。一般には定型 65% / 高度 35% 程度に分かれますが、プロダクトによって大きく振れます。ここを当てずっぽうにすると、プール設計の前提が崩れます。
手元のプロンプト履歴からサンプルを取り、安価なモデルで粗くラベリングして比率を見積もります。これはあくまで設計の当たりを付けるための事前計測で、本番の分類器そのものではありません。
from collections import Counter
# 本番ログやテストデータから代表的なプロンプトを 100〜300 件サンプリング
sample_prompts = [
"次の文から会社名だけ抽出: 『FlashLabs 株式会社は東京都千代田区にあります』",
"このコードベースに二分探索を実装し、境界条件のテストも書いてください。",
"問い合わせ本文を「請求」「障害」「その他」のいずれかに分類してください。",
# ... 実データを並べる
]
GRADER = (
"次のプロンプトを mundane か hard で分類し、その一語だけ返してください。\n"
"mundane = 抽出・分類・整形・短い定型処理。\n"
"hard = 多段推論・コード生成・長文脈・曖昧さの解消が必要な処理。\n\n"
"プロンプト:\n{p}"
)
def grade(p: str) -> str:
r = client.chat.completions.create(
model="deepseek/deepseek-v4-pro", # 計測用途には安価なモデルで十分
messages=[{"role": "user", "content": GRADER.format(p=p)}],
)
return r.choices[0].message.content.strip().lower()
dist = Counter(grade(p) for p in sample_prompts)
total = sum(dist.values())
for k, v in dist.items():
print(f"{k:8s}: {v:4d} ({v / total:.0%})")
出力例:
mundane : 198 (66%)
hard : 102 (34%)
この比率が、後の検証(Step 4)で「分類が意図どおりに効いているか」を測る基準値になります。mundane の比率が高いほど、プール設計による削減余地は大きくなります。
3. Step 2:Adaptive 戦略の Named Router を作る
ダッシュボードで Named Router を新規作成します。
- OrcaRouter ダッシュボードの Named Routers から新規作成します(例:
adaptive-router) - ルーティング戦略に
Adaptiveを選びます - この後(Step 3)で
Gatedモードを有効化し、Mundane / Hard プールを定義します
OrcaRouter の Named Router には複数のルーティング戦略があります。本記事で使うのは Adaptive です。
| 戦略 | 挙動 | 主な用途 |
|---|---|---|
Cheapest |
生存候補のうちトークン単価が最安のモデルを選択 | コスト最優先 |
Quality |
生存候補のうち品質スコアが最高のモデルを選択 | 品質最優先 |
Balanced |
コスト効率と品質のバランスで選択 | 汎用 |
Adaptive |
LinUCB 文脈バンディットで本番トラフィックの結果から継続学習 | 本番運用 |
Adaptive は、各リクエストの特徴量(embedding)と過去結果から「いまのクエリ群でどのモデルが期待値最大か」を学習します。成果の悪いモデルは自動的に振り分けが減り、新規モデルは Upper Confidence Bound 枠で少しだけ試行されます(探索と活用のバランス)。
コールドスタートをどう考えるか
学習型ルーターというと「最初は賢くないのでは」と不安になります。ここで効くのが次の Step の Gated モードです。Gated でプールの境界を構造的に決めておけば、LinUCB の学習が十分に貯まる前から、定型/高度の振り分けは初日から効きます。LinUCB は「プールの中の最適化」を時間をかけて深めていく、という役割分担です。
4. Step 3:Gated モードで Mundane / Hard プールを設計する
ここが本記事の核です。Gated モードを有効化すると、リクエストはまず難易度で分類され、別々のプールから選ばれます。
4-1. 分類の基準を決める
「何を mundane とし、何を hard とするか」は、自社のユースケースで定義します。目安は次のとおりです。
| 区分 | 典型的なプロンプト | 求められるもの |
|---|---|---|
| mundane(定型) | 抽出 / 分類 / 整形 / 短い要約 / 定型変換 / 単純な Q&A | 速さとコスト。オープンモデルで十分な品質が出る |
| hard(高度) | コード生成 / 多段推論 / 長文脈の読解 / 曖昧さの解消 / 設計・企画 | 推論力。フロンティアモデルの品質が効く |
Step 1 で計測した分布が、この境界設計の出発点になります。「請求書から合計金額を抽出」は mundane、「コードベースを読んで設計判断」は hard、といった具合に、自社の代表的なワークロードを 2 つの箱に振り分けてみてください。
4-2. 各プールにモデルを入れる
プールごとに、役割に合ったモデルを複数登録します。複数入れておくと、プール内で LinUCB が自社トラフィックに最も合うモデルを選び、障害時はプール内でフェイルオーバーします。
| プール | 入れるモデルの例 | 役割 |
|---|---|---|
| Mundane Pool |
deepseek/deepseek-v4-pro / qwen/qwen3.7-max / minimax/minimax-m3(Kimi K2.6 など中堅モデルも可) |
定型処理を低コストで。OSS/中堅モデルで「十分な品質」を狙う |
| Hard Pool |
anthropic/claude-opus-4.8 / openai/gpt-5.5(Gemini 3 Pro などフロンティアモデル) |
高度な推論を高品質で。難しいときだけここへ流す |
モデル ID(
プロバイダー/モデル名)はすべて例です。利用可能な最新モデルと正確な ID は OrcaRouter 公式ドキュメント のモデル一覧でご確認ください。
設計のイメージを表で整理すると、次のような構成になります。
adaptive-router (Strategy: Adaptive, Gated: ON)
├─ Mundane Pool
│ ├─ deepseek/deepseek-v4-pro
│ ├─ qwen/qwen3.7-max
│ └─ minimax/minimax-m3
└─ Hard Pool
├─ anthropic/claude-opus-4.8
└─ openai/gpt-5.5
4-3. 設計の指針
- まず保守的に切る。 迷うプロンプトは hard 側に倒しておくと、品質劣化のリスクを抑えられます。削減幅は検証しながら mundane を広げて詰めます
- 各プールに 2〜3 モデル入れる。 1 モデルだけだと、そのモデルが落ちたとき/劣化したときの逃げ場がありません
-
Mundane Pool は「十分な品質」で選ぶ。 最安だけを狙うと品質が安定しません。
Adaptiveがプール内で品質と成果を見て選ぶので、候補は複数渡しておきます
5. Step 4:コードから呼び、解決モデルを確認する
ルーターを定義したら、アプリ側はモデル ID をルーター名に置き換えるだけです。
response = client.chat.completions.create(
model="orcarouter/adaptive-router", # 個別モデルではなくルーターを指定
messages=[{"role": "user", "content": "請求書 PDF から合計金額を抽出してください。"}],
)
print(response.choices[0].message.content)
「実際にどのモデルが選ばれたか」は、レスポンスヘッダー X-Orca-Resolved-Model で確認できます。OpenAI Python SDK では、ヘッダーを取りたいときに with_raw_response を使います。
raw = client.chat.completions.with_raw_response.create(
model="orcarouter/adaptive-router",
messages=[{"role": "user", "content": "請求書 PDF から合計金額を抽出してください。"}],
)
# ヘッダーは大文字小文字を区別しません
resolved = raw.headers.get("x-orca-resolved-model")
completion = raw.parse() # ボディは parse() で取り出す
print("解決モデル:", resolved)
print("本文:", completion.choices[0].message.content)
定型プロンプトでは Mundane Pool のモデル(例:deepseek/deepseek-v4-pro)が、高度なプロンプトでは Hard Pool のモデル(例:anthropic/claude-opus-4.8)が解決モデルとして返れば、プール設計が意図どおりに効いている合図です。
振り分けが効いているかの最小テスト
「明らかに定型」「明らかに高度」のプロンプトを投げ、解決モデルが期待したプールに入っているかを確認します。
MUNDANE_POOL = {"deepseek/deepseek-v4-pro", "qwen/qwen3.7-max", "minimax/minimax-m3"}
HARD_POOL = {"anthropic/claude-opus-4.8", "openai/gpt-5.5"}
def resolved_model(prompt: str) -> str:
raw = client.chat.completions.with_raw_response.create(
model="orcarouter/adaptive-router",
messages=[{"role": "user", "content": prompt}],
)
return raw.headers.get("x-orca-resolved-model")
m = resolved_model("次の文を 10 字で要約してください: 『…』") # 定型 → mundane を期待
h = resolved_model("この設計の失敗モードを 3 つ挙げ、根拠を述べてください。") # 高度 → hard を期待
assert m in MUNDANE_POOL, f"定型が mundane に入っていない: {m}"
assert h in HARD_POOL, f"高度が hard に入っていない: {h}"
print("OK: 振り分けが意図どおりに効いています")
6. Step 5:監査ログで「分類が正しいか」を検証する
最小テストが通っても、本番では多様なプロンプトが流れます。プール設計が分布全体で意図どおりかは、リクエスト単位の監査ログで検証します。OrcaRouter は、どのリクエストがどの分類・モデル・プロバイダー・公開価格で処理されたかを記録します。
ダッシュボードでは次のように 1 リクエストずつ追跡できます。
| 分類 | モデル | プロバイダー | 公開価格 | 支払額 |
|---|---|---|---|---|
| 定型 | deepseek/deepseek-v4-pro |
DeepSeek | $0.0008 | $0.0008 |
| 高度 | anthropic/claude-opus-4.8 |
Anthropic Direct | $0.0420 | $0.0420 |
| 定型 | qwen/qwen3.7-max |
Alibaba Cloud | $0.0006 | $0.0006 |
「支払額 = 公開価格」が行単位で確認できます(これが上乗せ 0% の実証です)。さらに、解決モデルがどのプールに落ちたかの分布を集計すれば、Step 1 で見積もった mundane/hard 比率と突き合わせられます。
from collections import Counter
def pool_of(model_id: str) -> str:
if model_id in MUNDANE_POOL:
return "mundane"
if model_id in HARD_POOL:
return "hard"
return "other"
counter = Counter(pool_of(resolved_model(p)) for p in sample_prompts)
total = sum(counter.values())
for k, v in counter.items():
print(f"{k:8s}: {v:4d} ({v / total:.0%})")
# 期待: Step 1 の見積もり(例 mundane 66% / hard 34%)に近い分布になる
実測分布が見積もりから大きくずれていたら、プール設計か分類の基準を見直すサインです。
7. Step 6:チューニングのループ
検証結果から、プールの境界を詰めていきます。判断は 2 方向です。
- hard が mundane に落ちて品質が下がっている → そのユースケースを hard 寄りに。Mundane Pool のモデルを品質の高いものに差し替える、または分類基準を保守側へ
- mundane が hard に流れて払いすぎている → 監査ログで「定型なのに Hard Pool のモデルが選ばれている」行を探し、mundane 側を広げる
品質劣化を早期に捕まえるには、**eval(自社テストケースでの定期スコアリング)**を併用します。自社の正解データに対してルーターとモデルを定期スコアリングし、品質の落ち込みをユーザーより先に検知できます。プール内のモデル選定は LinUCB が自動で最適化していくので、あなたが管理し続けるのはプールの境界だけになります。
8. 本番投入前のチェック
ルーターを本番に乗せる前に、運用面の設計も確認しておきます。
- Gated から始める。 学習を待たずに定型/高度の振り分けが効くため、初日からコスト上振れを構造的に抑えられます
-
解決モデルの分布を監視する。
X-Orca-Resolved-Modelの分布を定期集計し、想定からのドリフトを検知します - ミッドストリーム・フェイルオーバー。 ストリーム途中でプロバイダーが劣化しても、エージェントのツール状態を維持したまま別プロバイダーへ切り替わります(リクエスト再起動なし)
- ガードレール 8 種。 PII Shield / Secrets & API Keys / Prompt Injection / Profanity & Brand Safety / Financial Data (PCI) / System-Prompt Leak / Compliance Logger / Prompt-Size Cap
- eval を定期実行。 自社テストケースで品質回帰を監視します
-
切り戻しは 1 行。
modelをルーター名から個別モデル ID に戻すだけで、いつでも元に戻せます。この可逆性が本番投入の心理的安全性になります
日本国内で本番運用する場合に必要な 円建て請求・適格請求書(インボイス)対応・JST 営業時間内の日本語サポート・国内データルーティング(AWS / GCP 日本リージョン) は、FlashLabs が Enterprise 契約に応じて即時構成して提供します。技術基盤(Continuum AI 側)に、日本市場の本番運用層(FlashLabs 側)を重ねる形です。
OrcaRouter の機能・価格・サポートモデル
ここまでで Adaptive Named Router の設計・検証手順を見てきました。実際にどの機能が、どの価格で、どのモデルに対して効くかを、リファレンスとして整理しておきます。
主要機能
- アダプティブ・ルーティング:プロンプトごとに難易度を判定し、難しい推論はフロンティアモデルへ、定型処理はオープンモデルへ自動振り分け
- 200+ モデル対応:Claude Opus 4.8、GPT-5.5 Pro、Gemini 3.5、DeepSeek V4 Pro、Qwen3.6-plus、Kimi K2.6 など
- LinUCB 文脈バンディット:リクエスト結果から学習し、成果が悪いモデルへの振り分けを自動削減
- ルーティング遅延 <1ms:ミリ秒未満の判定で UX を損なわない
- 完全可視化:判定結果・モデル・プロバイダー・公開価格をリクエスト単位で記録
価格
- 月額プラン:最大 10% ボーナスクレジット自動付与(毎月の請求サイクルごと)
- トークン課金:プロバイダー公開価格と同額(上乗せ 0%)
- ルーティング手数料:0%
サポートする主要モデル例
- Anthropic Claude Opus 4.8 API
- OpenAI GPT-5.5 API
- Gemini 3.5 Flash
- MiniMax M3
- DeepSeek V4 Pro API
- Qwen3.7 Max
公式: OrcaRouter 料金ページ
9. ハマりどころと対処
- 削減がほとんど出ない → 多くのプロンプトが Hard Pool に流れています。監査ログで定型リクエストの解決モデルを確認し、Mundane Pool 側を広げてください
- たまに品質が落ちる → 本来 hard な処理が mundane に分類されています。該当ユースケースを hard 寄りに倒し、eval で回帰を監視します
-
解決モデルが取れない → ボディだけ受け取る
create()ではヘッダーは取れません。with_raw_response.create()を使い、raw.parse()でボディを取り出します -
modelの指定形式 → 個別指定はプロバイダー/モデル名(例:openai/gpt-5.5)、ルーター指定はorcarouter/{ルーター名}です。接頭辞のないモデル名だけだと解決できないことがあります - 学習がいつ効くのか分からない → プール内最適化(LinUCB)はトラフィックが貯まるほど深まります。即効性が要るコスト制御は Gated の境界設計側で担保し、LinUCB は中長期の最適化と捉えると設計しやすくなります
-
既存ツールから使いたい → Cursor / Cline / Continue / Aider / LangChain / LlamaIndex などは OpenAI 互換設定で
base_urlを差し替えれば、そのまま OrcaRouter 経由にできます
10. まとめ
Adaptive Named Router を、自社トラフィックに合わせて設計・検証する手順を通しで実装しました。
- Step 1:安価なモデルで難易度分布を見積もる(mundane/hard 比率の基準値)
-
Step 2:
Adaptive戦略の Named Router を作る -
Step 3:
Gatedモードで Mundane / Hard プールを設計する(削減幅を決める核) - Step 4〜5:解決モデルと監査ログで、振り分けが意図どおりかを検証する
- Step 6:境界を詰めるチューニングのループを回す(プール内は LinUCB が自動最適化)
あなたが設計するのはプールの境界だけ。あとはゲートウェイが、見える形で振り分け、運用とともに最適化を深めます。乗り換えは 1 行、判断は全部見える。Continuum AI の先端を FlashLabs が日本に届けます。
始め方
- API キーを取得:OrcaRouter 登録ページ(500 万無料クレジト付き、クレジットカード不要) で 60 秒でライブ
- ドキュメント:OrcaRouter 公式ドキュメント
- 会社で本番運用を検討する場合:先着 100 社・無償診断レポート(推論クレジト ¥3 万付き) のお申し込みを FlashLabs まで
OrcaRouter について
OrcaRouter は、Continuum AI(米国)が開発し、FlashLabs が日本独占販売する適応型推論ゲートウェイです。プロンプトごとに難易度を判定し、難しい推論はフロンティアモデルへ、定型処理はオープンモデルへ自動ルーティングすることで、品質を守りながら LLM 支出を約 40% 削減します。判断根拠はリクエスト単位で可視化され、トークン上乗せは 0%、ルーティング遅延は <1ms です。200+ モデルを 1 エンドポイントで利用可能で、導入は 1 行から可能です。
公式サイト: https://www.orcarouter.ai/ja/
FlashLabs 株式会社について
FlashLabs は、営業とカスタマーエクスペリエンスを自動化し、最終的には自律化へ導くことを目指す AI 応用研究所です。機械の処理速度・精度と人間の戦略的洞察を融合させた "Human-AI Hybrid" で、従来手法を凌駕する成果を企業にもたらします。
主要製品として、AI 推論コスト 約 40%(最大 70%)削減 を実現する「OrcaRouter」、営業・マーケティング自動化プラットフォーム「FlashIntel」、AI 音声エージェント「Chroma」などを提供しています。
- 会社名:FlashLabs 株式会社
- 所在地:東京都千代田区
- 代表者:代表取締役 細井 洋一
- 事業内容:AI 応用研究、営業・カスタマーエクスペリエンス自動化ソリューションの開発・提供
- URL:https://www.flashlabs.ai/
Continuum AI について
Continuum AI は、次世代 AI インフラを開発する米国の研究機関です。適応型推論ゲートウェイ「OrcaRouter」を開発し、企業の AI 活用における品質とコストの両立を実現する技術を提供しています。



