☰
Litellm 模型网关实践:统一多模型接入与路由控制
2026/10/14 10:16:51 网站建设 项目流程

在接入第二个模型服务商之前,我一直觉得多套 SDK 并存没什么大不了。直到某一个月里,我在同一个项目里同时维护三套 API 的请求格式、鉴权方式和错误码,才意识到这是整个项目里最不该被低估的成本。那段时间我开始认真评估 Litellm,后来干脆把它架到了所有模型请求的最前面,团队里的接入方式从三套变成了一套。

Litellm 是一个开源的 LLM 代理与路由层,常用做法是把它部署成一个轻量服务,对外暴露统一接口,对内负责连接各类模型服务商。外部调用方只需按照一套通用格式发请求,剩下的模型路由、重试、成本统计、密钥管理全部由它接管。这篇文章适合两类人看:一类是项目里已经接了多个模型、被接口不统一和密钥散落折磨的开发者;另一类是刚开始选型模型网关、想知道这东西到底能解决什么问题的朋友。我会从实际部署和踩坑出发,把 Litellm 能做什么、怎么配置、边界在哪讲清楚。

提示:Litellm 和 LiteLLM 指的是同一个项目,只是官方文档和代码仓库里两种写法都在用,看到哪个都别迷惑。另外它不是模型服务,不托管任何模型权重,只是一个请求代理和路由网关。

1. 为什么我会被多模型接入逼到“想上代理”

1.1 多模型并行带来的三类典型麻烦

先说最直观的接口不统一。不同模型服务商有自己的消息结构,有的用 content 字段返回文本,有的用 response.text,有的把内容塞在嵌套对象里;流式输出的格式更是各家有各家的定义,事件类型、结束标记、增量字段全不一样。业务代码里如果到处写的是某个厂商专属的调用方式,换一家模型时几乎等于重写一遍调用层。

然后是密钥管理。起初我把各家 API Key 直接放在环境变量里,团队每个人本地开发都要复制一份,后端服务部署时又把真实 Key 打进镜像,想想都后怕。一旦 Key 泄露,除了去服务商后台手动吊销重新生成,没有任何隔离手段。

第三类是成本对不齐。月底汇总账单的时候,我需要分别登录每个服务商的后台,把 token 用量导出来,再用表格手工汇总。哪些业务线用了多少、哪个模型超支了,完全是一笔糊涂账。这三个问题单靠业务代码打补丁都能缓解一点,但解决不了根本,因为本质缺的是一个集中入口。

1.2 Litellm 切入的位置

Litellm 解决的是把“调用模型”这件事从应用代码里剥离出来。它有两种使用方式:一种是在代码里直接 import 它的 SDK,封装各家调用;另一种更常见、也更适合团队协作的方式,是把它作为代理服务独立运行。客户端只需要知道一个 base_url 和一个虚拟 Key,模型名叫什么、背后连的是哪家服务商,客户端不关心也不需要知道。

我选择代理模式还有一层考虑:团队成员不需要安装 Litellm 的 Python 包,不熟悉 Python 的前端同学也能直接通过 HTTP 接口调用模型。接入门槛从“读某厂商的 SDK 文档”降到了“发一个 POST 请求”。这个转变对团队协作效率的影响,比想象中大得多。

1.3 它和普通 API 转发器的区别

很多网关产品也做 API 转发,但 Litellm 的价值不只是转发。它内置了大量模型服务商的适配层,能自动完成格式转换、流式协议转换、错误码归一化;它在转发层之上还做了模型路由、负载均衡、预算控制、虚拟密钥和用量统计。这些能力组合在一起,才让它从“反向代理”变成了“模型治理入口”。

2. 核心抽象:为什么所有模型都能变成一套“通用接口”

2.1 一次请求的完整旅程

我实际抓过一份请求日志,把 Litellm 处理一次调用的全过程完整看完后,才对它的设计有了直观认识。

客户端向代理发送一个标准格式的对话补全请求,包含 model 字段、messages 数组、可选参数如 temperature 和 stream。Litellm 收到后先解析 model 字段,到模型列表配置里查找匹配项;然后根据配置好的路由策略,从可用的模型条目中选出一个;接着把标准格式翻译成目标服务商自己的请求结构,这一步就是适配层在做的事;再补上对应的真实 API Key、超时和重试参数,向后端发起真实请求;拿到结果后再统一翻译回标准格式返回给客户端。整个过程里,客户端眼里永远只有一套格式。

我在第一次跑通这个流程时反应是“就这么简单?”因为代理把最大量的兼容工作都藏在了内部,暴露出来的只有模型名、base_url 和 key 这三个概念。

2.2 为什么选这套标准格式作为“通用语”

Litellm 选择兼容一套通用格式作为对外标准,我个人认为这是它最聪明的设计决策之一。这套格式事实上已经被大量开源框架、第三方平台和私有化部署方案采用,很多模型服务商本身就提供兼容模式。Litellm 选择它作为标准,等于站在了生态最大公约数上,客户端生态工具链也最成熟。

这样做还有个隐性的好处:迁移成本低。如果你的项目之前已经按照通用格式写好了调用代码,那么接入 Litellm 时,客户端几乎不用改,只需要把 base_url 指向代理地址,把 API Key 换成虚拟 Key。我们内部迁移时,大部分服务只改了配置没动代码。

注意:这里说的“通用格式”指的是对话补全风格的接口,并不是只有一种形态。Litellm 对 embedding、图像生成、语音等任务也有对应支持,但日常使用频率最高的还是 chat 类接口,文章的配置示例也以这个为主。

2.3 适配层是怎么保持兼容的

Litellm 为大量服务商准备了独立的适配代码,每个适配器负责把标准请求映射到目标服务的参数。模型名写法也遵循“提供商/模型名”的规则,比如一个 OpenAI 系模型在 Litellm 里写成 openai/gpt-4o,一个 Anthropic 系模型写成 anthropic/claude-3-5-sonnet。这样设计的好处是同一个模型名在不同配置下可以指向不同真实后端,模型切换只是改配置的问题。

3. 从零搭一个代理服务:部署与最小配置实践

3.1 安装与依赖注意事项

先说安装。用 pip 安装时建议直接装带 proxy 的版本,这样才能使用代理服务模式:

pip install 'litellm[proxy]'

只装核心包也能用 SDK 模式,但跑不起来代理服务。装好后可以先看一眼版本号,如果发现 Python 版本太旧,可能需要先升级环境再装依赖。

我踩过一个小坑:如果依赖安装到一半报网络超时,大概率是镜像源的问题,换个国内可用的 PyPI 镜像再装就顺畅很多。这不是 Litellm 本身的坑,但几乎每个本地安装的人都会遇到一次,提前说一声省得走弯路。

3.2 两分钟跑起最小代理

安装完成后,最直接的启动方式是在命令行指定一个模型:

export OPENAI_API_KEY=sk-你的真实Key litellm --model gpt-4o --port 4000

启动之后,控制台会打印代理地址,通常是 http://localhost:4000。这时候用 curl 验证一下:

curl http://localhost:4000/v1/models curl http://localhost:4000/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{"model": "gpt-4o", "messages": [{"role": "user", "content": "你好"}]}'

第二个请求如果返回了正常的模型回复,就说明代理已经跑通。注意命令行方式适合临时验证,模型多了以后还是要靠配置文件来管理。

3.3 用 config.yaml 管理多模型

配置文件是 Litellm 代理模式的标准玩法。我推荐把模型列表、路由策略、密钥设置全部写在同一个 YAML 文件里,启动时加载它:

litellm --config config.yaml --port 4000

一个最小可用的 config.yaml 长这样:

model_list: - model_name: gpt-4o litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY - model_name: claude-3-5-sonnet litellm_params: model: anthropic/claude-3-5-sonnet api_key: os.environ/ANTHROPIC_API_KEY - model_name: local-llama litellm_params: model: ollama/llama3 api_base: http://localhost:11434

配置里有两层概念:model_name是客户端调用时用的别名,litellm_params.model是真实后端的完整模型标识。同一个别名可以对应多个真实后端,这就是后面讲路由功能的基础。api_key 里写的os.environ/OPENAI_API_KEY是 Litellm 自己的环境变量引用语法,启动前保证对应环境变量已经设置好就行。

3.4 客户端接入方式

代理跑起来之后,客户端接入可以用任意支持通用接口的 SDK。以 Python 为例:

from openai import OpenAI client = OpenAI( base_url="http://localhost:4000", api_key="sk-任意虚拟Key" ) resp = client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": "用一句话解释负载均衡"}] ) print(resp.choices[0].message.content)

这里有一个值得注意的点:代理模式下客户端传的 api_key 不一定是真实厂商 Key,只要代理没开启严格校验模式,它更接近一个身份标识。真正访问厂商时的鉴权由代理根据自己的配置完成。这也是很多第一次上手的人会迷惑的地方。

4. 生产环境必做的三件事:路由、预算与密钥

4.1 模型路由:让请求自动选择最合适的后端

路由是 Litellm 最核心的生产能力。早期我把它理解成“多个模型随机选一个”,实际用下来才发现它包含了两层意义:一是模型版本层面的负载均衡,二是业务策略层面的成本控制。

代理配置里可以给同一组后端定义同一个别名。比如有三个模型后端,两个便宜一个贵,我可以把两个便宜的模型都挂在别名 cheap-llm 下;客户端需要低成本处理时,请求里就传 cheap-llm,代理会根据策略在便宜模型间分担流量。另一个别名 expensive-llm 只指向贵模型,留给对质量要求高的场景。

路由策略的选择直接影响体验,我用下来比较常见的有这么几类:

策略工作方式适合场景
simple-shuffle从可用后端里随机选一个默认策略,适合同质化后端
least-busy优先选当前并发最低的后端后端响应速度差异大时
usage-based-routing根据已用配额比例分配需要按预算配比用量
latency-based-routing优先选近期延迟最低的后端对响应延迟敏感的业务

今年我在配置里把默认策略换成了 usage-based-routing,用了一周后,月底对账时明显省心不少,因为流量会自然地朝预算配额更宽裕的后端倾斜。如果你的场景就是几个等价模型之间做容灾,用默认的 simple-shuffle 就够,没必要为了复杂而复杂。

4.2 预算控制:把“花超了”变成“不允许花超”

预算控制是团队接入后最容易感受到价值的功能之一,它可以替代很多“事后对账”的疲惫感。

我在配置里设置了全局预算上限和每日上限,代理会在接近阈值时开始拒绝新请求并返回明确错误信息,而不是让账单先跑起来再想办法。模型级预算也很有用,特别是某些模型按额度单独计价时,可以避免一个应用把整月配额打光。

另外,配合路由策略的 usage-based-routing,预算管控的力度还能再进一层:让流量按不同后端的剩余预算比例分配。这样每个后端花的钱都控制在配额内,整体费用结构也更可预测。

4.3 虚拟密钥:把真实厂商 Key 藏起来

虚拟密钥是我上了生产环境后第一个主动启用的功能。它的思路和“数据库账号不直接用 root,而是给每个服务建独立账号”一样:真实供应商 Key 只存在于代理配置或环境变量里,对外只暴露虚拟 Key。

团队里每个成员或每套环境可以申请一个独立虚拟 Key,每个 Key 绑定独立的预算额度。有人误用或 Key 泄露时,只需要吊销对应的虚拟 Key,受影响的也仅仅是那一个范围,其他服务完全不受牵连。这比所有服务共用一把真实 Key 安全得多。管理入口既可以通过配置开启的 UI 面板,也可以通过管理接口创建,具体路径在不同版本里略有差异,但核心思想是不变的。

4.4 可观测性和成本报表

Litellm 的代理会替每个请求记录 token 用量、成本和延迟,并提供了查询接口和指标出口。我把它接入了现有的监控体系,用仪表盘展示每天请求数、token 消耗和成本趋势。相比之前月底手工整理账单,现在每天打开面板就能看到哪个应用在烧钱、哪个模型调用量异常。这个能力对预算敏感的中小型团队尤其有价值。

5. 实测中的常见坑与完整排查思路

5.1 环境变量不生效,请求一直 401

有一次我升级配置后启动代理,所有请求都返回鉴权失败。我第一反应是 Key 写错了,反复检查配置文件里的 api_key 字段,看着没问题。后来发现原因很朴素:我是在代理进程启动之后才重新 export 环境变量的,代理进程读到的还是旧环境。

这类问题的排查顺序建议固定下来:先确认配置里的 api_key 引用语法是否正确,再确认环境变量在启动命令之前是否已经生效,最后看启动日志是否加载了预期配置。把排查顺序固定下来,能省很多“改一行重启一次”的无效循环。

5.2 新版 SDK 与适配层的“时间差”

Litellm 的一大优势是适配层做得全,但这也意味着它依赖上游服务的接口稳定性。某次上游模型服务调整了返回字段,Litellm 的适配层还没有及时跟进,导致项目里所有经代理的请求都出现了解析异常。当时我第一时间不是去改业务代码,而是先把 Litellm 升级到最新版本,问题立刻消失。

遇到这类问题时,先把代理本身升级到最新版,再去看业务代码。绝大多数异常都是适配层版本跟不上导致的,升级操作比追查业务代码快得多。

5.3 自定义协议模型接入:别指望“自动适配一切”

Litellm 内置适配器覆盖了主流服务商,但总会遇到内部自建平台或者闭源模型服务,这时候它不会自动理解对方协议。我的经验是:优先看目标平台是否提供通用兼容接口,如果提供,直接按兼容模式接入即可;如果完全没有兼容接口,就需要写一层自定义适配逻辑,把请求转换成目标平台要求的格式。

这个边界要想清楚,Litellm 解决的是“统一接入体验”,不是“零代码接入所有平台”。评估新平台时,我会先确认它有没有提供兼容接口,再决定是直接接还是需要额外开发。

5.4 重试和兜底放大了“重复扣费”

这是我踩过最深的坑。当时我配置了主模型失败自动切换到后备模型,同时也开了超时重试。结果某天监控发现同一批请求被扣了两次费用:第一次请求超时被代理中止,但上游实际已经生成了结果;代理接着把请求发给了后备模型,又扣了一笔。

这个问题的本质是所有 API 网关都会遇到的“超时不一致”:客户端超时不等于服务端没处理。缓解手段有几个方向:减少激进的重试次数、设置合理的超时时间、对幂等要求高的调用在前端加一层去重标识。Litellm 本身提供了一些参数来控制这些行为,但最终的业务一致性需要自己根据业务特点调。

5.5 代理服务本身的单点风险

代理模式的一个天然代价是:所有模型请求都经过它,它就是链路里的单点。一开始我只部署了一个实例,有一次配置错误导致代理频繁重启,整个依赖模型的功能全部受了影响。后来我改成至少运行两个实例,前面加一层负载均衡,发布时逐个实例轮转,才把风险降下来。

另外配置文件的变更需要重启代理才能生效。如果你的团队经常调整模型列表或路由策略,建议在发布流程里加入配置检查步骤,避免一个语法错误导致整个代理起不来。

6. 什么场景真的值得上 Litellm

先说不适合的场景。如果项目只调用一家模型服务商的接口,业务代码里已经有稳定封装,团队也只有一两个人维护,那直接调 SDK 就好了,引入代理反而多了一层组件和运维成本。还有一类是极低延迟场景,比如在线游戏里的毫秒级响应,这类场景需要彻底掌控链路,代理转发的那一点开销也可能不可接受。

适合的场景其实很清晰:第一个是项目里已经出现两个及以上模型服务商,并且还在持续增加;第二个是团队多个人都在写模型调用代码,需要统一体验和自助接入;第三个是你对成本、密钥、配额有集中管控诉求,不想靠手工表格对账;第四种是你已经有兼容通用接口的调用栈,未来想平滑替换不同模型提供商,不想因为换模型而重写一遍业务代码。

我个人的实践原则是:单模型单调用方的项目,直接用厂商 SDK;一旦出现第二个模型服务商,或者第二个人要接入模型服务,就毫不犹豫上 Litellm。按这个规则走,既不会在小项目里过度设计,也不会在大项目里陷入多 SDK 泥潭。如果你也正在评估模型网关,建议先拿一个最小代理跑一周,把虚拟密钥、预算限制和日志面板用起来,再做最终决定。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询