为什么需要 Router
随便一个线上 AI 产品的真实状况:
- Azure OpenAI 的 GPT-4o 你开了 3 个 deployment,分别在 East-US / West-US / North-Europe,各自有独立 TPM 配额。
- 同一个"聊天"业务,主模型 GPT-4o,limiter 触发时要能降级到 Claude Sonnet,再触发降到 DeepSeek。
- "分类"业务只走最便宜的 Gemini Flash / DeepSeek。
- "推理"业务用 o3 / DeepSeek R1,这俩要分到不同 key 免得冲击额度。
- 某家挂了自动 cooldown 5 分钟不再打过去,避免雪崩。
这些需求如果在业务代码里一个个 if/else 手写,会变成一坨意大利面。LiteLLM Router 把它们统统抽成 "model_list + 路由策略 + fallback 链",业务层只调 router.completion(model="chat", ...),其他全在配置里。
第一个 Router
from litellm import Router model_list = [ { "model_name": "chat", # 别名, 业务代码用这个 "litellm_params": { "model": "gpt-4o-mini", "api_key": os.getenv("OPENAI_API_KEY"), }, "tpm": 1_000_000, # 可选: 每分钟 token 限额 "rpm": 500, # 可选: 每分钟请求限额 }, { "model_name": "chat", # 同一个别名, 多部署 "litellm_params": { "model": "azure/my-gpt4o", "api_key": os.getenv("AZURE_API_KEY"), "api_base": os.getenv("AZURE_API_BASE"), "api_version": "2024-10-21", }, "tpm": 2_000_000, "rpm": 1000, }, ] router = Router( model_list=model_list, routing_strategy="simple-shuffle", # 下面详讲 num_retries=3, timeout=30, ) resp = router.completion( model="chat", # 别名, Router 自动选一个 deployment messages=[{"role":"user","content":"hi"}], ) print(resp.choices[0].message.content)
几个关键概念:
五种路由策略
① simple-shuffle(默认)
每次随机挑一个。如果声明了 rpm/tpm,按权重随机——容量大的 deployment 被选中的概率更高。
router = Router(model_list=..., routing_strategy="simple-shuffle")
适合:大多数场景,简单可靠。你有三个 Azure deployment 容量是 1k/2k/3k RPM,simple-shuffle 就按 1:2:3 比例分流。
② least-busy
每次选"当前 in-flight 请求数最少"的那个。
router = Router(model_list=..., routing_strategy="least-busy")
适合:请求耗时波动大的场景。比如有的请求生成 100 token,有的生成 4000,least-busy 会避免把长请求堆到同一个 deployment。
③ usage-based-routing-v2
最聪明也最工程化。Router 在 Redis 里记录每个 deployment 当前窗口的 TPM/RPM 占用,优先选"离限额最远"的那个。
router = Router( model_list=..., routing_strategy="usage-based-routing-v2", redis_host="redis.internal", redis_port=6379, redis_password="...", )
适合:多进程/多实例部署。一台 pod 的 Python 进程不知道另一台 pod 打了多少请求——没有 Redis 就各算各的,容易整体超限。usage-based-v2 让所有实例共享一本"总账"。
④ latency-based-routing
把过去 N 次调用的平均延迟当成选择权重。延迟低的被选的概率大。
router = Router(model_list=..., routing_strategy="latency-based-routing")
适合:面向终端用户的 chat UI。你希望热的 deployment 继续热,冷的冷下来,整体 p50 延迟更低。
⑤ cost-based-routing
选单位 token 最便宜的那个。你挂了 GPT-4o、Claude Sonnet、DeepSeek,非必要时就走 DeepSeek。
router = Router(model_list=..., routing_strategy="cost-based-routing")
适合:极度省钱的批处理场景。注意这和"质量"是矛盾的——生产通常结合 tag 路由按任务类型区分。
fallback:挂了自动换一家
路由策略选出了 A,但 A 挂了怎么办?——fallback 链。
router = Router( model_list=[ {"model_name":"chat-primary", "litellm_params":{"model":"gpt-4o","api_key":...}}, {"model_name":"chat-backup", "litellm_params":{"model":"anthropic/claude-sonnet-4-5", "api_key":...}}, {"model_name":"chat-last-resort", "litellm_params":{"model":"deepseek/deepseek-chat","api_key":...}}, ], fallbacks=[ {"chat-primary": ["chat-backup", "chat-last-resort"]}, ], num_retries=2, ) # 业务代码完全不变 resp = router.completion(model="chat-primary", messages=msgs)
发生错误时 Router 的决策顺序:
- primary 失败 → 在同一个 model_name 的其他 deployment 里重试(num_retries 次)。
- 同名 deployment 全失败 → 走 fallback 链第一个(chat-backup)。
- backup 失败 → chat-last-resort。
- 全部失败 → 抛异常给业务层。
按错误类型做不同 fallback
router = Router( model_list=..., context_window_fallbacks=[ {"gpt-4o": ["gemini/gemini-1.5-pro"]} # 超窗口用长上下文模型 ], content_policy_fallbacks=[ {"gpt-4o": ["anthropic/claude-sonnet-4-5"]} # 被审核拦了换一家 ], fallbacks=[ {"gpt-4o": ["azure/gpt-4o"]} # 其他错误用备用 deployment ], )
这种分类 fallback 非常实用——被内容审核拦和超上下文,本来就是不同问题,应该走不同路径。
cooldown:挂了的 deployment 先别再打
默认情况下,某个 deployment 连续 N 次失败后,Router 会把它放进 cooldown(冷却期),接下来 X 秒不再选它。
router = Router( model_list=..., allowed_fails=3, # 一分钟内失败 3 次触发 cooldown cooldown_time=60, # cooldown 60 秒 disable_cooldowns=False, )
这就是"熔断器"模式。一个 Azure deployment 挂了,Router 不会继续硬怼它让用户一直等——直接跳过,用户无感。
Redis:多实例共享状态
生产多 pod 部署时,Router 的内部状态(限额计数、延迟统计、cooldown 标记)要共享。Redis 是标配:
router = Router( model_list=..., routing_strategy="usage-based-routing-v2", redis_host="redis.internal", redis_port=6379, redis_password="...", redis_namespace="prod-app-1", # 隔离多应用 )
不配 Redis 会怎样?——Router 仍然能跑,但每个 pod 各算各的限额,一起超标风险显著。单实例可以省,多实例必配。
tag-based routing:按任务类型分流
真实业务里你可能希望"classify 任务走便宜模型,chat 任务走主力模型,code 任务走 o1"。用 tags:
model_list = [
{"model_name":"smart",
"litellm_params":{"model":"gpt-4o","api_key":...},
"tags":["chat", "main"]},
{"model_name":"smart",
"litellm_params":{"model":"deepseek/deepseek-chat","api_key":...},
"tags":["classify", "cheap"]},
{"model_name":"smart",
"litellm_params":{"model":"o3","api_key":...},
"tags":["code", "reasoning"]},
]
router = Router(model_list=model_list, enable_tag_filtering=True)
# 调用时指定 tag, Router 只在匹配 tag 的部署里选
resp = router.completion(
model="smart",
messages=msgs,
metadata={"tags": ["classify"]}, # 只走便宜的
)
这是一种非常优雅的"业务类型 → 模型选择"解耦。业务代码写 tags=["classify"],基础设施层决定哪个模型最适合分类——SRE 调整模型时,业务代码不改。
priority queue:保住关键请求
限额紧张时,你可能希望"付费用户优先,试用用户靠边"。Router 支持 priority queue:
router = Router( model_list=..., enable_pre_call_checks=True, ) # 高优(数字越小越优先) high_resp = router.completion( model="chat", messages=msgs, priority=0, ) # 低优 low_resp = router.completion( model="chat", messages=msgs, priority=100, )
当上游限额触发时,Router 优先放过 priority=0 的请求,低优的排队或被拒。生产做法通常:
- 真实付费 VIP → 0
- 普通付费 → 10
- 试用/Free → 100
- 后台 batch → 999
Router + async + streaming
以上所有能力都有异步和流式版本:
# 异步 resp = await router.acompletion(model="chat", messages=msgs) # 流式 resp = router.completion(model="chat", messages=msgs, stream=True) for chunk in resp: print(chunk.choices[0].delta.content or "", end="", flush=True) # 异步 + 流式 resp = await router.acompletion(model="chat", messages=msgs, stream=True) async for chunk in resp: ...
fallback、重试、cooldown 在流式里也生效——如果流还没开始就挂了,Router 会静默切到 fallback;流一半挂了不会自动重试(除非开 stream 重试)。
YAML 配置:Router 作为 config 驱动
model_list 写在 Python 代码里很快就会臃肿。第 10 章的 Proxy 会用 YAML 配置——但其实 Router 本身就能直接加载 YAML:
# config.yaml model_list: - model_name: chat litellm_params: model: gpt-4o-mini api_key: os.environ/OPENAI_API_KEY rpm: 500 - model_name: chat litellm_params: model: azure/my-gpt4o api_key: os.environ/AZURE_API_KEY api_base: os.environ/AZURE_API_BASE api_version: "2024-10-21" rpm: 1000 router_settings: routing_strategy: usage-based-routing-v2 num_retries: 3 timeout: 30 redis_host: os.environ/REDIS_HOST litellm_settings: drop_params: true general_settings: enable_pre_call_checks: true
import yaml from litellm import Router with open("config.yaml") as f: cfg = yaml.safe_load(f) router = Router( model_list=cfg["model_list"], **cfg.get("router_settings", {}), )
业务代码和配置就此分离——SRE 改 YAML,重启服务,不用碰 Python。
健康检查与可观测
Router 暴露了好几个方法让你观察状态:
# 当前哪些 deployment 处于 cooldown cooling = await router.async_get_cooldown_deployments() print(cooling) # 某个 model_name 下还有哪些 healthy deployment healthy = await router.async_get_available_deployments( model="chat", messages=None, ) print(healthy) # 手动踢掉一个 deployment (运维热操作) router.flush_cache() # 清空所有路由状态
再配合第 11 章的 Prometheus / OpenTelemetry 集成,你能清楚看到:每个 deployment 的 QPS、成功率、p50/p99 延迟、cooldown 次数。
一个真实的生产 Router 模板
下面是一个可以抄作业的模板,涵盖多 provider、fallback、tag、Redis:
model_list: # === 主力 chat === - model_name: chat litellm_params: model: azure/gpt-4o-east api_key: os.environ/AZURE_EAST_KEY api_base: os.environ/AZURE_EAST_BASE api_version: "2024-10-21" tpm: 2000000 rpm: 1000 tags: [primary] - model_name: chat litellm_params: model: azure/gpt-4o-west api_key: os.environ/AZURE_WEST_KEY api_base: os.environ/AZURE_WEST_BASE api_version: "2024-10-21" tpm: 2000000 rpm: 1000 tags: [primary] # === 分类便宜档 === - model_name: cheap litellm_params: model: deepseek/deepseek-chat api_key: os.environ/DEEPSEEK_API_KEY rpm: 500 tags: [cheap, classify] - model_name: cheap litellm_params: model: gemini/gemini-2.0-flash api_key: os.environ/GEMINI_API_KEY rpm: 1000 tags: [cheap, classify] # === 推理重火力 === - model_name: reasoner litellm_params: model: o3 api_key: os.environ/OPENAI_API_KEY rpm: 100 tags: [reasoning] # === 最终兜底 === - model_name: last-resort litellm_params: model: anthropic/claude-sonnet-4-5 api_key: os.environ/ANTHROPIC_API_KEY rpm: 500 tags: [backup] router_settings: routing_strategy: usage-based-routing-v2 num_retries: 3 timeout: 30 cooldown_time: 60 allowed_fails: 3 redis_host: os.environ/REDIS_HOST redis_port: 6379 enable_pre_call_checks: true fallbacks: - chat: [last-resort] - cheap: [chat] - reasoner: [chat, last-resort] context_window_fallbacks: - chat: [gemini/gemini-2.5-pro] # 超 128k 切长上下文 content_policy_fallbacks: - chat: [last-resort] # 被 Azure 审核拦, 换 Claude
这套配置上线后,业务代码永远只写 router.completion(model="chat"/"cheap"/"reasoner", ...)。SRE 加一个新 deployment、调整一个限额、替换一家 provider,Python 代码一行不动。
本章小结
- Router 把多部署、多 provider、备份关系统一抽成 "model_list + 策略 + fallback"
- 五种路由策略:shuffle / least-busy / usage-based-v2 / latency / cost,按场景选
- fallback 链 + context_window / content_policy 分类 fallback,覆盖 95% 的容灾需求
- cooldown + allowed_fails 是熔断器,挂了的 deployment 自动跳过
- Redis 用于多实例共享限额状态,生产必选
- tags 实现"业务类型到模型的解耦",priority queue 保 VIP
- 把 model_list 写进 YAML,SRE 改配置业务代码不动