1. 项目概述与核心定位
1.1 这个项目到底解决什么问题
第一次接触 litellm 是在一个多模型混用的项目里。当时团队同时接入了好几个不同厂商的大模型服务,每个平台的接口规范、鉴权方式、返回结构都不一样,代码里到处是 if-else 分支,维护起来非常头疼。litellm 就是在这个背景下进入视野的——它本质上是一个统一的大模型调用中间层,用一套 OpenAI 兼容的接口格式,去对接市面上几乎所有主流的大模型服务。
说白了,它的核心价值就一句话:让你用同一套代码,调用不同厂商的模型。你不需要为每个平台单独写适配层,不需要记住每家的参数命名差异,也不需要为切换模型而重构业务逻辑。改一个模型名称字符串,就能从一家服务切到另一家。
这个项目适合谁?我认为三类人最需要它:一是做 AI 应用开发的工程师,尤其是需要在多个模型之间做对比测试或动态路由的场景;二是搭建内部 AI 网关的运维或平台团队,需要统一管理密钥、限流、计费;三是做研究和实验的开发者,想快速在不同模型上跑同一套评测逻辑。哪怕你只是个人开发者,想在自己的小工具里灵活切换模型,litellm 也能省掉大量重复劳动。
1.2 为什么是“统一接口”这个思路
大模型服务这个领域,过去两年最大的特点就是碎片化。每家厂商的 API 设计哲学不同,有的用messages数组,有的用prompt字符串;有的返回choices[0].message.content,有的返回output.text;流式输出的 SSE 格式也各有各的写法。如果每个都单独适配,代码量会随着接入模型数量线性增长。
litellm 选择的做法是以 OpenAI 的接口规范为事实标准。这个选择很务实——OpenAI 的接口格式目前是业界最广泛被模仿和兼容的,大量现有工具链、SDK、框架都围绕它构建。litellm 把其他厂商的接口“翻译”成这个格式,相当于在混乱中建立了一个公约数。你学会一套调用方式,就能覆盖绝大多数模型。
这个设计思路的好处是迁移成本极低。你现有的基于 OpenAI SDK 写的代码,只需要把base_url指向 litellm 的代理地址,把模型名改成对应的标识,其余几乎不用动。对于已经在用 OpenAI 接口的团队来说,接入成本接近于零。
1.3 核心能力全景
litellm 的能力可以分成几个层次来理解。最基础的是统一调用,支持上百种模型的标准化调用,包括各大云厂商的商用模型和本地部署的开源模型。往上一层是代理网关,提供一个独立的服务进程,对外暴露 OpenAI 兼容的 HTTP 接口,内部做路由、鉴权、限流、日志。再往上是成本追踪与预算控制,能记录每次调用的 token 消耗和费用,支持设置预算上限。还有负载均衡与故障转移,同一个模型可以配置多个后端,自动做权重分配和失败重试。
这些能力组合起来,litellm 就不只是一个 SDK 了,而是一个轻量级的 AI 基础设施层。小团队可以用它快速统一调用入口,大团队可以用它做多租户的模型网关。我见过不少公司把它当作内部 AI 平台的底座,上面再叠加自己的业务逻辑。
2. 核心架构与关键设计解析
2.1 两层架构:SDK 与 Proxy
litellm 的架构分两个独立但互补的部分,理解这个区分很重要,因为很多人一开始会混淆。
第一层是 Python SDK。你pip install litellm之后,直接在代码里import litellm,然后调用litellm.completion()就能发请求。这一层适合嵌入到你的应用代码里,轻量、直接,不需要额外起服务。它的工作方式是在运行时把统一的参数转换成目标厂商需要的格式,发出去,再把响应转换回统一格式。
第二层是 Proxy Server。这是一个独立的服务,通常用litellm --config config.yaml启动,对外暴露一个 HTTP 端口。你的应用不直接调用各家模型,而是把请求发给这个代理,代理再转发。这一层适合多服务共享、集中管理密钥、统一审计的场景。
两者的关系是:Proxy 内部其实也是用 SDK 来发请求的,只是外面包了一层 HTTP 服务和配置管理。所以你先搞懂 SDK 的调用逻辑,Proxy 的配置就很容易理解了。
2.2 模型路由的命名规则
litellm 用前缀加模型名的方式来标识目标模型,这个设计是整个项目的关键机制。格式大致是provider/model-name,比如openai/gpt-4o、anthropic/claude-3-5-sonnet、azure/your-deployment、ollama/llama3这样。
这个前缀决定了 litellm 用哪套转换逻辑、走哪个 API 端点、用哪个环境变量里的密钥。比如看到anthropic/前缀,它就知道要去读ANTHROPIC_API_KEY,把请求发到 Anthropic 的端点,并按 Anthropic 的格式组装参数。
注意:模型名的拼写必须和 litellm 内部维护的映射表一致,写错了会直接报“不支持的模型”。遇到不确定的模型名,最稳妥的办法是查官方文档的模型列表,或者用
litellm.model_list打印当前版本支持的所有模型。
对于自部署的模型,比如用 Ollama 或 vLLM 起的服务,前缀后面跟的是你本地的模型标识,同时需要在参数里指定api_base指向你的服务地址。这种灵活性让 litellm 既能对接云服务,也能对接私有部署。
2.3 配置驱动的代理设计
Proxy 的核心是一份 YAML 配置文件,里面定义了模型列表、路由策略、密钥管理、限流规则等。这种配置驱动的设计好处是运维友好——改配置重启服务就能调整行为,不需要改代码。
一份典型的配置里,model_list是核心,每一项定义一个可用的模型,包括它的对外名称、实际的后端模型、API 密钥来源、API 地址等。router_settings控制路由行为,比如重试次数、超时时间、负载均衡策略。general_settings管全局的,比如主密钥、数据库连接。
我个人的经验是,配置文件的组织要按环境分离。开发环境用一份配置,生产环境用另一份,通过环境变量注入密钥,配置文件本身不进版本库或者只进脱敏版本。这样既方便管理,又避免密钥泄露。
2.4 成本追踪的实现逻辑
成本追踪是 litellm 很实用的一个功能,它的原理是内置了一张模型价格表,记录了每个模型的输入输出 token 单价。每次调用完成后,它根据实际消耗的 token 数乘以单价,算出这次调用的费用。
这个费用数据可以写到日志、回调或者数据库里。Proxy 模式下,如果配置了数据库,还能按用户、按密钥、按时间段做聚合统计。对于需要做成本分摊或者预算控制的团队,这个功能省去了自己搭建计费系统的麻烦。
提示:内置价格表可能滞后于厂商调价,如果对费用精度要求高,建议定期核对官方价格,必要时在配置里手动覆盖单价。我就遇到过某模型降价后,litellm 内置价格还没更新的情况,导致统计偏高。
3. 实操部署与核心环节实现
3.1 环境准备与安装
先从最基础的 SDK 安装说起。Python 环境建议 3.8 以上,用虚拟环境隔离依赖。
python -m venv venv source venv/bin/activate pip install litellm如果你要用 Proxy 功能,安装时带上额外依赖:
pip install 'litellm[proxy]'这个[proxy]会装上 FastAPI、Uvicorn 等 Web 服务需要的包。安装完成后,可以用litellm --version确认版本。
密钥的管理我强烈建议用环境变量,不要硬编码在代码或配置里。比如:
export OPENAI_API_KEY="your-key-here" export ANTHROPIC_API_KEY="your-key-here"litellm 会自动读取这些约定俗成的环境变量名。不同厂商对应的变量名在官方文档里有完整列表,配置前先确认清楚。
3.2 SDK 直接调用实操
最简单的调用长这样:
import litellm response = litellm.completion( model="openai/gpt-4o", messages=[ {"role": "user", "content": "用一句话解释什么是统一接口"} ] ) print(response.choices[0].message.content)想换成另一个厂商的模型,只改model参数:
response = litellm.completion( model="anthropic/claude-3-5-sonnet-20241022", messages=[ {"role": "user", "content": "用一句话解释什么是统一接口"} ] )其余代码完全不用动。这就是统一接口的威力。
流式输出也支持,加个stream=True:
response = litellm.completion( model="openai/gpt-4o", messages=[{"role": "user", "content": "写一段关于秋天的散文"}], stream=True ) for chunk in response: delta = chunk.choices[0].delta.content if delta: print(delta, end="", flush=True)注意:不同厂商的流式返回在细节上可能有差异,比如有的会在最后一个 chunk 里带 usage 信息,有的不带。litellm 尽量做了统一,但涉及 usage 统计时,建议实测确认目标模型的行为。
3.3 Proxy 服务搭建全流程
Proxy 的搭建分几步。先写配置文件config.yaml:
model_list: - model_name: gpt-4o litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY - model_name: claude-sonnet litellm_params: model: anthropic/claude-3-5-sonnet-20241022 api_key: os.environ/ANTHROPIC_API_KEY general_settings: master_key: sk-your-master-key litellm_settings: drop_params: true这里model_name是对外暴露的名称,客户端调用时用这个;litellm_params.model是实际的后端模型。os.environ/前缀表示从环境变量读取密钥,避免明文。
启动服务:
litellm --config config.yaml --port 4000服务起来后,客户端就可以用 OpenAI SDK 来调用了,只需要把base_url指向代理:
from openai import OpenAI client = OpenAI( api_key="sk-your-master-key", base_url="http://localhost:4000" ) response = client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": "你好"}] )注意这里用的是标准的 OpenAI SDK,model填的是配置文件里的model_name。代理收到请求后,根据名称找到对应的后端配置,转发出去。
3.4 负载均衡与故障转移配置
生产环境里,同一个模型往往要配多个后端来提高可用性。比如你有两个 OpenAI 的密钥,想轮询使用:
model_list: - model_name: gpt-4o litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY_1 - model_name: gpt-4o litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY_2 router_settings: routing_strategy: simple-shuffle num_retries: 3 timeout: 30两个条目用了相同的model_name,litellm 会自动把它们当作同一个模型的两个后端。simple-shuffle策略会随机分配请求,num_retries控制失败重试次数。
路由策略还有几个选项值得了解。least-busy会把请求发给当前负载最低的后端,适合后端性能不均的场景。latency-based-routing根据历史延迟选择最快的后端,适合对响应速度敏感的应用。选择哪种取决于你的实际瓶颈在哪里。
实操心得:故障转移的重试次数不要设太高。我一开始设了 5 次,结果某个后端整体不可用时,请求会卡很久才失败。后来改成 2 到 3 次,配合合理的超时,整体体验好很多。重试次数和超时时间要一起调,单独调一个效果不好。
3.5 成本追踪与预算控制落地
开启成本追踪需要在配置里指定回调:
litellm_settings: success_callback: ["langfuse"] failure_callback: ["langfuse"]或者写到数据库:
general_settings: database_url: os.environ/DATABASE_URL数据库模式下,每次调用的详细信息都会落库,包括模型、token 数、费用、耗时、用户标识等。之后可以用 SQL 做各种维度的统计。
预算控制通过max_budget参数实现,可以设在密钥级别或用户级别。超过预算后,后续请求会被拒绝。这个功能对于给不同团队分配额度、防止意外超支很实用。
4. 常见问题与排查技巧实录
4.1 调用报错排查速查表
实际用下来,遇到的问题大多集中在几类。我整理了一张速查表:
| 报错现象 | 可能原因 | 排查方向 |
|---|---|---|
| 不支持的模型 | 模型名前缀或拼写错误 | 核对官方模型列表,确认前缀 |
| 鉴权失败 | 密钥未设置或变量名不对 | 检查环境变量名是否匹配 |
| 连接超时 | api_base 配置错误或网络不通 | 确认服务地址和端口可达 |
| 参数被忽略 | 目标模型不支持该参数 | 开启 drop_params 自动丢弃 |
| 流式中断 | 超时设置过短 | 调大 timeout 或检查网络 |
| 费用统计为零 | 模型不在价格表内 | 手动配置单价或更新版本 |
这张表覆盖了我遇到的大部分情况。排查时按“先看报错信息,再查配置,最后测网络”的顺序走,效率最高。
4.2 参数兼容性处理
不同模型支持的参数不一样。比如有的模型支持temperature但不支持top_p,有的支持max_tokens但字段名不同。litellm 做了大量转换工作,但不可能覆盖所有情况。
遇到参数不兼容时,drop_params: true这个设置很有用,它会自动丢弃目标模型不支持的参数,而不是报错。代价是这些参数静默失效,可能影响输出效果。所以我的建议是:开发阶段先关掉 drop_params,让不兼容的参数暴露出来,确认哪些参数真正生效;上线前再打开,保证服务稳定性。
对于确实需要但 litellm 没自动转换的参数,可以用extra_body透传:
response = litellm.completion( model="openai/gpt-4o", messages=[{"role": "user", "content": "测试"}], extra_body={"custom_param": "value"} )这个参数会原样塞进请求体,适合对接一些厂商的特有功能。
4.3 性能与并发调优
litellm 本身是异步友好的,Proxy 基于 FastAPI,天然支持高并发。但实际吞吐量受限于后端模型服务的能力。调优时关注几个点。
一是连接池。频繁调用时,复用 HTTP 连接能显著降低延迟。litellm 内部用了 httpx,默认会维护连接池,一般不用手动调,但如果并发特别高,可以适当调大池子大小。
二是超时设置。不同模型的响应时间差异很大,统一设一个超时值往往不合适。可以在模型级别单独配置超时,给慢模型更长的容忍时间。
三是批处理。如果业务允许,把多个请求合并成一次调用(比如用支持批处理的接口),能大幅提升吞吐。litellm 对部分厂商的批处理接口有支持,具体看文档。
踩过的坑:有一次压测时发现 QPS 上不去,排查半天发现是某个后端模型的并发限制卡住了。litellm 的重试机制在这种情况下会不断重试,反而加剧拥堵。后来给这个后端单独设了较低的并发上限,问题解决。所以后端的能力上限要如实配置,不要指望中间层能变魔术。
4.4 日志与可观测性
生产环境一定要开日志。litellm 支持多种回调,可以对接常见的可观测性平台。日志里最有价值的信息是:请求的模型、耗时、token 消耗、是否命中缓存、是否重试。
我习惯把成功和失败的日志分开处理。成功日志用于成本分析和性能监控,失败日志用于告警和排查。失败日志里要特别关注错误类型,是鉴权问题、限流问题还是模型本身的问题,处理方式完全不同。
如果日志量很大,建议做采样或者只记录关键字段,避免存储成本失控。全量记录详细请求体在排查时有用,但长期存储性价比不高。
5. 进阶用法与扩展思路
5.1 自定义回调与钩子
litellm 提供了回调机制,允许在请求前后插入自定义逻辑。这个能力可以用来做很多事,比如给请求打标签、做内容审核、记录自定义指标。
写一个自定义回调类,实现async_log_success_event等方法,然后在配置里注册。我见过有人用它做敏感词过滤,在请求发出前拦截不合规的内容;也有人用它做 A/B 测试,按比例把请求分到不同模型。
这个扩展点的价值在于把通用能力和业务逻辑解耦。litellm 负责调用和路由,你的业务逻辑通过回调注入,两边互不干扰。
5.2 多租户与密钥管理
给多个团队或客户提供服务时,密钥管理是个绕不开的问题。litellm 支持生成子密钥,每个子密钥可以绑定不同的预算、模型权限、有效期。
通过管理接口创建子密钥:
curl -X POST http://localhost:4000/key/generate \ -H "Authorization: Bearer sk-your-master-key" \ -H "Content-Type: application/json" \ -d '{"models": ["gpt-4o"], "max_budget": 100}'返回的子密钥只能访问指定的模型,且总消费不超过 100。这种机制让资源分配变得可控,也方便追踪每个租户的使用情况。
提示:子密钥的预算单位要和你的计费口径一致。litellm 默认按美元计,如果你的业务用其他货币或积分体系,需要在回调里做换算。
5.3 缓存策略降低重复成本
很多场景下,相同的请求会被重复发送。litellm 支持缓存,命中缓存时直接返回结果,不消耗后端 token。
缓存可以配置在内存、Redis 或其他后端。对于问答类应用,如果问题重复率高,缓存能省下可观的费用。配置方式是在litellm_settings里指定cache和cache_params。
不过缓存要谨慎使用。对于需要实时性或者结果有随机性的场景,缓存可能导致返回过时或重复的答案。我的做法是只对确定性强的请求开缓存,比如固定的知识查询,对生成类请求保持关闭。
5.4 与现有工具链的集成
litellm 的 OpenAI 兼容接口意味着它能无缝接入大量现有工具。比如各种基于 OpenAI 接口的客户端、评测框架、Agent 框架,只要支持自定义base_url,就能指向 litellm 代理。
这个特性在搭建评测流水线时特别有用。你可以用同一套评测代码,通过切换模型名,跑遍所有候选模型,结果格式统一,对比起来很方便。省去了为每个模型写适配脚本的功夫。
我在实际项目里,把 litellm 当作模型层的抽象,上层业务代码完全不感知具体用的是哪家模型。这样模型选型变化时,业务代码零改动,只需要调整配置。这种解耦带来的灵活性,在模型快速迭代的当下,价值非常大。
最后分享一个小技巧:litellm 的版本更新比较频繁,新模型支持往往很快跟进。建议定期升级,但升级前先在测试环境验证,确认现有配置和调用不受影响。我一般会关注 release notes 里的 breaking changes,提前做好适配。