做后端一年多了,从最早接各种大模型 API 一个个写 SDK 封装,到后来维护一套又一套接口代理,我算是被这类“重复造轮子”的活折磨过不少次。如果你最近也在折腾 LLM 应用,大概率听过一个叫litellm的名字。这东西最早是作为“把所有模型 API 转换成 OpenAI 格式”的工具被大家认识的,后来越用越深,才发现它根本就是一个完整的 LLM 网关,统一鉴权、负载均衡、成本追踪、重试兜底全都能干。
这篇文章就围绕 litellm 这个项目,把我实际部署和二次开发中积累的经验、踩过的坑、常用配置一并拆开讲清楚。内容适用对象是正在做 AI 应用开发、需要同时接多家模型服务(比如 OpenAI、Anthropic、Azure OpenAI、Google Gemini、各种国产模型和开源模型)的开发者,也适合刚入门想搞清楚“团队里到底该怎么统一管理大模型 API”的人。文章会覆盖它能做什么、设计上有哪些巧思、真实场景下的部署配置,以及我在实际使用中遇到的问题排查记录。
1. litellm 到底是干什么的:一个偏向“网关”而不是“SDK”的定位
1.1 先说清楚它和普通 SDK 封装的区别
很多人在第一次接触 litellm 的时候,最直观的印象是“它能用一套 OpenAI 风格的接口调用所有模型”。这话没错,但它绝不是一个简单的 SDK。
你可以把它理解为所有 SDK 调用的中间层。传统的做法是,你为要用的每个模型服务商单独拉一个 SDK,每家 SDK 有各自的初始化方式、超时设置、重试机制和异常类型。项目刚起步还好,等模型方一多,维护成本立刻上来。更麻烦的是,如果线上某个模型服务超时了,或者一个供应商被调用频率太高触发限流,你只能自己写一堆异常分支来判断“这个错误是从哪家返回的”。
litellm 把这个中间层抽出来之后,你的代码只管对接它,它内部再去适配各家模型服务商的协议。你的上游业务拿到的是统一格式的响应对象、统一格式的异常,这样下游任何模型变了,你只需要改配置,而不用改业务代码。
我实际维护过的项目里,最早接了三家模型服务,SDK 版本、异步模式、stream 参数格式都不一样。用 litellm 之后,所有调用统一走一个 4000 端口,业务侧只认识 OpenAI 风格的 request 和 response。后面再加模型,我只需要往配置里加一段 provider 描述,不需要重新发版,这一步体验是非常直接的。
1.2 为什么选择“OpenAI 格式”作为统一标准
litellm 对外暴露的接口长得很像 OpenAI 官方接口,比如 /v1/chat/completions、/v1/embeddings、/v1/completions。这不是偷懒,而是刻意为之。因为 OpenAI 格式已经事实性地成为大模型调用领域的“普通话”——大量开源项目、框架(比如各种 AI Agent 项目、函数调用类项目)都默认用 OpenAI 格式来对接模型。
这么设计有几个直接好处:
第一,团队接入成本极低。新同事只要写过 OpenAI 接口,就能直接写 litellm 的代码,不用额外学一套奇怪的调用方式。第二,生态兼容性好。很多现成工具,比如支持自定义 OpenAI API base 的客户端、监控面板、测试脚本,都能直接指向 litellm,不需要做任何适配。第三,迁移成本可控。以后如果你自研了一个完全兼容 OpenAI 的模型服务,你甚至可以绕过 litellm,代码都不用改。
我遇到过一些团队想用国产模型,但开发文档和 OpenAI 不一致,调起来想骂人。用 litellm 之后,它负责把国产模型的请求参数翻译成 OpenAI 风格,业务开发的人根本感知不到差异。
1.3 它和“模型聚合平台”之间的边界感
这里要有清晰的认知:litellm 不是模型聚合平台,它不负责训练模型,也不内置任何模型。它本质上是帮你把流量管理起来的那一层。
模型聚合平台关心的是模型选择界面、定价方案、用户配额;litellm 关心的是 API 格式转换、密钥管理、路由转发、成本统计、限流熔断。它解决的问题发生在“你的业务代码”与“模型服务商 API”之间。
一个比较容易混淆的点是:有些团队会直接把 litellm 当作生产环境的“网关”,在它前面再挂一层业务 API。也有人把它嵌入到内部工具里作为 sidecar。两种用法我都试过。前者适合团队规模大、多个后端服务都要共用模型能力的场景;后者适合单体项目但不想把代理单独部署的场景。明白这个边界之后,你对它的定位和使用方式就会比较清晰。
2. 核心功能逐一拆解:从接口代理到成本治理
2.1 统一接口转换(多模型接入协议适配)
litellm 支持几十家模型提供商,包括 OpenAI、Anthropic、Azure OpenAI、Google Gemini、AWS Bedrock、各种国产闭源模型,以及通过 Ollama、vLLM、TGI 之类的自托管开源模型。
它怎么做到统一格式转换的?在内部,它维护了一个模型映射表,把每个 model 名称(比如gpt-4o、claude-3-5-sonnet)和对应的 provider、请求参数模板、响应解析器绑定起来。你请求的时候,它先根据 model 名判断要走哪条线路,然后把 OpenAI 风格的请求体改写为目标 provider 需要的格式,再转发出去。响应回来之后再改写回 OpenAI 风格。
这里有一个在项目里容易忽略的细节:不是所有模型都能完整映射 OpenAI 格式的全部字段。比如有的模型不支持frequency_penalty,有的对max_tokens的命名不一样,有的是max_tokens、有的叫max_tokens_to_sample。litellm 的做法是在配置里允许你指定自定义映射,也可以选择丢弃不支持的参数。这个功能如果你只是简单调用默认模型,基本感知不到,但一旦你要接入一个比较小众的自部署模型,必须搞清楚这一层。
我在实操中曾经接一个自托管模型,它的参数里没有max_tokens,只有max_new_tokens,然后处理方式是写了一段自定义配置,把这个参数映射过去,才把调用调通。
2.2 密钥管理与多 Key 负载均衡(最关键的生产功能)
团队用一个账号的 key 开发,结果被限流,这是非常常见的生产事故。litellm 提供了秘钥管理机制,主要解决两件事:
一是虚拟 API Key。你可以在 litellm 里生成自己的 key,把它发给团队内部的不同人、不同项目或不同服务,这些 key 背后可以绑定真实的 provider key,也可以配置各自的预算。也就是说真实 provider key 被安全地放在 litellm 后端,不暴露给终端用户,最多只暴露一个虚拟 key 给调用方。万一这个虚拟 key 泄露了,你直接在管理端吊销它,一条命令的事。
二是多 Key 轮询负载均衡。同一个模型(比如gpt-4o)你可以配置多个真实 key,litellm 会在请求进来时按照策略轮换使用。默认是简单的轮询,也支持根据剩余额度、响应延迟、失败次数自动选择。这个功能的实用性在于,你可以把多个账号的额度聚合起来,支撑更大的并发,而不会被单个账号的速率限制卡死。
我上过生产环境的一个项目,最初只用了单个账号,结果每小时都被限流,后来在 litellm 里挂了四个 key 做轮询,问题直接消失。
2.3 Token 计量、成本追踪与预算控制
litellm 对每次调用都会记录 token 消耗。它不仅是记录输入输出 token,还会根据你配置的模型单价自动计算成本。你在管理后台甚至能看到每个虚拟 key、每个用户、每个团队每天/每月的用量曲线和花费金额。
预算控制这块,可以给虚拟 key 设置以下几种限制:
- 每分钟最大请求数(RPM)
- 每分钟最大 token 数(TPM)
- 单日/单月最大成本(美元或者其他币种)
- 最大并发数
超过限制之后,litellm 默认返回 429 限流错误,你可以自定义错误提示。
从工程角度看,token 统计和成本追踪特别适合用在“多租户/多部门”的场景。我给公司内部搭过一个统一入口,不同部门用不同虚拟 key 接入,月底直接导出成本报表,省掉了原来一群人手工统计 Excel 的麻烦。
2.4 模型重试、超时与熔断(生产高可用的关键)
模型服务商时不时会出问题:网络波动、5xx、限流、响应变慢。litellm 内置了多层次的错误处理。
- 请求失败自动重试,可配置重试次数和重试间隔。
- 支持自定义重试策略:比如某个模型持续 429,自动切换到一个备选模型。
- 内置超时控制,避免一个慢模型拖垮整个业务链路。
- 支持异常熔断:连续失败超过阈值后,自动将流量切到健康实例。
这里想特别说明 “模型回退(fallback)” 的价值。你配置了gpt-4o和claude-3-5-sonnet两个模型作为主备,当 litellm 检测到主模型连续报错,它会自动把请求转发给备选模型,对业务方完全透明。整个过程你的业务代码只需要感知到“这次请求成功了”,而不必知道背后发生了什么。
这类能力属于典型的“网关职责”,如果靠业务代码自行实现,一是每处调用都要写一套复杂容错逻辑,二是很容易遗漏异常类型。交给 litellm 之后,我只在配置里写清楚策略,剩下的全部交给网关层。
2.5 流式响应与工具调用(Function Calling)的支持
很多人在评估 litellm 的时候会担心“我的场景要流式输出,还要用 function calling,它能 hold 住吗?”我的实测结论是:都能。
流式输出这块,litellm 不仅只是转发流,它还会把流内容重新组装成 OpenAI 的 SSE 格式。你在业务侧可以像接 OpenAI 的流式响应一样处理。
Function calling 同样支持。你需要把 tools 定义透传给模型,litellm 会原样转发给目标 provider,并在响应里把 tool call 的结果转回统一格式。我在实际项目中用 litellm 做 Agent 场景,让模型调用内部查询接口,响应里拿到标准结构化 tool call 数据,整体稳定。
不过有一点要注意:不同模型对 function calling 的支持程度差异极大。有的模型格式遵循 OpenAI 标准,有的偏差很大。litellm 能做的是尽力转换,但如果底层模型本身不支持函数调用,那无论网关怎么转换都无能为力。
3. 部署 litellm 的完整实操:安装、起步配置与调用演示
3.1 环境准备:本地跑通最小实例
litellm 用 Python 编写,发布在 PyPI 上,安装非常简单。官方推荐 Python 3.8 以上。本地快速体验的流程如下:
# 使用 pip 安装 pip install 'litellm[proxy]' # 或者通过 docker 运行(生产环境更推荐) docker run -d \ --name litellm-proxy \ -p 4000:4000 \ -v $(pwd)/config.yaml:/app/config.yaml \ ghcr.io/berriai/litellm:main-latest \ --config /app/config.yaml安装完可以通过命令行快速验证:
litellm --model gpt-4o --port 4000这条命令会在 4000 端口启动一个最小代理,走默认配置。这时候你本地就可以用任何 OpenAI SDK 来调用它:
curl http://localhost:4000/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer sk-xxx" \ -d '{ "model": "gpt-4o", "messages": [{"role": "user", "content": "你好"}], "stream": false }'也就是说,你在本地只需要一条命令,就拥有了一个 OpenAI 兼容的 API 入口。
3.2 配置文件编写:从单模型走到多模型
本地验证没问题之后,下一步就是正式写 config.yaml。这个文件是整个网关的“智商核心”,它决定 litellm 如何路由、如何鉴权、如何限流。
下面是一个典型的生产配置示例:
model_list: - model_name: gpt-4o litellm_params: model: gpt-4o api_key: os.environ/OPENAI_API_KEY model_info: supports_function_calling: true - model_name: claude-3-5-sonnet litellm_params: model: anthropic/claude-3-5-sonnet api_key: os.environ/ANTHROPIC_API_KEY - model_name: azure-gpt-4o litellm_params: model: azure/gpt-4o api_base: https://xxx.openai.azure.com/ api_key: os.environ/AZURE_OPENAI_API_KEY router_settings: routing_strategy: "usage-based" # 可选 simple-shuffle / usage-based / latency-based num_retries: 3 request_timeout: 60 fallbacks: [ {"gpt-4o": ["claude-3-5-sonnet"]}, {"azure-gpt-4o": ["gpt-4o"]} ] litellm_settings: drop_params: true set_verbose: false general_settings: master_key: sk-master-123 database_url: postgresql://user:pass@localhost:5432/litellm几个关键点解释一下。
model_name是暴露给客户的模型名,litellm_params.model是实际发给 provider 的底层名。两者解耦之后,你完全可以在业务里叫它gpt-4o,后端实际走的却是经过企业内部网关的 Azure OpenAI 通道。这在企业里很有用处:业务侧不用感知底层供应商的切换。
fallbacks配置会按照顺序找备选模型,主模型连续报错时自动切换。
router_settings.request_timeout是每个请求的超时上限。不要太短,流式场景下模型首字返回时间可能较长;也不要太长,否则一个慢模型会拖满线程池。
drop_params设为 true 表示当某个请求带了目标 provider 不支持的参数时,直接丢弃而不是报错。这个开关务必打开,否则你可能在调用某个不支持response_format参数的小众模型时直接遇到 400。
3.3 用 Python SDK 和 OpenAI SDK 分别调用 litellm
litellm 自带一个 Python 客户端,同时也兼容 OpenAI SDK。两者我都跑通过,这里都给出示例。
方式一:直接用 litellm 的 Python 包
import litellm response = litellm.completion( model="gpt-4o", messages=[{"role": "user", "content": "你好,请介绍一下自己"}], api_base="http://localhost:4000", api_key="sk-xxx" ) print(response.choices[0].message.content)方式二:用 OpenAI SDK 指向 litellm
from openai import OpenAI client = OpenAI( base_url="http://localhost:4000/v1", api_key="sk-xxx" ) resp = client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": "你好"}] ) print(resp.choices[0].message.content)两种方式中,我实际更推荐第二种,因为业务团队通常已经在用 OpenAI SDK 了,改成 litellm 的 base_url 成本是最低的。
流式调用同样兼容:
stream = client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": "讲个故事"}], stream=True ) for chunk in stream: if chunk.choices[0].delta.content: print(chunk.choices[0].delta.content, end="")3.4 虚拟 Key 与成本预算的配置流程
生产环境里,强烈建议开启数据库和虚拟 key 功能。round-robin 注册的步骤如下:
首次启动 litellm 之前,在 config.yaml 里配置master_key和database_url。master key 是管理员的最高权限密钥,database_url 用来持久化存储 key、用户、日志、预算等数据。
启动后,通过管理 API 创建虚拟 key:
curl http://localhost:4000/key/generate \ -H "Content-Type: application/json" \ -H "Authorization: Bearer sk-master-123" \ -d '{ "models": ["gpt-4o", "claude-3-5-sonnet"], "max_budget": 20.0, "budget_duration": "1mo", "rpm_limit": 60, "tpm_limit": 100000 }'返回结果里会给你一个sk-xxx格式的虚拟 key。这个虚拟 key 就是你可以发给团队、发给测试环境、或者嵌入到不同项目里的凭证。
max_budget和budget_duration组合使用,就实现了“这个 key 一个月最多用 20 美元”。rpm_limit和tpm_limit则是分钟级别的速率控制。
这块尤其适合做事后成本分摊:每个部门一个 key,月底在 litellm 后台按 key 导出用量和费用,直接财务对账。
4. 实战经验:我在生产环境里遇到的典型问题与排查方法
4.1 问题一:模型参数不一致导致的 400 或空响应
在接一个开源模型的时候,我遇到了响应空内容的情况。排查发现是因为请求参数里带上了response_format,而这个模型没有实现该参数,直接忽略了,导致返回结果非常奇怪。
这类问题常常发生在你从 GPT 切换到一个非 OpenAI 系模型时。修改方案是开启drop_params: true,或者针对该模型在配置里自定义参数过滤。从那以后,我把所有模型的配置文件里都加上了drop_params,遇到参数不支持时宁可丢弃也不要带错。
4.2 问题二:流式响应在某些模型上速度极慢
我排查过一个现象:同样网络环境,调用 gpt-4o 流式响应很快,换成某个自部署模型后首字延迟高达十几秒。分析 litellm 的日志,发现请求在网关层等待了很久才收到目标服务的响应,最后定位到是自部署服务本身首 token 生成慢,不是网关问题。
这里给个经验:遇到流式慢的问题,先看目标 provider 的直接响应时间,而不是一开始就怀疑 litellm 转发有问题。网络层、模型推理层、网关转发层三个环节依次排查。
4.3 问题三:不同虚拟 Key 资源互相抢占
多个团队共用同一个 litellm 实例时,如果一个团队发起了大量请求,另一个团队的关键业务可能被影响。litellm 提供了 per-key RPM/TPM 限制,我后来给不同关键业务配置了独立的虚拟 key,并对每个 key 单独限流,保证任何一个团队的突发流量都不会影响其他人。
如果你的团队里既有实时交互型业务,又有离线批处理任务,强烈建议把离线任务和实时业务放到不同 key、不同模型甚至不同网络出入口上,避免流量“内耗”。
4.4 问题四:认证信息泄露与轮换
生产环境里,虚拟 key 泄露是迟早的事。litellm 的管理后台提供了 key 生命周期管理能力。你可以定期执行以下操作:定期遍历所有虚拟 key 的最近使用时间;对不再使用的 key 进行吊销;对疑似泄露的 key 快速吊销并生成新 key。
这里有一个需要注意的操作:轮换 key 的时候最好在业务低峰期做,否则可能出现大部分请求瞬间报 401 的情况。我采用的方式是先停旧 key 对应服务的定时任务,再切换新 key,再逐步观察。
4.5 常用运维命令速查
下面整理一批我经常用到的运维命令:
# 查看已注册模型列表 curl http://localhost:4000/v1/models \ -H "Authorization: Bearer sk-master-123" # 查看某个 key 的用量 curl http://localhost:4000/key/info \ -H "Authorization: Bearer sk-master-123" \ -d '{"key": "sk-xxx"}' # 生成新 key curl http://localhost:4000/key/generate \ -H "Authorization: Bearer sk-master-123" \ -d '{"models": ["gpt-4o"], "max_budget": 50}' # 删除 key curl http://localhost:4000/key/delete \ -H "Authorization: Bearer sk-master-123" \ -d '{"key": "sk-xxx"}'管理后台还可以直接看实时的日志、用量和错误分布。我个人建议把 litellm 的管理后台访问控制在一个内网网段,不要暴露到公网,除非你配置了足够严格的认证。
5. 进阶使用:多路由策略与自定义扩展
5.1 路由策略怎么选
litellm 支持多种路由策略,配置在 router_settings 的 routing_strategy 里。
simple-shuffle:在所有健康 key/模型间均匀轮询,适合多个 key 能力对等的场景。usage-based:优先选择剩余 token 配额最多的 key,适合账号配额不同、希望“先用掉不心疼的额度”的场景。latency-based:追踪历史延迟,自动优先选择延迟最低的模型实例,适合对响应速度敏感的业务。
举例来说,你手里有一个账号配额还剩 99%,另一个账号只剩 1%,simple-shuffle 会让两个账号工作量差不多,而使用次数计数会因为配额不平衡很快把剩下 1% 的账号打挂。usage-based 则会尽量让大额账号承担更多请求。
这个参数没有绝对最优,只有结合自己的业务流量特征去调。我倾向于对并发稳定、延迟优先的业务用 latency-based;对成本敏感、多 key 预算不均的业务用 usage-based。
5.2 自定义 provider 接入
有一些模型服务商不在 litellm 官方支持列表里。此时可以通过litellm_params里的custom_llm_provider和api_base来适配。
配置示意:
- model_name: my-custom-model litellm_params: model: openai/my-custom-model api_base: http://10.0.0.20:8000/v1 api_key: local-test custom_llm_provider: openai如果这个模型本身暴露的是 OpenAI 兼容接口,绝大多数情况直接这么配置就可接入。如果目标服务的接口不是 OpenAI 格式,那就只能写一段自定义代码,利用 litellm 的 handler 机制做请求改写和响应解析。
5.3 与企业内部系统的集成
litellm 本身可以作为一个独立服务部署,但如果企业内部有统一的 SSO 认证系统,人人各自搞一套 key 是不现实的。litellm 支持自定义认证逻辑,你可以通过编写一个 callable 来校验请求头,比如从企业内部 SSO 解析用户身份,再映射到对应的预算和模型权限。
这个能力在生产环境中非常实用。我的做法是:在 litellm 前挂一层企业内部认证网关,网关负责 SSO 登录、用户身份识别,再透传一个内部签名头让 litellm 信任。litellm 侧配置好虚拟 key,把它当作内部服务级凭证,而不是用户级凭证。
业务上,用户身份本身不接触 litellm 的任何一个 key,只在业务系统内部流转。整体的安全边界很清晰。
6. 避坑清单与个人的一点心得
6.1 容易踩的坑
- 不要在生产环境直接用默认内存存储跑多实例。litellm 默认支持 SQLite 等本地存储模式,但多实例部署时状态不共享,会导致 key 校验、用量统计各节点不一致。生产环境老老实实接 PostgreSQL。
- 不要把 master key 当成普通请求 key 使用。它的权限非常大,如果泄露,整个代理链路的 key 管理都会失控。我一般把 master key 放到专门的密钥管理服务里,只在自动化脚本和管理后台中使用。
- 不要忽略模型名称前缀。比如
anthropic/claude-3-5-sonnet和claude-3-5-sonnet可能映射到不同的 provider 行为。配置的时候最好显式写出 provider 前缀,避免 litellm 猜错。 - 不要在重试逻辑里开启无限重试。如果某个模型已经整体故障,无限重试只会让 litellm 的线程池被占满,进而拖垮所有请求。给重试加上次数上限和熔断阈值。
- 不要把所有后端直接指向一个 litellm 实例而不做高可用。litellm 本身是无状态代理,你完全可以部署两个实例,前面挂一层负载均衡,数据库共享同一份 Postgres。
6.2 关于扩展方向
litellm 的生态一直在长。除了最基本的请求代理,社区里还有人在做基于它扩展企业内部的模型评测平台、把 litellm 接入现有的可观测性系统(比如 Prometheus 指标导出)等。从我个人的视角看,更值得关注的是:它把模型调用层的通用能力沉淀下来,让应用开发真正聚焦在业务逻辑上。你在自己的项目里,后续也可以按自己的业务形态在它上面扩展属于自己的审计、配额、审批流。
就我个人而言,用了一段时间之后,我对“网关”这个词的理解比之前深了不少。真正的网关并不是多一层请求转发,而是把所有的横向能力(认证、限流、成本、高可用、可观测)集成到一个地方,让下游业务变得干净、可控。litellm 在这个方向做得非常扎实。如果你正在建设自己的 AI 应用基础设施,强烈建议拿它做一次小范围试点,先把两三个模型接进去跑通,然后逐步叠加虚拟 key、预算、路由策略。
最后说一个小细节:接入 litellm 之后,一定要把日志级别打开,它会清晰打印每一跳的耗时、请求参数、响应码。生产环境出现诡异问题的时候,这些日志往往比任何监控面板都更能帮你定位原因。先把日志看明白,再去怀疑网络和模型,大概率能少走很多弯路。