资讯动态

用litellm统一大模型接入:多模型路由与AI网关实践解析

发布时间:2026/10/13 15:58:57 来源:尧图企业网站定制
前阵子接手一个内部工具的改造需求写得很简单把原先只接一个模型的后端改成能同时接多家模型、还能自动切换。真动手才发现光是各家 API 的鉴权方式、返回结构、失败重试、计费口径就够写一个小型 SDK 了。后来我把目光放到 litellm 上问题一下子变得简单很多。litellm 是一个用 Python 写的统一大模型接入层只要在代码里调它就能用 OpenAI 风格的消息格式去访问几十种不同的模型服务GPT 系列、Claude、Gemini、本地 Ollama、vLLM 部署的模型都能接。它既能当一个 Python SDK 用也能以代理服务器的方式帮你部署一个 AI 网关适合团队协作、成本管理、灰度切换这类场景。如果你正在做多模型集成、模型路由、预算管控或者只是想少改几套 SDK这篇文章值得看完。我会从实际的接入过程讲起把配置、路由、成本、坑位一个个拆开尽量说人话也尽量把参数后面的原理讲清楚。1. 先看清问题为什么多模型接口会变成维护噩梦很多人刚开始接大模型 API 时都觉得“不就是发个 HTTP 请求吗”。确实单看任何一家的接口都不复杂但一旦数量多起来事情就会失控。1.1 你以为只是多接一个 API实际上多了三套逻辑我见过一个项目代码里并着三套模型调用逻辑一套走 GPT 风格的 chat completions一套走 Anthropic 风格的 messages 接口还有一套走本地方案。每套都有自己的鉴权头、请求体结构、错误码体系、返回字段命名。到了业务层你还得写三个转换函数把它们统一成自己内部的 Message 结构。这还只是“接进来”的部分。接进来之后还有重试问题A 家限流返回 429B 家超时返回 408C 家直接把连接断开。没有统一封装的话每种错误都要单独写处理分支。再往后是计费每家按 token 计价但 token 的统计口径还不一样有的按字符、有的按词、有的按消息轮次。真要精细对账的时候你会发现这些数据根本不是一套 SD 体系能算清的。这个阶段我最大的感受是AI 模型本身的推理能力反而不是瓶颈瓶颈全在“接口开发区”里。你越是想灵活切换模型越需要一个能把差异吞掉的中间层。1.2 litellm 切入的方式统一协议、统一返回、统一参数litellm 的核心思路不复杂对外只暴露一套 OpenAI 兼容协议对内负责把请求翻译成各家模型真正认识的格式。你在代码里构建的 messages 列表对 litellm 来说是标准输入它拿到之后根据你指定的模型名把请求改写成对应服务商需要的结构再把返回结果统一成 OpenAI 风格的 response 对象。参数层面也一样。OpenAI 体系的 temperature、max_tokens、stream 这些字段很多模型服务都支持但命名略有区别。litellm 做了一个参数映射层把常见参数标准化。遇到某些模型不支持的参数可以选择报错也可以选择自动丢弃这就对应后面要讲的 drop_params 开关。鉴权方面litellm 支持通过环境变量管理 API Key。它内部有一套优先级逻辑显式传入的 api_key 优先其次是环境变量再其次是代理服务器里保存的密钥。你不需要在业务代码里到处散落密钥集中管理反而更安全。2. SDK 还是代理先选对姿势再谈配置litellm 有两种使用方式很多人第一次接触时容易搞混。一种是在 Python 项目里直接 import 它当作 SDK另一种是把它作为独立进程跑起来当作代理网关。两种方式底层都是同一套封装但适用的架构完全不同。2.1 最小可用 demopip 装完就能在代码里调如果你是个人脚本、单服务、或者只想快速验证某个模型好不好用我推荐直接用 SDK 模式。安装很简单pip install litellm[all]我一般建议装 all 版本它会把常见服务商的依赖一起带进来省得后面报缺失模块。接下来设置环境变量再写一段调用代码import os from litellm import completion os.environ[OPENAI_API_KEY] sk-... os.environ[ANTHROPIC_API_KEY] sk-ant-... response completion( modelgpt-4o, messages[ {role: system, content: 你是一个简洁的助手}, {role: user, content: 用一句话解释什么是统一接口}, ], ) print(response[choices][0][message][content])跑完你会发现返回结构确实和 OpenAI SDK 几乎一样。这就是 litellm 的第一个价值不管你在 model 参数里填的是 gpt-4o、claude-3-5-sonnet、还是某本地模型的名称代码里那部分 messages 和 response 的结构都不用变。2.2 代理模式把 litellm 变成团队共用的 AI 网关代理模式是 litellm 真正拉开差距的地方。它本质上是把上面那套 SDK 封装成一个带路由、鉴权、预算管理能力的本地服务默认监听 4000 端口。你只需要一个配置文件就能让全团队的代码像调用 OpenAI 官方接口一样调用这个网关而网关背后可以接任意多家模型。先写一个简单的 config.yamlmodel_list: - model_name: gpt-4o litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY - model_name: claude-3-5-sonnet litellm_params: model: anthropic/claude-3-5-sonnet api_key: os.environ/ANTHROPIC_API_KEY litellm_settings: drop_params: true num_retries: 2 request_timeout: 60然后在命令行启动litellm --config config.yaml --port 4000启动之后任何能够调用 OpenAI 接口的客户端只要把 base_url 指到http://localhost:4000把 API Key 换成你在网关里配置的 master key就能直接使用。比如用 OpenAI 的 Python SDKfrom openai import OpenAI client OpenAI( api_keysk-1234, base_urlhttp://localhost:4000/v1, ) resp client.chat.completions.create( modelgpt-4o, messages[{role: user, content: 你好}], ) print(resp.choices[0].message.content)这里有一点需要注意代理里的 model 参数填什么取决于你 model_list 里怎么命名不一定要和上游模型名一致。你可以把 model_name 命名为任意字符串团队内部只认这个名字后面想换模型时只改网关配置业务代码一行都不用动。2.3 怎么选看你的调用方有几个如果调用方只有一个 Python 服务SDK 模式足够还少一层网络开销。但如果调用方是多个后端服务、定时任务、数据分析脚本、甚至前端直连那我就强烈建议上代理模式。统一网关之后密钥管理、调用审计、预算控制、模型灰度都能在一个地方完成而不是散落各处。代理模式还有一个隐性优势底层模型配置对于业务团队是黑盒。业务方只知道 model 名叫“gpt-4o”不知道网关后面其实已经悄悄把流量切了一部分到其他模型。这种解耦在做模型切换演练时非常有用。3. 代理模式的配置细节读懂 model_list 的组合逻辑代理模式是所有高级功能的基础所以值得把配置讲细一点。很多人拿到 config.yaml 就照抄出了问题不知道怎么排查归根结底是没有理解 model_list 的结构。3.1 model_name 与上游模型的关系在 config.yaml 里model_name 是你对外暴露的逻辑名litellm_params 里的 model 才是真正的上游模型标识。比如model_list: - model_name: my-assistant litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY - model_name: my-assistant litellm_params: model: anthropic/claude-3-5-sonnet api_key: os.environ/ANTHROPIC_API_KEY注意这里我写了两个条目model_name 都是 my-assistant但上游分别指向 GPT 和 Claude。这就是 litellm 做负载均衡和故障转移的入口多个上游可以共用一个逻辑名网关会按策略选择到底把请求发给谁。实际配置时litellm_params 里除了 model 和 api_key还能放 api_base、organization、temperature 等参数。如果你接的是内部部署的 vLLM 服务经常需要指定自定义的 api_base。如果是 Ollama本地默认地址是 8000你甚至不需要 api_key。3.2 环境变量、master_key、虚拟 Key 的权限层次代理启动时需要一个主密钥用法是在请求头里带Authorization: Bearer sk-1234。这个 master key 拥有全部管理权限可以创建新的“虚拟 Key”。虚拟 Key 是给团队里的不同成员、不同服务使用的可以分别设置额度、限速、过期时间。从安全角度讲我不建议所有人都拿 master key。之前在项目里吃过亏有人拿主密钥去调管理接口不小心把一个模型配置改了整组服务半夜开始报错。后面我把虚拟 Key 机制用起来团队里每个人一个 key最小权限原则立刻落实。创建虚拟 Key 最简单的方式是直接调管理接口curl -X POST http://localhost:4000/key/generate \ -H Authorization: Bearer sk-1234 \ -H Content-Type: application/json \ -d {budget: 20}返回结果里会带上新的 key 和 key 的 ID。这个 key 可以限制总预算、每分钟请求数、每分钟 token 数足够做到比较细的管控。3.3 OpenAI 客户端接入时最容易错的三个地方跑通代理模式之后大部分人会在接入环节翻车。我总结出三个高频点。一是 base_url 忘加/v1。OpenAI 官方 SDK 默认会在 base_url 后面拼接口路径比如 chat/completions 实际请求的是{base_url}/chat/completions。如果你只填http://localhost:4000它不会像我示例里那样带上/v1因为 litellm 的兼容端点监听在/v1/...。正确写法是http://localhost:4000/v1。二是自定义模型名没有出现在可用模型列表里。你要先确认 config.yaml 里写的 model_name 和调用代码里填的 model 完全一致包括大小写和特殊符号。代理启动日志里通常会显示已加载的模型列表先看一眼再调试能省不少时间。三是上游密钥写错但代理不报错。因为代理只是转发它把请求发到上游之后如果上游返回 401你收到的错误信息可能比较含糊。排查时先直接 curl 一下上游接口确认密钥本身有效再确认代理配置里的 api_key 是从哪个环境变量读进来的。4. 故障转移与负载均衡从单点调用变成冗余调度做多模型接入的最终目的通常不只是“能用”而是“坏了也能用”。模型服务是外部依赖任何一个服务商都可能限流、断连、报 5xx。litellm 的 Router 和代理配置都支持把多个上游绑到同一个逻辑名上让请求自动分发。4.1 同一个逻辑模型挂多个部署故障转移的前提是同一个 model_name 对应多个 litellm_params 条目。比如model_list: - model_name: main-llm litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY model_info: id: gpt-primary - model_name: main-llm litellm_params: model: anthropic/claude-3-5-sonnet api_key: os.environ/ANTHROPIC_API_KEY model_info: id: claude-fallback如果你通过 SDK 的 Router 对象来使用也可以把 model_list 直接喂给 Routerfrom litellm import Router router Router(model_listmodel_list, routing_strategyusage-based-routing) response router.completion( modelmain-llm, messages[{role: user, content: 测试}], )这里的核心是调用方始终只认逻辑名 main-llm网关自己决定把请求发给哪个上游。当某个上游连续失败达到阈值它会被自动标记为冷却状态后续请求改走其他可用上游。4.2 路由策略的取舍不止随机轮询litellm 提供了多种路由策略常见的有simple-shuffle简单打乱请求分配适合上游能力差不多的场景。least-busy按当前未完成的请求数分配适合上游响应速度差异较大的场景。usage-based-routing按每个上游过去一段时间的 token 用量占比分配适合想控制成本占比的场景。latency-based-routing偏向当前延迟更低的上游适合对响应时间敏感的场景。我实际用的最多的是 usage-based-routing尤其是接了多个价格差异明显的模型时。比如想把 70% 的流量给便宜模型、30% 给高质量模型就可以通过 cost 配置和策略参数来影响分配权重。不过要注意路由策略不是越复杂越好。least-busy 和 latency-based-routing 都需要代理具备持续观测能力在小流量场景下统计噪声很大反而会造成抖动。先想清楚你到底要优化什么再选策略。4.3 重试与冷却参数阈值设得太小反而容易误伤litellm_settings 里有两个参数经常被忽略allowed_fails 和 cooldown_time。router_settings: routing_strategy: usage-based-routing allowed_fails: 3 cooldown_time: 60 num_retries: 2allowed_fails 表示一个上游连续失败多少次后进入冷却cooldown_time 表示冷却多少秒。这两个值我一开始按官方默认的 2 次和 30 秒设结果发现生产环境里某个模型偶尔一次超时就导致它被标记成故障紧接着大量请求被切到另一个模型造成另一个模型也跟着限流。后来把 allowed_fails 调到 3、cooldown_time 调到 60情况才稳定。另外要注意失败不单单指 HTTP 5xx。超时、连接重置、上游返回内容格式异常都可能被计算为失败。如果你把 request_timeout 设得太小比如 10 秒而某个复杂任务本身需要 40 秒那么正常请求也会被当成失败。超时值和 allowed_fails 必须一起调否则故障转移机制会反过来制造新故障。5. 成本追踪与预算护栏多模型网关的必修课大模型调用不像传统 API 那样计价清晰token 消耗和单价是动态的。多人共用一个网关后成本会快速变复杂。litellm 在成本管理上做得比较完整但前提是你得先理解它的计费逻辑。5.1 litellm 是怎么算钱的litellm 本身不产生账单它只是把每次调用的输入输出 token 数乘上对应模型的单价算出一个估算成本。模型单价来自内置的模型信息表大部分主流模型的每百万 token 价格都有维护。如果你用的是内部部署模型或自定义模型也可以自己指定 price 信息让成本估算更准确。在代理模式下每次请求完成后litellm 会记录元数据用户、模型、输入 token、输出 token、估算成本、延迟、上游状态。这些记录可以通过管理接口查询也可以通过回调推到外部系统。我在部署时习惯把成功回调接到日志平台这样每个调用都有完整审计链路。5.2 用虚拟 Key 给团队划预算虚拟 Key 最实用的地方就是预算隔离。某团队要跑实验、某业务要上线、某同学只是临时测试都可以各发一个 key分别设置 budget。举个例子给测试环境创建一个总预算 50 美元的 keycurl -X POST http://localhost:4000/key/generate \ -H Authorization: Bearer sk-1234 \ -H Content-Type: application/json \ -d { key_alias: test-env-key, budget: 50, max_parallel_requests: 10, model_max_budget: {main-llm: 30} }budget 是总预算上限model_max_budget 可以针对单个模型再设上限。当某个 key 的用量达到上限代理会直接拒绝后续请求并返回 429。这个机制用来防止无人看守的定时任务半夜跑到天亮非常有效。预算快到上限时litellm 还可以通过回调发告警比如在 budget_remaining 低于某个阈值时调用 webhook。你可以把告警接到内部消息机器人实现“花到八成就报警”。5.3 把用量接到现有可观测体系里litellm 的成本和请求日志不是只能留在它自己数据库里。在 litellm_settings 里加上回调就能把数据推给外部系统litellm_settings: success_callback: [prometheus]如果你用 Prometheus 那套体系litellm 可以直接暴露指标端点。如果团队更习惯用日志平台也可以配置自定义回调把每次请求的 dict 原样写入日志流。这样做的最大好处是网关上的现象和业务侧的调用日志能关联起来排查问题时不用两头切。我当时就是把 spend 日志和业务日志打到同一个采集目录用 trace ID 关联。出了问题先看业务侧是哪次调用再去 spend 日志里翻对应模型、对应 key、对应 token 数整个链路非常清晰。6. 踩坑复盘参数、并发、超时这些隐藏问题最后集中说说我实际踩过、也帮别人排过的坑。这些点官方文档都写过但一般不到报错时刻不会真正重视。6.1 drop_params 是省心助手也可能成为静默杀手drop_paramstrue 的含义是如果某个参数上游模型不支持litellm 会自动把它从请求里丢掉而不是报错。好处显而易见同一套参数可以安全地发给不同模型。坏处也很明显你会失去报错提醒某些业务关键参数可能被悄悄忽略。比如你同时接了一个支持 reasoning_effort 的模型和一个不支持的模型。开启 drop_params 后不支持的模型那边不会报错但它也不会执行你期望的推理控制输出的质量可能和你预期的差一大截。如果你对参数有强要求宁可让调用失败也不要静默降级。我的建议是可以先开着跑通流程等业务稳定后关掉让异常暴露出来。6.2 异步与并发Router 对象不是默认并发安全的litellm 提供异步接口acompletion、arouter.completion。如果你的服务是 FastAPI 这类异步框架却直接在线程池里调同步方法很容易把事件循环卡住。正确做法是使用异步版本并且用信号量限制并发防止突发流量把上游压垮。import asyncio from litellm import Router router Router(model_listmodel_list) sem asyncio.Semaphore(20) async def ask(messages): async with sem: return await router.acompletion( modelmain-llm, messagesmessages, )并发数不宜直接拉满。大模型推理是资源密集型服务上游通常有 RPM/TPM 限制你在网关侧把并发压得太高收到的 429 会比成功响应还多。6.3 代理本身的超时与健康检查代理模式跑一段时间后可能会遇到“网关没问题但请求卡住”的情况。常见原因是某个上游长时间不响应而请求没有设置超时连接被一直占用。务必在 litellm_settings 里显式设置 request_timeout同时配合 num_retries避免一个慢请求把所有 worker 拖死。如果你是 Docker 部署还要记得给容器设置健康检查探测/health/liveliness或/health/readiness接口。编排平台会根据健康检查自动重启异常实例否则代理进程僵在那里你只能手动救。6.4 密钥优先级显式 api_key 覆盖环境变量litellm 读取密钥的优先级是litellm_params 里显式写的 api_key 优先于环境变量。这个看起来理所当然但配置多了以后容易出现“凭据张冠李戴”的情况。比如你明明在 config 里写了 A 家的 key但环境变量里也有一个 A 家的 key而且格式一样你很难判断实际生效的是哪个。排查方法是启动代理时加 verbose 日志或者临时在配置里删掉显式 api_key再看行为是否变化。如果行为没变说明之前生效的是环境变量里的那一个。对我个人来说litellm 真正省下的不是第一次接入的时间而是后续每次“换模型”都只需要改网关配置的从容。多模型并存这件事做一两次是临时方案做多了就会变成基础设施。如果你正在从单模型走向多模型或者被团队里五花八门的调用方式搞得头疼可以先用一套最小配置把网关跑起来再逐步把成本、预算、故障转移这些能力加进去。后面你会发现真正重要的从来不是某个特定模型有多强而是你切换模型时的代价有多低。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑