1. 项目概述:这玩意儿到底是干嘛的
如果你同时接过两家以上大模型厂商的接口,大概率体会过那种“对着不同文档改代码改到怀疑人生”的感觉。某家的请求体长这样,某家的鉴权方式不一样,某家的流式输出字段又换了个名字,加上各家 SDK 版本还在频繁更新——维护对接层的时间,往往比调 prompt 的时间还多。litellm 就是来解决这一坨麻烦的。
一句话概括:它是一个开源的 LLM 网关(网关这个词听着唬人,说白了就是“中转站”),把不同厂商的模型接口统一成一套格式,主要对标 OpenAI 的接口规范。你用它启动一个本地服务之后,所有业务代码都只管按 OpenAI 的格式发请求,至于背后实际调用的是哪家模型,是换 key 还是换供应商,全由 litellm 去处理。
这项目能解决的问题很实际:
- 把几十个模型供应商的 SDK 差异收拢到一个接口里,业务侧代码只需要维护一套调用方式
- 集中管理 API key,不用把各家密钥散落在多个服务或代码里
- 自动做模型故障转移(这家挂了自动切到另一家)
- 顺带完成调用量、费用、token 消耗的追踪统计
适合谁用?我个人的看法是:凡是产品里已经依赖两三家以上模型服务、或者担心被某一家供应商绑死、或者团队里多个人各自拿着不同的 key 在写代码的,都值得花半小时把 litellm 跑起来。哪怕你只是自己写脚本玩,它也能帮你省掉反复复制粘贴鉴权代码的功夫。
我最早接触这个项目是因为所在团队要同时接入某主流厂商和另一家开源模型的托管服务,两边文档风格差异极大,测试阶段光是处理返回字段的兼容性问题就花了两天。后来把 litellm 架在中间,业务代码再也没动过对接层,前后对比非常明显。
2. 核心机制拆解:它凭什么能统一这么多接口
很多刚接触的人会误以为 litellm 是一个“聚合了各家 API 的巨型封装库”,这么理解没错但太浅了。它真正的核心,是两套东西:一套是调用层的抽象引擎,另一套是路由和代理层的网关逻辑。
2.1 调用层:一个函数打天下
litellm 底层把接过的每家服务商都实现了一个对应的 provider 适配器,对外暴露的却是一致的接口。你写代码的时候,不管是调 GPT 系、Claude 系还是各家国产模型,核心入口几乎都是长这样的:
from litellm import completion response = completion( model="gpt-4o", messages=[{"role": "user", "content": "你好"}] )想换模型?改一行model参数就行。这一步背后做的工作量远超想象:每家厂商的请求体结构不一样、返回字段命名不一样、鉴权方式不一样、流式输出的协议也不同,litellm 内部全部做了归一化映射。你拿到手的 response 对象,字段结构永远是统一的那一套。
这套抽象的价值,不在一个函数有多好用,而在于你的业务代码和厂商接口之间从此有了一道“防火墙”。上游厂商接口升级了,或者你想换一个价格更低的同级别模型,业务代码不用动,改配置就行。
2.2 代理层:真正的“网关”身份
litellm 库可以直接在代码里调用,但我更推荐的是以代理服务的方式运行。它启动后会起一个本地 HTTP 服务,地址类似http://localhost:4000,这个服务暴露的接口完全兼容 OpenAI 的/v1/chat/completions格式。
也就是说,你原来的业务代码如果是用 OpenAI SDK 写的,连依赖都不用换,只需要把base_url改成本地这个代理地址:
from openai import OpenAI client = OpenAI( api_key="随便填一个", # 此时真正鉴权由 litellm 负责 base_url="http://localhost:4000/v1" # 指向本地的 litellm 服务 ) resp = client.chat.completions.create( model="claude-3-5-sonnet-20241022", # 在这里写你想要的任何模型 messages=[{"role": "user", "content": "hello"}] )这个设计非常聪明。它不要求你改业务代码,而是把 SDK 层面的适配问题全部拦截在网关层,业务侧几乎是零成本迁移。很多团队从直连各厂商迁到 litellm,工作量主要花在搭服务和写配置上,代码改动往往只有几行。
2.3 为什么是 OpenAI 格式,而不是别的
这里有个很实际的背景:OpenAI 的接口格式已经成为事实上的行业标准,市面上几乎所有模型服务商都会提供兼容 OpenAI 格式的接入方式,或者至少提供官方转换工具。litellm 把 OpenAI 格式作为“通用语言”,等于选择了和整个生态兼容性最高的基准点。你理解成 USB-C 接口就行了——各家设备自带不同的充电协议,但统一用一个物理接口标准,用起来就顺了。
我见过有人在团队里纠结要不要自研一套“统一接口标准”,我的建议是趁早打消这个念头。生态不自研,标准靠共识。litellm 选 OpenAI 格式不是因为它比其他方案更好,而是因为它已经被市场验证过了,你有现成的共识不用,自己去定一套,回头所有 SDK 和工具链都得自己适配,属于给自己找不痛快。
3. 部署与实操:从零到一跑起一个统一模型网关
理论说再多,不如上手跑一遍。下面这段我按自己实际的操作流程写,照着做基本不会有坑。
3.1 环境准备与安装
建议用 Python 3.9 以上版本,装的时候最好在虚拟环境里操作,避免和项目里其他依赖打架。直接用 pip 安装:
pip install 'litellm[proxy]'注意这个[proxy]扩展名,如果只装litellm本体,代理服务相关的依赖不会一起装进来,后面启动litellm --config时会报错。我第一次装的时候图省事只装了本体,启动代理时报缺少若干依赖,后来查文档才发现要装 proxy 版本。
装完可以跑一下litellm --help确认安装成功,能看到参数说明就说明基本环境 OK 了。
3.2 第一步配置:环境变量与模型列表
litellm 读取模型映射和供应商密钥主要通过环境变量或者一个配置文件。先说环境变量的方式,因为最简单:
export OPENAI_API_KEY="sk-你的key" export ANTHROPIC_API_KEY="sk-ant-你的key" export DEEPSEEK_API_KEY="sk-你的key"然后启动代理:
litellm --model gpt-4o --port 4000这样跑起来之后,http://localhost:4000/v1就能当成 OpenAI 接口用了,model参数传gpt-4o时,请求实际打给 OpenAI。
但这只是单模型的用法,有点浪费。实际生产里更常见的做法是用配置文件把“模型名 → 实际供应商模型”的映射关系都列出来,这样对外暴露的模型名可以由你自己控制,以后换供应商只改配置,业务代码彻底不用动。
3.3 配置文件:模型重命名的真正价值
在项目目录下建一个config.yaml,内容大致长这样:
model_list: - model_name: gpt-4o litellm_params: model: 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 - model_name: deepseek-chat litellm_params: model: deepseek/deepseek-chat api_key: os.environ/DEEPSEEK_API_KEY然后启动:
litellm --config config.yaml --port 4000这里最关键的一点是model_name和litellm_params.model是可以不一样的。前者是你暴露给业务方的名字,后者是实际调用的供应商模型。比如你可以把model_name设为my-llm,底层指向某家开源模型或商业模型,将来想换成别的,只需要改配置文件里的一行映射关系,业务方完全无感知。
部分云厂商提供带区域后缀的模型版本号,这类模型名是恶梦级别的,动辄一个完整版号有几十个字符,业务侧代码里到处传这种长字符串,管理成本极高。用 litellm 的模型重命名能力,能把它们全部伪装成简洁的内部代号,这是我在实际项目里觉得非常值钱的功能。
3.4 验证代理是否正常
配置写好之后,用 curl 快速验证一把:
curl -X POST http://localhost:4000/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer 任意字符串" \ -d '{"model": "gpt-4o", "messages": [{"role": "user", "content": "你好,介绍一下你自己"}]}'能正常返回 JSON 响应体,就说明网关已经通了。日常调试我一般都会用这个 curl 命令,比写脚本快得多,也有利于排查问题——能区分是网关配置问题还是业务代码问题。
如果是在自己的项目里接入,记得把 client 的base_url改成http://localhost:4000/v1,再跑通一个最小 demo,整个链路就完成了。至此,你的业务代码已经成功“不认识”任何具体供应商了,它只知道有一个 OpenAI 兼容接口。
3.5 用 Docker 部署的场景
有些团队的程序部署在容器环境里,或者不想在宿主机装 Python 环境,可以直接用官方镜像:
docker run -d \ -p 4000:4000 \ -v $(pwd)/config.yaml:/app/config.yaml \ -e OPENAI_API_KEY=sk-xxx \ -e ANTHROPIC_API_KEY=sk-ant-xxx \ ghcr.io/berriai/litellm:main-latest \ --config /app/config.yaml需要注意版本镜像的标签细节,不同仓库的镜像名称差异较大,最好是到项目发布页看一眼当前推荐镜像名。我踩过一个坑是用了某个旧标签,结果镜像里不包含最新的几个供应商适配器,导致新接入的模型一直报 provider 不识别。
4. 生产环境的使用要点:不只是转发请求那么简单
很多人在本地把 litellm 跑通了就以为大功告成,其实放到生产环境里,还有几个非常关键的能力需要认真配置。这些功能才是 litellm 相比你自己手写一个转发服务更值得用的原因。
4.1 多密钥管理与负载均衡
同一个模型可以配置多个 key,litellm 会自动做轮询负载均衡。配置也很直观,在litellm_params里把api_key换成api_keys列表:
- model_name: gpt-4o litellm_params: model: gpt-4o api_keys: - sk-key1 - sk-key2 - sk-key3它的工作机制是:请求进来时,litellm 依次把请求分发到不同 key 上。这样做的直接好处是让多个账号的并发配额叠加,降低触发限流的概率。我团队里有段时间单个 key 频繁触发厂商限流,配了三四个 key 做轮询之后,限流错误率肉眼可见地降下来了。
不过也提醒一句:多个 key 的用量会分开计费,对账的时候得自己汇总,别指望厂商那边能看到一个整合账单。
4.2 容灾转移:一家挂了你还在线
生产环境最怕的就是上游供应商宕机。litellm 的原生配置支持设置 fallback 模型,比如主模型是 gpt-4o,挂了之后自动尝试切到另一家的模型:
model_list: - model_name: gpt-4o litellm_params: model: gpt-4o api_key: os.environ/OPENAI_API_KEY model_info: mode: completion supports_function_calling: true litellm_settings: fallbacks: gpt-4o: - deepseek-chat - claude-sonnet写这个配置的时候注意两点:一是 fallback 模型的推理能力要能兜住主模型的业务场景,别拿一个参数规模差很多的模型去兜底;二是如果你业务用了 function calling,fallback 的模型必须也支持 function calling,否则切过去之后直接因格式不兼容报错。我在一次线上事故里就遇到过这个坑——主模型挂了顺利切到备用模型,结果备用模型不支持工具调用,业务报错比原来更难看。
4.3 成本追踪与调用审计
litellm 内置了一个简单的使用量记录,配合虚拟 key 功能,可以做到按项目、按团队维度统计 token 消耗和费用。启动服务时加一个数据库连接即可启用持久化:
litellm --config config.yaml --port 4000 --database_url postgres://user:password@host:5432/litellm如果需要快速的趋势观察,官方也提供了一套管理界面。生产环境我一般建议至少记录请求日志和 token 消耗。在大模型应用的账单上留个底,回头看能帮你省掉很多和财务对账的扯皮时间。项目早期亏在模型费用上的人不会告诉你,等到月底账单出来才发现某条链路消耗占了总费用的六成,再优化就晚了。
4.4 缓存机制,真的能省钱
同一个 prompt 短时间被反复请求的场景在业务里并不少见,比如用户反复点击某个按钮、定时任务重复查询同一份摘要。litellm 支持设置语义缓存,命中缓存时直接从本地取结果,不再向上游供应商发送请求。
litellm_settings: cache: true cache_params: type: redis ttl: 3600把缓存命中率调到合理区间之后,账单会肉眼可见地下降。我见过一个实际案例,某团队是信息查询类场景,prompt 高度相似,打开缓存后每天的费用直接降了一半以上。但这里也提醒不要盲目开缓存:如果场景对实时性要求很高(比如股票行情分析),缓存反而会产生旧数据误导业务,这类场景关注缓存 TTL 设置和键粒度设计。
4.5 限流与配额控制
多团队共用网关的场景,一定要控制每个团队能消耗的额度。litellm 支持按虚拟 key 设置速率限制和每日 token 上限,防止某个业务方“手滑”写了个死循环把整月预算跑光。
general_settings: master_key: sk-master-key router_settings: routing_strategy: usage-based-routing-v2 allowed_routes: - /v1/chat/completions - /v1/completions虚拟 key 功能类似网关层面的租户隔离。给每个团队发一把独立 key,litellm 管理界面里能精确看到哪个 key 消耗了多少,超了阈值直接熔断,不用再等月底看账单吓一跳。
5. 高频踩坑与排查笔记
这部分是我自己实际跑下来的问题记录,并不全在官方文档里明说,但遇到了是真的头大。
5.1 流式输出异常
症状:非流式请求正常,开了stream: true之后响应一直挂起,或者流式输出中途断掉。
排查思路:第一步看日志里有没有供应商返回的非标准 chunk 格式,litellm 对每家厂商的流式协议适配程度不同,一些新上线的小众模型流式返回头和尾的字段命名跟标准不一致,会直接导致解析失败。第二步看是不是代理层和业务侧之间超时设置太短,流式响应体是持续推送的,HTTP 代理层如果有空闲超时限制,长时间没有新 chunk 到达会被强制断开,表现就是“输出到一半没了”。
我处理这类问题最有效的办法是:先绕过 litellm,直连上游供应商的流式接口,确认上游流式本身正常,再检查代理层配置的timeout参数把超时放宽;最后确认模型名映射没有写错——别笑,这个问题排查过好几轮最后发现是把流式模式的参数拼错了。
5.2 鉴权穿透问题
症状:业务侧传了错误的 key,请求却通过了;或者业务侧没传 key,请求也通过了。
原因分析:litellm 代理默认对入站请求的Authorization头校验,取决于你有没有配置master_key。如果没设 master key,它对所有入站请求一律放行,这时候网关就完全暴露在内网里,任何人都能通过这个端口消耗你的上游额度。不管内网外网,强烈建议设置master_key,然后在请求头里带上这个 key 作为网关层鉴权凭证。
你可能会问:这个 master key 和上游换算 key 是什么关系?实际请求时,litellm 会把入站请求里的 Authorization 头替换成真正的上游供应商 key,再转发出去。网关层鉴权用 master key,上游鉴权用配置里写好的 key,两者互不影响。
5.3 模型前缀没带,报 “model not found”
litellm 对模型名的匹配非常严格,尤其是在配置文件里的litellm_params.model,如果写的是anthropic/claude-3-5-sonnet-20241022但漏掉了anthropic/前缀,它可能默认按 OpenAI 去解析,得到的结论就是 provider 不存在。这类问题报错往往不够直观,有时只说 “Unknown model”,很难让人第一时间怀疑到是前缀丢了的锅。
我的习惯是:所有供应商模型名的前缀统一小写、保持完整,不要依赖 litellm 的智能猜测。写完配置之后先跑一个litellm --test之类的自查命令(具体命令名看版本),或者直接 curl 一把验证。
5.4 依赖冲突问题
症状:项目里本来已经装了某个版本的 pydantic 或 httpx,装完 litellm 之后整个项目起不来了。
这个问题比较常见,litellm 为了维护对各家 SDK 的兼容性,依赖了一些颇为严格的第三方库版本区间。遇到冲突时,我建议优先用虚拟环境隔离,而不是跟项目全局的依赖硬刚。它在设计上更像一个独立服务组件,本来就不适合作为主业务项目里随意 import 的普通库。
5.5 本地代理压力过大
前面讲的用法都是让 litellm 以本地进程方式跑在业务服务器上。如果业务请求量大了,这个 Python 进程可能会成为瓶颈。生产环境建议把它部署成独立服务,前面再加一层 nginx 之类的负载均衡,不要和核心业务进程抢资源。litellm 本身支持多 worker 启动,具体参数可以查官方文档,要点是把它当成一个基础组件来运维,而不是业务代码里的一个 import。
6. 我对这套工具链的整体评价
litellm 不是那种“看起来很美但真用起来全是坑”的项目,它解决的问题是真实且高频的。如果你只是接了一个厂商的接口,确实没必要上它,自己写个几十行的封装类就够了;一旦超过两家、或者有换供应商的可能、或者多人协作场景,用它能少掉很多头发。
从我个人的实践体会来看,litellm 最舒服的地方是它的模型重命名机制和对外统一格式这两件事。它让你把技术决策前移:模型选型不再需要惊动业务侧,改一个配置文件就能完成整体切换。这个能力在大模型技术迭代飞快、各家模型能力犬牙交错的现状下,价值非常高。
最后分享一个我自己的使用习惯:每次接入新模型时,我会先直连厂商把核心能力测试完,再通过 litellm 走一遍全链路对比,最后才更新配置面向业务方开放。这样可以保证一旦业务方报问题,我能快速判断是上游模型的问题还是网关配置的问题,而不是两边互相甩锅。毕竟在真实工程里,多一个中间层固然灵活,也多了一个需要排查的环节——善用它,而不是迷信它。