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_KEYTOGETHER_API_KEY 等环境变量的配置,可在 OpenAI、Together AI、Anthropic、Ollama 等多种 provider 之间自由搭配,例如 issue #76 中的用户就成功跑通了本地 Ollama 的双模型(Phi4 + Llama3 8B)组合 资料来源:README.md:100-160

安装与最小配置

pyproject.toml 中声明了项目的 Python 包元数据与依赖。安装方式推荐使用 pip,安装完成后需要从 HuggingFace Hub 拉取路由器权重与评测数据缓存。

最小运行所需的配置包括:

  1. 设置所选 provider 的 API 密钥环境变量(OpenAI、Together 等)。
  2. 选择合适的路由器权重(mfbert),必要时指定嵌入模型路径。
  3. 在 Python 中调用 RouteLLM Controller,或在终端启动 OpenAI 兼容服务。

社区在 issue #78 中报告"按 demo 跑不通"的情况,常见根因多与速率限制(rate limit)、鉴权错误(authorization error)以及 Ollama 远程连接配置相关,因此在快速开始阶段建议先用环境变量确认 provider 可用 资料来源:README.md:120-200

两种使用方式示意

维度方式 A:Python SDK方式 B:OpenAI 兼容服务
启动入口Python 中直接导入 routellmpython -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 负责汇总顶层公共 ...

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 Controller 的职责

继续阅读本节完整说明和来源证据。

章节 路由器子模块

继续阅读本节完整说明和来源证据。

章节 模型包装层

继续阅读本节完整说明和来源证据。

概述与设计目标

RouteLLM 是一个面向大语言模型推理的"路由器"框架,其核心思想是在两个或多个模型之间,根据查询难度自动选择"强模型"与"弱模型",从而在成本与质量之间取得平衡。仓库代码按职责划分为四大模块:controller(控制器)、routers(路由策略)、model(模型包装层)以及对外暴露的 OpenAI 兼容服务层。routellm/__init__.py 负责汇总顶层公共 API(如 OpenAIServer 启动入口),对上层屏蔽内部模块细节。

资料来源:routellm/__init__.py:1-30

整体架构与请求流转

系统的请求生命周期可以划分为"客户端接入 → 路由判别 → 目标模型推理 → 流式/非流式回包"四个阶段:

  1. 客户端接入:通过 python -m routellm.openai_server 启动与 OpenAI Chat Completions API 兼容的 HTTP 服务(参见 issue #76 中用户尝试串联两个 Ollama 模型的用法)。
  2. 路由判别routellm/openai_server.py 接收请求后调用 Controller 的方法,让已加载的路由器(routers/routers.py 中的 ROUTERS 字典)针对 prompt 给出强弱模型选择。
  3. 模型调用routellm/controller.py 中的 Controller 根据路由器结果,将请求转发到对应的 OpenAIModel 包装器。
  4. 结果回传:控制器统一处理流式响应并将 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-80routellm/controller.py:1-60

控制器与路由器层

Controller 的职责

Controller 是整个框架的中枢,承担三件事:

  • 路由器加载:根据配置(--routers--config)从 routellm/routers/routers.pyROUTERS 字典中按名称实例化对应路由器类,并支持多路由器加权组合。
  • 强弱模型管理:内部维护 strong_modelweak_model 两个 OpenAIModel 包装器实例,并允许它们指向不同的 base_url,这一设计直接回应了 issue #27 中"允许强弱模型使用不同 base URL"的需求。
  • 请求编排:提供 chat_completionstream 等方法,把"路由决策 + 模型调用"封装为一次完整的 OpenAI 调用,调用方无需感知底层路由器。

资料来源:routellm/controller.py:30-120routellm/routers/routers.py:1-50

路由器子模块

路由器层位于 routellm/routers/,每个子目录对应一种路由策略:

子模块路由策略关键文件训练入口
matrix_factorization基于人类偏好数据的矩阵分解打分routers.pytrain_matrix_factorization.pytrain_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-90routellm/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-30routellm/routers/routers.py:1-20

资料来源:routellm/__init__.py:1-30

路由器实现机制详解

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.pyMatrixFactorization 类包含一个可学习的 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 风格的判别方式。

因果语言模型路由器(Causal LLM)

该方案利用一个小参数量的指令微调 LLM 直接以"分类"形式输出路由决策。

  • 模型包装model.py 中的 CausalLLMRouter 接受一个 HuggingFace pipeline,将聊天模板与系统提示注入后调用 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

常见问题与注意事项

总结

RouteLLM 的路由器模块通过统一的"查询 → 胜率 → 模型选择"管线,将路由算法抽象为可替换组件。矩阵分解路由器在性能与效率之间提供了最佳平衡,是生产部署的默认推荐;相似度加权路由器适合需要快速迭代与可解释性的场景;因果语言模型路由器则面向更高难度的查询判别任务。理解三类路由器的输入、训练机制与部署约束,是合理选型与排障的关键。

来源:https://github.com/lm-sys/RouteLLM / 项目说明书

Python SDK 与 Controller

RouteLLM 提供两种调用方式:直接在 Python 进程中以 SDK 形式调用,或启动一个兼容 OpenAI 的本地 HTTP 服务。两种方式都通过 Controller 类来调度路由器与底层大模型。Controller 是 Python SDK 的核心入口,封装了路由决策、模型调用与配置加载等逻辑。

章节 相关页面

继续阅读本节完整说明和来源证据。

Controller 的角色与初始化

Controller 是 SDK 的主要门面(facade)。它接收一组路由器(如 mfbertrandomsw_ranking)、一个强弱模型对(strong-modelweak-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(矩阵分解)、bertrandom
--weak-model / --strong-model指定弱模型与强模型的 litellm 名称
--config指定 YAML 配置文件路径,用于声明多个模型及 API 密钥
--port / --host监听地址,默认绑定本地端口

资料来源:README.md:40-90 routellm/openai_server.py:30-80

配置文件结构

config.example.yaml 中以字典形式定义模型集合,每个键为一个模型别名,可包含 model_namelitellm_paramsapi_keyapi_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 --> H

Controller 在接收到请求后,会构造一个查询嵌入(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

常见问题与社区反馈

  1. litellm.drop_params 报错(issue #63):运行 openai_server 时若本地 litellm 版本不兼容,会在调用阶段抛出 drop_params 异常,建议固定 litellm 版本或升级到最新发布版本。
  2. Ollama 双模型部署(issue #76):当强模型与弱模型均为本地 Ollama 实例时,必须分别为其配置独立的 api_base,否则会被默认 base URL 覆盖。
  3. 多模型与多维度路由(issue #23):当前控制器仅在强、弱两个模型之间二选一,社区已提出按任务类型、成本、隐私等级等多维度路由的扩展诉求。
  4. 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_baseapi_key,避免将密钥提交至版本控制。
  • 对外提供服务时建议增加反向代理(如 Nginx)并启用 HTTPS,同时限制 /v1/chat/completions 的速率以保护上游模型配额。
  • 启用 MF 或 BERT 路由器前,务必下载对应的训练权重与嵌入文件,否则路由器将无法完成推理。资料来源:README.md:90-140 routellm/openai_server.py:80-140

资料来源:README.md:40-90 routellm/openai_server.py:30-80

阈值校准与基准评估

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_thresholdcalibrate 两个函数构成,配合外部评估脚本完成端到端计算。其工作流可总结为:

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 路由器的训练入口。流程如下:

  1. 加载数据:使用 load_chat_dataload_win_rate_data 等工具加载 ChatBot Arena 上的对话与胜负标注。
  2. 加载嵌入:代码通过 np.load(...) 读取一个 .npy 文件作为固定查询嵌入向量;这些嵌入在训练期间不可微,仅作为 MF 模型的特征输入(资料来源:routellm/routers/matrix_factorization/train_matrix_factorization.py:58-62)。
  3. 构建模型MFRouter 通过矩阵分解将查询嵌入映射到一个标量 logits,预测选择强模型的概率。
  4. 训练:使用 PyTorch 优化器在 BCE 损失上做梯度下降。
  5. 保存权重:训练完成后将参数写入 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 中:

  1. 并行调用嵌入 API:脚本支持 OpenAIEmbeddingProvider,按对话分批调用嵌入接口。
  2. 分词与截断routellm/routers/similarity_weighted/utils.py 提供 tokenizetruncate 工具,将长 prompt 控制在嵌入模型的上下文长度之内(资料来源:routellm/routers/similarity_weighted/utils.py:1-60)。
  3. 写盘:最终保存为 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.yamlrouters/router.py 在推理服务中统一加载。理解 .npy 文件的来源(冻结的预训练嵌入)以及嵌入与权重在训练/推理中的角色,是定制 RouteLLM 路由行为的关键。

来源:https://github.com/lm-sys/RouteLLM / 项目说明书

扩展、集成与故障排除

RouteLLM 是一个用于在「强模型」与「弱模型」之间动态路由查询的框架。其核心抽象由路由器(Router)、控制器(Controller)和 OpenAI 兼容服务三层构成,分别负责打分决策、调用下游模型和对外暴露标准接口。本页聚焦三个维度:如何扩展系统、如何与外部工具链集成,以及如何应对社区中高频报告的故障。

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 路由器抽象与自定义路由器

继续阅读本节完整说明和来源证据。

章节 替换矩阵分解(MF)路由器的嵌入模型

继续阅读本节完整说明和来源证据。

章节 训练 BERT 路由器

继续阅读本节完整说明和来源证据。

概述

RouteLLM 是一个用于在「强模型」与「弱模型」之间动态路由查询的框架。其核心抽象由路由器(Router)、控制器(Controller)和 OpenAI 兼容服务三层构成,分别负责打分决策、调用下游模型和对外暴露标准接口。本页聚焦三个维度:如何扩展系统、如何与外部工具链集成,以及如何应对社区中高频报告的故障。

扩展机制

路由器抽象与自定义路由器

routellm/routers/routers.py 定义了路由器基类 Router 与若干内置实现,包括 mfbertrandomcausal_llmsimilarity 等。所有路由器必须实现 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_modelweak_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 路由会优先把困难查询送到强模型,因此越界使用会迅速消耗配额;可临时切换到 randomsimilarity 路由器以验证问题是否与上游配额相关。

BERT 路由器的 401/403 错误

bert 路由器加载 checkpoint 时若报授权错误(issue #78),通常是 Hugging Face Hub 上的私有模型访问受限。可改用本地路径或设置 HF_TOKEN 环境变量后再启动服务。

来源:https://github.com/lm-sys/RouteLLM / 项目说明书

失败模式与踩坑日记

保留 Doramagic 在发现、验证和编译中沉淀的项目专属风险,不把社区讨论只当作装饰信息。

high 来源证据:litellm.drop_params error when running the openapi server

可能增加新用户试用和生产接入成本。

medium 来源证据:Add AgentWeb business data integration

可能增加新用户试用和生产接入成本。

medium 来源证据:Try to run 2 Ollam

可能增加新用户试用和生产接入成本。

medium 能力判断依赖假设

假设不成立时,用户拿不到承诺的能力。

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 发现、验证与编译记录