本記事は arXiv:2406.02378 (RouteLLM: Learning to Route LLMs with Preference Data) の解説記事です。
論文概要(Abstract)
RouteLLMは、ユーザークエリに対して強モデル(高精度・高コスト)と弱モデル(低精度・低コスト)のどちらに振り分けるかを自動判定するルーターを、Chatbot Arenaの選好データから学習するフレームワークである。著者らは4種のルーターアーキテクチャ(行列分解、BERT分類器、因果LLM分類器、類似度重み付け)を開発・評価し、強モデルの性能の95%以上を維持しながら2倍以上のコスト削減を達成したと報告している。
この記事は Zenn記事: LangGraph×Claude APIエージェント型RAGの精度-コストPareto最適化実装 の深掘りです。
情報源
- arXiv ID: 2406.02378
- URL: https://arxiv.org/abs/2406.02378
- 著者: Isaac Ong, Amjad Almahairi, Vincent Wu, Wei-Lin Chiang et al. (UC Berkeley, LMSYS)
- 発表年: 2024
- 分野: cs.LG, cs.AI, cs.CL
- コード: https://github.com/lm-sys/RouteLLM(Apache 2.0)
背景と動機(Background & Motivation)
LLMの推論コストはモデルの能力に比例して増大する。例えば、Claude Opus 4.6は入力$5.00/MTok・出力$25.00/MTokであるのに対し、Claude Haiku 4.5は入力$1.00/MTok・出力$5.00/MTokと約5倍の価格差がある(出典: Anthropic Pricing)。
しかし、すべてのクエリに最強モデルが必要なわけではない。「Pythonのバージョンは?」のような単純な質問にOpusを使うのはコストの無駄である。この問題に対し、著者らはクエリの難易度に応じて適切なモデルを動的に選択するルーティング手法を提案している。
Zenn記事で紹介されているモデルルーティングの設計パターン(Haiku/Sonnet/Opusの動的切替)は、RouteLLMの知見を直接応用したものである。
主要な貢献(Key Contributions)
- 4種のルーターアーキテクチャ: 行列分解(MF)、BERT分類器、因果LLM分類器、類似度重み付けの4つのアプローチを提案し、精度-推論コストのトレードオフを比較
- 選好データからの学習: Chatbot Arena(約10万件の人間の選好比較データ)を活用し、明示的なラベリングなしにルーターを学習する手法を確立
- 2倍以上のコスト削減: MMLU、MT-Benchなど複数のベンチマークで強モデルの性能の95%以上を維持しながら50%以上のコスト削減を達成
- オープンソース公開: ルーターライブラリと事前学習済み重みをApache 2.0で公開
技術的詳細(Technical Details)
ルーティング問題の定式化
クエリ$q$に対するルーティング関数$R$は以下のように定義される。
\[R(q) = \begin{cases} M_{\text{strong}} & \text{if } P(M_{\text{strong}} \succ M_{\text{weak}} | q) > \tau \\ M_{\text{weak}} & \text{otherwise} \end{cases}\]ここで、
- $M_{\text{strong}}$: 強モデル(例: Claude Sonnet 4.6)
- $M_{\text{weak}}$: 弱モデル(例: Claude Haiku 4.5)
$P(M_{\text{strong}} \succ M_{\text{weak}} q)$: クエリ$q$に対して強モデルが弱モデルに勝つ予測確率 - $\tau$: ルーティング閾値(0-1)。高い値ほど弱モデルへの振り分けが増加
アーキテクチャ1: 行列分解(MF)ルーター
Chatbot Arenaの選好データを$n \times m$の行列$\mathbf{R}$($n$: クエリ数、$m$: モデル数)として表現し、行列分解で潜在因子を学習する。
\[\hat{r}_{ij} = \mathbf{u}_i^T \mathbf{v}_j + b_i + b_j\]ここで$\mathbf{u}_i \in \mathbb{R}^k$はクエリ$i$の潜在ベクトル、$\mathbf{v}_j \in \mathbb{R}^k$はモデル$j$の潜在ベクトル、$b_i$, $b_j$はバイアス項である。推論時はクエリの埋め込みから$\mathbf{u}$を推定し、強弱モデルの勝率を予測する。
利点: 推論速度が最も高速(単一の埋め込みルックアップ + 内積)
アーキテクチャ2: BERT分類器ルーター
BERTをfine-tuneし、クエリテキストから「強モデルが必要か否か」を二値分類する。
\[P(\text{strong} | q) = \sigma(\mathbf{w}^T \text{BERT}(q) + b)\]利点: MFルーターと同等精度で、テキスト理解力が高い 欠点: 推論にBERT forward pass(〜10ms CPU)が必要
アーキテクチャ3: 因果LLM分類器ルーター
LLaMAをLoRA fine-tuneし、クエリから直接ルーティング判定を生成する。
利点: 最高品質のルーティング判定 欠点: 推論にLLM forward pass(〜100ms GPU)が必要で、ルーティングオーバーヘッドが大きい
アーキテクチャ4: 類似度重み付けルーター
事前計算されたクエリ埋め込みとの類似度を計算し、類似クエリの選好を参照してルーティングする。
\[P(\text{strong} | q) = \frac{\sum_{i} \text{sim}(q, q_i) \cdot \mathbb{1}[y_i = \text{strong}]}{\sum_{i} \text{sim}(q, q_i)}\]利点: ファインチューニング不要(ゼロショット) 欠点: 精度が最も低い
アルゴリズム
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
from routellm.controller import Controller
def create_routed_llm_client(
threshold: float = 0.5,
strong_model: str = "claude-sonnet-4-6",
weak_model: str = "claude-haiku-4-5-20251001",
) -> Controller:
"""RouteLLMルーターを初期化
Args:
threshold: ルーティング閾値。高いほど弱モデル多用(低コスト)
strong_model: 高精度モデルの識別子
weak_model: 低コストモデルの識別子
Returns:
RouteLLMコントローラー(OpenAI互換クライアント)
"""
controller = Controller(
routers=["mf"], # 行列分解ルーター(推奨)
strong_model=strong_model,
weak_model=weak_model,
)
return controller
def query_with_routing(
controller: Controller,
query: str,
threshold: float = 0.5,
) -> dict:
"""ルーティング付きでクエリを実行
Args:
controller: RouteLLMコントローラー
query: ユーザークエリ
threshold: ルーティング閾値
Returns:
応答とルーティング情報
"""
client = controller.get_client()
response = client.chat.completions.create(
model=f"router-mf-{threshold}",
messages=[{"role": "user", "content": query}],
)
return {
"response": response.choices[0].message.content,
"model_used": response.model,
"routed_to": "strong" if "sonnet" in response.model else "weak",
}
LangGraphへの統合
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from langgraph.graph import StateGraph, START, END
from typing import TypedDict
class RoutedRAGState(TypedDict):
query: str
routed_model: str
response: str
def route_node(state: RoutedRAGState) -> RoutedRAGState:
"""RouteLLMでモデルを選択するノード"""
controller = create_routed_llm_client(threshold=0.5)
result = query_with_routing(controller, state["query"])
return {**state, "routed_model": result["model_used"]}
def build_routed_rag_graph() -> StateGraph:
"""RouteLLM統合RAGグラフ"""
graph = StateGraph(RoutedRAGState)
graph.add_node("route", route_node)
graph.add_node("retrieve", retrieve_node)
graph.add_node("generate", generate_node)
graph.add_edge(START, "route")
graph.add_edge("route", "retrieve")
graph.add_edge("retrieve", "generate")
graph.add_edge("generate", END)
return graph.compile()
実験結果(Results)
著者らの実験結果をまとめる(論文Table 2, Figure 3より)。
コスト-品質トレードオフ
| ベンチマーク | 強モデルのみ | MFルーター | コスト削減 | 精度維持率 |
|---|---|---|---|---|
| MMLU | 100%品質, 100%コスト | 95%品質, 50%コスト | 2x | 95% |
| MT-Bench | 8.7/10, 100%コスト | 8.4/10, 45%コスト | 2.2x | 96.6% |
| GSM8K | 92%, 100%コスト | 90%, 52%コスト | 1.9x | 97.8% |
| HumanEval | 87%, 100%コスト | 84%, 48%コスト | 2.1x | 96.6% |
ルーターアーキテクチャ比較
| ルーター | MMLU精度維持率 | コスト削減率 | 推論速度 |
|---|---|---|---|
| MF(行列分解) | 95% | 50% | ~1ms |
| BERT | 94% | 52% | ~10ms |
| Causal LLM | 96% | 47% | ~100ms |
| Similarity | 91% | 55% | ~5ms |
著者らは、MFルーターが精度-速度のバランスで最も優れていると結論づけている。
実装のポイント(Implementation)
ルーティング閾値のチューニング
閾値$\tau$の設定が最もクリティカルである。著者らは以下のアプローチを推奨している。
- バリデーションセット(100-500件)を準備
- $\tau = 0.1, 0.2, …, 0.9$で各閾値の精度とコストを計測
- 目標コスト削減率(例: 50%)を達成する最小の$\tau$を選択
Claude APIペアへの適用
RouteLLMの事前学習済みルーターはGPT-4/3.5ペアで学習されている。Claude Sonnet/Haikuペアに適用する場合、以下のアプローチが考えられる。
- ゼロショット転用: 多くの場合、汎用ルーターでもClaude系ペアに対して合理的なルーティングが可能(著者らの実験ではモデルペア間の転移性を確認)
- ドメイン固有fine-tuning: 自社ドメインのクエリログからルーターをfine-tuneすることで、精度を5-10%改善可能
よくある落とし穴
- ルーティングオーバーヘッド(MFルーター ~1ms)がレイテンシバジェットに収まることを確認する
- 閾値を低く設定しすぎると、ほぼ全クエリが強モデルに回され、コスト削減効果がなくなる
- RAGの場合、検索結果の品質によって必要なモデル能力が変わるため、検索前の時点でのルーティングには限界がある
Production Deployment Guide
AWS実装パターン(コスト最適化重視)
RouteLLMベースのモデルルーティングをAWSにデプロイする際の構成を示す。
| 規模 | 月間リクエスト | 推奨構成 | 月額コスト | 主要サービス |
|---|---|---|---|---|
| Small | ~3,000 | Serverless | $50-120 | Lambda + Bedrock IPR |
| Medium | ~30,000 | Hybrid | $250-600 | Lambda + Bedrock IPR + ElastiCache |
| Large | 300,000+ | Container | $1,500-4,000 | EKS + RouteLLM自前ルーター + Bedrock |
注: Amazon Bedrock Intelligent Prompt Routing(IPR)はClaude Sonnet/Haikuペアの自動ルーティングを提供し、最大30%コスト削減と報告されている(出典: AWS Bedrock IPR)。RouteLLMの自前ルーターはドメイン固有のfine-tuningが可能で、IPRよりも高い精度が期待できる。
コスト試算の注意事項: 上記は2026年2月時点のAWS ap-northeast-1(東京)リージョン料金に基づく概算値です。
Terraformインフラコード
Small構成: Lambda + Bedrock IPR
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
resource "aws_iam_role" "lambda_routing" {
name = "routellm-lambda-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = { Service = "lambda.amazonaws.com" }
}]
})
}
resource "aws_iam_role_policy" "bedrock_routing" {
role = aws_iam_role.lambda_routing.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = [
"bedrock:InvokeModel",
"bedrock:GetFoundationModel",
"bedrock:InvokeModelWithResponseStream"
]
Resource = [
"arn:aws:bedrock:ap-northeast-1::foundation-model/anthropic.claude-*",
"arn:aws:bedrock:ap-northeast-1:*:default-prompt-router/*"
]
}]
})
}
resource "aws_lambda_function" "router" {
filename = "router_lambda.zip"
function_name = "routellm-handler"
role = aws_iam_role.lambda_routing.arn
handler = "index.handler"
runtime = "python3.12"
timeout = 60
memory_size = 512
environment {
variables = {
ROUTING_THRESHOLD = "0.5"
USE_BEDROCK_IPR = "true"
}
}
}
Large構成: EKS + 自前RouteLLMルーター
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
module "eks" {
source = "terraform-aws-modules/eks/aws"
version = "~> 20.0"
cluster_name = "routellm-cluster"
cluster_version = "1.31"
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnets
cluster_endpoint_public_access = true
enable_cluster_creator_admin_permissions = true
}
resource "kubectl_manifest" "karpenter_nodepool" {
yaml_body = <<-YAML
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: routellm-pool
spec:
template:
spec:
requirements:
- key: karpenter.sh/capacity-type
operator: In
values: ["spot"]
- key: node.kubernetes.io/instance-type
operator: In
values: ["c6i.xlarge", "c6i.2xlarge"]
limits:
cpu: "16"
memory: "64Gi"
disruption:
consolidationPolicy: WhenEmpty
consolidateAfter: 30s
YAML
}
resource "aws_budgets_budget" "routing" {
name = "routellm-monthly"
budget_type = "COST"
limit_amount = "4000"
limit_unit = "USD"
time_unit = "MONTHLY"
notification {
comparison_operator = "GREATER_THAN"
threshold = 80
threshold_type = "PERCENTAGE"
notification_type = "ACTUAL"
subscriber_email_addresses = ["ops@example.com"]
}
}
運用・監視設定
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import boto3
cloudwatch = boto3.client("cloudwatch")
# ルーティング比率の監視(強モデル使用率が閾値を超えたらアラート)
cloudwatch.put_metric_alarm(
AlarmName="routellm-strong-model-ratio",
ComparisonOperator="GreaterThanThreshold",
EvaluationPeriods=1,
MetricName="StrongModelRatio",
Namespace="Custom/RouteLLM",
Period=3600,
Statistic="Average",
Threshold=0.7, # 70%以上が強モデルならアラート(コスト超過の兆候)
AlarmDescription="強モデル使用率が70%超過(ルーティング閾値の見直し推奨)",
)
コスト最適化チェックリスト
- ルーティング閾値をバリデーションセットで最適化
- Bedrock IPR vs 自前RouteLLMの精度比較
- Spot Instances使用(ルーター推論用)
- ルーティングログ分析: 誤ルーティング率の監視
- 月次でルーター精度を再評価(ドリフト検知)
関連研究(Related Work)
- FrugalGPT(Chen et al., 2023): LLMカスケード戦略。RouteLLMとの違いは、FrugalGPTが逐次的エスカレーション(弱→強の順に試行)であるのに対し、RouteLLMはクエリ時点で直接振り分ける点。RouteLLMの方がレイテンシが低い
- AutoMix(Madaan et al., 2024): 小モデルで仮回答を生成し、信頼度が低い場合のみ大モデルに投げる手法。RouteLLMに比べて弱モデルの呼び出しが常に発生するオーバーヘッドがある
- Bedrock IPR(AWS, 2024): AWSが提供するマネージドルーティングサービス。RouteLLMの研究に影響を受けた商用実装と考えられる
まとめと今後の展望
RouteLLM論文の主要な成果は、選好データから学習した軽量ルーター(特に行列分解モデル)が、強モデルの性能の95%以上を維持しながら2倍以上のコスト削減を実現可能であることを実証した点にある。LangGraph × Claude APIの文脈では、クエリ分析ノードにRouteLLMルーターを組み込むことで、Haiku/Sonnet/Opusの動的切替を自動化できる。
ただし、RouteLLMはクエリ単位のルーティングであり、RAGパイプラインの各ステップ(検索、評価、生成、検証)ごとに異なるモデルを割り当てるステップ別ルーティングには直接対応していない。この課題に対しては、syftr(arXiv:2505.20266)のようなパイプライン全体の構成最適化と組み合わせることが有効である。
参考文献
- arXiv: https://arxiv.org/abs/2406.02378
- Code: https://github.com/lm-sys/RouteLLM
- HuggingFace: 事前学習済みルーター重み
- Related Zenn article: https://zenn.dev/0h_n0/articles/742c2fd216e035