去年年底接手一个内部AI工单系统的时候,我们的技术选型还在“给每个模型供应商写一套对接代码”的原始阶段——OpenAI一套、Anthropic一套、本地私有化模型又得单独适配。后来发现写业务逻辑的时间还没写SDK适配器的时间多,我才认真开始评估litellm这个开源网关项目。今天这篇就用我真实的接入经历来聊聊这个工具:它到底解决什么问题、核心机制怎么运转、以及真正部署时那些文档里不会写清楚的坑。
1. 被模型SDK差异反复折磨之后,我为什么最终选了这样一个网关
先交代一下背景。我们那个系统的业务场景是工单自动分诊加客服回复建议,不同渠道、不同客户对数据敏感度的要求不一样,所以不能只绑一家大模型厂商。最开始我们对接了三个供应商:某云厂商的对话模型、美国那边的GPT系列、还有本地部署的开源模型。等代码写到一半,大家才发现一个让人头疼的事实——这三家的SDK虽然看着都像“给一段文本,返回一段文本”,但接口细节完全不是一个世界的。
OpenAI的接口把角色分成了system、user、assistant,参数直接放在顶层;Anthropic那边角色只有user和assistant,系统提示得塞进参数里,而且最大token那个参数的命名和默认上限都不一样;本地模型走的是某种私有协议,还得先在服务端配置模板。你要是只接一家,这些问题都不是问题。一旦接三家,同样的“判断工单紧急程度”这个功能,你得写三遍参数映射、三遍超时重试、三遍错误信息解析。更别说每个月还要人工对账,看看每个部门的Key分别烧了多少钱。
那会儿我拿这个问题去和一个做AI基建的朋友聊,他甩给我一句:“你没有用litellm吧。”我一开始以为这只是个封装SDK的小工具,直到我去翻了一遍它的源码和文档,才发现事情没那么简单。它确实是个SDK,用你熟悉的OpenAI调用格式去调各个厂商的模型;但它同时还是一个可以独立部署的网关服务,能统一承载Key管理、负载均衡、限流、费用统计这些团队协作设施。相当于你不光省掉了三套适配代码,还顺带把模型层的“账号管理和计量计费”收进了一个入口。对我们这种之后还要接更多模型的团队来说,这正好是痛点所在。
后来我看GitHub上它的star数和社区活跃度,又确认了一下它没有绑死在特定的商业模式里——开源主仓库是MIT协议,核心能力可以白嫖,那这就有得谈了。我决定先在一个不重要的模拟项目里试用一周,用真实的业务请求去检验一下它是不是真的像社区吹的那样“一个接口通吃所有”。
2. 两个核心使用模式拆解:SDK直连与代理模式
很多人第一次接触litellm都会懵一下,因为它有两种完全不同的用法,而文档又是混在一起写的。我建议你理解它的切入点是先分清楚:你到底是想在自己的代码里少写适配,还是想给整个团队一个统一的模型接入层。
SDK直连模式下,litellm是以Python包的形式装进你的项目,你在代码里调用它的一个函数,传入模型名和消息,它自己去找对应供应商的SDK、拼好参数、发起请求,再把结果转成统一格式返回。这个模式简单、直接,适合个人项目或者你只想快速验证某个模型效果。整个接入过程都不需要另起服务,也不要求你改变部署架构。
代理模式则是把litellm作为一个独立的网关服务跑起来,服务器上开一个端口,对外暴露的是一个OpenAI兼容的接口。你原有的代码只要把base_url指到网关地址,把API Key换成网关给你的虚拟Key,接下来写业务逻辑就像在对OpenAI说话一样。实际请求到了网关以后,litellm根据路由规则决定转给哪家真实供应商,这个过程中它还要负责把团队成员的虚拟Key映射到真实Key、检查限流、记录请求日志和费用数据。
代理模式的好处,用我们的话说就是“模型供应商的账号密码永远不会暴露给业务开发”。真实Key放在网关这一台机器上,业务侧谁要接入就给一个虚拟Key,就算某位同事离职了把他的Key带走,也不会伤害到根Key。更实用的是,业务团队要新接一个模型,不需要等基础设施的人改代码,直接改配置中心的路由规则就行。
我的建议是,如果你的团队大于三个人,或者公司里有明确的开发和运维分工,直接上代理模式。个人学习阶段用SDK模式就够了,不要过度设计。
3. 从零到一跑通首个请求:安装配置与动态模型映射
下面是我整理的最短接入路径,每个步骤都给到可执行的颗粒度,不是概念介绍,是我亲手敲过的过程。
第一步,环境准备。需要一台能装Python的Linux服务器,系统版本我推荐Ubuntu 20.04以上,Python用3.9以上版本。如果你先在自己电脑上试,macOS也没问题,但后面做代理部署时最好还是统一到一个干净的Linux环境里,避免因为本地环境变量残留导致排查困难。装包这一步很简单,执行:
pip install "litellm[proxy]"这里强烈建议直接用带proxy附加依赖的安装命令,不要先装基础包再单独补依赖,否则很容易遇到版本冲突。装完之后验证一下版本:
python -c "import litellm; print(litellm.__version__)"第二步,配置供应商的真实密钥。SDK模式下litellm不会替你去管理密钥存储,它就是读取环境变量里对应供应商的字段。用OpenAI那就设置OPENAI_API_KEY,用Anthropic就设置ANTHROPIC_API_KEY。为了便于维护,我还是建议用项目目录下的.env文件来管理,装一个python-dotenv然后在入口文件里加载它。
第三步,用一行代码发起同步请求。这个代码我抄过来改过好几次了,最终的简洁版是:
import litellm response = litellm.completion( model="gpt-4o", # 模型名直接写你往常习惯的那个 messages=[ {"role": "system", "content": "你是一个工单分诊助手。"}, {"role": "user", "content": "客户反馈登录后总是闪退。"}, ], temperature=0.2, ) print(response.choices[0].message.content)这样你能在几秒内就发现litellm和平时直接用OpenAI SDK写代码几乎没什么区别,只是import的对象变了,返回的对象结构也和OpenAI SDK是几乎一致的。你要做的就是在项目里全局替换原有的OpenAI客户端为litellm即可。
但如果这时候你试着把model参数换成Anthropic的模型名——比如claude-3-5-sonnet-20241014——你可能会遇到一个认知门槛:为什么还是返回OpenAI格式的结构?对,litellm就是这么设计的,它不管底层调的是谁,统一包装成你熟悉的OpenAI风格message结构,你后端的解析逻辑完全不用改。
第四步,体验动态模型映射。这是代理模式的精髓。当你把网关跑起来以后,业务团队根本不需要知道真实模型叫什么。你在网关配置里做一层“别名映射”,比如定义一个模型别名gpt-4o映射到OpenAI的真实模型,再定义一个claude-3-5-sonnet映射到Anthropic的真实模型。业务侧request里写哪个别名,网关就去转哪个。模型映射可以是简单的字符串到字符串对应,也支持更复杂的配置——比如按请求负载比例把流量分给不同的模型,或者在某个模型故障时自动降级到备用模型上。这块我后面单独讲代理配置时细说。
4. 代理模式进阶:负载均衡、团队密钥与成本追踪的真实用法
跑通了SDK模式以后,你只能说用上了litellm百分之四十的能力。真正让它变成一个团队基础设施的,是代理模式。我先说我部署代理时的完整路径,然后逐个讲清楚它的三个核心功能在实际运维里怎么用。
代理的启动方式很简单,用pip装好以后在服务器上执行:
litellm --config /etc/litellm/config.yaml --port 4000它默认监听4000端口,你会看到一个日志提示,app启动成功。这个网关对外就是一台普通的HTTP服务。要验证是否正常,直接在另一台机器上测试:
curl --location "http://网关服务器IP:4000/chat/completions" \ --header "Authorization: Bearer 你自己的虚拟Key" \ --header "Content-Type: application/json" \ --data '{ "model": "gpt-4o", "messages": [{"role": "user", "content": "请问有什么可以帮您?"}] }'如果走通了,说明你的业务代码只要把之前代码里OpenAI SDK的base_url改成http://网关服务器IP:4000,其余调用方式原样保留,就可以把流量切到网关上。
配置负载均衡是我在代理模式里最喜欢的功能。你在config.yaml里定义一个model_list,同一个模型名可以挂两个配置项,指向不同供应商的同档位模型。我举个例子,你想让“所有叫quick-chat的请求”均衡打到两个不同厂商的同级模型上,配置大概长这样:
model_list: - model_name: quick-chat litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY - model_name: quick-chat litellm_params: model: anthropic/claude-3-5-sonnet api_key: os.environ/ANTHROPIC_API_KEY请求进入网关后,litellm会按轮询策略把相邻的两次请求分给两个供应商。这样一来,任何一个供应商出问题的时候,另一个还能继续扛着;同时也避免单一供应商的账户被业务高峰流量打爆限流。你唯一要注意的是,同一个模型别名下挂的模型最好能力水平相当,否则同样的业务问同一个问题,两个模型回答质量差异会很大,用户会感觉系统行为不稳定。
团队密钥管理这块我不展开太多坑,只说最核心的一条:在代理模式下,业务方传的API Key不是你真实供应商Key,而是你在网关后台为每个成员或每类业务生成的虚拟Key。生成虚拟Key可以用页面操作,也可以调管理接口。你还以给虚拟Key绑定具体能访问哪些模型和每分钟调用上限。例如让实习生Key只能访问低成本的本地开源模型,禁止触达昂贵的商业模型。作为管理员,你可以随时吊销某个Key而不影响别人。
最后说成本追踪。之前我们每个月对账都是导出各厂商的账单再手合,用litellm代理之后,它自动把每次请求的模型、输入token数、输出token数、响应时间、费用估算全部记录。litellm本身不提供页面看板,但你可以把数据推到S3对象存储(兼容Amazon S3协议都可以),或者通过回调把数据同步到你的日志系统。我们后来是在网关的配置文件里加了一段写入对象存储的配置,整个费用报表自动化了,运维同学每周看一眼存储桶里的统计结果就行,再也不用手工加Excel公式。
5. 部署和运行中我踩过的四个坑,每个都让系统安静地出错过
配置过程看起来很快,但如果你直接照着我上面的步骤上生产,大概率会遇到下面几个坑。这些坑不一定每个都致命,但每一个都会让你付出至少一晚上的排查时间。我按踩坑顺序写下来。
第一个坑是长上下文请求的超时。litellm默认给不同路径设了超时时间,chat/completions请求的超时比较短,而embedding路径默认是600秒。我们有一次接某个开源模型做检索,文档比较长,首次请求时因为模型要加载到内存,响应耗时长,网关直接就把请求给超时断了。这个问题的表象是“为什么本地模型第一次调用总是失败”,实际原因是网关对那个路由的超时设定不匹配。解决方式是在config里把对应模型的timeout参数调大,同时用预热请求把模型先加载进内存,再让真实业务请求进来。
第二个坑是模型映射混淆。社区文档里写的model_name映射有两种形态,有一个是直接映射到真实模型名(字符串),还有一个是映射到完整配置对象(字典)。我在一个配置文件里混用了两种写法,结果网关解析的时候把字符串当成了需要再解析的规则,实际路由全部走错了。我的建议是,一个config文件里统一用完整的litellm_params字典写法,不要图省事用字符串简写。
第三个坑是环境变量优先级。.env文件里的变量会被系统环境变量覆盖,这件事和litellm没关系,但对litellm的踩坑影响特别大。我曾在macOS开发机上把OPENAI_API_KEY写进了.zshrc,之后项目里.env怎么换都没生效,请求一直用的是旧Key。排查了半天才发现,系统环境变量优先级比项目.env高。生产环境你更是要小心,多个部署脚本如果都设了同一变量,顺序不对就会导致网关拿错供应商配置。而且litellm在启动时把环境变量全读入内存了,你改了.env之后必须重启网关进程,它不像某些框架每次请求都重新读环境变量。
第四个坑是异步请求并发导致供应商限流。我们业务端有很多批量小请求,一开始用同步串行方式跑,反正也够用。后来为了效率改成了异步并发,一次发几十个请求,结果网关频繁返回429限流错误。litellm本身有限流配置,但因为我的虚拟Key没设上限,真实Key在供应商那边被限得很惨。解决方式是主动控制业务侧的并发数,同时在网关上为不同的真实Key设置较低的每分钟速率阈值,避免瞬时流量直接把账户打到禁用。
再补一个不算坑但容易误会的点:代理模式并不会自动处理供应商的流式响应兼容。如果你原来直接接了OpenAI的stream模式,切到litellm网关后会看到流式格式相似,但部分字段和结束标识的实现细节不完全一致。我的建议是,切流之前先用小流量验证一下流式解析代码,不要只测非流式就上线。
6. 我的选型建议与后续扩展方向
在用litellm跑了将近两个月的业务流量之后,我的结论很明确:如果你是一个小团队,正在从“单厂商SDK直连”走向“多模型接入”,litellm是性价比极高的选择。它的学习成本不高,但能明显减少你写SDK适配代码和维护多套密钥的时间。团队规模小或者方法论还不清晰的阶段,直接用SDK模式即可,不用强行上代理。
关于后续扩展,我们目前已经计划做两件事:一是把原来零散写在业务代码里的模型切换逻辑全部收敛进网关,让模型路由调整不再触发应用发布;二是在网关的模型映射层加一个“兜底模型”,当主模型连续失败时自动降级到便宜且稳定的备用模型,让客服系统永远有响应。等项目上线以后我再写一篇关于模型降级策略和流式转推的实战内容。
最后再分享一个我个人的习惯:每当你要决定是否引入一个新基建组件时,先不要看它官网的炫目功能列表,而是把自己团队里最烦的3个日常问题写在纸上,然后一条条去对照组件能不能闭环解决。litellm恰好把我们最烦的三个问题——SDK差异、密钥暴露、费用统计——全部闭环了,所以它留了下来。