Point:
NVIDIA NeMo Switchyardは、複数の大規模言語モデル(LLM)を一つのシステムとして組み合わせ、リクエストやエージェントの実行状況に応じて適切なモデルへ処理を振り分けるためのモデルルーティング(Model Routing)基盤である。NVIDIAはSwitchyardを、AIエージェントのワークフローにおいて各リクエストを適切なモデルへ自動的にルーティングするオープンソース(Apache 2.0ライセンス)のモデルルーティングライブラリとして位置付けている。
Switchyardは2026年8月11日、30Bパラメータのオープンウェイト・エージェント向けMoEモデルであるNemotron 3.5 Lightningと同時に発表された。すなわちSwitchyard単体の製品ではなく、「軽量な自社モデルと高性能なフロンティアモデルを組み合わせて使い分ける」というNVIDIAのSystem of Models構想の中核部品として位置付けられている。
ここでいう「適切なモデル」とは、単純に最も性能の高いモデルという意味ではない。タスクの難易度、モデルの能力、推論速度、コスト、現在のエージェントの状態などを考慮し、その時点で最も合理的なモデルを選択するという意味である。したがってSwitchyardの目的は、単一のLLMを高速化することではなく、複数のLLMを組み合わせることで、品質・コスト・レイテンシーの全体最適化を図ることにある。
従来のLLMアプリケーションでは、「アプリケーションから特定のモデルを呼び出す」という構成が一般的であった。例えば、すべてのリクエストを一つの高性能モデルに送る方式である。しかし、実際のLLMワークロードには、非常に簡単な処理から高度な推論を必要とする処理まで、さまざまな種類が混在している。
単純な質問への回答や定型的なコード編集まで高価なフロンティアモデルに処理させる必要はない。一方、複雑な推論、難しいバグ修正、専門的な問題解決などでは、小型モデルでは能力不足になる可能性がある。このため、「すべてを高性能モデルで処理する」のではなく、「簡単な仕事は安価で高速なモデル、難しい仕事は高性能モデル」という使い分けが合理的になる。NVIDIAの社内ベンチマークでは、こうしたルーティングによってタスク完了コストを、全ステップをOpus 4.8のみで処理した場合の約3分の1まで削減できたとされている。
このような考え方を一般化したものが
Switchyardの位置を単純化すると、
この構造によって、アプリケーションとモデルの結合を弱めることができる。例えば、アプリケーション側が「モデルAを使う」と固定的に記述していた場合、モデルを変更するたびにアプリケーションを変更する必要がある。Switchyardを間に置けば、アプリケーションは論理的なモデルやルーターを利用し、実際のモデル選択をSwitchyard側に委ねることができる。
したがって、Switchyardの重要な役割は、単に複数のモデルを呼び出すことではなく、
SwitchyardとvLLM Semantic Routerは、いずれも
したがって、概念的には「モデルサービング層」と「Agent/Application」の間に、SwitchyardまたはvLLM Semantic RouterのようなModel Routing層を置くことができる。ただし実際のシステムではGatewayやProxy、Agent Runtimeなどとの配置関係が異なるため、固定的な一階層として捉えるより、
Switchyardを理解するうえでは、
例えば、低コストで高速なモデルを「weak(efficient)」、高性能なモデルを「bg(capable)」として登録し、「通常の処理ではweakを使い、難しい処理ではbgを使う」というルーティングを定義できる。この場合、アプリケーションは具体的なモデル名やエンドポイントを直接判断する必要がない。
この分離によって、バックエンドモデルを変更してもルーティングポリシーを維持しやすくなる。これは、モデルの世代交代が非常に速い現在のLLMシステムにおいて重要な設計上の利点である。
Switchyardには複数のルーティング方式が存在する。公式に提供されているものとして、Random Routing、Capability(LLM Classifier)Routing、Stage Router、Capability+Stage(Composite)Router、Escalation Router、Advisor Gate Routing、Sub-Agent-Aware Routing、そしてユーザー定義の判定基準を使うCustom Routingがある。これらは「モデルを選ぶ」という共通の目的を持つが、選択の根拠が異なる。
Random Routingは文字どおりランダムにモデルへ振り分ける方式であり、A/Bテストや実験的なトラフィック分割などに利用できる。この方式は意味理解を必要としないため、Semantic Routingそのものではない。
Capability(LLM Classifier)Routingでは、LLMを分類器として利用し、最初のリクエストの内容からタスクの性質を判断してモデルを選択する。例えば、コーディング、数学、一般的な質問などを分類し、それぞれに適したモデルへ振り分けることができる。これはSwitchyardの中でも、vLLM Semantic Routerに比較的近い方式である。Capability+Stage(Composite)Routingは、この最初の分類判断とStage Routerによる進行状況の判断を組み合わせたものである。
Switchyardの特徴を理解するうえで特に重要なのが
例えばコーディングエージェントであれば、コードベースを探索している段階、エラーの原因を調査している段階、修正コードを作成している段階、テストを実行している段階などが存在する。それぞれで必要なモデル能力は異なる。
特に重要なのは、Stage Routerが
したがってStage Routerは、単純なSemantic Routerよりも
Escalation Routerは、さらに異なるアプローチを採用する。最初から高性能モデルを選択するのではなく、まず低コストのモデルで処理を開始する。そして、その処理の応答をLLMによる判定にかけ、問題が検出された場合に、より高性能なモデルへエスカレーションする。
つまり、モデル選択を一回限りの判断として扱わず、
例えば、最初は小型モデルで十分だと判断して処理を開始したものの、ツール実行を繰り返しても問題が解決しない場合がある。その時点で高性能モデルへ切り替えることで、「最初から高価なモデルを使う」ことと「最後まで小型モデルに任せる」ことの中間を取ることができる。
Escalation Routerがモデルそのものを切り替えるのに対し、
vLLM Semantic Routerは、vLLMプロジェクトにおいて複数のLLMを使い分けるための
その基本思想はSwitchyardと共通している。すなわち、一つのLLMにすべてのリクエストを送るのではなく、入力やコンテキストから得られる情報を利用して、複数のモデルから適切なモデルを選択するのである。
当初のアーキテクチャは「ユーザー入力 → MMLUベースのドメイン分類 → モデル選択」という単純なパイプラインであったが、ドメイン分類という単一次元だけでは、緊急性、セキュリティ機微性、意図の種類、複雑さといった多次元のシグナルを捉えきれないという制約があった。この課題に対応するため、プロジェクトは
ここでSemantic Routingという用語を明確にする必要がある。Semantic Routingとは、入力されたリクエストの
例えば、「この質問は数学なのか」「コーディングなのか」「医学なのか」「簡単なのか難しいのか」「特定の知識領域に属しているのか」といった情報を抽出し、その結果に応じてモデルを選択する。
したがってSemantic RoutingはModel Routingそのものではない。より正確には、
両者の共通点は非常に大きい。どちらも、複数のモデルを背後に配置し、それらを一つの論理的なLLMサービスとして扱うための技術である。
従来の構成では「Application → Model A」であったものを、「Application → Router → Model A/Model B/Model C」という構成に変える。アプリケーションは特定のモデルを直接選択する必要がなくなり、ルーターが適切なモデルを選択する。
また、両者とも単純なロードバランサーとは異なる。ロードバランサーの目的が同一サービスの複数インスタンスへ負荷を分散することであるのに対し、Model Routerは
一方で、両者を同一のものと考えることはできない。最も大きな違いは、設計の中心に置かれているものにある。
vLLM Semantic Routerは、名前が示すとおり
一方、SwitchyardはSemantic Routingを含みつつ、それをより広い
したがって、概念的には、
| 項目 | NeMo Switchyard | vLLM Semantic Router |
|---|---|---|
| 大きな領域 | Model Routing / Inference Orchestration | Semantic Routing / Model Routing |
| 中心的な思想 | 複数モデルをエージェントワークフローに組み込む | 意味的シグナルに基づいてモデルを選択する |
| 代表的な方式 | Random、Capability(LLM Classifier)、Stage Router、Composite、Escalation、Advisor Gate、Sub-Agent-Aware、Custom | キーワード・埋め込み・ニューラル分類器によるSignal-Decisionアーキテクチャ(intent、domain、complexity、jailbreak、PIIなど) |
| 入力内容の意味 | 利用する | 非常に重視する |
| エージェント状態 | 特に重視する | コンテキストやセッション等を利用可能 |
| ツール実行履歴 | Stage Router等で重要 | ルーティングシグナルの一部として扱える |
| 適応的エスカレーション | Escalation Router、Advisor Gateで対応 | 複数のルーティング・モデル選択方式を提供 |
| ライセンス | Apache 2.0(OSS) | OSS(vLLMプロジェクト傘下) |
| 組み込み形態 | Rust製プロキシサーバー、ライブラリ | Router/Gateway等のルーティング層 |
| 主な対象 | Agent、Gateway、Proxy、AI Application | LLM Application、Mixture-of-Models |
SwitchyardをSemantic Routerと呼ぶことは、一部の機能については正しいが、Switchyard全体を表す名称としては狭すぎる。
確かにCapability(LLM Classifier)Routerは、入力を分類して適切なモデルへ送るため、Semantic Routerに近い。しかし、Random Routingは意味を利用しない。またStage Routerはエージェントの進行状況を利用し、Escalation RouterやAdvisor Gateは処理結果を観測しながらモデルを切り替えたり判定を差し戻したりする。このためSwitchyard全体をSemantic Routerと定義することはできない。
逆に、Switchyardを単なる「モデル振り分け機」と考えるのも不十分である。モデルルーティングを実際のLLMプロキシやAgent Runtime、Gatewayへ組み込むためのサーバーおよびライブラリとして設計されているからである。
SwitchyardはLLM Gatewayと組み合わせて利用できるが、両者は同じものではない。LLM Gatewayの一般的な役割は、複数のLLMプロバイダーやモデルへの接続を統一し、認証、アクセス制御、レート制限、監視、トラフィック管理などを提供することである。
それに対してSwitchyardの中心的な役割は
したがって、Switchyardを「LLM Gateway」とだけ表現すると、その本質であるModel Routingの部分が見えなくなってしまう。
Switchyardの位置付けを理解するうえで重要なのが、NVIDIAがSwitchyardを単独の製品として閉じた形で利用させるのではなく、既存のAIソフトウェアスタックへ組み込む方向で展開していることである。
NVIDIAが公開時点で紹介している統合先には、Kong、LiteLLM、LangChain、Cognition、Boomi、Cadence、Nous Research、Ramp、Siemensなどがある。これはSwitchyardが特定のAgent FrameworkやGatewayそのものではなく、既存のシステムに
Kongの場合はAI Gatewayの内部でSwitchyardをネイティブに利用してモデル選択を行う。LiteLLMではプロキシ層へのプラグインとしてSwitchyardを組み込む対応を進めている。LangChainではDeep Agentsのモデルルーティングに利用する。CognitionではDevin Desktopの内部にstaged routerとして組み込まれている。Nous ResearchはオープンモデルHermesにSwitchyardを組み込み、開発者が容易に設定できるルーティングの仕組みを提供している。Cadenceは形式検証(formal verification)用途でChipStack AI Super Agentの効率改善に、Siemensは自社のFuse EDA AIエージェントの効率改善にそれぞれベンチマークを進めている。この違いは重要であり、Switchyardが単一の利用形態に限定されないことを示している。
NVIDIAが紹介する実例では、Boomiがドメインベースのルーティングで100%のドメインルーティング精度を達成し、トラフィックの59%を標準モデルより5倍高速なfine-tuned modelへ振り分け、後続ターンのレイテンシーを21%削減したとされる。Classmethodはopencodeおよびfireworksのワークロードに社内適用し、品質を維持したままコストを27%削減したという初期結果を報告している。CognitionはDevin Desktopにstaged routerを組み込み、FrontierCode Mainにおいてフロンティアモデル並みの性能をほぼ維持しながら、単一のフロンティアモデルにすべて送る場合と比べて平均コストを28%削減したとされる。
LangChainのDeep Agentsでは、145件のマルチターンタスクにおいて、フロンティアモデルへ送る呼び出しを全体の7%に限定することで、6%の精度低下と引き換えに74%のコスト削減を達成した例が示されている。Rampでは、自社のSWE-Bench環境においてフロンティアモデルと同等の性能を維持しながら、コストを58%、実行時間を33%削減した事例が紹介されている。Cadenceは形式検証タスクにおいて効率を9.9%改善したと報告している。
ただし、これらの数値の多くはNVIDIAまたは各パートナー自身が公表したものであり、第三者による独立検証を経たものではない点には留意が必要である。実際、アナリストの一部からは、NVIDIA社内ベンチマークの比較対象が「全ステップをフロンティアモデルのみで処理する」という、コストに敏感な開発チームであれば通常選ばない高コスト構成を基準に置いている点や、削減効果の大部分が最初にNemotron 3.5 Lightningを組み込んだ段階で生じており、モデルプールを増やすこと自体の追加的な寄与は限定的であるとの指摘も出ている。したがって、Switchyardの効果を評価する際には、公表された削減率だけでなく、比較対象となったベースラインの設定にも注意を払う必要がある。
これらの事例から分かるのは、Switchyardの目的が単純な「モデルの自動選択」ではなく、
両者を一つの階層で整理すると、最も上位に
この整理に従えば、vLLM Semantic Routerは
したがって、SwitchyardとvLLM Semantic Routerは部分的には競合するが、完全な一対一の競合関係ではない。特に「入力内容を理解して最適なモデルを選択する」という部分ではかなり重なる。一方、Switchyardが重視するAgent Stage、Escalation、Advisor Gate、プロトコル変換、Proxyとしての実行機能などまで含めると、両者の守備範囲には差がある。
むしろ重要なのは、両者が共通して
この観点から見ると、SwitchyardとvLLM Semantic Routerが属する本質的な技術領域は
Switchyard v0.2.0のソースコードを /content/Switchyard にダウンロードする。--branch v0.2.0 によって、今回検証するバージョンを明示的に固定している。
%cd /content
!git clone --branch v0.2.0 --depth 1 https://github.com/NVIDIA-NeMo/Switchyard.git
SwitchyardはRustで実装されているため、RustコンパイラとCargoが必要。rustc 1.96.1を利用。
!rustc --version
!cargo --version
Switchyardのサーバー実行バイナリをビルドする。
%cd /content/Switchyard
!cargo build -p switchyard-server
ビルドに成功すると、
/content/Switchyard/target/debug/switchyard-server
が生成される。ここでは実際のLLMモデルは必要ない。Switchyardそのものをコンパイルしているだけである。
実際のOpenAIなどのLLM APIを使う代わりに、Pythonの標準ライブラリだけでOpenAI Chat Completions互換のダミーサーバーを作る。
from pathlib import Path
Path("/content/dummy_llm.py").write_text(r'''
from http.server import BaseHTTPRequestHandler, HTTPServer
import json
import sys
import time
NAME = sys.argv[1]
PORT = int(sys.argv[2])
class Handler(BaseHTTPRequestHandler):
def do_POST(self):
length = int(self.headers.get("Content-Length", 0))
body = self.rfile.read(length)
try:
request = json.loads(body)
except Exception:
request = {}
response = {
"id": "dummy-" + NAME,
"object": "chat.completion",
"created": int(time.time()),
"model": NAME,
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "served by " + NAME
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 1,
"completion_tokens": 1,
"total_tokens": 2
}
}
data = json.dumps(response).encode("utf-8")
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(data)))
self.end_headers()
self.wfile.write(data)
def log_message(self, format, *args):
print(f"[{NAME}] {format % args}", flush=True)
print(f"{NAME} listening on {PORT}", flush=True)
server = HTTPServer(("127.0.0.1", PORT), Handler)
server.serve_forever()
''')
print("dummy_llm.py created")
2つのサーバーを、
cheap-model → 8001
strong-model → 8002
として起動する。
同じdummy_llm.pyを2つのプロセスとして起動する。したがって、構成は、
┌─→ :8001 → cheap-model
Client → Switchyard
└─→ :8002 → strong-model
この段階ではまだSwitchyardは介在していない。
Switchyardの構成を定義する。ここでは、Random Routerとして設定。
from pathlib import Path
config = """schema_version = 1
[llm_clients.cheap]
format = "openai_chat"
base_url = "http://127.0.0.1:8001/v1"
[llm_clients.strong]
format = "openai_chat"
base_url = "http://127.0.0.1:8002/v1"
[targets.cheap_model]
id = "cheap-model"
llm_client = "cheap"
[targets.strong_model]
id = "strong-model"
llm_client = "strong"
[routes.general]
id = "switchyard/general"
type = "random"
targets = ["cheap_model", "strong_model"]
weights = [7, 3]
seed = 42
"""
Path("/content/Switchyard/routes.toml").write_text(config)
print(config)
ここで初めてSwitchyard本体を起動する。
import subprocess
import time
switchyard_log = open("/content/switchyard.log", "w")
switchyard = subprocess.Popen(
[
"/content/Switchyard/target/debug/switchyard-server",
"--config",
"/content/Switchyard/routes.toml",
],
stdout=switchyard_log,
stderr=subprocess.STDOUT,
text=True,
)
time.sleep(2)
print("Switchyard PID:", switchyard.pid)
print(open("/content/switchyard.log").read())
ポート4000で待ち受けるため、全体の構成は次のようになる。
Switchyard
:4000
│
switchyard/general
│
Random Router
/ \
70% 30%
│ │
▼ ▼
cheap-model strong-model
:8001 :8002
│ │
▼ ▼
Dummy LLM Dummy LLM
import requests
import json
payload = {
"model": "switchyard/general",
"messages": [
{
"role": "user",
"content": "Hello from Switchyard"
}
]
}
r = requests.post(
"http://127.0.0.1:4000/v1/chat/completions",
json=payload
)
print("HTTP status:", r.status_code)
print(json.dumps(r.json(), indent=2, ensure_ascii=False))
実行した結果、
HTTP status: 200
となり、
{
"model": "cheap-model",
"choices": [
{
"message": {
"role": "assistant",
"content": "served by cheap-model"
}
}
]
}が返ってくれば成功。なお、クライアント側では、 model = "switchyard/general" を指定しただけであり、cheap-model をを直接指定していない。それにもかかわらず、SwitchyardがRandom Routerによってcheap-modelを選択し、そのHTTPエンドポイントへリクエストを転送し、最終的にダミーLLMから served by cheap-model が返ってきている。
したがって、SwitchyardのHTTPプロキシとしてのルーティングが実際に動作していることを確認できる。
今回、70:30のルーティングが実現するように設定している(weights = [7, 3])。設定が成功しているかを100回の実行によって確認する。
import requests
from collections import Counter
url = "http://127.0.0.1:4000/v1/chat/completions"
counts = Counter()
for i in range(100):
payload = {
"model": "switchyard/general",
"messages": [
{
"role": "user",
"content": f"test {i}"
}
]
}
r = requests.post(url, json=payload)
if r.status_code != 200:
print("ERROR:", r.status_code, r.text)
continue
data = r.json()
model = data["model"]
counts[model] += 1
print("routing result")
print("----------------")
for model, count in counts.items():
print(f"{model:15s}: {count:3d} ({count}%)")
期待される比率は、
cheap-model ≈ 70%
strong-model ≈ 30%
100回程度では完全に70回・30回になるとは限らないが、例えば、
cheap-model : 68
strong-model : 32
や、
cheap-model : 72
strong-model : 28
などであれば、7:3の重み付けが機能していると判断できる。
| 方式 | type | 何を基準に振り分けるか |
|---|---|---|
| Random Routing | random | 重み付きランダム |
| LLM Classifier | llm_classifier | 別のLLMによる分類 |
| Stage Router | stage_router | 会話中のシグナルや状態 |
| Escalation | llm_classifier + mode="escalation" | 弱いモデルの回答を判定し、必要なら強いモデルへ |
| Passthrough | passthrough | ルーティングせず特定モデルへ直接転送 |
Mathematics is the language with which God has written the universe.