如果你同时对接过两家以上大模型厂商的 API,大概率撞见过同一个尴尬场景:相同的请求逻辑,换一家服务商就得重写一遍接入层。请求体格式不一样、鉴权方式不一样、返回结构也不一样,连报错信息都各说各话。我在某次内部项目改造里被这个问题折磨了快两周,最后把入口收敛到一个叫 LiteLLM 的代理层上,才算把“多家模型随便切”这件事真正落地。这篇就围绕 LiteLLM 讲透:它是干什么的、怎么部署、核心配置怎么理解、有哪些我实测下来值得注意的坑。
LiteLLM 本质是一个统一的大模型 API 网关。它对外提供一套风格统一的接口,内部帮你转发到不同厂商,同时把 Key 管理、预算控制、模型路由、成本统计这些杂事一并收编。适合团队里同时用多家模型、或者想把模型调度能力做成公共服务的同学。不管你是后端开发、算法工程师,还是自己做 AI 应用的独立开发者,只要不想被某个单一模型厂商绑死,这套东西都能省下大量重复劳动。
1. 先弄明白它解决什么问题
很多人在第一次听说 LiteLLM 时容易绕进一个误区:以为它只是“又一个模型聚合库”。实际上它可以分成两层看,明白这两层之后,你就能判断自己到底需不需要它。
1.1 它和直接调 SDK 有什么不一样
直接用各家 SDK,代码可以工作,但你把“模型接入”这件事写死在了业务代码里。比如你在某处硬编码调用了某家平台的 chat 接口,后来想换另一家的模型,光是把请求体格式改对就可能花半天,更别提处理鉴权方式差异、超时重试策略这些细枝末节。
有了 LiteLLM 之后,业务代码里只跟“一个标准样式”打交道。它对外暴露的是兼容主流调用风格的接口,你原来如果习惯用某种请求结构,把 base_url 指到 LiteLLM 服务地址上,基本就能无缝迁移。我自己的做法是:所有模型调用全部改成走 LiteLLM 代理,业务方根本不关心背后到底是哪家在响应。
这样做直接带来两个好处:
- 切换模型时不用改业务代码,只需要调整代理层的配置
- 可以在代理层集中做降级、负载均衡、Key 轮询和预算兜底
1.2 它替你扛住的那些脏活累活
真正用过之后你会发现,LiteLLM 解决的不只是“格式统一”。它其实把一个模型接入团队最不愿意维护的四处基础设施都做了收敛:第一处是多厂商兼容,不用自己维护一堆 SDK 依赖;第二处是安全管控,调用方不再直接接触上游真实密钥,而是拿到代理下发的虚拟 Key,每个人的额度、模型范围可以分别限制;第三处是成本能见度,每一笔请求花了多少钱、哪个业务方消耗最大,都有日志可查;第四处是高可用,如果某个上游模型抽风,可以配置自动切换到备用模型。
我最看重的是第二处。以前给同事发真实 Key,既不敢给权限限制,又怕泄露。现在通过代理层签发只读 Key,配额、速率、预算都能单独设定,心里踏实很多。
2. 部署一个最小可用网关:先跑起来再深入
纸上谈兵没有意义,我建议你直接在本地跑一个最小实例。LiteLLM 部署非常轻,本质上就是一个 Python 服务,一条命令就能拉起。
2.1 安装与启动流程
建议用虚拟环境安装,避免污染全局 Python 环境。
python -m venv .venv source .venv/bin/activate pip install "litellm[proxy]"装完之后你可以直接用命令行参数启动一个极简代理:
litellm --model gpt-3.5-turbo --port 4000但我不建议长期用这种方式,因为真正的配置项多了之后,命令行根本管理不过来。更推荐的做法是用配置文件启动:
litellm --config config.yaml服务默认起在 4000 端口,如果你本机端口被占了,可以在配置里改。启动之后,LiteLLM 会输出日志,看到Uvicorn running on http://0.0.0.0:4000类似的字样就说明成功了。
2.2 写第一份模型路由配置
一个最小的 config.yaml 长这样:
model_list: - model_name: gpt-3.5-turbo litellm_params: model: gpt-3.5-turbo api_key: ${OPENAI_API_KEY}这里需要解释一下 model_name 和 model 的区别。model_name 是你在代理层暴露给调用方的名字,业务代码只认这个名字;model 是 LiteLLM 实际去上游厂商那里调用的真实模型标识。它们可以一样,也可以不一样。比如你可以在代理层把 model_name 命名为 our-chat,背后转发到各家不同模型,对外完全透明。
配置文件里也支持直接用环境变量注入密钥,避免把敏感信息提交到 Git。我的习惯是所有上游 Key 全部放在环境变量里,config.yaml 只写变量引用,这样换环境时只需要改环境配置。
2.3 用标准客户端验证连通性
代理起来之后,验证方式很简单。如果你平时用某种通用客户端工具发请求,把地址指向本地就行。我用一段 Python 示例来演示:
from openai import OpenAI client = OpenAI( api_key="sk-anything", base_url="http://localhost:4000" ) response = client.chat.completions.create( model="gpt-3.5-turbo", messages=[ {"role": "user", "content": "你好,请用一句话介绍自己"} ], temperature=0.7 ) print(response.choices[0].message.content)这里有个小细节:请求头里的 Key 其实可以随便填一个字符串,因为 LiteLLM 在没有开启虚拟 Key 校验时,不校验这个字段的真实性。但建议还是养成填正式 Key 的习惯,后续开启权限控制之后,这里就必须是代理签发的合法 Key 了。
跑通这一步,你已经拥有了一个统一的模型入口。剩下的复杂度,都是在入口之上叠加管理能力。
3. 核心机制拆解:模型路由、虚拟 Key 与预算控制
只跑通代理转发没什么稀罕的,LiteLLM 真正值钱的是它这一层丰富到有点过分的管理能力。我挑三个最常用的机制拆开讲,全部来自实际压测和配置经验。
3.1 模型路由是如何工作的
模型路由是 LiteLLM 的招牌能力,简单说就是:你可以给同一个 model_name 挂多个上游模型,代理按策略挑选一个响应。这个机制在两种场景下特别实用:一是想在多个模型之间分摊流量成本,二是想让特定模型当主力、另外几个当备胎。
配置里通过 model_group 和 routing_strategy 控制:
router_settings: routing_strategy: simple-shuffle model_list: - model_name: our-chat litellm_params: model: gpt-3.5-turbo api_key: ${OPENAI_API_KEY} tpm: 100000 rpm: 1000 - model_name: our-chat litellm_params: model: claude-3-haiku api_key: ${ANTHROPIC_API_KEY}这样配置之后,调用方仍然只发 model=our-chat,代理会按策略在 gpt-3.5-turbo 和 claude-3-haiku 之间做选择。如果我故意把某一家的模型名写错,让它起效失败,同时配置了 fallback,流量就会自动切到另一家,这在高可用场景里是救命级别的能力。
Routing strategy 我试过几种,simple-shuffle 适合随机分发和简单的压力分散,least-busy 会根据当前负载选择空闲模型。如果你拿不准,建议先用 simple-shuffle,逻辑简单、排障容易。
3.2 架构上的容灾设计:Fallback 与超时
把模型调度交给代理之后,最直接的好处是可以把 Failover 逻辑从业务代码里抽走。我配置过一个很典型的容灾方案:
router_settings: fallbacks: [ {"our-chat": ["gpt-3.5-turbo-16k", "claude-3-haiku"]} ]实际上我会把 fallbacks 放在更细致的位置,按我测试的效果,必须要确认:LiteLLM 只在遇到特定类型的报错(比如限流、超时、服务不可用)时才触发 fallback,而不是所有报错都让它切。这意味着你需要在配置里叠加连接超时和重试参数:
litellm_settings: connect_timeout: 10 read_timeout: 300 num_retries: 3 request_timeout: 600需要注意,timeout 不能盲目调大。曾经我把 read_timeout 调到 300 秒,结果发现量一大之后连接堆积严重,因为部分请求卡住进程不释放。最后我把 read_timeout 控制在 60 秒到 120 秒之间,num_retries 固定成 2 次,效果均衡得多。建议你上线前用真实流量压一遍,再根据 p99 延迟倒推合理超时值。
3.3 虚拟 Key 体系:安全管控的核心
这是 LiteLLM 里我反复安利给同事的功能。它允许你签发一套独立的虚拟密钥体系,调用方拿到的不是你的真实上游密钥,而是由 LiteLLM 生成的虚拟 Key。你可以在签发时直接指定这个 Key 的预算上限、速率限制、可用模型范围、过期时间。
签发的入口有两个:一个是通过页面管理界面,另一个是通过/key/generate接口。我更习惯用接口来签发,配合脚本可以作为自动化申请流程的一部分:
curl -X POST http://localhost:4000/key/generate \ -H "Authorization: Bearer sk-master-key" \ -H "Content-Type: application/json" \ -d '{ "models": ["our-chat"], "max_budget": 10.0, "rpm_limit": 60, "duration": "30d" }'返回结果里会带一个 sk- 开头的虚拟 Key,这个 Key 在有效期内可以正常调用代理,但无论如何都无法通过代理拿到上游的真实密钥。我把这种方式应用到项目组之后,再也没出现“同事把 Key 贴在群里”的破事。
价格和配额限制也很好理解:max_budget 是硬顶,一旦耗尽,这个 Key 会立刻返回额度不足的报错;rpm_limit 是每分钟请求数限制,适合控制疯狂循环调用的情况。对内部团队,我会把预算卡得松一点,主要卡速率;对对外分发,预算和速率都严格收紧。
4. 可观测性与成本核算:让每一分钱都看得见
聊完控制和转发,一定要讲一讲“看得见”的部分。很多人用代理只是图省事,但 LiteLLM 的统计能力在我自己的项目里甚至成了主要卖点。
4.1 请求日志与 Token 统计
LiteLLM 默认会把请求日志写入本地的 SQLite 数据库,包括模型名、请求耗时、输入输出 Token 数、费用估算、虚拟 Key 标识等。如果你部署在单机环境,这个默认方案够用;但要是正式环境多实例部署,必须换成 PostgreSQL,否则日志会散落在不同节点上。
我碰过一次本地数据库锁死的情况:单实例高并发写入 SQLite,偶尔出现 database is locked。最后直接把数据库切到了 PostgreSQL,这个问题就根治了。如果你也是小规模使用,注意控制一下日志写入频率,或者配置批量刷盘策略,也能缓解。
4.2 用查询接口做成本分析
除了看日志表,LiteLLM 还提供了一组管理端点。我常用的有这些:
/spend/logs:查所有请求的计费明细/spend/keys:按虚拟 Key 聚合花费/global/spend:看整体大盘
比如我想知道上周某个业务方在哪个模型上花钱最多,直接查 spend 相关端点,一目了然。
实际工作中,我习惯把这些端点接到内部监控看板上,每周自动拉一次成本报表。曾经发现某个客户对某个模型产生了超出预期的调用量,靠 Key 维度的统计很快定位到了异常调用方,及时做了限流。这个价值很难用数字衡量,但遇到一次就知道它的好。
4.3 自定义模型价格的补充
如果你用的是非标准模型或者自部署模型,LiteLLM 的成本估算未必准确。它内部有一套主流模型的价格表,但自建模型或者稀缺模型无法自动算准。这时可以通过模型参数里的 price 字段手动维护:
litellm_params: model: ollama/llama3 input_cost_per_token: 0.000001 output_cost_per_token: 0.000002我一般会在每次上线新模型时顺手补充价格参数,避免月底对账时“预估花费”和“实际账单”差距大到离谱。不要指望默认行为帮你搞定一切,花 5 秒钟配一个价格,后面省心很多。
5. 实测过程中最容易踩的坑
任何工具都有“文档里没写清楚”的部分。LiteLLM 整体成熟度挺高,但以下几个问题我实际使用中遇到过,罗列出来帮你避坑。
5.1 常见报错定位表
| 现象 | 常见位置 | 排查思路 |
|---|---|---|
| 提示没有可用模型 | 路由配置 | 检查 model_name 是否与请求中的 model 完全一致 |
| 请求超时 | 上游服务 | 用 curl 直连上游确认网络状况,再检查 timeout 参数 |
| 虚拟 Key 无效 | 权限管理 | 确认请求头用的是代理签发 Key,不是环境变量里的上游 Key |
| Fallback 未触发 | 路由策略 | 确认报错类型属于配置中开启的 fallback 条件 |
| 数据库锁死 | 持久化存储 | 多实例时需要升级为 PostgreSQL,不要用 SQLite 硬扛 |
| 日志中有敏感信息 | 监控体系 | 检查请求内容是否记录在日志表里,必要时脱敏 |
5.2 关于日志脱敏的补充提醒
这一点得专门提:LiteLLM 默认会在日志里记录请求和响应体内容。如果你传输的是业务敏感数据,建议在配置里关闭内容记录,只留元数据。
litellm_settings: disable_logging: false turn_off_message_logging: true关闭消息体日志之后,你仍然能看到调用了哪个模型、花了多少钱,但看不到具体对话内容。对合规要求高的场景,这一步必须做,别等审计发现问题再回头补。
5.3 多实例部署的注意事项
如果请求量上来了,单实例跑 LiteLLM 会成瓶颈,它本质还是一个无状态代理层,完全可以水平扩展。但这里有一个反直觉的地方:多个实例共用同一个数据库时,虚拟 Key 的配额扣减可能会出现竞争。
我当时用双实例跑了一段时间,发现偶尔有两个请求几乎同时扣减额度,导致总额微量超支。最稳妥的做法是:要么把虚拟 Key 配额放宽一点,留出余量;要么用外部 Redis 做配额中心。LiteLLM 本身支持一些外部协调,但需要额外配置。如果只是做内部工具,稍微放宽预算余量就能解决大部分问题。
6. 从代理到平台:LiteLLM 还能做什么
当你把 LiteLLM 跑顺之后,它其实已经不只是“模型代理”这么简单了。我目前的使用方式,更像是一个轻量级的 LLM 接入平台。
6.1 用管理接口搭建内部模型商店
因为虚拟 Key 的签发、配额、计量都齐了,完全可以封装成内部平台。同事自助申请 Key、选择模型、配置额度,不需要找你手动处理。我实践过一个类似自助申请的能力,大约只写了几十行代码,调用它的管理接口就可以完成。这个方向很适合做内部开发者工具,节省沟通成本立竿见影。
6.2 与开源生态的适配
LiteLLM 比较讨喜的一点是对主流开发框架都有接入方案。比如很多本地应用工具要配置模型 API 地址时,直接填http://localhost:4000就能工作。你甚至可以把多个不同的应用请求统一收敛到一个网关,方便做成本核算和权限回收。
我在一个跨平台系统的模拟改造中,让三个原本各自连不同厂商服务的应用全部指向 LiteLLM,只花了半天改完所有配置。从那以后,新增模型、切换供应商就再也不用重新发版了。
6.3 需要留意的局限
LiteLLM 不是银弹。它比较适合文本生成类任务;虽然也支持一些多模态模型,但我实测下来,对图片输入这类场景的支持不如纯文本流畅。另外,它内部封装的模型参数并不覆盖所有厂商的全量选项,个别冷门参数可能无法直接透传。如果你只需要一家固定模型,用它反而多了一层复杂度。只有当你有“多模型、多Key、多团队、计量计费”这类真实痛点时,它才真正值回票价。
7. 个人经验与最终建议
我自己把 LiteLLM 落地的过程里,最深刻的体会是:不要一上来就追求复杂配置。第一次使用时,只配置一个模型、一个路由,跑通调用链,再逐步叠加虚拟 Key、预算和 fallback。越级配置只会让你在排障时多绕很多弯路。
关于稳定性,我的建议是:默认配置先跑一周,再把超时、重试这些参数调到贴合自己流量特征的位置。不要照抄网上的参数,因为上游厂商限流策略、你的请求体大小都不一样,最优值只能来自你自己的压测数据,没有捷径。
最后分享一个小技巧——把 LiteLLM 的配置目录纳入版本管理,并用 CI 做一次配置校验,确保改动后语法正确再发布。很多时候线上故障不是代码引入的,而是改了配置没跑测试直接上线导致的。这个习惯帮我避免了至少三次“看起来像事故”的尴尬时刻。如果你正准备接模型网关,从最小配置起步,逐步把它养成整个团队的模型接入标准。