近一两年做 AI 应用,最让我头疼的往往不是模型本身的能力,而是“怎么把各个模型顺畅地接进自己的代码”。每家模型服务商的接口风格都不同,有的偏好流式事件,有的用完全不一样的鉴权方式,有的连请求字段和返回结构都有差异。我曾在好几个项目里反复写适配代码,每次换一个供应商,老半天都耗在看文档、调参数、重写输出解析上。直到我在某个项目里试着引入 LiteLLM,才发现这个困扰了大家很久的问题,本来是可以被一个通用层系统性地解决的。
简单说,LiteLLM 是一个统一的大模型接入库,也附带一个可选的轻量级网关服务。你在代码里只需要用一套固定的消息结构去请求,LiteLLM 会在底层完成各家协议之间的映射,并把结果统一成同一个响应结构。你既可以直接在 Python 代码里调用它,也可以把它部署成一个独立的 HTTP 服务,让多个应用、多个团队成员通过这一个网关去访问不同厂商的大模型。无论你接的是闭源商业模型,还是某个开源社区的模型,对上层业务来说入口和用法都保持稳定。
这听起来像是一个“协议翻译层”,但它的价值远不止翻译。它把供应商差异、鉴权、超时、重试、故障切换、负载均衡、成本统计这些基础设施问题,统一收敛到了一个组件里。对一个同时接多家模型、还得做成本核算的团队来说,这相当于把原来散落在各个业务代码里的切换逻辑,抽成了一个标准化的中间平台。这篇文章我会从功能拆解、快速上手、网关部署到常见坑位逐一讲清楚,过程中会给出大量可直接复制运行的代码和自己的实测经验。
1. 它到底解决了什么问题,为什么值得引入
先说背景。现在模型服务呈现出的趋势是“多而不统一”,有的擅长长文本,有的在推理上表现更好,有的价格便宜但速度很快。很多应用天然就需要同时结合多个模型来做事情,比如复杂问题走能力更强的模型,简单问题走轻量模型。问题在于,不同厂商的接口参数名千差万别,有的要求把 system prompt 放在特定字段里,有的要求用自定义参数传递工具集合,有的流式返回事件结构完全不一样。于是“接入方”被迫为每个供应商写一套独立客户端。
我用一个生活化的类比来说明这个困局:你家里同时装了宽带、有线电视和智能门锁,本应都归物业统一管,但现实中你却是每家给一个独立 App,每个 App 的操作界面都不同。LiteLLM 做的就是那个统一管理平台,让你只需要面对一个操作入口,至于背后接的是哪一家服务,那是配置层面的事,而不是代码层面的事。
引入 LiteLLM 对团队的实际收益主要有四个:
- 降低接入成本。新项目接模型时,不用再研究每个厂商的数据格式,只需要会用一套消息结构。
- 降低切换成本。想从 A 模型换到 B 模型时,改动几乎只是一行 model 参数,不需要重写调用逻辑。
- 让治理能力集中化。鉴权、密钥、限流、成本预算、访问日志都沉淀在统一层里,而不是写在各个业务的散落代码中。
- 减少生产事故。通过内置的自动重试、超时控制和备用链路,模型服务商偶发故障时,你的服务依然能兜住。
适合谁看?如果你正在做聊天机器人、知识库问答、代码助手、内容总结这类应用,每天为各种接口差异做重复劳动,这篇内容可以帮你省下大量时间。即使你是个人开发者,目前只接了一家模型,也可以提前看懂这套“多供应商统一接入”的架构思路,将来项目变大时不用推倒重来。
2. 核心功能拆解:它绝不只是一层格式转换
2.1 协议统一是最关键的一步
LiteLLM 把各家模型服务的请求和响应,收敛成一套固定的契约。对上层应用来说,你只需要传一个 messages 列表,里面每条消息包含 role 和 content 两个核心字段;对底层厂商来说,LiteLLM 负责在内部把统一的消息结构映射成各厂商自己能识别的格式。从程序设计角度看,这就是典型的适配器模式,但它做得比我概念中的适配器彻底得多,连鉴权、超时、重试、流式、工具调用这些边角也都一并覆盖了。
选择哪套协议作为基准,LiteLLM 做了一件很聪明的事。它没有自定义一套新协议,因为自定义协议意味着生态工具都要重新适配;而是直接对齐了当前业界最通用的那套协议形态,也就是 /v1/chat/completions 这种风格的消息结构。这样一来,LiteLLM 的收益是三方共赢:原本就支持这套协议的服务可以无缝接入,原本不支持的模型可以通过 LiteLLM 转换后同样暴露成这套协议,而下游已有的各种 SDK 和框架都可以继续沿用它们熟悉的调用方式。
你在代码里见到的最典型表现就是:模型名带前缀。LiteLLM 规定模型名形如“供应商前缀/具体模型名”,它通过前缀自动选择该用哪一家的 client,再通过后面的具体模型名去调用目标模型。这个设计虽然简单,但让整个体系的可扩展性变得极好,新增一个供应商基本上就是在内部注册一套新的 client 映射,对使用方完全无感。
2.2 自动重试、超时和故障切换
真实生产环境的模型调用,比很多人想象中脆弱得多。限流、网络抖动、服务端偶发 5xx、连接超时,都可能让一个原本运行正常的应用突然卡住。LiteLLM 内置了相对完善的重试与超时机制,而且它并不是“失败就盲目重试”,它可以识别错误类型:如果是限流导致的问题,就适当等待后重试;如果是参数错误,就快速抛出,不再做无意义的尝试。
更厉害的是故障切换能力。你可以给同一个请求配置多条备用链路:假设主模型调用失败,LiteLLM 会自动把请求转发到备用模型上。有人可能会担心,不同模型生成的回复风格不一致,会不会影响最终效果?在实际业务里,大多数用户更在意的其实是“有没有响应”,而不是“这个响应具体来自哪家模型的哪一次调用”。比如线上客服机器人,面对模型服务商正在维护的情况,能够立刻切换备用模型继续服务,远比死等主模型恢复要重要得多。
故障切换的配置有两种方式:在代码里传 fallbacks 参数,或者在网关配置文件中声明主备列表。我会在后面网关章节给出完整示例。这里想强调一个观点:很多团队早期只接一个供应商,觉得没必要做备用,但等某天遇到长时间限流的时候,再临时改代码接第二个供应商,就会发现所有逻辑都耦合在旧接口里,根本换不动。哪怕你现在只用一家模型,我也建议在架构层面预留好备用链路的位置。
2.3 负载均衡和路由策略
当应用流量涨起来,单一 API Key 很容易触发供应商的速率限制。LiteLLM 支持把多个 API Key、甚至多个供应商组合成一组资源,在组内做负载均衡。这就像一个请求分发器,把流量均匀地打给不同的上游资源,避免某个 Key 被限流后整个应用不可用。
负载均衡的具体策略可以很灵活,既支持最简单的轮询,也支持按权重分配。实际业务中我有两种用法比较常见:一种是让能力更强的模型承担大多数复杂请求,让轻量模型兜底简单请求;另一种是把多个供应商放在同一个虚拟模型名下,按价格和响应速度的权重来分流。比如某个供应商的价格便宜但偶尔慢,另一个供应商价格贵但稳定,我会把大部分流量分给便宜的,保留一部分给稳定的,兼顾成本与体验。
在 LiteLLM 的术语里,这套机制叫“模型列表加路由”。你可以定义一组真实模型,把它们包装成一个虚拟模型名,对外只暴露这个虚拟名字,由它来负责内部流量的真实分发。这样就算某一天你想调整供应商的流量占比,只需要改配置文件里的权重,下游业务代码一行都不用动。
2.4 成本统计、预算限制与日志记录
无论接一家还是多家模型,成本核对永远是项目上线后最先被问起的事。LiteLLM 的调用统计功能做得比较细,每次请求结束,它都会记录下输入 token 数、输出 token 数、请求耗时、调用的模型名,再按照各家模型的计价规则换算成金额。需要注意,不同模型的计费方式差异很大,有的按输入输出分开计价,有的对缓存命中价格不同,有的对小语种内容还有特殊倍率,所以成本换算不是一成不变的,需要根据最新定价定期校准。
预算限制是这个部分里我觉得最有价值的点。它可以做到“单日总成本超过某个阈值就自动熔断”“某个 API Key 只允许花多少钱”“某个虚拟模型每月最多消耗多少额度”。一旦触发限制,LiteLLM 会直接拒绝新的请求并记录告警日志。这在多团队共用网关时特别有用,相当于给每个业务线都发了一张独立的预算卡,谁也不能不小心把整体账单刷爆。
日志方面,LiteLLM 会把每次调用的元数据都留下来,方便对接监控平台。我一般会额外把这些日志采集到日志系统里,配合告警规则,一旦发现某个模型响应变慢或错误率上升就能及时感知。网关模式下,这个能力是全局生效的,不会像代码模式那样每个项目各记各的。
2.5 缓存机制:少一次调用就是多一分成本与速度
成本敏感的服务里,有一个场景大家一定遇到:用户反复问非常相似的问题。比如一个企业官网的知识库机器人,用户问得最多的永远是那几个:支持哪些支付方式、怎么退款、发货多久能到。如果每次都真实调用模型,浪费钱不说,响应还慢。LiteLLM 提供缓存功能,默认可以对完全相同的请求做响应级缓存,命中后直接返回历史结果,不再触发真实模型调用。
除了完全一致请求的缓存,它还支持语义缓存,也就是说内容差不多但表述略不同的请求也能命中同一个缓存结果。语义缓存的实现一般依赖向量相似度检索,效果受嵌入模型影响较大,但很适合问答类业务。我自己的经验是:先开最稳的精确缓存,再根据业务需要评估要不要开语义缓存,因为语义缓存有误判风险,某些动态场景里把不同问题当成相同问题返回旧答案,会带来比较差的体验。
3. 快速上手:从安装到第一个请求
3.1 安装与工程准备
LiteLLM 是 Python 库,安装方式很简单,直接通过 pip 安装即可,但有几个细节值得多说两句。第一,强烈建议在虚拟环境或容器里安装,因为 LiteLLM 依赖较多,直接装进系统环境容易引发版本冲突。第二,如果你只需要在代码里调用模型,装基础版就够;如果想跑独立网关,还需要装带 proxy 的扩展版本。安装命令如下:
pip install litellm # 如果要使用代理网关模式,执行: pip install 'litellm[proxy]'安装完成后,可以先做一个最简单的验证,确认核心包可以被正常导入:
import litellm print(litellm.models)这一步会输出当前 LiteLLM 能够识别的模型集合,里面包含了各类常见模型名称和前缀。看到输出说明安装环节没有问题。
版本管理是我的一个额外提醒。LiteLLM 迭代速度快,新功能和大版本更新频繁,建议在 requirements 文件里锁定版本,或者使用pip freeze > requirements.txt的方式固定。我见过不止一次因为升级了一个小版本,某个供应商的适配参数结构发生变化导致线上报错的情况。生产环境千万别用“最新版”这种不受控的依赖策略。
3.2 最小可运行示例
先演示最常用的库模式。假设你已经把对应模型服务商的密钥配置到环境变量里,代码如下:
from litellm import completion response = completion( model="provider-a/flagship-model", messages=[ {"role": "user", "content": "用一句话介绍你自己"} ], temperature=0.7, ) print(response.choices[0].message)这段代码里,model参数很有意思。中间的斜杠把模型名分成两部分,斜杠前面是供应商前缀,斜杠后面是具体的模型标识。LiteLLM 拿到这个字符串后,会自动选择该供应商对应的调用客户端,并读取该供应商对应的环境变量密钥。也就是说,你不需要在代码里判断供应商类型,也不需要手动传不同格式的 API Key 参数。
messages是标准的对话消息列表,支持 system、user、assistant 角色。temperature是采样温度,控制随机性,数值越大回复越发散,数值越小越稳定。实际使用时,如果只是做事实问答,我会把 temperature 调低到 0.2 左右;如果是做创意文案,可以调到 0.8 以上。
这里我要强调一个很多人容易踩的误区:model参数写不写前缀差别很大。如果你只写一个模型名不带前缀,LiteLLM 会按内部默认规则处理,它可能默认去请求某一家你并非本意的供应商。所以即便你只使用一家模型,也建议养成写完整前缀的习惯,既清晰又不容易出错。
3.3 流式输出与工具调用
大多数 AI 应用追求打字机式的流式输出,因为等待时间太长会严重影响用户体验。LiteLLM 对流的支持很直接,只需要在请求参数里加一个stream=True:
response = completion( model="provider-a/flagship-model", messages=[{"role": "user", "content": "写一段 200 字的产品宣传文案"}], stream=True, ) for chunk in response: content = chunk.choices[0].delta.content if content: print(content, end="", flush=True)流式响应的结构是增量式的,每个 chunk 里可能只包含一小段增量内容,需要调用方自己拼装。上面代码里delta.content就是每个增量分片的内容字段。需要注意,不同供应商的流式事件细节有差异,LiteLLM 在这里做了统一处理,但如果你在底层开启了非常精细的超时控制,建议对流的空闲间隔单独做超时判断,避免连接“假死”被系统判定为正常状态。
工具调用是另一个值得关注的能力。现在的应用早就不满足于纯文本问答,很多场景需要模型能够调用外部函数获取实时数据,比如查天气、查订单状态。LiteLLM 支持工具调用,并且会把各家差异较大的工具参数框架做映射。使用方式和普通请求类似,只不过需要在 messages 之外额外传入一个 tools 列表。最需要注意的是,不是所有模型都支持工具调用,尤其是部分轻量模型,强行传入 tools 参数可能导致请求失败。我一般会在路由配置里用 model_info 标记每个模型是否支持工具调用,这样上层应用在选择模型时就能自动避开不支持工具能力的模型。
4. 网关模式:把模型接入变成基础设施
4.1 为什么我建议团队用网关而不是库
代码模式解决的是单个应用内部的问题,而网关模式解决的是整个团队、多个应用共用一套模型接入能力的问题。我的经验是,当团队超过两三个人、同时维护超过两个应用时,把 LiteLLM 做成独立网关的收益是远大于前期投入的。
网关模式有几个肉眼可见的好处。第一是密钥不落地:前端和各个业务服务不需要保存各家模型服务商的密钥,只需要保存网关分发的 key,即使某个服务被攻破也不会泄露上游模型密钥。第二是配置集中:换模型、调权重、改路由,都只改网关的一处配置,下游服务无感。第三是治理能力统一:所有模型调用都会经过网关,日志、限流、预算、缓存都天然成为全局能力,不需要每个服务各自实现一遍。
如果你是个人开发者,可能会觉得网关搭建起来麻烦,但我也建议至少在项目架构上预留这种模式的位置。因为个人项目一旦将来上线、有真实用户、需要多模型冗余,再回头改造的复杂度会比一开始就用网关高得多。
4.2 最小可用配置启动网关
网关模式通过 YAML 配置文件描述模型列表和相关设置。我先给一个最基础的配置示例:
model_list: - model_name: main-assistant litellm_params: model: provider-a/flagship-model api_key: os.environ/PROVIDER_A_API_KEY litellm_settings: drop_params: true set_verbose: false general_settings: master_key: sk-my-gateway-master-key配置里的model_list是网关对外暴露的模型目录。model_name是给下游用的虚拟名,litellm_params里写真正的模型和密钥来源。api_key用os.environ/PROVIDER_A_API_KEY这种写法表示从环境变量读取,而不是把密钥明文写到配置文件里,这是我一再强调的安全红线。master_key是访问网关时的统一入口密钥,所有下游服务都通过它来鉴权。
启动命令很简单:
litellm --config config.yaml --port 4000启动之后,网关会默认对外提供一套标准化的 HTTP 接口。你可以直接用 curl 或任意 HTTP 客户端请求它,方式跟直接请求模型供应商类似,只不过地址换成了你的网关:
curl http://localhost:4000/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer sk-my-gateway-master-key" \ -d '{ "model": "main-assistant", "messages": [{"role": "user", "content": "你好,介绍一下你的能力"}] }'注意到这里model传的是虚拟名“main-assistant”,网关收到后会自动把请求映射到真实的模型上。对下游来说,它只需要知道网关的地址和管理员分配的模型名,完全不需要关心上游供应商是谁。
4.3 配置备用链路与路由策略
我在前面章节强调过故障切换的重要性,现在给出网关模式下的具体写法。核心是在配置里增加 fallbacks 字段:
model_list: - model_name: assistant litellm_params: model: provider-a/flagship-model api_key: os.environ/PROVIDER_A_API_KEY - model_name: backup-assistant litellm_params: model: provider-b/solid-model api_key: os.environ/PROVIDER_B_API_KEY litellm_settings: fallbacks: [{"assistant": ["backup-assistant"]}]这段配置表达的意思是:当“assistant”这个模型请求失败时,自动改用“backup-assistant”。在实际响应里,LiteLLM 会额外返回一些标识信息,方便你判断这次请求最终由哪个模型处理。这个判断在排障时很重要,因为如果一个模型频繁触发 fallback,你会希望尽早发现并调整权重,而不是让备用链路默默承担所有压力。
路由方面还可以做权重分配。假设你想让主供应商承担 80% 流量,备用供应商承担 20%,可以像下面这样配置:
model_list: - model_name: assistant litellm_params: model: provider-a/flagship-model api_key: os.environ/PROVIDER_A_API_KEY model_info: weight: 80 - model_name: assistant litellm_params: model: provider-b/solid-model api_key: os.environ/PROVIDER_B_API_KEY model_info: weight: 20这里有个细节需要特别说明:两个虚拟模型名都叫“assistant”,在 LiteLLM 里这就构成了同一个虚拟模型下的多个真实上游。当请求指定 model 为“assistant”时,网关会按权重在 provider-a 和 provider-b 之间做分发。这种写法是把“容灾”和“负载均衡”结合到了一起,既保证了可用性,也让便宜的供应商承担了更多流量,整体成本更可控。
4.4 用通用协议从下游访问网关
网关模式最大的兼容性优势在于,它对外提供的接口协议和业界主流的聊天补全协议一致。这意味着你现有的开发工具、测试工具、监控工具,只要是按这套协议写的,都能直接对接网关,基本是零侵入改造。
实际写起来大概是这样的感觉:
client = OpenAI( base_url="http://localhost:4000/v1", api_key="sk-my-gateway-master-key", ) response = client.chat.completions.create( model="main-assistant", messages=[{"role": "user", "content": "用三句话总结这篇内容"}], )这里我刻意没有指定真实模型供应商,因为 base_url 已经指向网关。下游代码只需要知道“该调哪个虚拟模型”,完全不关心这个虚拟模型背后是哪家供应商、用的什么密钥、模型版本是什么。对老项目来说,这种无侵入改造是最容易说服团队采用的方案。
5. 真实环境中的故障排查与老手技巧
5.1 高频问题排查清单
LiteLLM 虽然做了很多统一工作,但毕竟要面对的是各不相同的模型服务商,实际用起来还是有一些常见坑位。下面按我的经验整理成速查表:
| 常见现象 | 大概率原因 | 处理建议 |
|---|---|---|
| 返回 401 鉴权失败 | 环境变量里没有配对应供应商的密钥,或密钥已失效 | 检查网关环境变量、更新密钥 |
| 模型名报“no provider found” | 前缀写错,或该供应商未被 LiteLLM 识别 | 用litellm.models核对支持的模型列表 |
| 请求一直重试直到超时 | 上游触发限流或网络不稳定 | 调低并发、加大重试间隔,或引入多 key 负载均衡 |
| 明明设了 max_tokens 还是截断 | 输出 token 估算偏差大,不同模型对 token 计算方式不同 | 适当上调 max_tokens,预留缓冲量 |
| 流式输出有时不结束 | 对空闲时间没有单独超时判断 | 在调用层增加流空闲超时 |
| 计费金额明显不准 | 内置计费表未覆盖最新模型,或计价规则有变 | 手动校准价格表,或定期更新 LiteLLM 版本 |
| 某些模型工具调用失败 | 模型本身不支持 function calling | 在 model_info 里标记支持能力,路由时做筛选 |
第一行的 401 问题,我遇到最多的情况其实是环境变量名混淆。LiteLLM 对不同供应商的默认环境变量名有约定,如果多个供应商的密钥前缀类似,很容易配串。建议在配置文件里显式写明api_key引用的是哪个环境变量,不要依赖默认行为。
第二行的模型名前缀问题也非常高频。很多人从文档里复制了一个模型全名过来,但这个全名所属的供应商可能并没有被当前版本的 LiteLLM 支持,或者前缀拼写有细微差别。遇到这种情况,别急着怀疑代码,先运行litellm.models或者查官方模型列表,确认目标模型确实在当前版本的维护范围内。
第三行的重试问题,和生产环境的稳定性直接相关。LiteLLM 默认的重试策略对偶发错误有效,但遇到长时间大规模限流,仍然会让所有请求排队等待。我一般会给重试参数单独配置一个目标:总重试时长不要超过业务的合理等待时间,超过之后宁可快速失败并降级,也不要让用户一直打转。
5.2 我的一些实测技巧和架构经验
第一,合理使用虚拟模型名来隔离上下游。虚拟模型名的价值不只是“换个名字”,它是上游供应商与下游业务之间的一个解耦层。比如你把某家的模型包装成“main-assistant”,有一天这家模型升级了版本,你只需要把那一家模型名从 v1 改成 v2,下游完全没有感知。再比如你把两家供应商包装成同一个虚拟模型,业务侧甚至感受不到你已经做了均衡和容灾。
第二,预算和告警一定要在网关层做,而不是依赖各家供应商后台。各家控制台的预算指标口径不同,有些还滞后很久。LiteLLM 网关的统计是按实际调用发生的,能够比较及时地反映成本,配合自定义告警规则,通知到负责人才是真正可控的成本治理。
第三,缓存的开启要分环境分场景。本地开发永远建议关掉重试或关闭缓存,因为开发时需要实时看到最新响应。生产环境则要对不同业务语义做评估,精确缓存几乎没有副作用,语义缓存则需要谨慎,在结果允许一定误差的问答型业务里再开启。
第四,所有下游服务连网关时,尽量使用网关分发的独立密钥而不是 master_key。LiteLLM 网关可以在较新版本中支持按 key 做维度管理,你可以给不同团队发不同的 key,分别设置预算和访问范围,这样即便某个团队的 key 泄漏,也能快速隔离风险,影响面可控。
关于项目落地,我的体会是 LiteLLM 并不需要一开始就做到很复杂的路由和负载均衡配置。最简单的做法是:先用库模式把项目跑通,理解清楚调用方式和配置格式,等真正要上生产或接入第二个模型供应商时,再迁移到网关模式。迁移过程中保持虚拟模型名不变、只改下游的 base_url,基本半天就能完成切换。也不要贪多求全,一次性把所有高级功能全部启用,等业务真的增长到那个阶段,再逐步把缓存、语义路由、按 key 预算、多重备用链路加进去,架构演进会顺畅得多。