Skip to main content
Glama

LLM 路由:一个实测基准,以及它论证的路由器

CI Python 3.10–3.13 License: MIT

一个成本感知的 LLM 路由服务(LangGraph + MCP),以及决定其策略的 417 任务基准。

在能够验证回答正确的最便宜模型上作答,仅在验证失败时升级。这是否优于直接为最佳模型付费,并非观点问题——它取决于你选择的模型,本仓库在三个真实价格阶梯上进行了测量。

一句话结论:当最高档确实更好且验证成本低廉时,采用级联——没有任何价格比阈值能同时适用于三个阶梯。 所交付的路由器根据已提交的测量结果为每个阶梯计算该结论,并拒绝为没有数据的阶梯作答。

运行内容

一个 LangGraph 状态机——classify → answer → verify → escalate ⟲——在升级循环内部包含人工审批和检查点恢复,通过 MCP 提供五个工具和四个资源。

决定其策略的内容

417 个任务(MBPP+ 代码、MATH-500 第 5 级)、9 种策略、3 个价格阶梯,全部在真实模型上测量:成本–质量前沿、精确 McNemar、配对 bootstrap。

构建工具

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 打印三条典型轨迹——级联在廉价档获胜、级联支付两次、以及验证精确且免费的代码案例。其中第一条:

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

这四行是对下图的一次遍历,该图是从 router_agent/graph.py 解析出来的,而非手工绘制——升级边循环回 answer,正是这个循环使其成为级联而非路由器。

LangGraph 状态机:classify、answer、verify、escalate、finalize

来自 DeepSeek 的三次独立采样都给出了正确答案,因此级联接受并从未调用 Opus 5——比直接路由到最高档便宜约 27 倍。当验证失败时,级联升级并支付两档费用。这一权衡是否值得,正是本仓库其余部分所测量的。

Related MCP server: whichmodel-mcp

结论

预先注册的对比,针对始终为最佳模型付费的简单方案。配对结果上的精确 McNemar,每个阶梯 n=209 个保留任务。

阶梯

档位

级联

始终昂贵

Δ 准确率

p

Δ 成本/任务

wide

v4-flash → Opus 5

95.7%

92.3%

+3.3%

0.039

−$0.00307

claude

Haiku 4.5 → Sonnet 5 → Opus 5

96.7%

92.3%

+4.3%

0.012

+$0.00097

deepseek

v4-flash → v4-pro

86.6%

83.7%

+2.9%

0.070

−$0.00000

级联对比始终昂贵,在准确率和成本上,三个阶梯

在 wide 上,级联更准确且便宜四倍。在 claude 上,它以溢价购买准确率——当廉价档是 Haiku 且数学一半从它抽取五个样本时,验证并非免费。阶梯决定符号,这就是为什么下面的路由器读取它而非假设它。

另外三个结果,每个都有数字和注意事项,见 docs/RESULTS.md:

  • 预测性路由不优于抛硬币——六次比较全部如此。 无论是 LLM 作为路由器还是 RouteLLM 的预训练 BERT,在任何阶梯上都不优于成本匹配的随机零假设,而级联在每个阶梯上都优于两者。区别在于决策何时做出:预测性路由器在尝试之前就承诺,级联在验证一次之后才决定。 → 六次比较,以及背后的前沿 AUC

  • 准确率掩盖了路由器实际做了什么。 两种策略可以通过升级正确的十个任务或升级所有任务达到相同的准确率。always_expensive 升级了 201 个任务以购买 27 次救援,在无法改进答案的升级上烧掉 $0.71;cascade 获得其中 24 次救援,浪费 $0.084。 → 每种策略的记分卡

  • 每种策略是一条曲线,而非一个点。 这里的每个路由器都有一个旋钮在准确率和成本之间权衡,因此在单一设置下比较两个,让设置旋钮的人选择赢家。frontier.py 扫描每个旋钮的整个范围并比较所得曲线。 → 前沿,以及为什么价格比不决定它

每个结果在 figures/ 中都有对应图表,该目录列出了每张图表声称的内容以及它从 runs/ 中的哪个工件绘制。

基准自带结论

以表格结尾的基准让读者自行应用。这个基准以一个函数结尾。findings.ratio_verdict(ladder) 读取该阶梯的已提交前沿并返回其结论。同一查询,两个阶梯,相反答案:

$ 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 默认值都调用同一个函数,因此改变基准测量的内容会改变路由器推荐的内容。没有会过时的常量——曾经有一个,其三个结论中有两个是反的。

布局

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/

两半共享一个模型客户端、一个价格表和一个响应缓存,这使路由器中的美元数字与表格中的美元数字含义相同。箭头单向运行——router_agent 导入 llm_routing,绝不反向——CI 中有一个作业的唯一目的就是保持这一点。逐模块说明:docs/ARCHITECTURE.md。

从 MCP 客户端使用

路由器是一个 MCP 服务器:五个工具(route_query、resume_routing、estimate_cost、compare_policies、explain_routing)、routing:// 下的四个只读资源,以及一个引导客户端选择策略的提示。已提交一个 .mcp.json,因此 Claude Code 在 pip install -e ".[agent,mcp]" 后自动拾取服务器,无需其他操作。对于 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 节点在通过时清除它——因此三档阶梯询问两次,客户端必须继续恢复直到 stop_reason 变为其他值。检查点是服务器进程中的 InMemorySaver,因此两次调用必须到达同一运行中的服务器:每次调用生成一个服务器的客户端(包括 scripts/mcp_call.py)永远无法恢复前一个暂停的内容。不存在的 thread_id 返回 no_suspended_run,而非来自 LangGraph 内部的 KeyError。

一次查看整个表面

python scripts/demo_mcp.py

一个脚本化的服务器遍历,通过真实 stdio 客户端会话——它宣传什么,以及它自己的哪些调用花费、一个资源、阶梯翻转、免费投影、路由答案,以及双向回答的审批循环。无需密钥,无花费;最后打印查询在生产中会花费多少,对比实际从账户中扣除的金额。

它启动两个服务器,原因正是 ROUTER_K 的意义:自洽性样本按样本索引缓存,因此 k 在启动时固定为响应购买时的参数——对于在廉价档验证的查询为 k=3,对于第四次采样不一致并触发升级的查询为 k=4。demo.py 展示路由器做什么;这展示服务器做什么。

从终端驱动

scripts/mcp_call.py 是一次性 MCP 客户端——它启动服务器、握手、调用一个工具并打印结果:

python scripts/mcp_call.py --list
python scripts/mcp_call.py explain_routing ladder=wide
python scripts/mcp_call.py --resource routing://findings/probe

手动通过管道输入 JSON-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.00

三次 HTTP 调用——一次贪婪回答和两次检查其自身——在廉价档一致接受,因此从未触及 v4-pro。再次运行,backend_cost_usd 为 $0.00 而 cost_usd 不变:响应在输出时被缓存,这与基准免费重放 5,075 条响应的机制相同。这两个数字有意分开——一个是生产中的服务成本,另一个是账户中扣除的金额。

服务查询所购买的内容落入 cache/serving.<ladder>.jsonl,而非基准的 cache/raw_calls.<ladder>.jsonl。两者都包含真实付费响应,但只有一个是证据:基准文件是计算所有已发布表格的封闭集合,让任意查询追加它会改变下面引用的响应计数和总花费。服务仍然读取基准缓存,这正是 --demo 免费的原因。

验证

python scripts/check_mcp_server.py

两个阶段,而第二阶段才是关键。它先在进程内列出并调用工具,然后将服务器作为子进程启动,并手工与它进行 JSON-RPC 通信——因为在 stdio 上,stdout 就是协议,而工具内部任何一次多余的 print 都会破坏帧,同时所有进程内测试仍然通过。这并非假设:response_cache 曾在 stdout 上输出过期键的警告,而那条代码路径只有 route_query 会走到,因此服务器完美地列出了自己的工具,却在第一次真实调用时返回了一个被破坏的答案。

复现一切

回放模式会针对已提交的响应重新运行已发布的分析——无需密钥、无需网络、花费 $0.00:

ROUTER_MODE=replay python scripts/run_all_ladders.py --ladders wide   # ~30 min

三个都去掉 --ladders wide,大约 75 分钟。已发布的数字正是在删除所有派生产物后以这种方式生成的:0 次调用到达后端,0 行是模拟数据,每个重新生成的文件都与已提交的文件逐字节一致。

回放完全不需要安装任何东西——纯标准库、离线、直到数字都逐字节确定——而且它是默认模式,所以上面的命令都没有指定模式。真实模式需要密钥并花钱。还有第三种模式 mock,它为测试套件伪造响应,而每个分析模块都拒绝在该模式下运行。这三种模式,以及每个分析入口点和购买数据的顺序,都在 docs/METHOD.md 中。

文档

文件

何时阅读

docs/EXPLAINED.md

你想要通俗版本,不需要熟悉路由知识——从这里开始

docs/RESULTS.md

你想要所有发现,包括数字及其成本

docs/METHOD.md

你想要方法:任务集、为什么选这些数据集、阶梯、策略、验证器、退化实验、如何真实运行,以及这个项目在自己身上发现的 bug

docs/ARCHITECTURE.md

你想知道基准测试和服务层如何逐模块地组合在一起

docs/LIMITATIONS.md

你想知道什么限制了这些结论

什么限制了结论,以及这里的新东西

在首页就明确说明而不是埋藏在深处:产生信号的验证器并不是随产品发布的验证器。 代码部分是通过执行 MBPP+ 提供的测试来评分的,而部署的路由器并没有这些测试。

这个差距是被定价的,而不只是被提及,而给它定价正是这个仓库对文献的贡献。FrugalGPT(2305.05176)是级联基线,它和 AutoMix 都把验证器视为给定的;Dekoninck 等人(2410.10347)指出质量估计器的准确性是决定这一切是否有效的因素,但他们是靠注入合成噪声来测试的。而这里的 sweep_degraded.py 则是在客观评分的任务上,以受控的量使真实验证器退化,同时保持领域、模型、提示词和评分器不变——因此发布一个代理验证器是沿着一条已测量的曲线移动,而不是踏入未知。

所有其他限制都在 docs/LIMITATIONS.md 中说明了一次,并附带了什么可以解决它们,完整的参考文献在 docs/METHOD.md 中。

许可证

MIT——见 LICENSE。

Maintenance

ActivitySlowing
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    F
    maintenance
    LLM routing proxy that cuts API costs 60-90% by auto-selecting the cheapest capable model across OpenAI, Anthropic, and Google. Provides stats, config, and model comparison tools via MCP.
    21 npm
    1
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    Enables policy-governed MCP interactions with deterministic authorization, tenant isolation, minimized PII exposure, and human approval gates for sensitive mutations, while producing structured audit events.
    3
    MIT