1. 一个名字带 Lite 的 API 网关,凭什么值得部署
先讲结论:LiteLLM 是一个面向大语言模型调用的代理层,也包含一套 Python SDK,可以把各种模型 API 统一成一个 OpenAI 兼容格式。也就是说,无论你背后想接的是哪家商业大模型、哪家云厂商的托管模型,还是自己在机房跑的开源模型,业务代码只需认准一个入口,剩下的转发、鉴权、重试、成本统计都由它来处理。
我第一次意识到这类工具的价值,是在一个同时接了好几个模型平台的项目里。业务代码里散落着两三种调用方式,每个平台都有自己的鉴权方式、请求体结构、错误返回格式,连“模型不存在”这类问题的返回字段都不一样。为了对齐语义,我们不得不写一堆适配层,还要担心某个平台的 SDK 升级后把原有逻辑弄坏。后来把入口统一到 LiteLLM 代理上,情况明显好了很多:客户端只需要配一个 base_url 和一个 key,内部到底路由到哪家模型,由网关决定。
适合谁来用呢?如果你是个人开发者,正在折腾几个模型 API,LiteLLM 更像一条捷径;如果你是在团队里维护基础服务,想让多个人共享模型资源、控制预算、记录调用日志,那它基本就是一个现成的网关方案。它不承担模型推理本身,推理还是在各家上游完成,它负责的是“调度”这件事。
1.1 为什么会出现这样的项目
早期做大模型应用,通常只需要面对一家平台的接口就够了,脑子里记住一种请求格式、一种鉴权方式就行。但现在的现实是:同一个项目里可能要同时用到擅长写代码的模型、擅长长文本总结的模型,还要考虑某平台临时故障时切到另一个可用模型。每家接口长得又不一样,如果全部让业务代码直接适配,维护成本会指数级上升。
这种需求本质上和微服务里的 API 网关是一样的。微服务多了,前端不可能知道每个服务在哪、用什么协议,于是网关统一收口;大模型供应商多了,业务代码也不该去记每个厂商的地址和格式,它只需要知道“我发一个标准聊天请求,网关帮我选一个合适的模型来处理”。
LiteLLM 把这件事做得特别轻。它没有把简单的事情复杂化,而是定了一套规则:对外尽量模仿 OpenAI 风格的接口,对内用提供方前缀/模型名的方式标记每个真实模型。业务侧只要遵循对外协议,网关侧通过配置文件切换上游,就能做到“模型可替换、业务零改动”。
1.2 它和普通 Python 封装库有什么区别
市面上把各家模型封装成统一调用的 Python 库并不少,但 LiteLLM 给了两种使用方式。第一种是纯库模式,在你自己的 Python 进程里直接调用litellm.completion(),只负责把不同的上游请求转换成标准响应;第二种是代理模式,启动一个独立服务,对外提供 HTTP 接口,其他语言、其他团队都可以共用。
这个区别很关键。纯库模式适合嵌入到现有服务里,不增加网络跳数;代理模式则适合作为共享基础设施,让多个业务共用同一个入口、同一套成本统计。很多人在最开始只看文档会觉得它只是个 Python 库,实际生产环境里,更多人会用代理模式,因为它能集中管理模型密钥,避免每个服务都存一份上游 API Key。
所以你可以把它理解成一个具备双重形态的工具:要轻就只在代码里 import 使用,要重就把它当作一个独立服务部署起来。两种模式共用同一套模型配置逻辑,切换成本很低。
2. 从零搭一个最小可用代理,先把请求跑通
坦白说,LiteLLM 的上手门槛低到有点不像正经网关。在小环境里,只需要两条命令就能把代理拉起来,甚至不需要先写配置文件。对新手来说,这比一上来就啃部署文档友好得多。
2.1 安装前先想清楚用哪种模式
安装命令很简单。如果你只想在 Python 代码里直接调用,装基础版本就够了:
pip install litellm但如果你要跑代理服务,推荐装带 proxy 额外依赖的版本,这样会把代理接口相关的依赖一起拉进来:
pip install 'litellm[proxy]'这里有个容易踩的坑:很多人直接pip install litellm然后在命令行敲litellm --port 4000,会提示找不到命令。原因就是代理模式的入口文件在额外依赖里,基础包并不包含 CLI 的服务启停部分。装带[proxy]的版本最省心。
另外需要注意 Python 版本。现在 LiteLLM 对 Python 3.8 以下的支持越来越弱,新版本基本都要求 3.8 以上,推荐直接用 3.10 或 3.11。生产环境我建议跑在 Linux 容器里,一来资源占用可控,二来后续接 Docker 编排、接 K8s 都比在裸机上直接跑方便。
2.2 第一步:用命令行起一个临时代理
最小启动方式是这样的:先在环境变量里配置你要接的那个平台密钥,然后指定一个模型跑起来。
export OPENAI_API_KEY=sk-上面的真实密钥别写成明文 litellm --model openai/gpt-4o-mini --port 4000跑起来后,代理默认监听 4000 端口,对外暴露/v1路径。也就是说,本来你要发给上游平台的请求,现在可以改发给http://localhost:4000/v1,请求体和返回格式保持 OpenAI 风格。
验证是否跑通,最直接的方式是用 curl 打一个聊天补全请求:
curl http://localhost:4000/v1/chat/completions \ -H "Authorization: Bearer sk-临时随便填一个也行" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-4o-mini", "messages": [{"role": "user", "content": "你好"}] }'如果你看到返回里带着choices字段,说明代理已经正确把请求转发到上游,并且把响应转换回标准格式了。
2.3 用配置文件管理真实模型列表
命令行只适合验证功能,真正用起来一定要写配置文件。原因很简单:一个项目里不太可能只用一个模型,而模型可能要分优先级、分批次上下线,写在命令行又乱又没法提交到 Git 里审查。
常见做法是创建config.yaml,然后用litellm --config config.yaml --port 4000启动。配置文件里最核心的部分是model_list,它描述了这个网关能对外提供哪些模型名,以及每个模型名背后真实对应的上游模型是什么。
model_list: - model_name: gpt-4o-mini litellm_params: model: openai/gpt-4o-mini api_key: os.environ/OPENAI_API_KEY - model_name: my-embed-model litellm_params: model: openai/text-embedding-3-small api_key: os.environ/OPENAI_API_KEY注意这里model_name是外部名字,客户端请求里写的就是这个;litellm_params.model才是真实要去调用的上游模型。
2.4 为什么 model 字段要带一个斜杠前缀
很多刚接触的人会困惑:model_name明明写成gpt-4o-mini了,为什么litellm_params.model还要再多写一个openai/gpt-4o-mini?
这个前缀其实是提供方标识。LiteLLM 需要靠它来决定用哪一套适配逻辑去解析上游请求。不同平台的请求体、鉴权方式、响应解析逻辑都不同,比如有的平台把系统提示词放在system字段里,有的放在messages里,有的直接要求配置项单独传。前缀的作用就是告诉 LiteLLM:该用哪套“翻译规则”。
从工程习惯上,我建议每个人都把前缀写全。不要依赖 LiteLLM 根据模型名自动猜测,因为自动猜测在模型名重叠时容易出错,尤其是那些在多个平台都有部署的同名开源模型。写全前缀虽然多几个字符,但能把歧义彻底消除。
3. 路由、负载均衡与成本控制,这才是网关的灵魂
如果 LiteLLM 只是把多个模型接口统一了,那它顶多算一个适配层。真正让它有网关感觉的,是它的路由策略、故障转移和预算控制能力。这些功能对团队协作非常重要。
3.1 让同一个外部模型名背后挂多个真实上游
假设你的业务需要调用开源模型,你觉得某一家平台的响应不稳定,想同时接两个平台做互相备份。传统做法是自己在业务代码里写重试逻辑,而现在,你只需要在model_list里定义两个指向不同上游的条目,并且让它们的model_name相同。
model_list: - model_name: llama3-8b litellm_params: model: openai/llama3-8b api_key: os.environ/KEY_A rpm: 100 - model_name: llama3-8b litellm_params: model: openai/llama3-8b api_key: os.environ/KEY_B rpm: 80客户端请求时依然只写"model": "llama3-8b",LiteLLM 会从配置里找出所有同名条目,按照你的路由策略选中其中一个上游转发。
这里rpm是每分钟请求上限,只写上不会自动让 LiteLLM 做限流控制,但它能帮助路由算法更均衡地分配流量。更重要的是,你不需要在业务代码里关心某个 key 的配额还剩多少,所有这些都被收敛到了网关层。
3.2 路由策略不是玄学,要按场景选
LiteLLM 支持多种路由策略,简单整理一下:
| 策略名 | 工作方式 | 适合场景 |
|---|---|---|
| round-robin | 轮流分配请求 | 上游能力完全一致 |
| least-busy | 找当前并发请求数最少的上游 | 各上游负载不均 |
| usage-based-routing | 按剩余配额比例分配 | 上游按额度计费 |
| latency-based-routing | 优先选响应延迟低的上游 | 对延迟敏感 |
从个人使用经验来看,单机小规模场景里 round-robin 已经很好用。因为多数时候我们只是在做故障转移,而不是真的在做复杂流量调度。只有在大量并发的团队场景里,least-busy 或者 latency-based 才有明显收益。
不过要注意,路由策略只是“选谁”,真正的容错还要靠重试。生产环境里务必在配置里设置合理的重试次数:
litellm_settings: num_retries: 3 request_timeout: 30num_retries控制同一个请求在遇到上游 500、429 等错误时自动换另一个上游重试的次数。默认值比较保守,我一般调到 2 或者 3,太多反而会放大对上游的压力,在上游真故障时拖垮整个网关。
3.3 预算与成本统计要放在上线前配置
成本问题是我见过很多团队忽视的部分。业务刚起步时流量小,大家都不在乎几十块钱的调用费;流量一涨,又发现没有统计,月底对账只能翻日志。
LiteLLM 有一套成本统计机制,它内部库里预置了上百种公开模型的 token 单价,响应返回后根据输入输出 token 数自动估算费用。如果你用的是相对小众的模型,可以在配置里手动补充价格。
model_list: - model_name: custom-model litellm_params: model: openai/custom-model api_key: os.environ/KEY input_cost_per_token: 0.000002 output_cost_per_token: 0.000006你可以在代理运行一段时间后访问/cost路径,查看按模型、按 API Key 汇总的费用。这样的好处是,不管哪个业务线调用得最多,都能一眼看出来。
在团队里,我更推荐用虚拟 key 做预算隔离。给每个业务组创建一个虚拟 key,设好月度上限,超过后 LiteLLM 直接拒绝请求,避免一个人写错循环把整个月的预算跑穿。
4. 把 LiteLLM 当作团队网关来用的日常操作
LiteLLM 在个人项目里是“省事”,但在团队里是“省心”。所谓团队化,本质上就三件事:统一入口、收敛密钥、分配预算。
4.1 业务代码只需改一个 base_url
我见过很多团队引入 LiteLLM 之前,最担心的是改动量太大。实际上,如果你的业务代码本来就是用 OpenAI 风格 SDK 写的,接入 LiteLLM 只需要改两处:接口地址和 API Key。
以 Python 为例,改动非常小:
from openai import OpenAI client = OpenAI( base_url="http://localhost:4000/v1", api_key="sk-虚拟key" ) resp = client.chat.completions.create( model="gpt-4o-mini", messages=[{"role": "user", "content": "今天天气怎么样"}] )如果原来代码里用的就是 OpenAI 官方的 client,那这次改造几乎是无感的。改完以后,你的业务代码甚至不需要知道上游模型是来自哪家平台,也不需要关心 API Key 是否轮换。
如果业务代码用的是其他语言,比如 Go、Java,处理方式也类似:只要 HTTP 层能发标准请求,直接指向代理的/v1路径就行。这个优势在团队里有很强说服力:一次接入,长期受益。
4.2 虚拟 key 的正确用法
LiteLLM 内置了一套 key 管理体系。你可以先用 master key 创建一个虚拟 key 来调管理接口,然后给内部每个团队或每个业务分配不同的虚拟 key。
创建虚拟 key 很简单:
curl -X POST "http://localhost:4000/key/generate" \ -H "Authorization: Bearer sk-master-key" \ -H "Content-Type: application/json" \ -d '{"max_budget": 100, "models": ["gpt-4o-mini"], "expires": "2026-01-01T00:00:00Z"}'这条命令创建一个只能调用gpt-4o-mini、预算上限 100 美元、明年到期的虚拟 key。把这个 key 交给对应业务方,他们只能在这个范围内使用,不能看别人家的调用记录,也不能换到更贵的模型。
另外,虚拟 key 支持随时吊销。一旦某个 key 泄露,直接在管理接口里删掉,不影响其他 key。这一点比直接共用主 Key 安全太多。
4.3 把可观测性接进已有监控体系
网关一旦成为团队入口,就不只是转发请求那么简单,它还需要日志、指标、告警。LiteLLM 在这方面做了不少工作,最常用的是 callback 机制。
你可以在配置里声明一个回调地址,让网关在每次请求结束后把结果同步过去:
litellm_settings: success_callback: ["http://your-server/hooks/litellm"] failure_callback: ["http://your-server/hooks/litellm"]这样每次成功的请求、失败的请求都会发送一条 webhook 通知。对于自建监控面板的团队,把指标接到 Prometheus 更省事,直接在配置里启用对应指标端点即可。我不建议什么数据都往日志里打,能走指标和结构化回调的就尽量别用文本日志,否则排查问题时会非常痛苦。
5. 真实环境里的排障经验,比文档更有参考价值的部分
代理这种中间层,平时看不出存在感,一旦出了问题,所有人都会盯着它。运行 LiteLLM 的过程中,我遇到的大部分坑并不是 LiteLLM 本身难用,而是各种环境因素叠加导致的。下面这些内容,是我认为比官方文档更值得一看的实战总结。
5.1 常见问题速查表
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| 请求返回 401 | 上游 key 失效、虚拟 key 被吊销、虚拟 key 无预算 | 先用 curl 直接测上游 key,再测虚拟 key |
| 请求返回 429 | 上游限流、预算封顶、rpm配额耗尽 | 查看上游控制台配额,临时调整虚拟 key 预算 |
| 请求返回 400,提示 model not found | 配置里model写错、该模型未在当前平台开通 | 检查model_list中真实模型名 |
| 响应非常慢 | 上游本身慢、代理超时参数偏短、无连接池 | 调大request_timeout,检查网络链路 |
| 服务内存持续上涨 | 大并发流式请求、日志缓冲过多 | 限制最大并发数,减少 verbose 日志输出 |
5.2 延迟和超时参数,不能照抄默认值
LiteLLM 代理本身只是转发,所以延迟主要由上游决定。但如果代理的超时时间设置得比上游响应时间还短,上游本来能成功的请求也会被代理判定为失败,这是很多“超时报错”的根源。
我建议上线前先做一次简单的压测,把不同模型的最长响应时间摸清楚。对长文本生成场景来说,30 秒响应其实是常态,如果代理层只给了 10 秒超时,用户会看到大量不稳定的失败。在配置里把request_timeout调到合适范围,比事后抱怨上游更快。
还有一点容易忽略:流式输出时,代理默认会逐块转发结果。如果上游迟迟不返回第一块内容,客户端可能已经断开,代理还挂着连接占用资源。这种情况建议在上游和代理两侧都设置空闲超时,避免连接被长时间占用。
5.3 运维中容易忽略的三个边界问题
第一个是日志泄露风险。启动代理时如果用--detailed_debug查看详细信息,日志里可能会打印请求头里的鉴权信息。生产环境一定要关掉 verbose 输出,或者至少保证日志系统不把请求体完整记录到持久化存储中。
第二个是配置热加载并不是万能的。修改config.yaml后,某些参数可以热加载,但模型列表相关的部分最好重启验证。我遇到过修改模型列表后代理没报错、实际却仍按旧配置路由的情况,所以只要动了model_list,我都会重启容器再观察。
第三个是并发上限。LiteLLM 默认不做并发限制。平时看着没问题,真来一波流量高峰,可能直接打穿上下游。建议在代理层设置一个最大并发数,宁可让超出的请求排队或快速失败,也别让代理进程被压垮。
6. 顺着 LiteLLM 还能玩出什么花样
基础的路由和鉴权聊完了,最后说几个我觉得很有价值的扩展方向。这些功能官方文档都有,但很多人用 LiteLLM 只把它当“转发器”,没有完全发挥它的能力。
6.1 统一 Embedding 接口,解决多种向量化模型混用的问题
如果你在做 RAG 应用,很可能要面临不同向量模型之间切换的问题。LiteLLM 对 Embedding 接口的支持很完整,和聊天补全一样,对外提供标准/embeddings路径,内部可以按配置路由到不同的向量模型。
业务代码只需要把文本传进去,拿到向量,不需要关心当前用的是哪家的 Embedding 模型。尤其在重构向量存储、换向量模型时,这个统一接口能大幅降低改动范围。
6.2 把本地开源模型包装成标准接口
本地部署的开源模型通常有一套自己的调用方式,团队里其他人想直接用不太方便。用 LiteLLM 可以很轻松地把本地模型暴露成一个标准接口。
比如你在本地启动了模型服务,就可以在配置里把它编入model_list,然后用代理的网络地址对外提供服务。团队成员不需要知道本地服务的实际地址和端口,也不需要安装额外 SDK,统一走代理入口即可。这样最大的好处是:今天用本地模型,明天想换商业模型,业务代码一行都不用改。
6.3 只用 SDK 也能做轻量路由
如果你还没有搭建独立代理的打算,也可以在业务代码里直接用 LiteLLM 的 SDK 模式。这种场景下不需要起服务,只需要在进程里调用litellm.completion(),写起来非常短:
from litellm import completion resp = completion( model="openai/gpt-4o-mini", messages=[{"role": "user", "content": "你好"}], )这种方式适合接入点不多、服务规模也不大的场景。用起来比裸调各家 SDK 少了很多适配代码,又比部署代理轻得多。假如日后流量涨了,再把同一套配置搬到代理模式下,迁移成本也不会很高。
最后分享一个我在实际部署里养成的习惯:所有 API Key 一定通过环境变量注入,配置文件里只写os.environ/某某这种引用形式,绝不写明文。LiteLLM 在调试模式下可能把配置打印到日志里,一旦日志被同步到集中收集系统,几个上游 Key 等于裸奔。把密钥管理做好,再用好路由和预算功能,这个网关才能真正让人省心。