1. 为什么前端我都需要一个"大模型接入中间层"
1.1 多个供应商接入的混乱现状
先从我最近遇到的实际问题说起。我的一个后端服务原本只接了某一家模型API,代码里用一套SDK就能完成调用。后来需求变多,要同时接上开源模型托管平台、云厂商原生模型服务、还有另一家闭源模型厂商,每个服务的鉴权方式完全不一样。有的把API Key放在Header里就完事,有的要求先获取临时令牌再签名,有的是每分钟请求数限流,有的则是按token配额。我只能在调用层维护一个越来越长的if-else分支来分发不同请求,只要某个供应商更新SDK或者下架旧模型,我就得跟着改一遍兼容代码。更要命的是各家计费口径也不统一,有的按百万token计价,有的按调用次数计价,我把几个供应商的调用量合并成一份成本报表,光是对账就花了好几个晚上。
这时候我才意识到,问题根本不是某一个SDK难用,而是接入层压根没有和业务层解耦。正当我打算自己写一个适配层时,发现已经有人把这个适配层做成了开源项目litellm,而且比我预想的完整得多。
litellm本质上是一个开源的LLM API网关。它把各家模型接口统一抽象起来,对外提供一套标准格式,你在业务层用同一种调用方式,把"使用哪个供应商、什么模型、用哪个key、花多少预算"全部交给网关处理。简单说,它就是模型调用层面的负载均衡器加协议转换器。现在我的理解很明确:litellm解决的不是某一个调用问题,而是整条模型接入链路的混乱。
1.2 litellm在系统架构里的位置
把litellm加进架构之后,调用链条从"业务代码直接连各家SDK"变成"业务代码连网关,网关连供应商"。具体来说:
- 业务服务只需要关心一个统一入口地址,例如网关的
/v1/chat/completions端点; - litellm收到请求后,根据配置文件里的路由规则,把请求转发给对应的模型供应商;
- 供应商返回结果后,litellm再把响应整理成标准格式还给业务服务;
- 转发的过程中它还会记录token消耗、扣预算、执行限流、写入日志。
用一个生活化的类比:如果模型供应商是一堆发电站,你的应用是家里各种电器,litellm就是那个配电箱。配电箱把插座规格统一了,背后的线怎么接、哪路电来自哪里,使用电器的用户根本不用关心。
更直白的价值是,你不再需要维护N个SDK和N套鉴权代码,只需要维护一份路由配置。模型切换、故障转移到备用供应商、给不同团队分配配额,都可以通过配置和管理接口完成,不用再动业务代码。
1.3 什么时候才需要引入litellm
不过我先把话说在前面,如果你的项目只是调一个模型、写个小Demo,拢共十几行代码,那不需要上litellm。网关本身就是要部署、要维护、要关注的组件,多一层自然多一份运维成本。一般来说,出现下面几种情况时,引入网关的价值才开始真正显现:
- 业务要接入两个以上模型供应商,并且存在切换需求;
- 多个团队、多个应用同时需要调用大模型API,你希望统一管理Key、预算和限流,避免某个项目超支了都没人知道;
- 你想做模型容灾,主供应商挂了能秒切备用供应商;
- 需要把模型调用成本按项目、按应用、按团队分账;
- 你不想把最高权限的API Key直接暴露给每个开发环境。
我实际用下来的感受是:litellm把"接入模型"从重复劳动变成了配置项。这对中后台系统、AI工具类应用、内部自动化平台尤其合适,因为它天然需要统一管理多个模型来源和多个调用方。
2. litellm的核心能力清单:一个代理层到底替你干了哪些事
2.1 统一协议,翻译各家接口
litellm对外提供的接口和目前行业里最通用的OpenAI兼容协议保持一致,包括/v1/chat/completions、/v1/completions、/v1/embeddings、/v1/images/generations这些端点。你以前用什么方式调标准模型接口,现在就用什么方式调litellm,业务代码改动量很小,很多时候只是把base_url换一下。
而在内部,litellm维护了大量供应商适配器。它会把标准格式的请求转换成各个供应商原生接口的请求体,再把各家返回的响应转换成统一结构。外部接口是标准化的,内部适配是插件化的。加上开源生态的接受度越来越高,从本地推理框架到各类模型托管平台,litellm基本都能覆盖。
这样做还有一个隐藏好处:如果某个模型服务升级了接口协议,只有litellm的适配器需要跟着改,你的业务代码、测试脚本、监控规则都不需要动。经历过SDK升级导致全链路联调的同学,应该懂这个价值有多大。
2.2 路由策略:不只是转发,是智能分派
litellm并不仅仅是把请求转发给同一个模型,它可以根据配置在多套模型之间做路由。我实际用到的路由方式大概有四种,整理成表格方便对比:
| 路由策略 | 行为描述 | 适合场景 |
|---|---|---|
| 简单轮询 | 在配置的几个端点之间轮流选择,可加权重 | 多个供应商并发,均衡流量 |
| 最少负载 | 优先选择当前请求最少、负载最低的端点 | 各供应商能力不一时,防止某个被打满 |
| 成本优先 | 优先选择单价更低的模型 | 对成本敏感、模型质量差距不大 |
| 延迟优先 | 优先选响应最快的端点 | 实时对话类应用,对首字延迟敏感 |
我实际生产里最常用的是"成本优先加故障回退"的组合:正常请求走性价比模型,一旦返回错误或超时,自动转给高可用备用模型。用户感知不到模型切换,但后台统计里能看到fallback记录,成本也能控制住。
2.3 虚拟Key和密钥分层
虚拟Key是litellm里很实用的设计。litellm用一个主密钥作为管理入口,你可以通过管理接口或控制台生成一堆虚拟Key。每个虚拟Key可以绑定一个用户、一个应用或一个团队,可以单独设置预算、限流、可访问的模型范围。
好处非常直接:
- 前端和子服务不需要接触主密钥,即使某个虚拟Key泄露,你可以在面板里一键吊销,不影响其他Key;
- 每个Key独立计费,出账时按Key分组就能知道是哪个项目花的钱;
- 可以给客户的试用账号分配一个限时限量的Key,到期自动失效。
我在一个多团队项目中,给每个后端服务分配一个虚拟Key。某个团队超预算了,一查Key就能定位问题,比从前大家共用一个Key查账方便太多了。
2.4 限流、预算、审计一起做掉
在网关层面,限流和预算不再是业务层的临时代码,而是配置化能力。你可以在每个模型或每个Key下面设置:
rpm:每分钟最多请求数;tpm:每分钟最多token数;- 预算金额:超过一定美元数后,拒绝继续调用或者发警报;
- 模型白名单:这个Key只能调用哪些模型。
这些参数既可以在配置文件中写死,也可以动态通过管理API修改。所有请求日志都会落库,litellm还提供Prometheus指标,你可以把token消耗、请求量、错误率接入现有监控体系。想做一套"AI调用成本看板",这些指标足够了。
3. 本地部署:20分钟把网关跑起来
3.1 最快的方式:用容器跑
litellm是Python写的服务,官方发布容器镜像,我建议直接用容器部署,比装Python依赖省心,也好迁移。假设你已经装好容器运行时,只需要准备一个配置文件和一个主密钥。
先把最基本的启动命令放出来:
docker run -d --name litellm \ -p 4000:4000 \ -e LITELLM_MASTER_KEY="sk-master-123456" \ -v $(pwd)/config.yaml:/app/config.yaml \ --restart unless-stopped \ litellm:main-latest \ --config /app/config.yaml --port 4000 --num_workers 2几个环境变量和参数说明一下:
LITELLM_MASTER_KEY是网关的管理密钥,也是后面调用管理接口时的凭证;-v参数把本机的config.yaml挂载进容器,改路由配置不需要重新构建镜像;--num_workers控制进程数,本地测试2个就够,生产环境按CPU核数和请求量来调。
3.2 一份最简config.yaml
litellm的配置核心是model_list。一份最简配置大概长这样:
model_list: - model_name: base-chat litellm_params: model: provider-a/chat-large api_key: os.environ/PROVIDER_A_KEY - model_name: base-embedding litellm_params: model: provider-b/embedding-v2 api_key: os.environ/PROVIDER_B_KEYmodel_name是你对外提供的模型别名,业务层调用时传这个名称就行;litellm_params.model是指向某个供应商原生模型的标识。api_key可以直接写,但生产环境建议都走环境变量,避免密钥写死在配置文件里。
注意:这里的
provider-a、provider-b是占位写法。litellm到底支持哪一百多家供应商,每家的原生模型标识怎么写,建议直接看项目文档里的Provider列表,不同供应商的字段命名差异比较大。
3.3 第一次调用,验证链路
网关默认监听4000端口。拉起来之后,先用最简单的方式确认健康状态:
curl http://localhost:4000/health/liveliness然后发一个基础的对话请求:
curl -X POST http://localhost:4000/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer sk-master-123456" \ -d '{ "model": "base-chat", "messages": [ {"role": "user", "content": "你好,介绍一下你自己"} ], "temperature": 0.7 }'如果配置正确,你会收到一个和标准对话接口格式几乎一样的JSON响应,里面有choices、usage这些字段。此时网关已经完成了协议转换、密钥透传、token统计整套流程。
我第一次验证时还习惯加上"stream": true测一下流式输出,因为很多真实场景后端要边生成边推送给前端,litellm对流式请求也是支持的,响应体按data:分片返回。这一步走通,基本可以宣告本地链路没问题了。
3.4 为什么用容器而不是裸Python进程
litellm本身也可以像普通FastAPI应用一样用pip install litellm[proxy]装完再跑,但我个人建议走容器,原因有三:
- 依赖锁得快,官方镜像里的Python版本和依赖组合是经过验证的,自带排坑;
- 升级方便,换一个镜像tag重启就完事,不用在服务器上折腾虚拟环境;
- 日志、停止、恢复都符合容器管护习惯,和已有日志收集、监控系统好对接。
4. 从Demo走向生产:路由、预算、缓存与高可用
4.1 多模型路由真实配置:权重、备用、可用性
本地跑通之后,生产环境第一个需求往往是"同一个模型名背后挂多个真实供应商",实现高可用。做法是在model_list里给同一个model_name配置多个端点,litellm默认会做简单轮询,你还可以显式加权重:
model_list: - model_name: chat-main litellm_params: model: provider-a/chat-large api_key: os.environ/PROVIDER_A_KEY weight: 4 - model_name: chat-main litellm_params: model: provider-b/chat-plus api_key: os.environ/PROVIDER_B_KEY weight: 1上面的配置意味着chat-main这个模型名背后有两个真实模型,流量比例为4比1。当provider-a对应的模型返回限流、超时或者不可用状态时,litellm会按故障转移逻辑把请求转到provider-b。
更细的控制可以放在router_settings里:
router_settings: routing_strategy: usage-based-routing enable_pre_call_checks: true allowed_fails: 3 cooldown_time: 60这些参数的意思依次是:按成本优先策略选模型;调用前先做预算和模型准入检查;某端点连续失败3次后进入60秒冷却,冷却期间不再把流量发过去。这套机制对线上稳定性很有帮助,某个单一供应商出问题的时候,用户端几乎无感。
4.2 预算体系怎么落地:Key、团队、全局三档
预算控制是网关在生产环境最不可替代的功能之一。我落地的时候分三个层级:
- 全局预算:整个网关每月的总调用金额上限,防止成本失控;
- 团队预算:为某个业务团队设置月预算,超了自动拦截,避免几个团队互相影响;
- Key预算:为某个具体虚拟Key设置高频配额,适合给外部试用账号。
在litellm里面,可以通过管理接口创建Team、创建Key时传入budget_duration和max_budget参数实现。比如给外部测试客户分配一个虚拟Key:
curl -X POST http://localhost:4000/v1/key/generate \ -H "Authorization: Bearer sk-master-123456" \ -H "Content-Type: application/json" \ -d '{ "key_alias": "customer-trial", "max_budget": 5.0, "models": ["chat-main"], "rpm": 10, "tpm": 100000, "budget_duration": "30d" }'这个Key一旦30天内的调用金额超过5美元,或者每分钟请求超过10次,就会被litellm自动拦截,错误信息里会明确提示是预算超了还是限流触发。审计时一查请求日志,所有调用都挂在customer-trial这个别名下,按量对账很方便。
4.3 缓存和限流:省成本的事先做起来
litellm的缓存设计挺实用。最基础的是Redis结果缓存:同样的请求在缓存有效期内直接返回,不再真实调用模型。对高频、问题重复率高的场景,比如知识库问答、客服预审,成本下降非常明显。
开启方式是在general_settings里加一段:
general_settings: redis_host: localhost redis_port: 6379 redis_password: "${REDIS_PASSWORD}" cache: true cache_ttl: 3600另外它支持语义缓存,不光是完全相同的请求能命中,语义接近的请求也能命中。不过语义缓存需要向量检索能力,配置复杂度更高,我建议普通团队先用精确结果缓存。
限流这块,litellm既支持RPM(每分钟请求数)也支持TPM(每分钟token数)。注意token限流是按估算token数抵扣的,它会在调用前用词表粗算一遍,所以跟实际计费的token数会有一些误差。我在给外部客户开Key时一般只设RPM,因为TPM的估算误差容易引起误拦。内部调用场景两个都设,防止文本生成过长拖垮后端。
4.4 可观测性:请求日志与监控指标
到了生产环境,我第一件事就是把litellm的日志和指标接入现有监控系统。配置上主要做两块:
一是配置数据库连接。litellm会把每次请求的模型、输入输出token、延迟、供应商、Key、成功失败状态写入请求日志表:
general_settings: database_url: postgresql://user:pass@host:5432/litellm_db二是在网关容器暴露指标服务。litellm自带/metrics端点,输出Prometheus格式指标,包括请求总量、token消耗总量、各供应商成功率、P95延迟等。你在Prometheus里加一个采集任务,再配Grafana看板,整个大模型调用量、成本、错误率一眼能看全。
这套监控对回答"为什么这周成本涨了"尤其有效。有一次我发现某团队深夜调用量异常高,顺着虚拟Key和模型维度下钻,很快定位到是一个定时任务没有加缓存,修掉之后成本恢复正常。
4.5 多实例部署的注意事项
当单实例网关不够用,要横向扩成多个副本时,注意三件事:
- 所有实例必须连接同一个Redis和同一个数据库实例,这样预算计数、限流计数、缓存才是全局一致的;
LITELLM_MASTER_KEY和各供应商密钥要在所有实例上保持一致,不要每台机器一套;- 路由配置最好收敛到一份,要么每个实例挂同一个config文件,要么用管理API动态写入后统一从数据库读取模型列表。
litellm的模型列表支持持久化到数据库,之后在控制台增删模型会自动同步到所有实例,比维护多个config文件舒服。不过我也遇到过数据库模型列表和本地config同时存在时的优先级问题,所以我的建议是:不要两套混用,要么全走文件,要么全走数据库,否则排查配置冲突会非常费神。
5. 我踩过的几个坑,顺便帮大家排一下雷
5.1 版本升级带来的配置变化
litellm迭代非常快,新版本会调整配置项名称,甚至改变默认行为。我刚开始接触时参考了一些旧文章的配置,直接复制到新版本就报错了,后来查文档才发现字段已经改名。所以使用前最好看一眼官方最新文档,或者直接看镜像对应的版本说明。
我自己的做法是:先把正在使用的版本固定住,镜像tag锁到具体版本,升级前在测试环境跑一遍配置校验和冒烟测试,再更新生产。不要每次随手拉最新tag,否则配置变动会让人很头疼。
5.2 成本估算和真实账单的误差
litellm内置了一套模型单价表,用来估算token消耗成本。这套表覆盖了主流的闭源和开源模型,但它毕竟是估算,价格更新也未必和各家官网完全同步。如果你用的是新定价模型、私有部署模型、或者按次计费的模型,一定要在配置里显式传入成本参数,否则预算报表会失真。
比如在litellm_params里可以加:
litellm_params: model: provider-c/custom-chat api_key: os.environ/PROVIDER_C_KEY input_cost_per_token: 0.0000015 output_cost_per_token: 0.000002有了这种自定义单价的方式,同一个网关里既能用官方价格表覆盖的标准模型,也能接入你自己定价的私有模型,预算管控才谈得上准确。
5.3 超时设置,尤其流式输出
litellm默认的请求超时在某些场景下不够用。模型思考时间长的对话、长文档生成,如果网关超时太短,会自动断掉正常请求。我遇到过一次很典型的问题:外部客户陆续报错"请求超时",查了日志发现模型端其实还在正常生成,只是生成时间超过了网关超时阈值,连接被切断。
解决办法是按模型单独调大超时:
litellm_params: model: provider-a/chat-large api_key: os.environ/PROVIDER_A_KEY timeout: 120流式请求也一样,流式是持续传输的,超时配置要看的是"多久没有数据返回",而不是"总时长"受限。我把这个调整为30秒无数据才超时,长生成就稳定了。
5.4 主密钥别乱用
前面讲了虚拟Key的好处,但实践中容易被忽视的是,自己图省事把主密钥直接给前端用。这就等于把网关的一切管理权限交给所有能访问页面的用户,一旦主密钥泄露,别人可以生成任意Key、查所有日志、改预算设置。
我在这里栽过一次:某内部工具页面写死了主密钥作为调用凭证,后来页面配置被外部扫描到,好在发现早没有造成损失。之后我把主密钥严格限定在管理API、控制台、运维脚本三个场景,所有业务调用一律走虚拟Key,并且给虚拟Key开启预算、限流和模型白名单。
5.5 模型别名保持业务语义稳定
最后一个小建议:对外暴露的model_name最好不要用具体版本号,而是用业务语义,比如chat-light、chat-intensive、embedding-base。底层模型升级了、换了一家供应商,只需要改网关配置映射,业务代码一行不动。反过来,如果业务代码里到处写死具体模型名,换模型时就要全局搜索替换代码,还会出现新旧版本同时在线的情况,后面排查起来很麻烦。
一些使用体会
对我来说,litellm最大的意义不是省了几百行适配代码,而是让模型接入这件事变得可管理。它把一个混乱的、各种SDK拼车式的接入过程,变成了"改配置、看监控、配预算"的规范操作。尤其在多个团队共用网关的场景下,谁调了多少token、花了多少钱、有没有异常流量,一张看板全部说清楚。如果你现在的AI服务还只有一两个供应商,暂时不想引入网关也完全可以;但当你发现代码里开始堆砌SDK适配、成本账算不清、API Key难以控制时,litellm值得认真试一试。