1. 为什么我会盯上 LiteLLM?
先交代一个背景。最近几个月我一直在折腾大模型应用,单是接不同厂商的 API 就快把我逼疯了。这家模型要单独写一套鉴权参数,那家 SDK 命名风格完全不一样,文档里的请求体字段五花八门,今天这个上游把接口改了,明天那个上游又限流了。群里同行的状态基本就是:一边换模型一边改代码,改完代码再调参数,调完参数还得记着清理上一家的缓存。说实话,模型本身没把我难住,难住我的是“如何和一堆模型供应商相处”。
后来瞄到了 LiteLLM 这个开源项目。一句话说清楚它是什么:LiteLLM 是一个统一了 100 多种大模型 API 接入方式的 LLM 网关,它屏蔽掉不同供应商的差异,对外只暴露一个 OpenAI 兼容的接口。你只要用一套代码,就可以在多个模型之间切换、负载均衡、自动重试、记录请求日志,甚至还能做预算控制和用量统计。
谁适合用它?如果你有这样的处境,我觉得值得往下看:
- 手上接了好几家 LLM 服务,想统一管理 API Key,不想散落在代码里。
- 项目里要用到多个模型(比如用开源模型做私有化,用云端模型做主力),需要一套路由和切换机制。
- 团队里不同成员各自写了一套 Prompt,账单混乱,需要统一管一下 token 消耗。
- 或者你只是单纯受够了改供应商 SDK 的日子,想找一份省心的轮子直接用。
这篇就从我实际的部署和调试经验出发,聊聊 LiteLLM 的核心逻辑、怎么落地、有哪些坑,以及我踩过之后梳理出一套比较稳的配置思路。如果你是冲着“抄作业”来的,后面几节会给你可以直接用的代码和 YAML。
2. LiteLLM 到底在解决什么问题?
2.1 一个被很多项目忽略的“模型接入复杂度”
很多人最初以为接入大模型就是发一个 HTTP 请求的事,实际做过之后才发现,没这么简单。不同的厂商在 API 形态上的差异太大了:
- 请求格式不一样:有的支持 OpenAI 风格,有的必须用自家 SDK,有的甚至要传固定版本的参数。
- 鉴权方式不一样:有的是 Bearer Token,有的是额外签名头,有的要求动态生成时间戳。
- 响应格式不一样:有的返回流式事件,有的直接给 JSON,有的报错结构五花八门。
- 能力和限制不一样:上下文长度、并发上限、计费单位、私有化部署方式都不同。
LiteLLM 做的事情,就是把这些“不一样”全部收敛到一层。你不需要在自己的业务代码里写一堆 if-else 去判断当前用的是哪家模型,只需要固定用 OpenAI 兼容风格去请求 LiteLLM,由网关在后端完成协议转换和适配。它就像一座桥,把业务端和模型供应商端彻底解耦。
2.2 从“多头管理”到“集中治理”
我见过不少团队的代码里直接硬编码了各家 API Key,散落在环境变量、配置文件、甚至是前端代码里。一旦某个 Key 需要轮换,你就是全组群发消息,一大片代码同步改,改慢一点就会收到上游限流通知。用 LiteLLM 之后,API Key 全部收敛到网关配置中,业务侧只需要知道 LiteLLM 的地址就好。Key 轮换只需要改网关,其余服务零感知。
这才是网关类产品真正有价值的地方:它不是简单包一层 SDK,而是把安全、成本、路由、可观测性这些治理能力集中了起来。比如:
- 哪个部门调用了什么模型、花了多少钱,在 LiteLLM 的后台都能查到。
- 某个应用调用的模型需要降级到备用模型,可以在路由层做规则,不用改业务代码。
- 某个用户被拖入了黑名单,直接返回拒绝请求,不用在业务侧加逻辑。
这些能力听起来不算炫酷,但在生产环境里每一项都能省下不少心。
3. LiteLLM 的核心架构与工作原理
3.1 一套 OpenAI 兼容接口 + 路由层
LiteLLM 的架构并不复杂。它的核心是一个可独立运行的服务(也可以作为库嵌入使用),对外暴露的接口完全兼容 OpenAI Chat Completions 格式。业务服务只需要把 base_url 指向 LiteLLM 的地址,再加上一个你自己定义的虚拟 Key,就可以像调用 OpenAI 一样调用它。
背后,LiteLLM 会根据模型的配置信息,把收到的请求翻译成对应供应商的真实请求。这个过程主要包括:
- 识别 model 参数中指定的模型名称。
- 从数据库或配置文件中查到这个模型对应的 provider、API Key、base_url 等元数据。
- 根据 provider 的协议规范,把请求体转换成对方需要的格式。
- 把响应(包括流式结果)转换回 OpenAI 统一格式返回给调用方。
因为接口兼容,你可以直接用 OpenAI 官方 Python SDK 来访问 LiteLLM,完全不需要引入额外依赖。这不得不说是个聪明的设计,省去了学习新 SDK 的成本。
3.2 路由和负载均衡是怎么一回事
liteLLM 把“路由能力”实现得比较实在。它允许你把同一个模型配置在多组 Key 或多个供应商账户上,然后在请求时按策略挑选一个“可用端点”去发起调用。常见路由策略包括:
- 简单轮询:随机挑选可用端点。
- 权重轮询:按权重分配流量,比如主账户 80%,备用账户 20%。
- 请求头自定义路由:按照请求中的 metadata 指定目标端点和 Key。
这个设计对稳定性特别有用。比方说你的云端模型账户被限流了,或者某个区域的 IP 被临时禁止了,请求在网关这一层就可以自动换到另一个可用的端点,业务侧无感。负载均衡也能顺带解决“多账号互备”的需求,以至于很多人把它当大模型场景的 API 网关用。
我比较欣赏的是它把“路由策略”做成可配置,而不是硬编码。你可以在配置里指定当前用哪个策略,运行时也能通过请求参数临时指定,灵活度比较高。当然,灵活也带来了一点学习成本,后面我会给一份常用的配置模板。
3.3 Token 计数、预算控制和日志
LiteLLM 的另一个亮点是对用量和成本的统一计量。它上游调用完模型后,会根据响应信息和模型定价表计算 token 使用量。由于不同供应商的价格差异很大,它内置了一份延迟更新的定价表,你可以按请求记录 cost,也可以按 Key、用户、标签汇总统计。
在控制面板上,你能直观看到每个虚拟 Key 的消耗情况、每日请求数、模型分布等信息。这些数据在生产环境特别有用,比如排查一个应用为什么费用飙升,拉一下日志就清楚了,不再需要找每个上游去对账。
而且它支持设置预算上限。你可以给某个 Key 设置一个每日或每月的最大金额,触顶后 LiteLLM 会自动拒绝后续请求。这点对于给团队内部开放模型能力时非常实用,防止有人写个死循环把成本跑飞。
4. 部署与基础配置:从零开始搭一个网关
4.1 快速启动:最简安装方式
LiteLLM 本身支持三种使用形态:
- 作为 Python 库使用,直接调用 litellm.completion()。
- 作为独立服务,通过 CLI 启动一个网关进程。
- 作为 Docker 容器运行,方便集成到现有基础设施中。
最直接的试用方式是 pip 安装后启动服务:
pip install 'litellm[proxy]'启动一个最基本的代理服务:
litellm --model gpt-3.5-turbo --port 4000这样它就监听 4000 端口,接受 OpenAI 格式请求,然后转发到指定的模型。但这种方式只能算一个透传,不能发挥 LiteLLM 的真正长处,所以要配置一个 YAML 文件,把多模型、多 Key、预算、路由等全部声明出来。
先看一个最基础的 config.yaml 长什么样:
model_list: - model_name: gpt-3.5-turbo litellm_params: model: gpt-3.5-turbo api_key: ${OPENAI_API_KEY} model_info: mode: completion cost_per_1k_tokens: 0.001然后启动:
litellm --config config.yaml --port 4000当你在代码里请求时,base_url 指向http://localhost:4000,model 名称填gpt-3.5-turbo,ak 填一个虚拟 Key(启动服务时生成的 master key),其余和调用 OpenAI 完全一致。
4.2 多供应商配置实战
真正用得爽的是把多家模型放到同一个网关里。比如我想同时支持 OpenAI 的 gpt-4o、某个国内模型厂商的接口,以及本地部署的私有化模型,那么 config.yaml 可以这样写:
model_list: - model_name: my-azure-openai litellm_params: model: azure/gpt-4o api_base: "https://xxx.openai.azure.com" api_key: ${AZURE_API_KEY} - model_name: my-thrid-party litellm_params: model: openai/xxx-chat api_base: "https://api.example.com/v1" api_key: ${THIRD_PARTY_KEY} - model_name: my-local-llm litellm_params: model: openai/qwen2.5-14b api_base: "http://localhost:8000/v1" api_key: "sk-local-no-need"注意 model 字段的前缀规则:azure/表示走 Azure OpenAI 的适配器,openai/表示走 OpenAI 兼容的通用适配器,vllm/则适用于 vLLM 的服务端口。LiteLLM 通过前缀识别 provider 类型,这个设计比较实用。如果你用的模型服务兼容 OpenAI 协议但又不是 OpenAI 官方,按openai/前缀通常都可以适配。
启动后,我可以只用一套代码切换三个模型。业务侧只需要改 model 字段,网关自动找到对应配置并调用。
4.3 虚拟 Key 与默认用户管理
LiteLLM 还有一个很容易被忽略但实际很重要的功能:虚拟 Key。它和上游厂商的真实 Key 是隔离的,业务侧拿着一串sk-...形式的虚拟 Key,在 LiteLLM 里分配权限、限速、限预算。就算虚拟 Key 泄露,也不直接关联上游资源,可以在网关里立即撤销,非常适合作“密钥代理”来用。
生成虚拟 Key 最简单的方式是在启动服务后调用管理接口:
curl http://localhost:4000/key/generate \ -H "Authorization: Bearer ${MASTER_KEY}" \ -H "Content-Type: application/json" \ -d '{ "models": ["gpt-3.5-turbo", "my-local-llm"], "max_budget": 10, "budget_duration": "1d" }'返回结果里会给你一个虚拟 Key,把这个 Key 下发到业务服务,上游真实 Key 始终不出内网。这个思路跟微服务里的配置中心差不多,只是这里管的是“模型密钥”。
5. 深入到调用细节:流式、重试、超时与成本控制
5.1 流式输出怎么接
大模型应用几乎都离不开流式输出。LiteLLM 对流式的支持也很成熟,你只需要像调用 OpenAI 一样传stream=True即可:
from openai import OpenAI client = OpenAI( api_key="sk-your-virtual-key", base_url="http://localhost:4000/v1" ) response = client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": "讲个故事"}], stream=True ) for chunk in response: delta = chunk.choices[0].delta if chunk.choices else None content = delta.content if delta else "" if content: print(content, end="")网关会持续把上游流式数据转为 OpenAI 的 SSE 格式推回给你。这一步看起来没啥稀奇,但实际实现中如果 provider 的流式响应格式差异很大,LiteLLM 做了不少转换工作。比如有的模型只支持增量 token 输出,有的又会在流式结束时附加 meta 信息,这些细节你都不用操心。
5.2 自动重试与超时配置
生产环境里模型请求失败太常见了:上游 5xx、网络抖动、限流触发。与其在业务代码里自己写重试,不如在网关层统一配置。LiteLLM 支持基于异常类型的重试策略,下面是一个比较稳妥的配置示例:
router_settings: retry_policy: Timeout: 1 RateLimitError: 3 InternalServerError: 2 APIConnectionError: 2 APIStatusError: 2 context_window_fallbacks: [] # 当上下文超限时尝试的模型列表 fallbacks: ["my-local-llm"] # 当前模型不可用时 fallback 到本地模型 cooldown_time: 30 # 供应商触发失败后冷却时间(秒) num_retries: 2 request_timeout: 60建议你不要把所有异常都重试很多次,尤其当上游明确返回 4xx 参数错误时,重试只会加重负担。最有效的组合是“超时重试 1 次 + 限流重试 3 次 + 服务器错误重试 2 次”,每次重试之间有一定的间隔,避免雪崩。
5.3 预算控制实测
预算控制要放在网关层做,因为它能全局掌握所有请求的用量。配置里可以给每个模型设置单价,也可以给每个 Key 设置额度。一个实际场景:我开放给内部若干小组试用,每个小组一个虚拟 Key,每个月固定预算 20 美元,超出就自动拒绝。这样既方便大家试用,也不会因为某个同事的误操作让整月账单爆表。
配置方式是在虚拟 Key 里带上max_budget和budget_duration,同时在配置文件里声明模型的单位价格。LiteLLM 会根据实际 token 数实时累积费用,达到阈值后返回 429。我看了一下它的统计逻辑,支持按小时、按天、按月统计,也能自定义时长,基本覆盖日常需求。
成本控制这一块比较适合当作“事后核对”和“事前拦截”双层使用。如果是重要的生产流量,我建议事前拦截阈值设得宽松一点,事后核对时再针对性收紧,避免误伤正常请求。
6. 常见问题与排查经验
6.1 模型请求一直报 401
刚上手时最容易踩的坑其实是虚拟 Key 忘记配置。默认启动 LiteLLM 后,你访问接口需要带一个Authorization: Bearer ${MASTER_KEY},直接在配置里写死 master key 也行,但生产环境不建议。
如果你确认 Key 没问题,再看一看配置里的 model 名称是否和model_list里的model_name完全一致,大小写、空格都要对齐。LiteLLM 会按照 model 字段精确匹配,如果没匹配到就会报 not found。
还有一个隐蔽问题,有些提供商要求必须传api_base,你没有传,那么 LiteLLM 默认按 OpenAI 公共地址去请求,自然就 401 了。
6.2 请求超时,但上游明明很快
如果业务侧设置了很短的 HTTP 超时,但 LiteLLM 内部连接某个上游比较慢,整体请求就会被业务侧掐断。我的经验是:
- 业务侧的
timeout至少设为 60 秒以上,流式响应不要用苛刻的读超时。 - LiteLLM 的
request_timeout建议根据最慢模型设,不要为了“保护”设得太短。 - 如果你接入的是本地私有化模型,首次加载权重可能要几十秒,这时必须区分连接超时和请求超时。
另外,LiteLLM 在内网部署时也要检查 DNS 解析和代理设置。我遇到过一例,LiteLLM 服务所在机器配置了全局 HTTP 代理,导致它访问上游时走了代理,延迟飙升。排查下来把代理环境变量清掉就好了,这类问题很隐蔽。
6.3 日志里 token 数不准
LiteLLM 的 token 计数依赖各 providers 返回的 usage 字段,某些模型或适配器可能不返回完整 usage,系统只能估算。比如有些私有化模型返回的 usage 字段里没有 completion_tokens,LiteLLM 会按照响应文本长度粗略估算,成本和实际会有偏差。
应对方法有两种,一是接受估算误差,适用于对成本不是极度敏感的团队;二是在配置中为这类模型手动维护model_info里的cost_per_1k_tokens,并把计数方式改为按字符估算。我在使用一些比较小众的模型时,会隔几天对照账单校准一次单价配置,效果还行。
6.4 高并发场景
LiteLLM 基于 FastAPI,单实例并发能力不弱,但如果你要服务大量业务请求,建议在它前面加一层负载均衡,并启用多 worker 模式:
litellm --config config.yaml --port 4000 --num_workers 4这里要注意 PostgreSQL/Redis 的连接数配置。LiteLLM 默认使用本地 SQLite 存储数据,但在多 worker 模式下 SQLite 并发写会有锁问题,所以生产环境务必要切换为 PostgreSQL,并且把 Redis 用作缓存和限流存储。这一点很多文章没强调,但并发了之后你会非常明显地感受到差距。
6.5 流式输出中断
如果你发现流式输出偶尔中断,先看是不是上游自己断了,再看 LiteLLM 有没有配置合适的超时。有些上游模型在长输出时会间隔几十秒不返回任何 token,如果网关的读超时设置得太短,就会主动断开。这里建议把request_timeout拉长,同时确保客户端侧支持 SSE 的心跳机制,不要让 HTTP 层闲置连接被回收。
我自己之前在这个问题上踩过一次坑:用 docker 部署 LiteLLM 时,默认的 Nginx 代理的 proxy_read_timeout 设成了 60 秒,超过后把长流式响应掐断。排查到最后发现是网关没用,反而在反向代理上栽了一下。如果你也用 Nginx 代理,记得调:
proxy_read_timeout 300s; proxy_buffering off;proxy_buffering off尤其重要,否则 SSE 响应会被缓冲,前端迟迟收不到数据。
7. 我对 LiteLLM 的整体评价与经验分享
用了一段时间后,我的结论是:LiteLLM 适合作为大多数团队接入大模型的第一层基础设施,目的不是增加复杂度,而是把各家 API 的差异、密钥管理、成本统计这些脏活收拢到一个可控的模块里。
我比较推荐的落地方式是“双环境分离”:
- 开发环境用 SQLite + 单进程启动,配置简单,方便调试。
- 生产环境用 PostgreSQL + Redis + 多 worker,配好 Nginx 或负载均衡,并设置好预算与重试策略。
如果你的团队没有专门的运维人员,也不想引入太多组件,直接从 SQLite 单机开始也完全没问题。等流量上来了再平滑迁移,LiteLLM 的配置结构足够允许这种渐进式演进。
最后再分享一个记忆点很深的经验:不要绕过 LiteLLM 去直连模型,哪怕只是临时调试。因为一旦某个请求被绕过,它的日志、预算、统计都是缺失的,事后你很难判断费用异常来自哪里。我刚开始部署时为了方便直连过几次,结果月底对账多出一笔不明消耗,找了好久才定位出来。从那以后,所有模型流量一律走网关,没有例外。
LiteLLM 算不上完美,它的配置项很多,偶尔上游模型更新后适配器也要跟着更新,但如果你要在生产里稳定地使用大模型,它值得作为你架构中的固定组件。
想深入了解的人,直接去翻它的官方文档,重点看 router settings 和 custom pricing 两个章节,几乎所有有用的高级功能都集中在那里。希望这篇内容能帮你少踩一些坑。