多模型接入治理:用Litellm网关统一大模型API、路由与成本管理
发布时间:2026/10/13 17:32:22 锦皓数字建站

如果你手头同时维护着两个以上大模型接口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 是进程内的依赖要跟业务代码一起部署。一旦多个服务都引用同一个 SDKSDK 升级就得所有服务一起升否则行为不一致。而且密钥仍然在每个服务的环境变量里安全边界很模糊。如果某个服务的日志把请求体打出来密钥也就跟着泄了。独立网关则把这些问题收敛到了一起。所有业务服务通过 HTTP 访问网关业务代码里几乎没有模型厂商的概念。网关升级不影响业务密钥只放在网关这一层模型路由的变化由网关处理。代价是多一跳网络延迟但绝大多数场景下这点延迟是可以忽略的。我做过一个对比方便理解维度SDK 封装litellm 网关部署方式跟随业务服务独立部署升级成本所有引用服务发版重启/滚动升级即可密钥管理分散在各服务集中在网关多服务共享不方便天然支持额外延迟无多一跳内网请求故障影响只影响当前服务网关不可用则全链路影响网关的问题也很明显它变成了一个关键依赖部署上需要做高可用。但这和数据库、缓存、消息队列一样属于基础设施建设成本可以接受。2.2 模型别名与路由机制litellm 最核心的抽象是“模型别名”。配置中的model_name并不是上游真实模型名而是你业务系统里定义的逻辑名。比如业务侧都叫my-chat网关配置里可以把这个逻辑名同时指向 A 厂商和 B 厂商的模型。请求进来后网关会按路由策略从一组真实模型里选一个去转发。这背后做了几件事同一个别名可以对应多个上游天然支持负载均衡某个上游连续失败时网关会自动把它隔离一段时间并尝试其他上游可以配置 fallback主模型失败后自动走备用模型可以通过权重控制流量分配比如 90% 走模型 A10% 走模型 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_KEYxxx \ -e PROVIDER_B_KEYxxx \ --name litellm-gateway \ your-registry/litellm:stable注意这里your-registry/litellm:stable要替换成你们实际镜像仓库里的地址。配置文件和密钥通过挂载和环境变量传进去镜像本身保持只读。3.2 写第一份 config.yamllitellm 的配置就是一个 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_urlgeneral_settings: master_key: sk-master-demo database_url: postgresql://user:passwordlocalhost: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 这类工具并不神秘核心价值就是把“接入模型”这件事从业务代码里抽离出来变成一份可以管理、可以观察、可以控制的配置。希望这篇内容能帮你少踩几个坑。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。