Switchyard:基于 Rust 的 LLM 流量代理与路由库项目

Switchyard lets LLM applications route traffic across models and providers while preserving native OpenAI and Anthropic API compatibility - enabling flexible model selection, benchmarking, and cost/performance optimization.

Branch58Tags5
This repository is empty

Switchyard

Switchyard

Switchyard 会将每次 LLM 调用路由到仍可胜任该任务的最便宜模型,而无需改动你智能体的任何一行代码。

快速开始 →

Terminal-Bench 2.1 上准确率与总成本的对比。Switchyard 的分级、升级和分类器路由可达到 71-76% 的准确率,同时总成本比 Opus 4.8 基线低 13-30%;而单一固定模型的准确率则始终低于 56%。

*总成本基于平均 ISP token 成本

什么是 Switchyard

Switchyard 负责决定由哪个模型处理每次 LLM 调用。

使用 Switchyard

Switchyard 可运行在你已有的网关内。

  • NeMo Relay — 原生插件。将 routes.toml 加载到你已在运行的 Relay 部署中。配置 →
  • LiteLLM — 适用于 LiteLLM 的 Router 和代理的路由插件。 examples/litellm
  • 更多集成即将推出。
flowchart LR
    subgraph R["LiteLLM · NeMo Relay"]
        P["Switchyard"]
    end
    P--> M["Efficient model"]
    P--> N["Capable model"]
    P--> O[etc.]
    G[You] -->|"request"| P
    style P fill:#76B900,stroke:#5A8F00,color:#000

将 Switchyard 集成到你的网关或宿主框架

将路由算法嵌入到你自己的宿主框架中。Switchyard 负责选择模型,你的 宿主框架负责发起调用,因此你的传输、重试与凭证均保持原样。

  • 安装:pip install nemo-switchyard
  • 然后按照 Path 2 — 嵌入库: 构造一个算法,驱动其步骤流,并发起回答调用。
  • Rust 中也可使用 switchyard-libsy;Path 2 中提供了 Cargo.toml 配置块。
flowchart LR
    subgraph R["Your LLM gateway / harness"]
        P["Switchyard"]
    end
    P--> M["Efficient model"]
    P--> N["Capable model"]
    P--> O[etc.]
    G["Your users"] -->|"request"| P
    style P fill:#76B900,stroke:#5A8F00,color:#000

将 Switchyard 作为独立代理服务运行

作为位于智能体前方的服务器,当你没有可部署 Switchyard 的网关时:

cargo install --locked switchyard-server
switchyard-server --config routes.toml --port 4000

将 Claude Code、Codex CLI 或任意 OpenAI/Anthropic SDK 客户端指向 proxy。 Switchyard 会逐轮决定由哪个模型来响应。

flowchart LR
    P["Switchyard<br/>standalone proxy"]
    P--> M["Efficient model"]
    P--> N["Capable model"]
    P--> O[etc.]
    G[You] -->|"unchanged native API"| P
    style P fill:#76B900,stroke:#5A8F00,color:#000

组件

当前为 1.0 之前的软件。API、配置和路由行为可能随版本发布而变化——请锁定你要集成的版本。

组件 稳定性 适用场景 说明
switchyard-libsy Beta 将路由嵌入到你自己的网关或运行框架中。模型调用、凭据和重试策略均由你负责。 适用于试用集成。v1.0 之前 API 可能变化。
switchyard-llm-client Alpha 配合 libsy 执行 HTTP 模型调用和协议转换。 适用于实验和试点。
switchyard-runner Alpha 在其他运行时中运行已配置的路由,例如 NeMo Relay。 适用于集成开发和受控试点。
switchyard-server Demo 独立运行的 OpenAI 和 Anthropic 兼容代理。 仅用于演示和评估,不适用于生产环境。

快速开始

提供三条路径,顺序与上文一致。每条路径均独立完整:从第 1 步开始,直到达成标题中所述结果即可停止。

路径 1 — 加载 NeMo Relay 插件

完成后,现有 NeMo Relay 部署将通过 Switchyard 进行路由。 需要 NeMo Relay >=0.8.1,<0.9.0,并使用 Rust 工具链构建该插件。

1. 构建、打包并注册插件。 按照插件 README 中的安装指南执行第 1 至 3 步。 这些步骤会构建共享库,将其打包为包含带摘要 relay-plugin.toml 的插件包,并通过 nemo-relay plugins add 完成注册。

2. 编写 Switchyard 部署配置,写入 /etc/switchyard/routes.toml——与代理使用的 version-1 TOML 相同。可复制下方路径 3 第 2 步中的文件。

3. 将插件指向部署配置。nemo-relay plugins add 生成的 [[plugins.dynamic]] 条目中添加一个 config 表,并添加允许 Relay 加载未签名插件包的策略覆盖。部署来源必须且只能使用一种:此处所示的路径,或嵌套在 switchyard_config 下的配置。

[[plugins.dynamic]]
manifest = "./plugins/switchyard/relay-plugin.toml"

[plugins.dynamic.config]
priority = 0
switchyard_config_path = "/etc/switchyard/routes.toml"

[plugins.policy.overrides."nvidia.switchyard"]
attestation = "integrity_only"

4. 启用、校验并重启 Relay。

nemo-relay plugins enable nvidia.switchyard
nemo-relay plugins validate nvidia.switchyard

Relay 现在可以运行 switchyard-runner 支持的任意算法,而 Switchyard 负责提供商 HTTP 调度。

详情:switchyard-nemo-relay-pluginTOML schema 参考

路径 2 —— 嵌入库

最终,你自己的运行框架会根据每个请求选择模型,并自行发起每一次模型调用。 以下示例使用 Python;Rust API 具有相同结构。

1. 安装。 下文中的 StepLlmResponse API 比 PyPI 上的 nemo-switchyard 0.2.0 发布版本更新,后者提供的是基于旧版 LlmTarget 的接口。在下一次发布之前,请从源代码构建(需要 Rust 工具链):

pip install git+https://github.com/NVIDIA-NeMo/Switchyard.git

对于 Rust,v0.2.0 标签中也有旧版 run_stream 接口形态,因此请依赖该仓库的 main 分支,并锁定你已测试过的 rev

[dependencies]
async-trait = "0.1"
futures = "0.3"
switchyard-libsy = { git = "https://github.com/NVIDIA-NeMo/Switchyard.git", branch = "main" }
switchyard-protocol = { git = "https://github.com/NVIDIA-NeMo/Switchyard.git", branch = "main" }
tokio = { version = "1", features = ["macros", "rt"] }

2. 构造一个算法。 目标名称就是你的 harness 对模型所起的名称。这是基准测试中的阶段路由器;randomllm_task_classifierllm_classifier 都以相同方式构建。

from switchyard.libsy import LlmResponse, Step
from switchyard.libsy.algorithms import stage_router

algorithm = stage_router(
    "capable",
    "efficient",
    picker="efficient_first",
    confidence_threshold=0.5,
)

3. 驱动它。 run_stream 接受的是规范化后的 Switchyard 请求字典,而不是 OpenAI 原始请求负载:即来自 switchyard-protocolRequest 结构,其中 messagescontent 是一组类型化内容块。它会逐步输出执行步骤。CallModel 步骤是一次分类器或评审调用——请用自己的客户端发起该调用,并将规范化后的响应包装为 LlmResponse.Agg 返回。Done 携带最终选择。

async def call_with_fallback(request: dict, models: list[str], clients: dict) -> LlmResponse.Agg:
    error: Exception | None = None
    for model in models:
        try:
            return LlmResponse.Agg(await clients[model].call({**request, "model": model}))
        except Exception as exc:
            error = exc
    raise error or RuntimeError("no candidate models")


async def route(request: dict, clients: dict) -> LlmResponse.Agg | LlmResponse.Stream:
    async for step in algorithm.run_stream(request):
        match step:
            case Step.CallModel(call):
                try:
                    call.respond(await call_with_fallback(call.request, call.models, clients))
                except Exception as error:
                    call.fail(error)
            case Step.Done(outcome):
                if outcome.response is not None:
                    return outcome.response
                return await call_with_fallback(
                    outcome.request, outcome.selected_model_ids, clients
                )
    raise RuntimeError("algorithm ended without a decision")

clients 将每个目标名称映射到你现有的客户端;每个 call 接收一个规范化请求字典,并返回一个规范化响应字典。call.modelsoutcome.selected_model_ids 按顺序列出候选项,因此辅助函数会依次尝试每一个,直到放弃。outcome.request 是需要发送的请求,其中可能包含算法施加的改写。当 outcome.response 已设置时,路由已经生成答案,无需再进一步调用。

4. 发起回答调用 使用你自己的 HTTP 客户端、重试和凭证,就像上面的 call_with_fallback 所做的那样。一个包含流式响应的完整可运行版本见 examples/libsy.py

类型参考:switchyard-libsyswitchyard-protocol。在 Rust 中,该循环为 Algorithm::run_stream,依次产出 Step::CallModelStep::Done,并且可以使用 switchyard-llm-clientrun 来替你驱动它。

路径 3 — 运行独立代理

最终你会得到一个位于 localhost:4000 的服务器,任何 OpenAI 或 Anthropic 客户端都可以调用。需要 Rust with Cargo

1. 安装服务器。

cargo install --locked switchyard-server

2. 编写 routes.toml 一个针对上述基准测试中相同模型对的阶段路由器:如何访问提供商、 使用哪些模型、以及如何在它们之间进行选择。--config 可接受任意路径;此操作会将其写入当前目录。

cat > routes.toml <<'TOML'
schema_version = 1

[llm_clients.openrouter]
format = "openai_chat"
base_url = "https://openrouter.ai/api/v1"
api_key_env = "OPENROUTER_API_KEY"

[targets.capable]
id = "anthropic/claude-opus-4.8"
llm_client = "openrouter"

[targets.efficient]
id = "z-ai/glm-5.2"
llm_client = "openrouter"

[routes.switchyard]
id = "switchyard"
type = "stage_router"
capable_target = "capable"
efficient_target = "efficient"
picker = "efficient_first"
confidence_threshold = 0.5
TOML

所有键均已在 TOML schema 参考 中说明。

3. 启动它。 --dry-run 会加载配置,打印 server OK: 及其对外暴露的模型 ID,然后退出,而不会启动服务器。

export OPENROUTER_API_KEY="your-openrouter-key"  # pragma: allowlist secret
switchyard-server --config routes.toml --dry-run
switchyard-server --config routes.toml --host 127.0.0.1 --port 4000

4. 发送请求。 路由的 id 即为客户端请求时使用的模型名称。

curl http://localhost:4000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model":"switchyard","messages":[{"role":"user","content":"hello"}]}'

同一路由也会在 /v1/messages(Anthropic Messages)和 /v1/responses(OpenAI Responses)上提供响应。/v1/stats 会报告各个目标分别处理了哪些请求,/metrics 则提供 Prometheus 计数器,用于统计请求、错误、延迟、token 和路由开销。

5. 将编码智能体指向它。

export ANTHROPIC_BASE_URL="http://localhost:4000"
export ANTHROPIC_MODEL="switchyard"
claude

Codex CLI 以及其他 OpenAI 客户端会使用 OpenAI 变量替代:

export OPENAI_BASE_URL="http://localhost:4000/v1"

路由算法

大多数算法使用 LLM 作为裁判。它们都在 高效 模型与 高能力 模型之间进行选择;差异在于决策何时做出以及如何做出。

算法 决策方式 路由 type 基准结果
能力 首个请求由 LLM 判定。 llm_classifier 71.2%,成本 $79.32
阶段 工具响应通过模式匹配或 LLM 判定。 stage_router 72.7%,成本 $68.19
能力 + 阶段 组合上述两种算法。 composite 尚未完成基准测试
升级 初始使用高效模型;响应由 LLM 判定是否存在问题,再升级。 llm_classifier + mode = "escalation" 75.7%,成本 $85.00
顾问门控 单一模型负责每一轮;更强的顾问模型批准其计划和“已完成”声明,或将其退回。 advisor 将弱执行器从 43.8% 提升至 54.7%
子智能体感知 委派的子智能体流量与父智能体分开路由。 passthroughstage_router 上的 subagents 尚未完成基准测试
自定义 首个请求由 LLM 根据你定义的标准判定,并在你拥有的两个及以上模型之间路由。 llm_classifier + target_selector 策略 尚未完成基准测试
随机 每个请求按均匀或加权随机方式路由。 random 基线机制

基准测试基于 Terminal-Bench 2.1,并以 $98.06 的 Opus 4.8 基线(76.0%)作为对照。 passthrough 路由在单个模型 ID 下注册一个目标,且不进行路由决策。有关常见路由结构和自托管目标,请参见 路由概览

文档

基准测试来源

配置 准确率 总成本 相比 Opus 4.8 基线
Opus 4.8 基线 76.0% $98.06
升级 75.7% $85.00 准确率达基线的 99.6%,成本降低 13.3%
分级 72.7% $68.19 准确率达基线的 95.7%,成本降低 30.5%
能力 71.2% $79.32 准确率达基线的 93.7%,成本降低 19.1%
仅使用 Kimi K2.6 55.8% $76.28
仅使用 GLM 5.2 52.4% $16.47
仅使用 DeepSeek V4 Pro 48.7% $96.92
仅使用 Ultra 3 39.0% $29.66

这些是 v0.2.0 版本的 Terminal-Bench 2.1 基准测试结果,来自 使用 NVIDIA NeMo Switchyard 跨模型路由 AI 智能体工作负载。 这些测试运行使用了 NVIDIA 内部推理端点,因此在其他服务栈上,绝对任务成功率可能会有所变化;这里的路由参数即为实际运行参数。

升级部署已提交至 benchmark/routing-profiles/tb21-escalation-opus-glm-deepseek.toml,并已将目标替换为 OpenRouter 目标,使其可公开运行。要运行测试框架,请参见 benchmark/README.md;如需关注延迟和路由开销而非任务成功率,请参见浸泡测试

社区

许可证

Apache 2.0 许可证。版权所有 NVIDIA Corporation。

Introduction

Switchyard lets LLM applications route traffic across models and providers while preserving native OpenAI and Anthropic API compatibility - enabling flexible model selection, benchmarking, and cost/performance optimization.

Customize your domain
92.73 K243Visit GitHub