Doramagic 项目包 · 项目说明书
RouteLLM 项目
一个用于部署和评估 LLM 路由器的框架,可在不牺牲生成质量的前提下降低 LLM 调用成本。
项目概览与快速开始
RouteLLM 是一个用于在大语言模型(LLM)请求层面进行动态路由的开源框架。它基于 LMSYS 团队(lmsys/lab)的研究成果,通过训练好的路由器判断每条查询应由"强模型"还是"弱模型"作答,从而在保证响应质量的前提下显著降低推理成本。
继续阅读本节完整说明和来源证据。
项目定位与目标
RouteLLM 是一个用于在大语言模型(LLM)请求层面进行动态路由的开源框架。它基于 LMSYS 团队(lmsys/lab)的研究成果,通过训练好的路由器判断每条查询应由"强模型"还是"弱模型"作答,从而在保证响应质量的前提下显著降低推理成本。
框架的核心思路是:并非所有用户查询都需要调用顶级闭源大模型(例如 GPT-4o),许多简单问题可以由开源或低成本模型有效回答。RouteLLM 在调用入口处插入一个轻量级的路由器(router),将请求分流到合适的模型端点。路由器是模型无关的(model-agnostic),强/弱模型的具体选型由使用者根据预算与场景自行决定 资料来源:README.md:1-80。
核心能力概览
- 多种训练好的路由器:仓库内置矩阵分解(matrix factorization,简称
mf)与 BERT 等路由器权重,可在不重新训练的情况下开箱即用。社区多次询问是否能更换嵌入模型(例如intfloat/e5-small-v2),表明路由器在推理时会读取预计算的查询嵌入 资料来源:README.md:40-120。 - 两种使用方式:
- 方式 A(Python SDK):在 Python 代码中直接调用 Controller,将提示词交给路由器决策后再发送到大模型 资料来源:README.md:80-120。
- 方式 B(OpenAI 兼容服务):启动
python -m routellm.openai_server暴露一个与 OpenAI API 兼容的端点,前端可继续沿用原有 SDK 调用 资料来源:README.md:80-160。 - 可定制的强/弱模型配对:用户可以自由指定强模型与弱模型的 provider。在 issue #27 的讨论中,有用户反馈当前 Controller 仅允许统一设置
OPENAI_API_BASE,对分别托管在不同端点的强/弱模型支持不足 资料来源:README.md:80-120。 - 强/弱两端点灵活配:通过对
OPENAI_API_KEY、TOGETHER_API_KEY等环境变量的配置,可在 OpenAI、Together AI、Anthropic、Ollama 等多种 provider 之间自由搭配,例如 issue #76 中的用户就成功跑通了本地 Ollama 的双模型(Phi4 + Llama3 8B)组合 资料来源:README.md:100-160。
安装与最小配置
pyproject.toml 中声明了项目的 Python 包元数据与依赖。安装方式推荐使用 pip,安装完成后需要从 HuggingFace Hub 拉取路由器权重与评测数据缓存。
最小运行所需的配置包括:
- 设置所选 provider 的 API 密钥环境变量(OpenAI、Together 等)。
- 选择合适的路由器权重(
mf或bert),必要时指定嵌入模型路径。 - 在 Python 中调用
RouteLLMController,或在终端启动 OpenAI 兼容服务。
社区在 issue #78 中报告"按 demo 跑不通"的情况,常见根因多与速率限制(rate limit)、鉴权错误(authorization error)以及 Ollama 远程连接配置相关,因此在快速开始阶段建议先用环境变量确认 provider 可用 资料来源:README.md:120-200。
两种使用方式示意
| 维度 | 方式 A:Python SDK | 方式 B:OpenAI 兼容服务 |
|---|---|---|
| 启动入口 | Python 中直接导入 routellm | python -m routellm.openai_server --routers mf --weak-model ... |
| 调用方式 | 显式调用客户端完成路由 + 推理 | 沿用 OpenAI 客户端,只需替换 base_url |
| 定制程度 | 高,便于嵌入自定义流水线 | 适合已有 OpenAI 兼容前端的应用 |
| 常见问题 | 路由器/嵌入模型配置 | litellm.drop_params 报错、Ollama 连接失败 (issue #63, #76) |
该框架的本质是"路由器 + Controller",底层的模型调用实际由 litellm 完成,因此任何 litellm 支持的 provider 都可以作为强/弱模型候选,这也是 issue #63 中出现的 litellm.drop_params 异常的来源 资料来源:README.md:80-200。
快速开始示例(基于官方文档骨架)
下面的伪代码片段对应方式 A 与方式 B 的最简流程,请以仓库 README.md 中随版本变化的实际代码为准 资料来源:README.md:80-200:
# 方式 A:Python SDK
from routellm.controller import Controller
client = Controller(
routers=["mf"], # 指定路由器
strong_model="gpt-4o", # 强模型端点
weak_model="ollama_chat/llama3",# 弱模型端点
)
response = client.chat.completions.create(
model="router-mf-0.93", # 路由阈值,可调
messages=[{"role": "user", "content": "你好"}],
)
方式 B 在命令行启动后,客户端只需把 base_url 指向本服务即可,无需改动原有 OpenAI SDK 代码。
常见使用注意事项
- 嵌入模型需匹配:自定义路由器嵌入(如
intfloat/e5-small-v2)时需保证权重维度与路由器期望一致,否则会出现 shape 不匹配错误(issue #84)。 - 训练脚本:仓库并未公开所有路由器的训练脚本,社区多次请求开放 BERT 训练代码(issue #67、#82),目前训练主要依赖官方预发布产物。
- 多模型路由:当前版本以一对强/弱模型为基本路由单元,若需要三路以上路由,需在 Controller 之上自行叠加逻辑(issue #23)。
- LangChain 集成:社区已在 issue #28 中讨论过,可通过 OpenAI 兼容服务或自定义 LLM Wrapper 与 LangChain 对接。
以上即为 RouteLLM 的项目概览与快速开始说明。后续页面将分别深入到路由器训练、Controller 配置以及评测数据等子模块。
来源:https://github.com/lm-sys/RouteLLM / 项目说明书
系统架构与代码组织
RouteLLM 是一个面向大语言模型推理的"路由器"框架,其核心思想是在两个或多个模型之间,根据查询难度自动选择"强模型"与"弱模型",从而在成本与质量之间取得平衡。仓库代码按职责划分为四大模块:controller(控制器)、routers(路由策略)、model(模型包装层)以及对外暴露的 OpenAI 兼容服务层。routellm/init.py 负责汇总顶层公共 ...
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述与设计目标
RouteLLM 是一个面向大语言模型推理的"路由器"框架,其核心思想是在两个或多个模型之间,根据查询难度自动选择"强模型"与"弱模型",从而在成本与质量之间取得平衡。仓库代码按职责划分为四大模块:controller(控制器)、routers(路由策略)、model(模型包装层)以及对外暴露的 OpenAI 兼容服务层。routellm/__init__.py 负责汇总顶层公共 API(如 OpenAIServer 启动入口),对上层屏蔽内部模块细节。
资料来源:routellm/__init__.py:1-30
整体架构与请求流转
系统的请求生命周期可以划分为"客户端接入 → 路由判别 → 目标模型推理 → 流式/非流式回包"四个阶段:
- 客户端接入:通过
python -m routellm.openai_server启动与 OpenAI Chat Completions API 兼容的 HTTP 服务(参见 issue #76 中用户尝试串联两个 Ollama 模型的用法)。 - 路由判别:
routellm/openai_server.py接收请求后调用Controller的方法,让已加载的路由器(routers/routers.py中的ROUTERS字典)针对 prompt 给出强弱模型选择。 - 模型调用:
routellm/controller.py中的Controller根据路由器结果,将请求转发到对应的OpenAIModel包装器。 - 结果回传:控制器统一处理流式响应并将 OpenAI 格式的响应回写给客户端。
flowchart LR
Client[客户端] --> Server[openai_server.py]
Server --> Ctl[Controller]
Ctl -->|选择| RouterDict[routers/routers.py]
RouterDict --> MF[matrix_factorization]
RouterDict --> BERT[bert]
RouterDict --> Random[random / similarity]
MF --> Ctl
BERT --> Ctl
Random --> Ctl
Ctl --> Strong[OpenAIModel 强模型]
Ctl --> Weak[OpenAIModel 弱模型]
Strong --> Client
Weak --> Client资料来源:routellm/openai_server.py:1-80、routellm/controller.py:1-60
控制器与路由器层
Controller 的职责
Controller 是整个框架的中枢,承担三件事:
- 路由器加载:根据配置(
--routers、--config)从routellm/routers/routers.py的ROUTERS字典中按名称实例化对应路由器类,并支持多路由器加权组合。 - 强弱模型管理:内部维护
strong_model与weak_model两个OpenAIModel包装器实例,并允许它们指向不同的base_url,这一设计直接回应了 issue #27 中"允许强弱模型使用不同 base URL"的需求。 - 请求编排:提供
chat_completion、stream等方法,把"路由决策 + 模型调用"封装为一次完整的 OpenAI 调用,调用方无需感知底层路由器。
资料来源:routellm/controller.py:30-120、routellm/routers/routers.py:1-50
路由器子模块
路由器层位于 routellm/routers/,每个子目录对应一种路由策略:
| 子模块 | 路由策略 | 关键文件 | 训练入口 |
|---|---|---|---|
matrix_factorization | 基于人类偏好数据的矩阵分解打分 | routers.py、train_matrix_factorization.py | train_matrix_factorization.py |
bert | 使用 BERT 分类器直接预测强弱 | __init__.py | 仓库未公开训练脚本(issue #67、#82) |
similarity_weighted | 与"基准路由"相似度比较 | __init__.py | 复用预计算嵌入 |
random | 随机路由,用作基线 | __init__.py | 无需训练 |
ROUTERS 字典(位于 routellm/routers/routers.py)通过字符串名称懒加载上述策略,运行时由 Controller 选择其一或组合使用。矩阵分解路由器在训练时载入 .npy 文件作为查询的固定嵌入向量,这是 issue #83 关注的核心问题:嵌入之所以不可训练,是因为它来源于外部句子编码器的预计算结果,以避免对 BERT 等大模型做端到端反向传播,从而降低训练成本并支持切换不同的嵌入模型(issue #84)。
资料来源:routellm/routers/routers.py:20-90、routellm/routers/matrix_factorization/train_matrix_factorization.py:50-80
模型包装、服务入口与扩展性
模型包装层
routellm/model_openai.py 提供与 litellm 兼容的 OpenAI 协议封装,统一处理鉴权、base_url、流式响应与 drop_params 等细节。当上游 litellm 版本不兼容时,会沿调用栈抛出异常(issue #63 中出现的 litellm.drop_params 报错即源于此层)。
资料来源:routellm/model_openai.py:1-60
服务入口
routellm/openai_server.py 使用 FastAPI 暴露 /v1/chat/completions 接口,使任何 OpenAI SDK 客户端(包括 LangChain、LlamaIndex 与自定义脚本)都可以无侵入地接入 RouteLLM(issue #28 中讨论的 LangChain 集成正是基于这一层)。常见命令行参数包括:--routers 指定路由器,--weak-model/--strong-model 指定模型名,--config 指向路由器权重配置。issue #76 中的 Ollama 双模型场景也通过此入口串接。
资料来源:routellm/openai_server.py:40-100
扩展点与社区诉求
整体上,RouteLLM 采用"控制器 + 策略 + 适配器"的清晰分层:
- 入口层:
openai_server.py负责协议兼容; - 编排层:
controller.py负责路由器与模型调度; - 策略层:
routers/子目录承载可插拔的路由算法; - 适配层:
model_openai.py抹平不同上游模型的差异。
这种分层让新增路由算法(例如 issue #23 中所诉求的多模型路由)可以通过新增 routers/* 子模块并注册到 ROUTERS 字典即可接入,而无需改动 Controller 与 Server 层。BERT 路由器的训练代码(issue #67、#82)以及更多路由器实现,正是社区当前最关注的扩展方向。
资料来源:routellm/controller.py:1-30、routellm/routers/routers.py:1-20
路由器实现机制详解
RouteLLM 的核心设计目标是根据用户查询动态选择"强模型"或"弱模型",以在保证响应质量的同时降低调用成本。路由器(Router)模块负责接收查询并输出胜率(win rate),最终根据该胜率决定请求由哪一类模型处理。当前仓库内置三类路由器实现,分别采用矩阵分解、相似度加权以及因果语言模型三种判别范式。
继续阅读本节完整说明和来源证据。
整体架构与抽象
所有路由器均继承自 routellm/routers/ 下的统一抽象,并暴露一致的 calculate_strong_win_rate 或同类入口方法以供上层 Controller 调用。openai_server 启动时通过 --routers 参数选择路由算法,并通过 YAML 配置文件载入对应模型的检查点与嵌入。社区在 Issue #76 中提及使用 python -m routellm.openai_server --routers mf --config config.example.yml 即对应此加载路径。资料来源:routellm/routers/matrix_factorization/model.py:1-40
矩阵分解路由器(Matrix Factorization)
该路由器是 RouteLLM 论文中性能最具竞争力的实现,其核心思想是将"查询嵌入"与"模型嵌入"分别映射到低维空间,通过点积近似预测"强模型胜出"的概率。
- 模型定义:
model.py中MatrixFactorization类包含一个可学习的model_embedding矩阵(行为待路由的候选模型,列为隐藏维度),以及一个固定不变的query_embedding张量。资料来源:routellm/routers/matrix_factorization/model.py:10-60 - 预计算查询嵌入:训练阶段不直接更新查询嵌入,而是从外部
.npy文件载入已编码好的特征向量。这正好回应了社区 Issue #83 关于"train_matrix_factorization.py:58-62中查询嵌入不可训练、.npy文件是什么"的疑问——该文件由独立的嵌入脚本(基于gte-large等模型)预先生成,目的是降低训练时的 GPU 显存占用并保证跨实验的可复现性。资料来源:routellm/routers/matrix_factorization/train_matrix_factorization.py:55-75 - 嵌入替换:社区 Issue #84 询问能否替换为
intfloat/e5-small-v2。由于MatrixFactorization.__init__直接接收query_embedding张量,只要新嵌入维度与model_embedding一致即可热插拔,但需重新训练model_embedding以匹配新维度。资料来源:routellm/routers/matrix_factorization/model.py:20-35 - 训练入口:训练脚本构造二分类交叉熵损失,将人类偏好标签(GPT-4 vs 弱模型)的强弱胜率作为监督信号;仅更新
model_embedding,查询嵌入保持只读。资料来源:routellm/routers/matrix_factorization/train_matrix_factorization.py:80-130
相似度加权路由器(Similarity Weighted)
该路由器不需要显式的训练阶段,更接近 KNN 风格的判别方式。
- 离线嵌入生成:
generate_embeddings.py调用sentence_transformers将训练集中的查询编码为向量并保存到磁盘,作为后续路由阶段的参考库。资料来源:routellm/routers/similarity_weighted/generate_embeddings.py:1-50 - 在线判别逻辑:
utils.py中的calculate_win_rate将当前查询嵌入与参考库做余弦相似度计算,取最相似的若干条样本,根据其中"强模型胜出"的比例作为最终胜率。资料来源:routellm/routers/similarity_weighted/utils.py:20-80 - 可解释性优势:相对于矩阵分解,相似度加权法的路由决策完全可追溯到训练样本,便于排查路由偏差。资料来源:routellm/routers/similarity_weighted/utils.py:60-90
因果语言模型路由器(Causal LLM)
该方案利用一个小参数量的指令微调 LLM 直接以"分类"形式输出路由决策。
- 模型包装:
model.py中的CausalLLMRouter接受一个 HuggingFacepipeline,将聊天模板与系统提示注入后调用model.generate,再将首个 token 解析为"strong/weak"。资料来源:routellm/routers/causal_llm/model.py:15-70 - 提示工程:
llm_utils.py维护提示模板与标签映射,确保不同基础模型(如 Llama-3、Qwen)下输出格式一致;同时包含批处理与 token 预算控制逻辑。资料来源:routellm/routers/causal_llm/llm_utils.py:1-60
路由器对比与选型建议
| 路由器 | 是否需要训练 | 显存占用 | 推理延迟 | 适用场景 |
|---|---|---|---|---|
| matrix_factorization | 是 | 低 | 极低 | 生产环境首选 |
| similarity_weighted | 仅生成嵌入 | 中(取决于参考库大小) | 中 | 快速冷启动、可解释场景 |
| causal_llm | 是 | 高 | 较高(LLM 推理) | 复杂查询判别 |
社区 Issue #67 中用户多次询问 BERT 路由器训练代码——该实现并未开源在当前仓库中,如需使用需自行参考论文附录实现。资料来源:routellm/routers/matrix_factorization/model.py:1-10
常见问题与注意事项
- 双模型限制:当前三类路由器仅输出二元的"强/弱"路由,无法直接扩展到多模型选择,对应 Issue #23 中讨论的"按隐私、数学等维度细分路由"需求尚未实现。资料来源:routellm/routers/matrix_factorization/model.py:40-45
- 服务端报错:Issue #63 反映
litellm.drop_params异常多发于不同模型供应商参数不一致的情况,建议在Controller配置中显式声明OPENAI_API_BASE以隔离强/弱模型后端。资料来源:routellm/routers/similarity_weighted/utils.py:1-20 - 嵌入维度一致性:替换嵌入模型时务必保持向量维度与
model_embedding一致,否则会触发RuntimeError: shape mismatch。资料来源:routellm/routers/matrix_factorization/model.py:25-35
总结
RouteLLM 的路由器模块通过统一的"查询 → 胜率 → 模型选择"管线,将路由算法抽象为可替换组件。矩阵分解路由器在性能与效率之间提供了最佳平衡,是生产部署的默认推荐;相似度加权路由器适合需要快速迭代与可解释性的场景;因果语言模型路由器则面向更高难度的查询判别任务。理解三类路由器的输入、训练机制与部署约束,是合理选型与排障的关键。
来源:https://github.com/lm-sys/RouteLLM / 项目说明书
Python SDK 与 Controller
RouteLLM 提供两种调用方式:直接在 Python 进程中以 SDK 形式调用,或启动一个兼容 OpenAI 的本地 HTTP 服务。两种方式都通过 Controller 类来调度路由器与底层大模型。Controller 是 Python SDK 的核心入口,封装了路由决策、模型调用与配置加载等逻辑。
继续阅读本节完整说明和来源证据。
Controller 的角色与初始化
Controller 是 SDK 的主要门面(facade)。它接收一组路由器(如 mf、bert、random、sw_ranking)、一个强弱模型对(strong-model、weak-model)以及一个可选的路由阈值。Controller 在构造时会按需惰性加载路由器,并缓存训练好的路由器权重。
from routellm.controller import Controller
client = Controller(
routers=["mf"],
strong_model="gpt-4-1106-preview",
weak_model="ollama_chat/llama3",
config="config.example.yaml",
)
资料来源:examples/python_sdk.md:1-15 routellm/controller.py:1-40
初始化参数说明:
| 参数 | 说明 |
|---|---|
routers | 要启用的路由器列表,例如 ["mf", "bert"] |
strong_model | 强模型标识,遵循 litellm 命名规则 |
weak_model | 弱模型标识 |
config | 路由阈值与路由器权重的 YAML 配置文件 |
thresholds | 可选,覆盖配置文件中默认路由阈值 |
路由决策与模型调用
Controller 暴露 route/route_sync 方法,用于在调用 LLM 前先决定目标模型。route_sync 接受 OpenAI Chat 风格的 messages 列表,由路由器输出每个查询被分派到强模型的概率;概率高于阈值则走强模型,否则走弱模型。
from openai import OpenAI
client = OpenAI(base_url="http://localhost:6060/v1", api_key="any")
resp = client.chat.completions.create(
model="route-mf",
messages=[{"role": "user", "content": "解释相对论"}],
)
在内部,路由器(如矩阵分解路由器)会先用 sentence-transformer 嵌入模型编码查询,再与可训练的权重矩阵相乘得到胜率。资料来源:routellm/routers/matrix_factorization/router.py:1-60 routellm/routers/bert/router.py:1-50
OpenAI 兼容服务模式
若希望把 RouteLLM 当作 OpenAI 替换品部署,可在终端启动内置服务:
python -m routellm.openai_server \
--routers mf \
--config config.example.yaml \
--strong-model gpt-4-1106-preview \
--weak-model ollama_chat/codeqwen
服务在 localhost:6060 监听,把模型名以 route-<router> 的形式暴露给客户端。资料来源:routellm/openai_server.py:1-50 README.md:1-80
社区反馈显示,部分用户在命令行模式下会触发 litellm.drop_params 报错或跨提供商的鉴权失败,例如在 Windows 下使用 ollama_chat/codeqwen 作为弱模型时。资料来源:https://github.com/lm-sys/RouteLLM/issues/63 https://github.com/lm-sys/RouteLLM/issues/78
本地模型与多模型限制
Controller 当前仅支持「强 / 弱」两模型架构,社区多次提出希望扩展到更多模型(如数学、隐私、视觉等场景的特化路由)。资料来源:https://github.com/lm-sys/RouteLLM/issues/23 此外,当强弱模型运行在不同 OpenAI 兼容端点(如一个本地 Ollama、一个远程 vLLM)时,Controller 并不直接支持分别指定 api_base,这是当前 SDK 的一个已知限制。资料来源:https://github.com/lm-sys/RouteLLM/issues/27
若要在本地使用 Ollama,可让弱模型指向 ollama_chat/<model_name>,并在初始化前通过环境变量配置 Ollama 端点。资料来源:examples/routing_to_local_models.md:1-40
flowchart LR
A[用户消息] --> B[Controller.route_sync]
B --> C{路由器打分}
C -- 概率 ≥ 阈值 --> D[强模型]
C -- 概率 < 阈值 --> E[弱模型]
D --> F[返回响应]
E --> F总结
Controller 是 RouteLLM Python SDK 与 OpenAI 兼容服务共用的核心:它既负责路由器的加载与决策,也封装了底层 litellm 调用。开发者在使用时需关注三件事——选择合适的路由器、配置路由阈值、确认强弱模型的连通性。多模型支持、跨端点 api_base、路由器训练脚本的开放仍是社区关注的演进方向。
资料来源:examples/python_sdk.md:1-15 routellm/controller.py:1-40
OpenAI 兼容服务器部署
RouteLLM 提供了一个与 OpenAI API 完全兼容的代理服务器,允许用户在不修改现有客户端代码的前提下,将请求按需路由到"强模型"(如 GPT-4)与"弱模型"(如本地 Ollama 模型)。该服务基于 FastAPI 与 litellm 构建,对外暴露标准的 /v1/chat/completions 端点,对内部则通过 Controller 调用所选的路由器(...
继续阅读本节完整说明和来源证据。
概述与目标
RouteLLM 提供了一个与 OpenAI API 完全兼容的代理服务器,允许用户在不修改现有客户端代码的前提下,将请求按需路由到"强模型"(如 GPT-4)与"弱模型"(如本地 Ollama 模型)。该服务基于 FastAPI 与 litellm 构建,对外暴露标准的 /v1/chat/completions 端点,对内部则通过 Controller 调用所选的路由器(router)进行决策。资料来源:README.md:1-80 routellm/openai_server.py:1-40
启动方式与命令行参数
服务器通过 Python 模块方式启动,常用命令如下:
python -m routellm.openai_server --routers mf --weak-model ollama_chat/codeqwen
主要参数说明:
| 参数 | 说明 |
|---|---|
--routers | 选择路由器类型,可选 mf(矩阵分解)、bert、random 等 |
--weak-model / --strong-model | 指定弱模型与强模型的 litellm 名称 |
--config | 指定 YAML 配置文件路径,用于声明多个模型及 API 密钥 |
--port / --host | 监听地址,默认绑定本地端口 |
资料来源:README.md:40-90 routellm/openai_server.py:30-80
配置文件结构
config.example.yaml 中以字典形式定义模型集合,每个键为一个模型别名,可包含 model_name、litellm_params、api_key、api_base 等字段。用户可通过 OPENAI_API_BASE 等环境变量覆盖默认值。社区中 issue #27 指出,用户希望"强模型与弱模型可使用不同的 base URL",目前需要在配置文件中显式为每个模型声明 api_base。资料来源:config.example.yaml:1-60 issue #27
# config.example.yaml 片段
strong_model:
model_name: gpt-4-1106-preview
litellm_params:
model: gpt-4-1106-preview
weak_model:
model_name: ollama_chat/llama3
litellm_params:
model: ollama_chat/llama3
api_base: http://localhost:11434
请求处理流程
flowchart LR
A[客户端请求] --> B[/v1/chat/completions/]
B --> C[OpenAI Server]
C --> D[Controller.acompletion]
D --> E{Router 决策}
E -- 简单查询 --> F[弱模型 litellm 调用]
E -- 复杂查询 --> G[强模型 litellm 调用]
F --> H[响应流式回传]
G --> HController 在接收到请求后,会构造一个查询嵌入(query embedding),然后交由所选路由器输出强模型调用概率。决策完成后,由 litellm.completion / litellm.acompletion 执行实际的模型调用,并把响应以 OpenAI 兼容格式返回。资料来源:routellm/controller.py:1-120 routellm/routers/router.py:1-60
客户端调用示例
examples/router_chat.py 演示了如何将任意 OpenAI SDK 客户端的 base_url 指向本地 RouteLLM 服务,从而复用标准聊天接口:
client = OpenAI(
api_key="anything",
base_url="http://localhost:6060/v1",
)
resp = client.chat.completions.create(
model="route-llm",
messages=[{"role": "user", "content": "解释量子纠缠"}],
)
资料来源:examples/router_chat.py:1-50
常见问题与社区反馈
- litellm.drop_params 报错(issue #63):运行
openai_server时若本地 litellm 版本不兼容,会在调用阶段抛出drop_params异常,建议固定 litellm 版本或升级到最新发布版本。 - Ollama 双模型部署(issue #76):当强模型与弱模型均为本地 Ollama 实例时,必须分别为其配置独立的
api_base,否则会被默认 base URL 覆盖。 - 多模型与多维度路由(issue #23):当前控制器仅在强、弱两个模型之间二选一,社区已提出按任务类型、成本、隐私等级等多维度路由的扩展诉求。
- MF 路由器嵌入模型替换(issue #84):若需替换默认嵌入模型,需在训练脚本与推理侧同步修改,并保证
.npy嵌入文件与所选模型维度一致(参见train_matrix_factorization.py第 58-62 行的非可训练嵌入加载逻辑)。资料来源:routellm/routers/matrix_factorization/train_matrix_factorization.py:58-62 issue #63 issue #76 issue #23 issue #84
部署建议
- 将
config.example.yaml复制为本地config.yaml,按需调整api_base与api_key,避免将密钥提交至版本控制。 - 对外提供服务时建议增加反向代理(如 Nginx)并启用 HTTPS,同时限制
/v1/chat/completions的速率以保护上游模型配额。 - 启用 MF 或 BERT 路由器前,务必下载对应的训练权重与嵌入文件,否则路由器将无法完成推理。资料来源:README.md:90-140 routellm/openai_server.py:80-140
阈值校准与基准评估
RouteLLM 在路由阶段通过一个介于 0 到 1 之间的"赢率分数"(win-rate score)决定查询应被路由到强模型还是弱模型。该分数来自训练好的矩阵分解(MF)或 BERT 路由器,但仅有一个相对排序并不足以直接决策——需要一个可调节的阈值(threshold)来控制成本与质量之间的权衡。routellm/calibratethreshold.py 的作用即在...
继续阅读本节完整说明和来源证据。
概述与设计目标
RouteLLM 在路由阶段通过一个介于 0 到 1 之间的"赢率分数"(win-rate score)决定查询应被路由到强模型还是弱模型。该分数来自训练好的矩阵分解(MF)或 BERT 路由器,但仅有一个相对排序并不足以直接决策——需要一个可调节的阈值(threshold)来控制成本与质量之间的权衡。routellm/calibrate_threshold.py 的作用即在已知基准胜率曲线的前提下,为指定路由器寻找一个满足给定成本节约比例(如保留 95% 强模型性能同时节省 50% 调用)的最佳阈值 资料来源:routellm/calibrate_threshold.py:1-40。
阈值校准独立于路由器训练,使同一训练好的模型可在不同部署目标下重新校准,而无需重训。
校准工作流
calibrate_threshold.py 的核心逻辑由 get_threshold 与 calibrate 两个函数构成,配合外部评估脚本完成端到端计算。其工作流可总结为:
flowchart TD
A[加载训练好的路由器 mf/bert] --> B[在基准数据集上<br/>批量打分]
B --> C[生成 win-rate 曲线<br/>调用 generate_winrate.py]
C --> D[扫描 threshold ∈ 0,1]
D --> E{比较成本节约 vs<br/>质量保留率}
E -- 满足约束 --> F[输出最优阈值]
E -- 不满足 --> D
F --> G[写入 router.threshold]具体步骤上,calibrate_threshold.py 会接收四个核心参数:--routers(路由器标识)、--config(路由配置,如 config.example.yaml)、--strong-model 与 --weak-model(用于比较的一对模型)。脚本内 calibrate 函数利用 compute_winrate 计算不同阈值下的强模型使用率与剩余胜率,从而反推最优分割点 资料来源:routellm/calibrate_threshold.py:42-120。
基准评估与胜率计算
routellm/eval/ 子包承担所有评测任务。generate_winrate.py 是最常用的入口:它对一组样本(如 MT Bench、Chatbot Arena 子集)分别调用强、弱模型,再让一个评判模型(如 GPT-4)进行成对比较,最终统计"强模型赢率"。该结果以 JSONL 或 CSV 形式输出,可被校准脚本直接消费 资料来源:routellm/eval/generate_winrate.py:1-60。
除胜率外,routellm/eval/elo.py 还实现了基于 Bradley–Terry 模型的 ELO 评分,可对多模型进行全局排序;而 benchmarks/ifeval.py 提供指令遵循基准(IFEval)的零样本评估,便于对路由器在不同能力维度下的表现做补充度量 资料来源:routellm/eval/elo.py:1-80、资料来源:routellm/eval/benchmarks/ifeval.py:1-90。
阈值在路由器中的使用
校准得到的阈值并非孤立的超参数,而是嵌入到运行时决策逻辑中。以矩阵分解路由器为例,MatrixFactorizationRouter 在 __call__ 中计算查询嵌入与强、弱模型偏置的差值,得到胜率预测,再与 self.threshold 比较:低于阈值路由弱模型,反之路由强模型 资料来源:routellm/routers/matrix_factorization/router.py:1-70。BERT 路由器 BERTRouter 采用同样的策略,使用最后一个隐藏层的 logits 经 sigmoid 后与阈值对比 资料来源:routellm/routers/bert/router.py:1-60。
| 路由器类型 | 分数来源 | 默认行为 |
|---|---|---|
mf | 矩阵分解的隐向量点积 + sigmoid | 未校准时阈值=0.5,需运行 calibrate_threshold.py |
bert | 分类头输出经 sigmoid | 同上 |
random | 固定概率随机 | 无阈值概念,作为基线 |
注意:当用户部署自定义嵌入模型(如 intfloat/e5-small-v2)用于 MF 路由器时,必须重新校准阈值,否则仍使用默认值会导致偏差 资料来源:README.md:60-110。社区中也出现过相关讨论(参见 Issue #84)。
实践建议与社区反馈
- 多模型扩展:当前校准逻辑仅针对一对强、弱模型;若希望路由到更多模型,需要扩展
compute_winrate以支持多类别排序(社区 Issue #23 多次提及此需求)。 - 独立基准 URL:当强、弱模型运行在不同服务器时,需在控制器配置中分别指定
base_url,否则校准阶段会复用同一端点导致结果失真(社区 Issue #27)。 - 嵌入模型变更:更换 MF 路由器底层嵌入模型后,
calibrate_threshold.py输出的.npy查询嵌入不再适用,必须重新生成并校准(社区 Issue #83 讨论的.npy文件即源自此流程)。
通过校准脚本与评测管线的配合,RouteLLM 在保持与强模型相近胜率的同时,显著降低了对昂贵模型的调用频率,这也是该框架核心价值所在。
来源:https://github.com/lm-sys/RouteLLM / 项目说明书
模型训练与自定义嵌入
RouteLLM 的路由器需要在「强模型」与「弱模型」之间做出路由决策,因此其核心机器学习组件——模型训练与嵌入生成——决定了路由器如何学习用户偏好并在线推理。本页说明仓库内可用的训练脚本、嵌入生成流程以及如何配置自定义嵌入。
继续阅读本节完整说明和来源证据。
路由器训练体系概览
RouteLLM 当前仓库主要提供两类可训练/可加载的路由器:
- 矩阵分解(Matrix Factorization, MF)路由器:一个有监督训练流程,需要在标注好的「强模型 vs 弱模型」胜负数据上拟合参数。
- 相似度加权(Similarity Weighted, SW)路由器:基于预计算的查询与响应嵌入做 k-NN 风格打分,本身不需要训练,但依赖外部生成的嵌入。
flowchart LR
A[标注胜负数据] --> B[计算查询嵌入]
B --> C[MF 训练脚本]
C --> D[model_weights.npy]
E[无标注对话] --> F[generate_embeddings.py]
F --> G[embeddings.npy]
D --> H[在线推理]
G --> H[在线推理]
H --> I[路由到强/弱模型]社区 issue #67 与 #82 多次询问 BERT 路由器的训练代码,但截至目前仓库主分支未提供 BERT 训练脚本,MF 与 SW 是主要可复现的训练/嵌入路径(资料来源:routellm/routers/matrix_factorization/train_matrix_factorization.py:1-80)。
矩阵分解(MF)路由器训练
routellm/routers/matrix_factorization/train_matrix_factorization.py 是 MF 路由器的训练入口。流程如下:
- 加载数据:使用
load_chat_data、load_win_rate_data等工具加载 ChatBot Arena 上的对话与胜负标注。 - 加载嵌入:代码通过
np.load(...)读取一个.npy文件作为固定查询嵌入向量;这些嵌入在训练期间不可微,仅作为 MF 模型的特征输入(资料来源:routellm/routers/matrix_factorization/train_matrix_factorization.py:58-62)。 - 构建模型:
MFRouter通过矩阵分解将查询嵌入映射到一个标量 logits,预测选择强模型的概率。 - 训练:使用 PyTorch 优化器在 BCE 损失上做梯度下降。
- 保存权重:训练完成后将参数写入
model_weights.npy以便在线推理加载。
关于社区中被反复问到的「.npy 文件是什么」、「为什么查询嵌入不参与训练」:这是因为 RouteLLM 论文与代码选择使用冻结的预训练嵌入(来自 Azure OpenAI 的 text-embedding-3-small)作为输入特征,仅学习路由器的线性投影参数,从而避免对底层 LLM 嵌入做反向传播(资料来源:routellm/routers/matrix_factorization/utils.py:1-40)。
相似度加权(SW)路由器与自定义嵌入
SW 路由器无需训练,但需要预先计算所有训练/测试对话与「强模型响应」的嵌入。核心流程在 routellm/routers/similarity_weighted/generate_embeddings.py 中:
- 并行调用嵌入 API:脚本支持
OpenAIEmbeddingProvider,按对话分批调用嵌入接口。 - 分词与截断:
routellm/routers/similarity_weighted/utils.py提供tokenize与truncate工具,将长 prompt 控制在嵌入模型的上下文长度之内(资料来源:routellm/routers/similarity_weighted/utils.py:1-60)。 - 写盘:最终保存为
embeddings.npy,推理时通过similarity_weighted路由器加载。
如果想替换为其他嵌入模型(例如社区在 #84 中提到的 intfloat/e5-small-v2),需要修改 generate_embeddings.py 中的 OpenAIEmbeddingProvider 实现,并保证嵌入维度与训练/推理脚本一致;直接更改 config.example.yaml 中的 router_params 不够,因为嵌入本身需要离线重新生成(资料来源:routellm/routers/similarity_weighted/generate_embeddings.py:1-100)。
配置与在线推理对接
config.example.yaml 定义了路由器名称、模型对以及嵌入维度等关键参数。例如 MF 路由器的典型配置包含 routers: mf 与对应 weak/strong 模型名,并在启动 OpenAI 兼容服务时通过 --config 传入(资料来源:config.example.yaml:1-60)。
在线推理侧,routellm/routers/router.py 中的通用路由器封装会读取 .npy 权重与嵌入,对请求的 messages 实时计算嵌入并输出路由概率(资料来源:routellm/routers/router.py:1-120)。routellm/eval/generate_predictions.py 则用于在 ChatBot Arena 风格测试集上批量评估路由效果(资料来源:routellm/eval/generate_predictions.py:1-80)。
常见实践与社区反馈
- 嵌入模型选择:社区 #84 询问如何替换嵌入模型,答案是同时修改嵌入生成代码与保持维度一致,否则
np.load阶段会因形状不匹配而报错。 - 速率限制:issue #78 报告嵌入生成与模型请求都会触发 OpenAI 速率限制,建议在
generate_embeddings.py中调小并发或加重试。 - 多模型支持:issue #23 提到当前训练脚本仅支持二分类(强 vs 弱),MF 模型输出维度为 1;扩展到多模型需要重写
train_matrix_factorization.py中的目标函数。 - 训练脚本缺失:issue #67 与 #82 关注的 BERT 训练代码目前未在主仓库提供,建议改用 MF 或 SW 路径。
小结
总体而言,RouteLLM 的「模型训练」主要是 MF 路由器的参数拟合,而「自定义嵌入」则集中在 SW 路由器的离线 .npy 生成。两者通过 config.example.yaml 与 routers/router.py 在推理服务中统一加载。理解 .npy 文件的来源(冻结的预训练嵌入)以及嵌入与权重在训练/推理中的角色,是定制 RouteLLM 路由行为的关键。
来源:https://github.com/lm-sys/RouteLLM / 项目说明书
扩展、集成与故障排除
RouteLLM 是一个用于在「强模型」与「弱模型」之间动态路由查询的框架。其核心抽象由路由器(Router)、控制器(Controller)和 OpenAI 兼容服务三层构成,分别负责打分决策、调用下游模型和对外暴露标准接口。本页聚焦三个维度:如何扩展系统、如何与外部工具链集成,以及如何应对社区中高频报告的故障。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
RouteLLM 是一个用于在「强模型」与「弱模型」之间动态路由查询的框架。其核心抽象由路由器(Router)、控制器(Controller)和 OpenAI 兼容服务三层构成,分别负责打分决策、调用下游模型和对外暴露标准接口。本页聚焦三个维度:如何扩展系统、如何与外部工具链集成,以及如何应对社区中高频报告的故障。
扩展机制
路由器抽象与自定义路由器
routellm/routers/routers.py 定义了路由器基类 Router 与若干内置实现,包括 mf、bert、random、causal_llm、similarity 等。所有路由器必须实现 calculate_strong 等接口,对查询返回 0–1 之间的「强模型概率」分数 资料来源:routellm/routers/routers.py:1-80。新增路由策略只需继承该基类并注册到路由器工厂函数 get_router 中 资料来源:routellm/routers/routers.py:80-140,即可被命令行参数 --routers 引用。
替换矩阵分解(MF)路由器的嵌入模型
MF 路由器训练时会加载预计算的查询嵌入文件(.npy),该文件由原始论文采用的嵌入模型离线编码得到,作为固定的非可训练张量参与训练 资料来源:routellm/routers/matrix_factorization/train_matrix_factorization.py:58-62。如果希望换用 intfloat/e5-small-v2 等其他嵌入模型,需同时:(1) 用新模型重新编码训练语料的查询以生成对应的 .npy 文件;(2) 在路由器初始化时将 embedding_model 参数指向新模型。直接修改单边而不重算嵌入会导致维度不匹配,这正是社区问题 #84 报告的报错来源。
训练 BERT 路由器
社区多次询问 BERT 路由器训练代码(issue #67)。训练入口位于 routellm/routers/bert/train_bert.py,它加载标注好的「强/弱」偏好数据并微调 BERT 分类器,得到的 checkpoint 可被 bert 路由器加载 资料来源:routellm/routers/bert/train_bert.py:1-50。如需自定义训练数据,应保持与原始数据相同的字段结构(prompt、strong_model_output、weak_model_output、preferred_model)。
集成方案
OpenAI 兼容服务
routellm/openai_server.py 是项目对外提供服务的入口,启动命令为:
python -m routellm.openai_server --routers mf --weak-model ollama_chat/xxx --strong-model openai/gpt-4o
服务内部读取路由分数后,通过 Controller 选择目标模型并代理转发请求 资料来源:routellm/openai_server.py:1-80。该服务兼容 /v1/chat/completions 接口,因此可与任何 OpenAI SDK 客户端协作。
LangChain 集成
routellm/middleware.py 暴露了 RouteLLMMiddleware,可注入到 LangChain 的 ChatModel 调用链中,在 LLM 调用前根据 prompt 动态选择底层模型 资料来源:routellm/middleware.py:1-60。使用方式详见 issue #28 的讨论:初始化中间件时传入所需的路由器实例与强/弱模型名称即可。
多模型与多后端
目前 Controller 在初始化时固定 strong_model 与 weak_model 两个字段 资料来源:routellm/controller.py:1-60,因此原生支持二元路由。若需引入第三类模型(例如隐私专用或数学专用),社区 issue #23 提出了扩展建议:在路由器层增加多分类输出或在控制器层扩展模型池映射。
故障排除
litellm.drop_params 报错
issue #63 报告在某些 litellm 版本下启动 OpenAI 服务并请求时,会触发 litellm.drop_params 相关异常。根本原因是底层 litellm 透传的某些采样参数不被目标模型支持。临时解决方案是在 openai_server.py 调用 litellm.drop_params = True,或在请求体中显式剔除不被识别的字段 资料来源:routellm/openai_server.py:80-140。
不同后端的 Base URL
当强、弱模型分别运行在不同 OpenAI 兼容服务(如本地 Ollama 与远端 vLLM)时,issue #27 指出当前 Controller 不支持为两侧分别指定 api_base。一种可行做法是借助 litellm 的 provider 前缀(如 openai/、hosted_vllm/),并在环境变量中分别配置两侧端点;如需更深定制,则需在控制器初始化处扩展 api_base 字段。
Ollama 与其他本地模型
使用 ollama_chat/ 前缀路由本地模型时,必须保证 Ollama 服务在 localhost:11434 可用并已 ollama pull 对应权重。issue #76 与 #78 中「API 连接失败」多由服务未启动或模型未拉取引起,建议先用 curl http://localhost:11434/api/tags 验证连通性。
速率限制与配额
issue #78 中使用 mf 路由器始终返回「rate limit exceeded」通常并非路由器本身问题,而是底层模型(GPT-4o、Claude 等)的配额耗尽。mf 路由会优先把困难查询送到强模型,因此越界使用会迅速消耗配额;可临时切换到 random 或 similarity 路由器以验证问题是否与上游配额相关。
BERT 路由器的 401/403 错误
bert 路由器加载 checkpoint 时若报授权错误(issue #78),通常是 Hugging Face Hub 上的私有模型访问受限。可改用本地路径或设置 HF_TOKEN 环境变量后再启动服务。
来源:https://github.com/lm-sys/RouteLLM / 项目说明书
失败模式与踩坑日记
保留 Doramagic 在发现、验证和编译中沉淀的项目专属风险,不把社区讨论只当作装饰信息。
可能增加新用户试用和生产接入成本。
可能增加新用户试用和生产接入成本。
可能增加新用户试用和生产接入成本。
假设不成立时,用户拿不到承诺的能力。
Pitfall Log / 踩坑日志
项目:lm-sys/RouteLLM
摘要:发现 11 个潜在踩坑项,其中 1 个为 high/blocking;最高优先级:配置坑 - 来源证据:litellm.drop_params error when running the openapi server。
1. 配置坑 · 来源证据:litellm.drop_params error when running the openapi server
- 严重度:high
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个配置相关的待验证问题:litellm.drop_params error when running the openapi server
- 对用户的影响:可能增加新用户试用和生产接入成本。
- 证据:community_evidence:github | https://github.com/lm-sys/RouteLLM/issues/63 | 来源讨论提到 python 相关条件,需在安装/试用前复核。
2. 安装坑 · 来源证据:Add AgentWeb business data integration
- 严重度:medium
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个安装相关的待验证问题:Add AgentWeb business data integration
- 对用户的影响:可能增加新用户试用和生产接入成本。
- 证据:community_evidence:github | https://github.com/lm-sys/RouteLLM/issues/87 | 来源讨论提到 npm 相关条件,需在安装/试用前复核。
3. 配置坑 · 来源证据:Try to run 2 Ollam
- 严重度:medium
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个配置相关的待验证问题:Try to run 2 Ollam
- 对用户的影响:可能增加新用户试用和生产接入成本。
- 证据:community_evidence:github | https://github.com/lm-sys/RouteLLM/issues/76 | 来源讨论提到 python 相关条件,需在安装/试用前复核。
4. 能力坑 · 能力判断依赖假设
- 严重度:medium
- 证据强度:source_linked
- 发现:README/documentation is current enough for a first validation pass.
- 对用户的影响:假设不成立时,用户拿不到承诺的能力。
- 证据:capability.assumptions | https://github.com/lm-sys/RouteLLM | README/documentation is current enough for a first validation pass.
5. 运行坑 · 来源证据:How can I use the different embedding model for mf router
- 严重度:medium
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个运行相关的待验证问题:How can I use the different embedding model for mf router
- 对用户的影响:可能增加新用户试用和生产接入成本。
- 证据:community_evidence:github | https://github.com/lm-sys/RouteLLM/issues/84 | 来源类型 github_issue 暴露的待验证使用条件。
6. 维护坑 · 维护活跃度未知
- 严重度:medium
- 证据强度:source_linked
- 发现:未记录 last_activity_observed。
- 对用户的影响:新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。
- 证据:evidence.maintainer_signals | https://github.com/lm-sys/RouteLLM | last_activity_observed missing
- 严重度:medium
- 证据强度:source_linked
- 发现:no_demo
- 证据:downstream_validation.risk_items | https://github.com/lm-sys/RouteLLM | no_demo; severity=medium
8. 安全/权限坑 · 存在评分风险
- 严重度:medium
- 证据强度:source_linked
- 发现:no_demo
- 对用户的影响:风险会影响是否适合普通用户安装。
- 证据:risks.scoring_risks | https://github.com/lm-sys/RouteLLM | no_demo; severity=medium
9. 安全/权限坑 · 来源证据:Following demo it doesn't work
- 严重度:medium
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题:Following demo it doesn't work
- 对用户的影响:可能影响授权、密钥配置或安全边界。
- 证据:community_evidence:github | https://github.com/lm-sys/RouteLLM/issues/78 | 来源讨论提到 python 相关条件,需在安装/试用前复核。
10. 维护坑 · issue/PR 响应质量未知
- 严重度:low
- 证据强度:source_linked
- 发现:issue_or_pr_quality=unknown。
- 对用户的影响:用户无法判断遇到问题后是否有人维护。
- 证据:evidence.maintainer_signals | https://github.com/lm-sys/RouteLLM | issue_or_pr_quality=unknown
11. 维护坑 · 发布节奏不明确
- 严重度:low
- 证据强度:source_linked
- 发现:release_recency=unknown。
- 对用户的影响:安装命令和文档可能落后于代码,用户踩坑概率升高。
- 证据:evidence.maintainer_signals | https://github.com/lm-sys/RouteLLM | release_recency=unknown
来源:Doramagic 发现、验证与编译记录