RouteLLM
RouteLLM 是一个用于部署和评估 LLM 路由器的框架。
我们的核心功能包括:
- 作为 OpenAI 客户端的即插即用替代品(或启动一个 OpenAI 兼容服务器),将更简单的查询路由到更便宜的模型。
- 开箱即用地提供经过训练的 router,我们已证明其在 MT Bench 等广泛使用的基准测试上,在保持 95% GPT-4 性能 的同时,将成本降低高达 85%。
- 基准测试还表明,这些 router 在性能上与商业产品相当,同时便宜 >40%。
- 轻松扩展框架以包含新的 router,并在多个基准测试中比较 router 的性能。
安装
从 PyPI
pip install "routellm[serve,eval]"
从源码
git clone https://github.com/lm-sys/RouteLLM.git
cd RouteLLM
pip install -e .[serve,eval]
快速入门
让我们通过一个示例,演示如何将现有的 OpenAI 客户端替换为在多个 LLM 之间路由查询,而不是仅使用单一模型。
- 首先,让我们通过初始化 RouteLLM 控制器并使用
mf路由器来替换我们的 OpenAI 客户端。默认情况下,RouteLLM 将使用性能最佳的配置:
import os
from routellm.controller import Controller
os.environ["OPENAI_API_KEY"] = "sk-XXXXXX"
# Replace with your model provider, we use Anyscale's Mixtral here.
os.environ["ANYSCALE_API_KEY"] = "esecret_XXXXXX"
client = Controller(
routers=["mf"],
strong_model="gpt-4-1106-preview",
weak_model="anyscale/mistralai/Mixtral-8x7B-Instruct-v0.1",
)
在上述代码中,我们选择 gpt-4-1106-preview 作为强模型,anyscale/mistralai/Mixtral-8x7B-Instruct-v0.1 作为弱模型,并相应地设置 API 密钥。您可以通过更新模型名称,在不同的模型对或提供商之间进行路由,具体方法请参阅 Model Support。
想要路由到本地模型?请查看 Routing to Local Models。
- 每个路由请求都有一个 cost threshold(成本阈值),用于控制成本与质量之间的权衡。我们应根据接收到的查询类型来校准此阈值,以最大化路由性能。例如,让我们使用 Chatbot Arena 的数据,为 50% 的 GPT-4 调用校准我们的阈值。
> python -m routellm.calibrate_threshold --routers mf --strong-model-pct 0.5 --config config.example.yaml
For 50.0% strong model calls for mf, threshold = 0.11593
这意味着我们希望将 0.11593 用作阈值,以便大约 50% 的查询(即最需要 GPT-4 的那些)将被路由到它(详见 Threshold Calibration)。
- 现在,让我们在生成补全时更新
model字段,以指定要使用的路由器和阈值:
response = client.chat.completions.create(
# This tells RouteLLM to use the MF router with a cost threshold of 0.11593
model="router-mf-0.11593",
messages=[
{"role": "user", "content": "Hello!"}
]
)
就这样!现在,请求将根据需求在强模型和弱模型之间进行路由,在保持高质量响应的同时节省成本。
根据您的使用场景,您可能需要考虑使用不同的模型对、修改配置,或根据您接收到的查询类型来校准阈值,以提升性能。
服务器与演示
除了使用 Python SDK,您还可以启动一个兼容 OpenAI 的服务器,该服务器可与任何现有的 OpenAI 客户端配合使用,步骤类似:
> export OPENAI_API_KEY=sk-XXXXXX
> export ANYSCALE_API_KEY=esecret_XXXXXX
> python -m routellm.openai_server --routers mf --strong-model gpt-4-1106-preview --weak-model anyscale/mistralai/Mixtral-8x7B-Instruct-v0.1
INFO: Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:6060 (Press CTRL+C to quit)
服务器启动后,您可以启动一个本地路由聊天机器人,以查看不同消息是如何被路由的。
python -m examples.router_chat --router mf --threshold 0.11593
模型支持
在以上示例中,GPT-4 和 Mixtral 8x7B 被用作模型对,但你可以通过 strong-model 和 weak-model 参数来修改此设置。
我们利用 LiteLLM 来支持来自广泛开源和闭源模型的聊天补全。通常,你需要设置一个 API 密钥,并使用适当的模型名称指向提供商。或者,你也可以通过以 openai/ 为前缀添加模型名称,并设置 --base-url 和 --api-key 标志,来使用任何 OpenAI 兼容的端点。
请注意,无论使用哪种模型对,目前仍然需要 OPENAI_API_KEY 才能为 mf 和 sw_ranking 路由器生成嵌入。
为流行提供商设置 API 密钥的说明:
- 使用 Ollama 的本地模型:参见 此指南
- Anthropic
- Gemini - Google AI Studio
- Amazon Bedrock
- Together AI
- Anyscale Endpoints
对于其他模型提供商,请在此处 查找说明 或提交问题。
动机
不同的 LLM 在成本和能力上差异巨大,这导致在部署它们时面临困境:将所有查询路由到能力最强的模型会产生最高质量的响应,但可能非常昂贵;而将查询路由到较小的模型可以节省成本,但可能导致响应质量较低。
LLM 路由 提供了一种解决方案。我们引入了一个路由器,它查看查询并将较简单的查询路由到更小、更便宜的模型,从而在保持质量的同时节省成本。我们专注于在 2 个模型之间进行路由:一个更强、更昂贵的模型和一个更便宜但较弱的模型。每个请求还与一个 成本阈值 相关联,该阈值决定了该请求的成本-质量权衡 - 较高的成本阈值会导致较低的成本,但可能导致较低质量的响应。
本仓库中的研究是在 与 Anyscale 的合作中 进行的,我们感谢他们的帮助和支持。
服务器
RouteLLM 提供了一个轻量级的 OpenAI 兼容服务器,用于根据不同的路由策略路由请求:
python -m routellm.openai_server --routers mf --config config.example.yaml
--routers指定了服务器可用的路由器列表。例如,此处服务器启动时配置了一个可用路由器:mf(路由器列表见下文)。--config指定了路由器配置文件的路径。如果未指定,服务器将默认使用我们性能最佳的配置(详见 Configuration)。
对于大多数使用场景,我们推荐 mf 路由器,因为我们评估其非常强大且轻量。
向服务器发起请求时,客户端使用 model 字段指定每个请求所使用的路由器和成本阈值,格式如下 router-[ROUTER NAME]-[THRESHOLD]。例如,使用 model 为 router-mf-0.5 表示请求应使用 mf 路由器,阈值为 0.5。
Threshold Calibration
用于路由的阈值控制成本与质量之间的权衡。有意义的阈值范围取决于路由器类型以及您接收到的查询。因此,我们建议使用您接收到的查询样本,以及您希望路由到更强模型的查询百分比来校准阈值。
默认情况下,我们支持基于公开的 Chatbot Arena dataset 来校准阈值。例如,要校准 mf 路由器的阈值,使得 50% 的调用被路由到更强的模型:
> python -m routellm.calibrate_threshold --task calibrate --routers mf --strong-model-pct 0.5 --config config.example.yaml
For 50.0% strong model calls for mf, threshold = 0.11593
这意味着应将 mf 路由器的阈值设置为 0.1881,以便大约 50% 的调用被路由到强模型,即使用值为 router-mf-0.1159 的 model 字段。
然而,请注意,由于我们基于现有数据集校准阈值,路由到每个模型的调用百分比将根据实际接收到的查询而有所不同。因此,我们建议在与您接收的查询类型非常相似的数据集上进行校准。
评估
RouteLLM 还包含一个评估框架,用于衡量不同路由策略在基准测试上的性能。
要在基准测试上评估路由器,您可以使用以下命令:
python -m routellm.evals.evaluate --routers random sw_ranking bert --benchmark gsm8k --config config.example.yaml
--routers指定要评估的路由器列表,例如,在此情况下为random和bert。--benchmark指定用于评估路由器的特定基准测试。我们目前支持:mmlu、gsm8k和mt-bench。
评估结果将打印到控制台。还会在当前目录中生成路由器性能的图表(使用 --output 覆盖路径)。为避免重新计算结果,路由器在给定基准测试上的结果默认会被缓存。可以使用 --overwrite-cache 标志来覆盖此行为,该标志接受一个路由器列表以覆盖缓存。
我们所有基准测试的结果均已缓存。对于 MT Bench,我们使用目标模型对的预计算评判结果。对于 MMLU 和 GSM8K,我们利用 SGLang 计算目标模型对的结果——如果您想评估不同的模型对,可以在基准测试目录中找到完整的代码。
默认情况下,GPT-4 和 Mixtral 用作评估的模型对。要修改使用的模型对,请使用 --strong-model 和 --weak-model 标志进行设置。
Routers
开箱即用,RouteLLM 支持 4 个在 gpt-4-1106-preview 和 mixtral-8x7b-instruct-v0.1 模型对上训练的 router。
完整的 router 列表:
mf:使用在偏好数据上训练的矩阵分解模型(推荐)。sw_ranking:使用加权 Elo 计算进行路由,其中每个投票根据其与用户提示的相似度进行加权。bert:使用在偏好数据上训练的 BERT 分类器。causal_llm:使用在偏好数据上调整的基于 LLM 的分类器。random:随机路由到任一模型。
虽然这些 router 是在 gpt-4-1106-preview 和 mixtral-8x7b-instruct-v0.1 模型对上训练的,但我们发现这些 router 也能很好地泛化到其他强弱模型对。因此,您可以替换用于路由的模型对,而无需重新训练这些模型!
我们还在以下 notebook 中提供了如何训练基于 LLM 的分类器的详细说明。
有关完整详情,请参阅我们的 paper。
Configuration
路由器的配置通过 Controller 的 config 参数指定,或者通过 --config 标志传入 YAML 文件的路径。它是一个从路由器名称到用于路由器初始化的关键字参数的顶层映射。
config.example.yaml 文件中提供了一个示例配置 - 它提供了在 Arena 数据上使用 GPT-4 作为评判器进行增强的路由器配置。所使用的模型和数据集均托管在 Hugging Face 的 RouteLLM 和 LMSYS 组织下。
贡献
我们欢迎贡献!如果您有任何建议或改进,请随时提交 issue 或 pull request。
添加新的路由器
要向 RouteLLM 添加新的路由器,请在 routers.py 中实现抽象类 Router,并将新路由器添加到 ROUTER_CLS 字典中。然后,您可以立即在服务器或评估框架中使用新的路由器。
只有一个方法需要实现:calculate_strong_win_rate,它接收用户提示并返回在该给定提示条件下强模型的胜率 - 如果该胜率大于用户指定的成本阈值,则请求被路由到强模型。否则,它被路由到弱模型。
添加新的基准
要将新的基准测试添加到 RouteLLM,请在 benchmarks.py 中实现抽象 Benchmark 类,并更新 evaluate.py 模块以正确初始化新的基准测试类。理想情况下,基准测试的结果应预先计算,以避免在每次评估运行时重新生成结果——请参阅现有基准测试以了解如何执行此操作的示例。
Citation
本仓库中的代码基于 paper 的研究。如果您觉得该仓库有帮助,请引用。
@misc{ong2024routellmlearningroutellms,
title={RouteLLM: Learning to Route LLMs with Preference Data},
author={Isaac Ong and Amjad Almahairi and Vincent Wu and Wei-Lin Chiang and Tianhao Wu and Joseph E. Gonzalez and M Waleed Kadous and Ion Stoica},
year={2024},
eprint={2406.18665},
archivePrefix={arXiv},
primaryClass={cs.LG},
url={https://arxiv.org/abs/2406.18665},
}