[控场AI]
· 10 分钟阅读· 5,081 字

LiteLLM Router:告别单一供应商硬编码

LiteLLM Router:告别单一供应商硬编码

用 LiteLLM 统一接口与 Router 回退,替换单供应商硬编码,提升 LLM 调用可靠性。

文章指出,把单一供应商写死在客户端代码中,会在限流或宕机时让整个生产流程停摆。LiteLLM 通过 OpenAI 兼容接口统一接入 100 多家模型服务商,让业务代码沿用 chat completions 的调用方式,而把供应商选择下沉到 model_list 与 Router 配置。Router 将重试与回退拆成两件事:num_retries 在同一别名组内处理瞬时故障,fallbacks 在整组持续失败后切换到另一供应商组。业务代码只依赖面向应用的 model_name 别名,无需导入备用供应商 SDK。多服务共享规则时可改用 AI Gateway 代理,用 YAML 集中管理模型列表、预算和虚拟密钥。最后,文章给出落地清单,并建议把回退耗尽的请求视为产品事故,用于构建评估集。

当 OpenAI 连续返回二十分钟 429 错误时,依赖它的客服机器人就会彻底停摆。问题不在产品本身,而在于客户端代码里只写死了一家供应商。LiteLLM 通过一个兼容 OpenAI 的接口统一接入 100 多家模型服务商,并用 Router 组件在同组模型内重试、在主模型持续失败时自动切换到备用组。业务代码依然使用 chat completions 接口,可靠性管理则下沉到路由配置中。

LiteLLM Router 示意图

为什么单供应商硬编码会拖垮生产环境

多数团队最初都会写出这样的代码:

from openai import OpenAI
client = OpenAI()
client.chat.completions.create(model="gpt-4o-mini", messages=...)

原型阶段没问题,但进入生产后需求会变:需要一个能在限流或宕机时顶上的备用供应商;无论哪个模型回答,消息格式都要保持一致;重试逻辑无需在每个调用点重写;成本与失败日志要集中管理,而不是到处散落 try/except。

LiteLLM 的解决思路是保留 OpenAI 客户端的使用形态,把供应商选择挪到 model_list 加 Router 中。

LiteLLM 的核心抽象是 OpenAI 兼容层。OpenAI 的 chat.completions.create 接口事实上已经成为业界事实标准,Anthropic、Google Vertex、Bedrock、Cohere、Ollama 等供应商的官方 API 在请求体、响应结构和异常类型上都与之存在差异。LiteLLM 在中间做协议转换:把统一入参翻译成各供应商的原生请求,再把返回结果与错误码映射回 OpenAI 结构,例如将 Anthropic 的 overloaded_error 转成 RateLimitError。这意味着业务代码只需理解一套数据结构,切换供应商时不需要重写解析逻辑,也不需要为每家 SDK 维护独立的异常分支。

安装与一行调用

先安装 SDK:

pip install litellm
# 或者:uv add litellm

不启用代理时,可以直接用 SDK 风格调用。所有供应商共用同一个 completion() 形态:

from litellm import completion
import os

os.environ["OPENAI_API_KEY"] = "..."
os.environ["ANTHROPIC_API_KEY"] = "..."

r = completion(
    model="openai/gpt-4o-mini",
    messages=[{"role": "user", "content": "Summarize this ticket in one line."}],
)
print(r.choices[0].message.content)

r2 = completion(
    model="anthropic/claude-sonnet-4-5",
    messages=[{"role": "user", "content": "Summarize this ticket in one line."}],
)

每个响应都是 OpenAI 结构。异常也会映射成 OpenAI 风格,例如 RateLimitError、AuthenticationError,现有的错误处理代码不需要改动。

关键流程:Router 与 fallbacks

这才是真正要上线的部分。以下四步构成一个完整的故障转移闭环。

1. 用共享别名定义部署

import os
from litellm import Router

model_list = [
    {
        "model_name": "support-summarizer",  # 面向应用的别名
        "litellm_params": {
            "model": "openai/gpt-4o-mini",
            "api_key": os.environ["OPENAI_API_KEY"],
        },
    },
    {
        "model_name": "support-summarizer-backup",
        "litellm_params": {
            "model": "anthropic/claude-haiku-4-5",
            "api_key": os.environ["ANTHROPIC_API_KEY"],
        },
    },
]

2. 配置重试与回退

router = Router(
    model_list=model_list,
    num_retries=2,
    fallbacks=[{"support-summarizer": ["support-summarizer-backup"]}],
)

重试留在同一个 model_name 组内,回退则离开当前组、进入列表中的下一个组。这种拆分是有意为之:如果主供应商还有另一个可用部署能响应,就不该把备用供应商浪费在一个偶发失败的单次请求上。

理解这里的关键是区分重试(retry)与回退(fallback)两个正交概念。num_retries 作用于同一个 model_name 组内:如果 support-summarizer 下挂了多个 gpt-4o-mini 部署(不同密钥或不同区域),一次 429 会先在同组内轮询重试,因为这类瞬时故障往往换个密钥就能成功。fallbacks 则只在整组重试仍失败后触发,切换到另一家供应商,本质上是一次跨供应商故障转移。把两者分开的意义在于成本与语义:同组重试代价低、延迟可控,跨组回退可能带来输出风格差异和更高单价,因此不该被偶发的单次失败轻易触发。此外,Router 还支持冷却(cooldown)机制,会把持续失败的部署短暂摘除,避免请求反复打到已知不可用的端点上。

3. 像调用 OpenAI 一样调用它

response = router.completion(
    model="support-summarizer",
    messages=[
        {"role": "system", "content": "One-line summary. No preamble."},
        {"role": "user", "content": ticket_body},
    ],
)
summary = response.choices[0].message.content

整个工单流水线从不导入 Anthropic。如果 OpenAI 在重试后仍被限流,LiteLLM 会自动切到备用别名。

4. 记录最终仍然失败的请求

在回退耗尽后捕获 litellm.RateLimitError 或 APIError。这些输入可以成为明天的评估集,也是提高预算或增加新区域的信号。

可选方案:用代理替代内嵌 Router

如果多个服务需要共享同一套故障转移规则,可以运行 LiteLLM AI Gateway,让所有 OpenAI 客户端指向它:

from openai import OpenAI

client = OpenAI(
    api_key="sk-your-virtual-key",
    base_url="http://localhost:4000",
)
client.chat.completions.create(
    model="support-summarizer",
    messages=[{"role": "user", "content": "hello"}],
)

配置 YAML 负责 model_list、fallbacks、预算和虚拟密钥。应用保持简单,网关负责可靠性。

LiteLLM 架构示意

LiteLLM AI Gateway 是把 Router 能力从进程内搬到独立服务的一种部署形态。它本质上是一个 HTTP 服务,对外暴露 /v1/chat/completions 等 OpenAI 兼容端点,应用只需把 base_url 指向网关即可。模型列表、回退规则、预算上限、速率限制和虚拟密钥都由服务端 YAML 管理。虚拟密钥的价值在于:它是网关签发的代理密钥,映射到真实供应商密钥但可以独立设置额度与作用域,因此上层服务永远接触不到原始 API Key。相比每个服务内嵌 Router,代理模式的优势是规则集中、变更无需重新部署应用;代价是多一跳网络延迟和单点运维负担。

什么情况下不必折腾

  • 只有一个业余脚本、一个密钥、一个模型,直接用原生 SDK 就够了。
  • 已经有一个成熟的内部网关,具备相同功能。
  • 延迟预算极其紧张,额外的一跳或跨供应商回退比短暂的 429 更糟糕。

除此之外,所有被单供应商故障坑过的团队,都应该把回退配置放在模型列表旁边,而不是散落在十几个调用点里。

落地检查清单

  1. 用 LiteLLM 的 completion 或指向代理的 OpenAI 客户端,替换零散的供应商 SDK。
  2. 为生产任务提供面向应用的 model_name,而不是原始供应商 ID。
  3. 设置 num_retries,处理组内的瞬时故障。
  4. 设置 fallbacks,在持续故障时切换到不同供应商或区域。
  5. 记录回退耗尽的场景,把它们视为产品事故,而不是“奇怪的 LLM 噪声”。

参考资源

当你的主 LLM 供应商限流时,你现在用的是希望、第二个硬编码客户端,还是一个真正的路由器?

背景补充

关于 model_name 与 litellm_params.model 的分工,值得再强调一次:前者是面向应用的别名,业务代码只依赖它;后者是真实的路由目标,采用 provider/model-id 格式(如 openai/gpt-4o-mini)。别名机制让同一组回退配置可以整体替换底层模型——比如把 support-summarizer 从 gpt-4o-mini 升级到新版本,只需改一处配置,所有调用点无需改动。这也是判断是否该引入 LiteLLM 的实用信号:如果你的代码里到处出现具体模型 ID 的字符串,那么供应商切换的成本就会被分散到每一处调用点。

#LiteLLM#LLM Router#OpenAI 兼容接口#多供应商故障转移#LLM 容错#AI Gateway#API 限流处理
分享:

相关推荐