资讯动态

用 litellm 构建多模型统一网关,解决大模型接入痛点

发布时间:2026/10/14 8:44:56 来源:尧图企业网站定制
接第三家模型接口的那天晚上我终于决定认真用一下 litellm。当时手头的项目已经为两家模型供应商各写了一套调用封装第二套代码还没稳定第三家又发来一套完全不同风格的 SDK。每个供应商的消息结构不一样鉴权方式不一样超时和重试策略也各玩各的。与其继续写第四个 if-else 分支不如把请求先统一收口到一个网关层让上游只认一种协议、一个地址、一把密钥。这篇文章就从我实际接入 litellm 的过程聊起内容包括它能解决什么问题、怎么快速跑通、怎么以网关模式给团队共用以及上线前必须想清楚的路由、预算、审计和常见报错。适合正在做多模型接入、或者在团队里负责模型调用层的开发者参考。1. litellm 在解决什么问题我为什么把一个小适配层做成了团队入口1.1 多供应商接入的真正痛点不是格式不同很多人以为多模型接入的麻烦只是请求格式不一样。实际上等你在生产环境同时跑两三家供应商的模型会发现下面这些事比格式更磨人每家供应商的 SDK 风格差异很大有的封装得特别好有的文档和实现完全对不上。密钥管理混乱。每个供应商一把 key前端要调模型就得把 key 下发到客户端要么就得在后端写多个代理接口。限流和报错语义完全不同。有的返回 429有的返回 503有的干脆一直 pending 不给你结果重试策略没法统一。想切换模型做 A/B 测试必须改代码重新发布产品经理的需求来得比发版还快。账单和用量数据散落在各家控制台没人能说清楚这个月到底花了多少钱、哪些业务消耗最多。格式转换反而是最好解决的那部分。litellm 真正的价值是把上面这些长期问题集中到一个入口处理。1.2 litellm 的两副面孔库模式和网关模式litellm 可以当普通的 Python 库用在代码里直接 import 然后调用也可以作为服务跑起来变成一个 HTTP 网关让任何语言的调用方都能用同一套 request 格式访问后面多个模型。两种模式处理的问题深浅不一样库模式适合在自己项目内部收敛调用逻辑改造成本低几乎不动现有架构。网关模式适合团队共用。所有模型请求都走一个地址密钥集中在服务端前端不需要关心背后到底用了哪家模型。实际项目里通常先从库模式试水验证没问题之后再把请求收敛到网关上。这样改动范围可控出问题也能快速回退。1.3 一个具体的收敛例子我之前在做某内部运营工具时业务方同时要文本生成和摘要两类能力。最初代码长这样def call_vendor_a(messages): # vendor A 的专用 SDK 调用 ... def call_vendor_b(messages): # vendor B 的 REST 调用消息格式完全不同 ... def unify(model_name, messages): if model_name vendor-a-1: return call_vendor_a(messages) elif model_name vendor-b-1: return call_vendor_b(messages)接第三家时我不仅要写call_vendor_c还要在unify里加分支然后处理不同返回结构的差异。改成 litellm 之后核心调用就简化成一条路径from litellm import completion def unify(model_name, messages): response completion( modelmodel_name, messagesmessages, ) return response.choices[0].message.content新增供应商时只需要在配置里加一个映射不用为每家的 SDK 重写业务逻辑。这一步做完后面的路由重试和用量统计才真正有了基础。2. 最小可跑的调用路径安装、密钥与第一批消息2.1 安装litellm 是纯 Python 项目依赖不算重安装命令很简单pip install litellm[proxy][proxy]这个 extra 会带上跑网关模式需要的依赖。如果你一开始只打算在 Python 代码里调用装核心包就够了pip install litellm我建议直接装带 proxy 的版本免得后续想转成网关模式又重新装一遍。Python 版本要求方面保持 3.9 以上基本都没问题。2.2 第一段可运行的调用假设你已经从某家模型服务商那里拿到了 API key。先设置环境变量然后再写代码export VENDOR_A_API_KEYsk-你的密钥然后跑这个最小示例from litellm import completion response completion( modelvendor_a/your-model-name, messages[ {role: system, content: 你是一个简洁的助手。}, {role: user, content: 你好请用一句话介绍你自己。} ], ) print(response.choices[0].message.content)注意model字段的写法厂商标识/具体模型名。这个斜杠前缀不是装饰litellm 靠它识别该把请求转给哪家供应商的适配层。如果你写错了前缀它会直接报 provider 找不到的错误。那段代码里的vendor_a是占位符实际操作时替换成你用的服务商标识模型名也换成你在那个平台开通的模型 ID。2.3 密钥处理最容易翻车的一环litellm 的 key 处理逻辑一开始容易让人困惑。它不是让你把所有供应商的 key 都塞进一个统一变量里而是每个供应商读自己约定的那个环境变量名。代码里你可以通过api_key参数临时显式传 keyresponse completion( modelvendor_a/your-model-name, messagesmessages, api_keysk-临时密钥, )但生产环境我更推荐环境变量方式原因有两个密钥不会散落在代码仓库里后续切换到网关模式时配置方式可以直接平移。这里有第一个容易踩的坑如果你用.env文件管理环境变量注意 litellm 读取环境变量的时机。它会在初始化客户端时读取所以改完.env必须重启进程不要指望热加载。2.4 怎么确认调用真的通了第一次跑通后建议先把日志打开export LITELLM_LOGDEBUGLITELLM_LOG设为 DEBUG 后控制台会打印出 litellm 内部选择的供应商、传输层发往的地址、以及一些关键耗时。这个日志能让你区分请求发到了哪家和实际上报错了什么后面排查问题会省很多时间。调试完把日志级别调回 INFO 或 WARNING避免生产环境日志量太大。3. 网关模式让整个团队只认一个模型地址3.1 为什么要把 litellm 跑成服务库模式改造成本低但它有个问题每个调用方都要在自己的进程里维护一份 litellm 配置和密钥。团队超过三个人以后每个人电脑上的环境变量开始变得不一样你无法统一控制版本。网关模式就是把 litellm 部署成一个常驻服务所有要调模型的上游应用只发 HTTP 请求到这个服务密钥、路由、重试策略都在服务端统一管理。另外还有个实际好处网关起来之后团队里用 Java、Go、Node.js 的同学不需要装 Python SDK 了。他们只需要按标准的 chat 补全请求格式往网关发 JSON就能用上后面接的任意模型。3.2 用一份配置文件启动网关我习惯用一个 YAML 来管理网关配置例如model_list: - model_name: text-service litellm_params: model: vendor_a/your-model-name api_key: os.environ/VENDOR_A_API_KEY - model_name: image-service litellm_params: model: vendor_b/your-vision-model api_key: os.environ/VENDOR_B_API_KEY这里的model_name是对外暴露的别名。上游调用方传text-service时litellm 才会根据配置映射到具体的vendor_a/your-model-name。这种命名解耦很有用将来你把背后模型从 vendor A 换成 vendor B只要改配置不用让调用方重新发版。启动命令litellm --config ./config.yaml --port 40003.3 上游怎么调用网关网关默认暴露的请求路径是对应标准对话补全接口的路径/chat/completions。用 curl 试一下curl http://localhost:4000/chat/completions \ -H Content-Type: application/json \ -d { model: text-service, messages: [{role: user, content: 你好}] }如果你希望网关对外提供流式输出可以在请求体里加stream: true。litellm 会负责把后面各家供应商的流式协议统一转换成标准的 SSE 格式。流式转换在自研适配层里是最费事的这里直接帮你省了。3.4 多人共用之前先把虚拟 key 开起来网关裸奔不是不行但一旦团队多人共用我强烈建议开启虚拟 key 认证litellm --config ./config.yaml --master_key sk-master-keymaster key 用来生成和管理虚拟 key。每个成员或每个应用拿一把不同的 key走网关时 litellm 会校验这把虚拟 key 是否有权限调用指定的模型。这样不仅安全还能为后面的预算和审计打基础。谁在用哪个模型、消耗了多少 token都能归因到具体 key 上。4. 路由、预算与日志上线之前必须想清楚的配置项4.1 重试和故障转移配置不当反而放大故障litellm 支持在同一份配置里给多个供应商配置 fallback。例如model_list: - model_name: text-service litellm_params: model: vendor_a/your-model-name fallbacks: [text-service-backup] - model_name: text-service-backup litellm_params: model: vendor_b/your-backup-model主模型超时或返回异常时litellm 会自动把请求转发给备选模型。这个功能看起来很美好但实际使用时要注意两点fallback 会掩盖主模型的真实故障。如果主模型因为参数写错一直报错请求会持续打到备用模型上你看到的结果是能用但成本和延迟都异常。不是所有错误都应该 fallback。限流和宕机可以走备用但请求参数非法这类错误fallback 十次也一样还会浪费资源。我建议在配置里用max_fallbacks限制转移次数同时务必把 fallback 事件记录下来。后面日志部分会说到怎么接。重试参数max_retries也要谨慎。默认重试策略未必适合你的场景比如遇到 429 限流如果你立刻重试可能连续撞上限流窗口。实践上更稳妥的做法是设置合理的超时并把重试次数控制在小范围让网关配合指数退避。litellm 对超时时间有具体配置项比如litellm_params: model: vendor_a/your-model-name timeout: 30 max_retries: 24.2 用量统计别再对着账单猜了网关模式跑一段时间后我有一次检查消费金额发现账单比预期高了不少。原因是有个测试脚本用了一个昂贵的模型而且没有做频率限制。litellm 的用量数据存在本地可以启动时指定数据库连接litellm --config ./config.yaml --database_url sqlite:///litellm.db后续你可以通过网关提供的接口查询 token 消耗按 key、按模型、按时间段统计基本能把账对上。如果用量数据需要接入团队自己的监控系统litellm 也允许把每次调用的 usage、latency、key 信息通过回调发出去。下面是我参考团队惯例写的一个最小日志回调import json import requests def send_log(data): requests.post(http://内部监控地址/log, jsondata, timeout3) def log_success(data): send_log({ event: call_success, model: data.get(model), key: data.get(metadata, {}).get(user_key), total_cost: data.get(response_cost), latency: data.get(completion_start_time), }) def log_failure(data): send_log({event: call_failure, error: str(data.get(exception))})然后注册回调import litellm litellm.success_callback [log_success] litellm.failure_callback [log_failure]这样做的好处是每次调用成功还是失败都有迹可查能回溯到具体 key、模型和错误信息。第一次接回调时记得先打日志别一上来就发到生产监控因为回调本身执行失败不应该影响主流程。4.3 预算和速率限制防止失控的最后防线litellm 提供多层限制按 key 设置总预算、每分钟请求数上限、每分钟 token 数上限。虽然这些限制无法做到精确到小数点但作为失控保护足够了。我在内部配置时一般这么干给测试 key 设置很小的预算和 rpm 上限避免测试脚本烧钱。给生产 key 设置略高于实际峰值的速率上限防止流量异常时把供应商限流打爆。设置整体预算告警超过阈值时回调里发通知。注意速率上限不是越严越好。限流策略如果设置得比实际峰值低网关会主动拒绝请求影响业务。先跑几天看看用量曲线再逐步收紧更稳。5. 排错实录三个让我折腾最久的报错与定位过程5.1 model 前缀不对导致的 not found现象是调用某个模型时报 provider not found但我确认这个模型明明存在。排查步骤先看日志里 litellm 解析出的 provider 是什么也就是它识别成了哪家供应商。检查model字符串的前缀。我那次写成了自定义别名但网关配置里没有显式映射到具体的供应商模型litellm 自然找不到对应适配器。确认当前模式下是否漏了配置映射。这类错误根因一般是模型命名和配置不一致。建议强制约定企业内部的别名统一放在网关配置里映射代码里永远只调别名不要直接在调用方写厂商/模型的原始格式。这样日后换模型不会牵动一堆服务。5.2 超时和限流反复出现现象是生产环境时不时报超时重试后偶发成功。我最初以为是供应商不稳定后来把日志时间线拉出来看才发现请求到 litellm 很快但 litellm 转发到供应商时部分请求要排队。当时默认的 timeout 太短重试又太频繁等于在排队高峰期反复插队。解决办法调大合理范围内的 timeout先确认正常情况下最长响应时间是多少。把重试次数降下来加上稍微等一会儿再重试的策略。区分哪些错误值得重试哪些错误重试无意义。这一步做完超时告警基本消失。经验是99% 的供应商不稳定其实是自己这边的参数没有对齐。5.3 改了环境变量但没生效现象是明明.env里更新了密钥网关重启后请求还是走旧 key。排查后发现问题在于进程启动目录不对litellm 从项目目录加载的是另一个.env文件。改的地方和实际读取的地方不是同一个文件。处理方式启动时显式指定环境变量文件不让它自动猜。或者干脆用 shell 直接 exportexport 完确保echo $VENDOR_A_API_KEY能看到新值。改完环境变量务必重启网关进程litellm 不会热加载环境变量。同样的坑也会出现在配置文件的api_key: os.environ/VENDOR_A_API_KEY这种写法上。如果网关启动后环境变量还没准备好litellm 会直接取到空值后面每个请求都会报鉴权失败。先确认环境变量存在再启动网关。5.4 一个通用的排查顺序如果你也遇到调用异常我建议按这个顺序排查比我当年乱试高效很多打开LITELLM_LOGDEBUG看日志里实际请求了哪个地址。用 curl 直接向网关发请求绕过业务代码确认是不是网关本身的问题。用 curl 直连最后的供应商接口确认 key 和模型名是有效的。检查网关配置里是否有 fallback 和重试掩盖了原始错误。日志、最小复现、逐层剥离这三步能解决绝大部分调用问题。6. 边界在哪什么时候不该用 litellm6.1 别为了用而用litellm 确实方便但它不是银弹。如果项目只接一家供应商而且没有切换模型、没有团队协作、没有成本统计的需求直接调那家 SDK 更简单。多一层抽象就多一个可以出故障的环节没必要为不存在的问题提前付费。我自己判断的标准很简单当你手上出现第二家供应商或者第二拨人要接入模型调用时再认真考虑引入统一层。在那之前写个薄薄的封装就够了。6.2 网关模式的固有代价网关模式下所有请求都多了一跳网络传输。内网调用延迟还好如果调用方和网关跨地域这一跳的耗时可能比模型本身还明显。网关服务本身也有并发上限团队规模大了之后要么给网关扩容要么把不同的业务拆成多个网关实例按模型或业务域分流。另外网关集中管理所有密钥安全风险也随之集中。一旦网关被攻破所有供应商的 key 都可能泄露。所以网关部署区域要放到可信网络里虚拟 key 和 master key 的权限要分开别让所有人拿到 master key。6.3 你的需求到底是统一 SDK还是统一网关选型之前想清楚一个关键区别如果只是代码层面想让调用方便用库模式如果目的是做团队级别的稳定入口、成本控制和权限管理用网关模式。这两者后续维护成本不一样前者基本跟着代码仓库走后者需要专门的人负责配置、容量、密钥和监控。从我实际操作中的体会来说litellm 适合的是这样一个时刻你已经有至少两个以上的模型供应商、至少两三个调用方、开始关心成本和权限。到那个阶段它会替你省下大量重复代码和排错时间。如果还不到这个阶段先留着它备用就好不用急着把整个架构架上去。

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

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

免费获取报价 →
↑