LiteLLM 大模型 API 网关实战:统一多模型接入、路由与成本管控
如果你同时对接过两家以上大模型厂商的 API大概率撞见过同一个尴尬场景相同的请求逻辑换一家服务商就得重写一遍接入层。请求体格式不一样、鉴权方式不一样、返回结构也不一样连报错信息都各说各话。我在某次内部项目改造里被这个问题折磨了快两周最后把入口收敛到一个叫 LiteLLM 的代理层上才算把“多家模型随便切”这件事真正落地。这篇就围绕 LiteLLM 讲透它是干什么的、怎么部署、核心配置怎么理解、有哪些我实测下来值得注意的坑。LiteLLM 本质是一个统一的大模型 API 网关。它对外提供一套风格统一的接口内部帮你转发到不同厂商同时把 Key 管理、预算控制、模型路由、成本统计这些杂事一并收编。适合团队里同时用多家模型、或者想把模型调度能力做成公共服务的同学。不管你是后端开发、算法工程师还是自己做 AI 应用的独立开发者只要不想被某个单一模型厂商绑死这套东西都能省下大量重复劳动。1. 先弄明白它解决什么问题很多人在第一次听说 LiteLLM 时容易绕进一个误区以为它只是“又一个模型聚合库”。实际上它可以分成两层看明白这两层之后你就能判断自己到底需不需要它。1.1 它和直接调 SDK 有什么不一样直接用各家 SDK代码可以工作但你把“模型接入”这件事写死在了业务代码里。比如你在某处硬编码调用了某家平台的 chat 接口后来想换另一家的模型光是把请求体格式改对就可能花半天更别提处理鉴权方式差异、超时重试策略这些细枝末节。有了 LiteLLM 之后业务代码里只跟“一个标准样式”打交道。它对外暴露的是兼容主流调用风格的接口你原来如果习惯用某种请求结构把 base_url 指到 LiteLLM 服务地址上基本就能无缝迁移。我自己的做法是所有模型调用全部改成走 LiteLLM 代理业务方根本不关心背后到底是哪家在响应。这样做直接带来两个好处切换模型时不用改业务代码只需要调整代理层的配置可以在代理层集中做降级、负载均衡、Key 轮询和预算兜底1.2 它替你扛住的那些脏活累活真正用过之后你会发现LiteLLM 解决的不只是“格式统一”。它其实把一个模型接入团队最不愿意维护的四处基础设施都做了收敛第一处是多厂商兼容不用自己维护一堆 SDK 依赖第二处是安全管控调用方不再直接接触上游真实密钥而是拿到代理下发的虚拟 Key每个人的额度、模型范围可以分别限制第三处是成本能见度每一笔请求花了多少钱、哪个业务方消耗最大都有日志可查第四处是高可用如果某个上游模型抽风可以配置自动切换到备用模型。我最看重的是第二处。以前给同事发真实 Key既不敢给权限限制又怕泄露。现在通过代理层签发只读 Key配额、速率、预算都能单独设定心里踏实很多。2. 部署一个最小可用网关先跑起来再深入纸上谈兵没有意义我建议你直接在本地跑一个最小实例。LiteLLM 部署非常轻本质上就是一个 Python 服务一条命令就能拉起。2.1 安装与启动流程建议用虚拟环境安装避免污染全局 Python 环境。python -m venv .venv source .venv/bin/activate pip install litellm[proxy]装完之后你可以直接用命令行参数启动一个极简代理litellm --model gpt-3.5-turbo --port 4000但我不建议长期用这种方式因为真正的配置项多了之后命令行根本管理不过来。更推荐的做法是用配置文件启动litellm --config config.yaml服务默认起在 4000 端口如果你本机端口被占了可以在配置里改。启动之后LiteLLM 会输出日志看到Uvicorn running on http://0.0.0.0:4000类似的字样就说明成功了。2.2 写第一份模型路由配置一个最小的 config.yaml 长这样model_list: - model_name: gpt-3.5-turbo litellm_params: model: gpt-3.5-turbo api_key: ${OPENAI_API_KEY}这里需要解释一下 model_name 和 model 的区别。model_name 是你在代理层暴露给调用方的名字业务代码只认这个名字model 是 LiteLLM 实际去上游厂商那里调用的真实模型标识。它们可以一样也可以不一样。比如你可以在代理层把 model_name 命名为 our-chat背后转发到各家不同模型对外完全透明。配置文件里也支持直接用环境变量注入密钥避免把敏感信息提交到 Git。我的习惯是所有上游 Key 全部放在环境变量里config.yaml 只写变量引用这样换环境时只需要改环境配置。2.3 用标准客户端验证连通性代理起来之后验证方式很简单。如果你平时用某种通用客户端工具发请求把地址指向本地就行。我用一段 Python 示例来演示from openai import OpenAI client OpenAI( api_keysk-anything, base_urlhttp://localhost:4000 ) response client.chat.completions.create( modelgpt-3.5-turbo, messages[ {role: user, content: 你好请用一句话介绍自己} ], temperature0.7 ) print(response.choices[0].message.content)这里有个小细节请求头里的 Key 其实可以随便填一个字符串因为 LiteLLM 在没有开启虚拟 Key 校验时不校验这个字段的真实性。但建议还是养成填正式 Key 的习惯后续开启权限控制之后这里就必须是代理签发的合法 Key 了。跑通这一步你已经拥有了一个统一的模型入口。剩下的复杂度都是在入口之上叠加管理能力。3. 核心机制拆解模型路由、虚拟 Key 与预算控制只跑通代理转发没什么稀罕的LiteLLM 真正值钱的是它这一层丰富到有点过分的管理能力。我挑三个最常用的机制拆开讲全部来自实际压测和配置经验。3.1 模型路由是如何工作的模型路由是 LiteLLM 的招牌能力简单说就是你可以给同一个 model_name 挂多个上游模型代理按策略挑选一个响应。这个机制在两种场景下特别实用一是想在多个模型之间分摊流量成本二是想让特定模型当主力、另外几个当备胎。配置里通过 model_group 和 routing_strategy 控制router_settings: routing_strategy: simple-shuffle model_list: - model_name: our-chat litellm_params: model: gpt-3.5-turbo api_key: ${OPENAI_API_KEY} tpm: 100000 rpm: 1000 - model_name: our-chat litellm_params: model: claude-3-haiku api_key: ${ANTHROPIC_API_KEY}这样配置之后调用方仍然只发 modelour-chat代理会按策略在 gpt-3.5-turbo 和 claude-3-haiku 之间做选择。如果我故意把某一家的模型名写错让它起效失败同时配置了 fallback流量就会自动切到另一家这在高可用场景里是救命级别的能力。Routing strategy 我试过几种simple-shuffle 适合随机分发和简单的压力分散least-busy 会根据当前负载选择空闲模型。如果你拿不准建议先用 simple-shuffle逻辑简单、排障容易。3.2 架构上的容灾设计Fallback 与超时把模型调度交给代理之后最直接的好处是可以把 Failover 逻辑从业务代码里抽走。我配置过一个很典型的容灾方案router_settings: fallbacks: [ {our-chat: [gpt-3.5-turbo-16k, claude-3-haiku]} ]实际上我会把 fallbacks 放在更细致的位置按我测试的效果必须要确认LiteLLM 只在遇到特定类型的报错比如限流、超时、服务不可用时才触发 fallback而不是所有报错都让它切。这意味着你需要在配置里叠加连接超时和重试参数litellm_settings: connect_timeout: 10 read_timeout: 300 num_retries: 3 request_timeout: 600需要注意timeout 不能盲目调大。曾经我把 read_timeout 调到 300 秒结果发现量一大之后连接堆积严重因为部分请求卡住进程不释放。最后我把 read_timeout 控制在 60 秒到 120 秒之间num_retries 固定成 2 次效果均衡得多。建议你上线前用真实流量压一遍再根据 p99 延迟倒推合理超时值。3.3 虚拟 Key 体系安全管控的核心这是 LiteLLM 里我反复安利给同事的功能。它允许你签发一套独立的虚拟密钥体系调用方拿到的不是你的真实上游密钥而是由 LiteLLM 生成的虚拟 Key。你可以在签发时直接指定这个 Key 的预算上限、速率限制、可用模型范围、过期时间。签发的入口有两个一个是通过页面管理界面另一个是通过/key/generate接口。我更习惯用接口来签发配合脚本可以作为自动化申请流程的一部分curl -X POST http://localhost:4000/key/generate \ -H Authorization: Bearer sk-master-key \ -H Content-Type: application/json \ -d { models: [our-chat], max_budget: 10.0, rpm_limit: 60, duration: 30d }返回结果里会带一个 sk- 开头的虚拟 Key这个 Key 在有效期内可以正常调用代理但无论如何都无法通过代理拿到上游的真实密钥。我把这种方式应用到项目组之后再也没出现“同事把 Key 贴在群里”的破事。价格和配额限制也很好理解max_budget 是硬顶一旦耗尽这个 Key 会立刻返回额度不足的报错rpm_limit 是每分钟请求数限制适合控制疯狂循环调用的情况。对内部团队我会把预算卡得松一点主要卡速率对对外分发预算和速率都严格收紧。4. 可观测性与成本核算让每一分钱都看得见聊完控制和转发一定要讲一讲“看得见”的部分。很多人用代理只是图省事但 LiteLLM 的统计能力在我自己的项目里甚至成了主要卖点。4.1 请求日志与 Token 统计LiteLLM 默认会把请求日志写入本地的 SQLite 数据库包括模型名、请求耗时、输入输出 Token 数、费用估算、虚拟 Key 标识等。如果你部署在单机环境这个默认方案够用但要是正式环境多实例部署必须换成 PostgreSQL否则日志会散落在不同节点上。我碰过一次本地数据库锁死的情况单实例高并发写入 SQLite偶尔出现 database is locked。最后直接把数据库切到了 PostgreSQL这个问题就根治了。如果你也是小规模使用注意控制一下日志写入频率或者配置批量刷盘策略也能缓解。4.2 用查询接口做成本分析除了看日志表LiteLLM 还提供了一组管理端点。我常用的有这些/spend/logs查所有请求的计费明细/spend/keys按虚拟 Key 聚合花费/global/spend看整体大盘比如我想知道上周某个业务方在哪个模型上花钱最多直接查 spend 相关端点一目了然。实际工作中我习惯把这些端点接到内部监控看板上每周自动拉一次成本报表。曾经发现某个客户对某个模型产生了超出预期的调用量靠 Key 维度的统计很快定位到了异常调用方及时做了限流。这个价值很难用数字衡量但遇到一次就知道它的好。4.3 自定义模型价格的补充如果你用的是非标准模型或者自部署模型LiteLLM 的成本估算未必准确。它内部有一套主流模型的价格表但自建模型或者稀缺模型无法自动算准。这时可以通过模型参数里的 price 字段手动维护litellm_params: model: ollama/llama3 input_cost_per_token: 0.000001 output_cost_per_token: 0.000002我一般会在每次上线新模型时顺手补充价格参数避免月底对账时“预估花费”和“实际账单”差距大到离谱。不要指望默认行为帮你搞定一切花 5 秒钟配一个价格后面省心很多。5. 实测过程中最容易踩的坑任何工具都有“文档里没写清楚”的部分。LiteLLM 整体成熟度挺高但以下几个问题我实际使用中遇到过罗列出来帮你避坑。5.1 常见报错定位表现象常见位置排查思路提示没有可用模型路由配置检查 model_name 是否与请求中的 model 完全一致请求超时上游服务用 curl 直连上游确认网络状况再检查 timeout 参数虚拟 Key 无效权限管理确认请求头用的是代理签发 Key不是环境变量里的上游 KeyFallback 未触发路由策略确认报错类型属于配置中开启的 fallback 条件数据库锁死持久化存储多实例时需要升级为 PostgreSQL不要用 SQLite 硬扛日志中有敏感信息监控体系检查请求内容是否记录在日志表里必要时脱敏5.2 关于日志脱敏的补充提醒这一点得专门提LiteLLM 默认会在日志里记录请求和响应体内容。如果你传输的是业务敏感数据建议在配置里关闭内容记录只留元数据。litellm_settings: disable_logging: false turn_off_message_logging: true关闭消息体日志之后你仍然能看到调用了哪个模型、花了多少钱但看不到具体对话内容。对合规要求高的场景这一步必须做别等审计发现问题再回头补。5.3 多实例部署的注意事项如果请求量上来了单实例跑 LiteLLM 会成瓶颈它本质还是一个无状态代理层完全可以水平扩展。但这里有一个反直觉的地方多个实例共用同一个数据库时虚拟 Key 的配额扣减可能会出现竞争。我当时用双实例跑了一段时间发现偶尔有两个请求几乎同时扣减额度导致总额微量超支。最稳妥的做法是要么把虚拟 Key 配额放宽一点留出余量要么用外部 Redis 做配额中心。LiteLLM 本身支持一些外部协调但需要额外配置。如果只是做内部工具稍微放宽预算余量就能解决大部分问题。6. 从代理到平台LiteLLM 还能做什么当你把 LiteLLM 跑顺之后它其实已经不只是“模型代理”这么简单了。我目前的使用方式更像是一个轻量级的 LLM 接入平台。6.1 用管理接口搭建内部模型商店因为虚拟 Key 的签发、配额、计量都齐了完全可以封装成内部平台。同事自助申请 Key、选择模型、配置额度不需要找你手动处理。我实践过一个类似自助申请的能力大约只写了几十行代码调用它的管理接口就可以完成。这个方向很适合做内部开发者工具节省沟通成本立竿见影。6.2 与开源生态的适配LiteLLM 比较讨喜的一点是对主流开发框架都有接入方案。比如很多本地应用工具要配置模型 API 地址时直接填http://localhost:4000就能工作。你甚至可以把多个不同的应用请求统一收敛到一个网关方便做成本核算和权限回收。我在一个跨平台系统的模拟改造中让三个原本各自连不同厂商服务的应用全部指向 LiteLLM只花了半天改完所有配置。从那以后新增模型、切换供应商就再也不用重新发版了。6.3 需要留意的局限LiteLLM 不是银弹。它比较适合文本生成类任务虽然也支持一些多模态模型但我实测下来对图片输入这类场景的支持不如纯文本流畅。另外它内部封装的模型参数并不覆盖所有厂商的全量选项个别冷门参数可能无法直接透传。如果你只需要一家固定模型用它反而多了一层复杂度。只有当你有“多模型、多Key、多团队、计量计费”这类真实痛点时它才真正值回票价。7. 个人经验与最终建议我自己把 LiteLLM 落地的过程里最深刻的体会是不要一上来就追求复杂配置。第一次使用时只配置一个模型、一个路由跑通调用链再逐步叠加虚拟 Key、预算和 fallback。越级配置只会让你在排障时多绕很多弯路。关于稳定性我的建议是默认配置先跑一周再把超时、重试这些参数调到贴合自己流量特征的位置。不要照抄网上的参数因为上游厂商限流策略、你的请求体大小都不一样最优值只能来自你自己的压测数据没有捷径。最后分享一个小技巧——把 LiteLLM 的配置目录纳入版本管理并用 CI 做一次配置校验确保改动后语法正确再发布。很多时候线上故障不是代码引入的而是改了配置没跑测试直接上线导致的。这个习惯帮我避免了至少三次“看起来像事故”的尴尬时刻。如果你正准备接模型网关从最小配置起步逐步把它养成整个团队的模型接入标准。