☰
多模型接入治理:用Litellm网关统一大模型API、路由与成本管理
2026/10/13 17:32:07 网站建设 项目流程

如果你手头同时维护着两个以上大模型接口,litellm 这个名字应该不陌生。第一次看到它时,我的第一反应是:这不就是一个把各家模型 API 搓到一起的代理吗?后来真正在团队里用起来才发现,它的价值远不止“统一接口”这么简单。litellm 是一个开源的大模型网关服务,帮你把不同模型厂商的 API 协议差异、密钥管理、路由策略、成本统计全部收敛到一个独立的服务里。业务侧只需要记住一个地址和一把密钥,剩下的复杂逻辑都由网关处理。这篇文章我会从一个实际使用者的角度,把 litellm 的设计思路、部署方式、团队落地经验以及踩过的坑一次讲清楚。

1. 先看问题:多模型接入到底乱在哪

1.1 一个应用接三个模型,代码就快失控

先说痛点。很多项目一开始只接一个模型,代码写得很开心。等第二个、第三个模型进来的时候,麻烦就开始冒头了。

各家服务商的接口长得都不一样。有的参数叫max_tokens,有的叫max_new_tokens;有的用top_p控制随机性,有的靠temperature;有的把消息格式叫messages,有的还分system、user、assistant之外额外带一个history字段。更别提那些微妙的差异:同一个温度参数,在模型 A 上表现正常,换到模型 B 上可能生成风格完全变了。错误码也是各写各的,上游限流返回 429,网络超时返回 5xx,但具体字段千奇百怪,你没法用一套逻辑统一处理。

如果业务上还需要做模型对比、灰度切流,那就更难受。今天想试一个新模型,得改代码、做测试、重新发布,整个链路走完可能大半天。结果试下来效果不好,又要回滚。几个回合之后,项目里就会堆出一层又一层封装代码,谁都不敢动。

我见过最夸张的情况:一个服务里同时塞了四五个模型 SDK,每个 SDK 初始化方式不同、重试策略不同,连日志格式都对不上。出了问题,排查要翻遍各个 SDK 的源码。这种状态一旦持续下去,后面每加一个新模型都是一次痛苦的重构。

1.2 litellm 到底解决了什么

litellm 的核心思路很直接:它把你对模型厂商的调用全部集中到网关里面,网关对外暴露一套稳定的 HTTP 接口。你不再需要关心上游是谁、请求格式是什么、密钥怎么传,只需要按照一个约定好的格式发请求。

它内部维护一个“模型目录”。你可以给每个虚拟模型名分配一个或多个真实模型。请求进来之后,网关根据虚拟模型名去配置里找对应的上游,然后完成协议转换、鉴权注入、超时控制、重试、负载均衡,最后再把上游的响应转成统一格式返回给调用方。

在这套机制下,业务代码里写死的不是某个厂商的模型名,而是你自己定义的虚拟名字。以后想切换供应商,只要改网关配置,业务代码一行都不用动。

我实际用下来的感觉是:它解决的不只是“格式转换”,而是一整套“模型接入治理”问题。尤其是当你的团队里有多条业务线、多套服务都在调用大模型时,网关带来的收益会非常明显。

1.3 什么时候该上网关

先说结论:如果只有一个服务、一个模型,规模也很小,那直接调厂商接口是最省事的。但出现下面任意一条,网关就值得考虑:

  • 多个服务共用同一个模型,密钥散落在各个环境变量里;
  • 需要在不同模型之间切换、灰度、做 A/B 对比;
  • 想要统计每个业务线花了多少 token、多少钱;
  • 需要控制不同团队能用哪些模型、不能超多少预算;
  • 担心某家供应商单点故障,想要一个故障转移机制。

我从个人经验看,很多团队都是等到“模型越来越多、密钥管理失控、成本对不上账”这三个问题同时爆发时,才想起来上网关。其实早点上,后面能省很多事。

2. 核心设计拆解:为什么“网关”而不是“SDK”

2.1 代理模式和 SDK 封装的本质区别

市面上已经有不少模型封装库,它们在代码里帮你去适配各家 API。litellm 本身最初也有纯 Python 库的模式,可以直接在业务代码里调用。但我现在更推荐把它当独立网关来用,原因很现实。

SDK 是进程内的依赖,要跟业务代码一起部署。一旦多个服务都引用同一个 SDK,SDK 升级就得所有服务一起升,否则行为不一致。而且密钥仍然在每个服务的环境变量里,安全边界很模糊。如果某个服务的日志把请求体打出来,密钥也就跟着泄了。

独立网关则把这些问题收敛到了一起。所有业务服务通过 HTTP 访问网关,业务代码里几乎没有模型厂商的概念。网关升级不影响业务,密钥只放在网关这一层,模型路由的变化由网关处理。代价是多一跳网络延迟,但绝大多数场景下这点延迟是可以忽略的。

我做过一个对比,方便理解:

维度SDK 封装litellm 网关
部署方式跟随业务服务独立部署
升级成本所有引用服务发版重启/滚动升级即可
密钥管理分散在各服务集中在网关
多服务共享不方便天然支持
额外延迟无多一跳内网请求
故障影响只影响当前服务网关不可用则全链路影响

网关的问题也很明显:它变成了一个关键依赖,部署上需要做高可用。但这和数据库、缓存、消息队列一样,属于基础设施建设成本,可以接受。

2.2 模型别名与路由机制

litellm 最核心的抽象是“模型别名”。配置中的model_name并不是上游真实模型名,而是你业务系统里定义的逻辑名。比如业务侧都叫my-chat,网关配置里可以把这个逻辑名同时指向 A 厂商和 B 厂商的模型。

请求进来后,网关会按路由策略从一组真实模型里选一个去转发。这背后做了几件事:

  • 同一个别名可以对应多个上游,天然支持负载均衡;
  • 某个上游连续失败时,网关会自动把它隔离一段时间,并尝试其他上游;
  • 可以配置 fallback,主模型失败后自动走备用模型;
  • 可以通过权重控制流量分配,比如 90% 走模型 A,10% 走模型 B。

这套机制对业务侧完全透明。业务方只知道我发了一个请求给my-chat,具体是谁在响应,业务不关心。

2.3 虚拟密钥和预算管理

我推荐团队使用 litellm 的一个重要理由是它的密钥管理设计。它没有直接把上游厂商的 key 暴露给业务方,而是自己生成一套虚拟 key。

这套虚拟 key 可以绑定模型、限定预算、设置速率和有效期。开发者手里拿到的只是自己那把 key,网关负责统计用量,超过额度直接拒绝请求。这个设计很像银行卡的副卡,主卡权限很大,副卡额头和额度都有限。

对内部平台来说,这个能力非常实用。每个团队一把 key,每个 key 设置自己的月预算,谁超了谁负责,财务对账的时候也不用再去爬厂商账单。

2.4 日志、指标与可观测性

网关还有一个好处:所有请求都经过它,日志和指标自然汇聚到一个点。litellm 支持把调用日志写入 SQLite、PostgreSQL、MySQL、Redis 等存储,记录每次请求的模型、输入输出 token 数、响应时间、调用方身份。

标准指标格式的暴露能力也很有用。接上常见的监控告警体系之后,就能看到“某个虚拟模型今天平均延迟飙升”“某个 key 请求量异常高”“调用成功率下降”这些信号。团队里如果有运维或者平台角色,这一步基本是标配。

3. 快速上手:把一个 litellm 网关跑起来

3.1 环境准备

先明确一点:litellm 依赖 Python,生产环境我更推荐用容器方式跑,避免污染本机环境。

本地快速体验可以直接安装:

pip install "litellm[proxy]"

安装完之后命令行就会多一个litellm命令。如果想用容器,可以先把配置写好再启动。下面这种启动方式适合本地调试:

docker run -d -p 4000:4000 \ -v $(pwd)/config.yaml:/app/config.yaml \ -e PROVIDER_A_KEY=xxx \ -e PROVIDER_B_KEY=xxx \ --name litellm-gateway \ your-registry/litellm:stable

注意,这里your-registry/litellm:stable要替换成你们实际镜像仓库里的地址。配置文件和密钥通过挂载和环境变量传进去,镜像本身保持只读。

3.2 写第一份 config.yaml

litellm 的配置就是一个 YAML 文件,核心是model_list。下面这份配置可以当作最小示例:

model_list: - model_name: my-chat litellm_params: provider: provider_a model: provider_a/general-chat api_key: os.environ/PROVIDER_A_KEY - model_name: my-chat litellm_params: provider: provider_b model: provider_b/general-chat api_key: os.environ/PROVIDER_B_KEY general_settings: master_key: sk-master-demo

解释一下关键字段:

  • model_name:对外暴露的虚拟模型名,业务方只用这个名字调用。
  • litellm_params:真正发给上游服务的参数集合。
  • provider:服务商标识,请根据 litellm 官方文档填对应值,这里用provider_a和provider_b做占位。
  • model:上游模型名,通常写作“服务商标识/模型名”的形式。
  • api_key:建议用环境变量引用,不要直接写在 YAML 里。
  • master_key:管理端主密钥,用来生成虚拟 key、查询日志、管理配置。

为什么my-chat出现了两次?这不是配置冲突,而是故意让同一个虚拟名对应两个上游,形成一组可切换、可负载均衡的模型池。如果暂时不想做多供应商冗余,只保留一项也可以。

配置写好后启动服务:

litellm --config config.yaml --port 4000

看到日志输出监听端口后,用 curl 验证:

curl http://localhost:4000/v1/chat/completions \ -H "Authorization: Bearer sk-master-demo" \ -H "Content-Type: application/json" \ -d '{ "model": "my-chat", "messages": [{"role": "user", "content": "你好"}] }'

如果你能拿到上游模型的正常回复,说明网关已经跑通了。注意这里用master_key测试只是因为刚起步,正式环境应该生成独立虚拟 key。

3.3 配置负载均衡与故障转移

多供应商的核心价值是故障转移。假设你的主用模型比较稳,但也想保留一个备用模型,可以在model_list里再加一项:

model_list: - model_name: my-chat litellm_params: provider: provider_a model: provider_a/general-chat api_key: os.environ/PROVIDER_A_KEY - model_name: my-chat litellm_params: provider: provider_b model: provider_b/general-chat api_key: os.environ/PROVIDER_B_KEY - model_name: backup-chat litellm_params: provider: provider_c model: provider_c/fallback-chat api_key: os.environ/PROVIDER_C_KEY router_settings: routing_strategy: simple-shuffle fallbacks: - my-chat: ["backup-chat"] cooldown_time: 30 allowed_fails: 3 num_retries: 2

这里router_settings的意思是:

  • routing_strategy: simple-shuffle:在可用上游之间做随机轮询,避免每次都打同一个厂商。
  • fallbacks:当my-chat对应的两个上游都不可用时,自动尝试backup-chat。
  • cooldown_time:某个上游连续失败后,冷却 30 秒再放流量过去。
  • allowed_fails:连续失败多少次后判定为不健康。
  • num_retries:网关对单次请求的最大重试次数。

这套配置落地之后,你就不用再写“if 上游挂了 else 备用模型”的逻辑了。网关帮你做了健康判定和灰度和转移。

3.4 业务侧接入方式

业务侧接入其实是最简单的部分。不管前端、后端还是脚本,只需要把请求地址指向 litellm,模型名改成虚拟名,密钥换成网关生成的 key 即可。

Python 里用最普通的 HTTP 请求就能完成:

import requests resp = requests.post( "http://litellm-gateway:4000/v1/chat/completions", headers={ "Authorization": "Bearer sk-虚拟key", "Content-Type": "application/json", }, json={ "model": "my-chat", "messages": [ {"role": "system", "content": "你是一个助手"}, {"role": "user", "content": "帮我总结一下这篇文章"}, ], "temperature": 0.3, "stream": False, }, ) print(resp.json()["choices"][0]["message"]["content"])

这一步的关键点是:业务代码里不应该再出现任何真实厂商的模型名和密钥。模型名统一叫my-chat,密钥统一从环境变量或配置中心获取。以后加模型换模型,只发生在网关那一层。

4. 团队落地:密钥、预算与成本治理

4.1 虚拟密钥的生命周期

litellm 提供管理接口来生成虚拟 key。用它而不是 master key 去业务场景里调用,是标准做法。

curl http://localhost:4000/key/generate \ -H "Authorization: Bearer sk-master-demo" \ -H "Content-Type: application/json" \ -d '{ "models": ["my-chat"], "max_budget": 100, "budget_duration": "30d", "max_parallel_requests": 5 }'

这个接口的含义是:生成一把虚拟 key,只允许访问my-chat这个模型,30 天内预算上限 100 元,并发请求最多 5 个。

返回结果里会包含key字段,这把 key 只在生成时完整出现一次,之后只能看到脱敏信息。所以拿到之后要立刻存好,分发到对应服务的环境变量里。

你可以为每个业务线生成一把 key,甚至为每个人生成一把 key。这样出问题的时候,按 key 一查就能定位到是哪个服务、哪个调用方在捣乱。

4.2 配额限流与团队隔离

预算之外,限流同样重要。如果某个测试服务不小心写了个死循环,疯狂发请求,不仅消耗预算,还可能拖垮整个网关。通过虚拟 key 的max_parallel_requests和max_budget可以限制并发和总量,让一个团队的行为不至于影响其他人。

更细一点的团队隔离可以结合 key 绑定信息来做。不同项目组使用不同的 key,每个 key 只能看到自己可用的模型和预算。这样一来,A 团队超预算挂掉的时候,B 团队完全不受影响,排查问题也能按 key 快速分界。

4.3 成本追踪怎么落

成本追踪的第一步是配置持久化存储。litellm 默认可以跑,但重启之后日志就没了,团队场景肯定不行。可以在general_settings里指定database_url:

general_settings: master_key: sk-master-demo database_url: postgresql://user:password@localhost:5432/litellm

配置好数据库之后,每次调用都会记录输入输出 token 数、模型名、调用方 key、时间戳和估算成本。通过这些数据可以做几件事:

  • 按虚拟 key 汇总每个团队的月度消耗;
  • 按模型维度统计哪个模型最烧钱;
  • 对比不同供应商同规格模型的成本差异;
  • 把用量和财务账单对账。

如果团队已经有监控告警体系,还可以在网关层采集调用量、延迟和异常率,设置“某个模型成功率低于 95% 就告警”这样的规则。成本问题越早暴露越好,等月底账单出来再追查,通常已经晚了。

4.4 安全实践注意事项

网关集中了所有上游密钥,等于把安全风险也集中了。这里说几个我自己实际踩过或者见别人踩过的规矩:

  • master key 绝对不要出现在前端代码、日志、或者是发给第三方调用的接口文档里。
  • 生产环境网关应该跑在内部网络,不能对公网裸奔。
  • 每条业务线用独立虚拟 key,定期轮换;人员离职时及时吊销对应 key。
  • 日志采集时注意过滤请求体中的敏感内容,有些业务数据不该落到日志里。
  • 如果通过公网访问,必须开启 TLS。

我见过一个团队把 master key 写进前端配置里,结果 key 直接被浏览器网络请求面板看到了。这种事故虽然低级,但一旦发生,所有上游密钥都得跟着换,非常麻烦。

5. 常见问题与排查实录

5.1 所有请求都打到了同一个模型上

有段时间我发现某个虚拟模型名下的两个上游,流量几乎没有按预期均分,全部打到了第一个上面。后来排查发现是配置里第二个上游的健康检查没过,网关认为它不可用,所以一直不往那边转发。

检查思路:

  • 先看两个上游的api_key是否正确,环境变量有没有真正加载。
  • 确认第二个上游的模型名是否写对,有没有手滑少个字符。
  • 调大日志级别,看网关转发时的实际报错。

还有一种情况是配置顺序问题。litellm 会依次处理 model list,如果不做 shuffle 类策略,流量顺序可能并不均匀。把routing_strategy明确写上,目前体验最稳。

5.2 流式输出不生效或者卡住

接入流式输出是踩坑重灾区。常见现象是:直连上游模型流式正常,但经过 litellm 之后就感觉变卡,甚至会一直转圈。

排查清单:

  • 请求体里是否带了"stream": true,以及客户端是不是也在等增量。
  • 如果是通过 Nginx 转发,必须关掉缓冲,否则 SSE 流会被积压。Nginx 配置里给对应 location 加上proxy_buffering off;。
  • 网关和上游之间是否设置了合理的超时。流式场景下,上游可能长时间不发数据,需要把超时时间调大,避免中间层提前断开。
  • 确认客户端没有把聚合请求响应解析成普通 JSON。

流式链路比普通请求多几个环节,建议先用curl -N测试经过网关的原始流,看看是否正常,然后再回来看客户端代码。

5.3 超时和重试的尺度问题

上游模型响应慢很正常,尤其是生成长文本的时候。最初我遇到过网关默认超时太短,稍微长一点的请求就被切断。解决办法是在litellm_params里给单个模型调大超时:

litellm_params: provider: provider_a model: provider_a/general-chat api_key: os.environ/PROVIDER_A_KEY timeout: 600

超时值并不是越大越好。太大意味着一个慢请求会长时间占用网关连接,太小则会把本来能成功的请求误杀。我习惯先观察线上 P95 耗时,再设定 1.5 到 2 倍于 P95 的超时时间。

重试也要讲究。普通文本请求可以自动重试,但流式请求如果已经向用户返回了一部分内容,再重试就会产生重复片段。这类请求我建议关掉自动重试,让客户端自己做幂等控制。

5.4 数据库启动失败和日志积压

小规模试用时用 SQLite 很方便,但并发一上来,SQLite 的写锁问题就会冒出来,表现为页面卡顿、日志写入失败、启动报数据库被锁定。团队环境直接切到 PostgreSQL 或者 MySQL,别在这个问题上挣扎太久。

另外日志表会涨得很快。每一条请求都会落库,一天的读写量可能几十万行。建议给日志表做分区或者定期归档,不然一个月后查询会越来越慢。

以前我碰到过一次启动失败,原因是数据库连接串里的密码带特殊字符,没有做 URL 编码。这个坑很无聊但很常见,看到数据库相关报错时,先检查连接串。

5.5 鉴权 401 和 403

用 master key 测试没问题,换虚拟 key 就报 403,大概率是 key 没有授权对应的模型。虚拟 key 在生成时绑定了models,如果后续在配置里新增了一个虚拟模型名,旧 key 默认没权限访问它。

排查方法是用管理接口查 key 的信息,看绑定模型列表。需要扩容时,重新生成或者更新 key 的权限记录。

还有一个小坑:调用方如果误把 master key 当普通 key 传给业务服务,风险很大。master 和虚拟 key 要严格分区,一个管运营,一个管业务调用。

6. 最后聊聊我的使用习惯

文章的最后,不打算给你一份功能清单,只想分享一点实际经验。

我习惯把 litellm 配置纳入版本管理,但密钥永远只放环境变量或密钥管理服务。配置变更走 MR 评审,发布时由 CI/CD 重新加载配置。这样任何一个模型参数的修改都能留痕,回滚也容易。

环境上,开发、测试、生产各跑一套独立网关,数据库、虚拟 key、预算策略都分开。开发环境的预算可以设得很低,防止误操作烧钱。生产环境则只对受控的虚拟 key 开放。

新模型接入的时候,我不会直接切全部流量,而是先把它挂到一个单独的虚拟模型名下,用一小部分请求做对比测试,没问题再改配置切流量。这种做法在 litellm 里实现成本很低,收益却很大。

如果非要说一个最值得立刻做的事:先把所有上游 key 收回到网关里。只要做到这一步,后面加模型、换供应商、做成本分摊都会顺畅很多。litellm 这类工具并不神秘,核心价值就是把“接入模型”这件事从业务代码里抽离出来,变成一份可以管理、可以观察、可以控制的配置。希望这篇内容能帮你少踩几个坑。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询