大模型应用做到一定规模后最让人头疼的往往不是模型效果而是接入流程本身A 家今天发了新 SDKB 家明天改了限流策略C 家的返回结构跟别家完全不一样业务代码里的 if-else 越堆越厚每换一次供应商都要动一遍代码。LiteLLM 这个开源项目就是为了终结这种混乱而生的——它把主流大模型供应商的接口统一成一套兼容格式并内置了负载均衡、故障回退、费用统计、预算管控等网关级能力。无论你是正在做 AI 应用的开发者还是需要给团队搭统一模型入口的平台工程师这篇文章都值得看完。1. 这个项目是什么多模型调用的“总闸门”1.1 为什么应用会卡在多供应商泥潭里先说一个我自己的真实场景。早先做一个智能客服系统最开始只接了一家模型服务代码写得很舒服。后来为了效果对比和降本陆续接入了另外两家灾难就开始了每家供应商的 SDK 都不一样有的直接调用随手写的 HTTP 封装有的必须用官方 SDK请求参数五花八门系统提示词放在哪个字段、温度参数叫什么名字各家有各自的习惯返回结构差异更大有的把结果放在 choices 里有的直接放在 text 字段有的还要先解析 tool_calls限流和超时策略全靠自己写重试写浅了不稳定写深了又容易把下游打爆。代码里慢慢就出现了一堆if provider A这种分支加一个新供应商就要在所有调用点补条件。到后来团队里已经没人敢动那段调用逻辑生怕改漏一个分支导致线上事故。LiteLLM 解决的就是这个问题。它把几十上百家模型供应商的调用统一成一套接口格式你的业务代码只需要面向这套统一格式编程背后是哪家供应商、什么模型、走什么协议都由 LiteLLM 帮你翻译和转发。用句话总结它就是多模型世界的总闸门或者叫模型路由器。1.2 LiteLLM 的能力边界LiteLLM 不是一个大而全的 AI 平台它的核心能力可以分成四块统一接口提供和业界标准兼容格式一致的 SDK 和 HTTP 代理所有供应商的对话补全、嵌入、图片生成等能力都通过同一套方法调用。智能路由支持在多个模型、多个供应商账号之间做负载均衡主模型挂了自动回退到备用模型限流时自动重试不用业务侧关心。成本与权限能统计每次调用的 token 消耗和费用给不同团队、不同成员发放虚拟密钥按预算上限管控。可观测扩展可以通过回调把调用日志、token 数、延迟数据推到自己的监控系统里方便做费用归因和告警。也要说清楚它做不到什么。LiteLLM 本身不训练模型、不托管模型权重它只是一个调度层所有能力都来自上游供应商。如果你的上游模型本身效果不好或者某个供应商直接停服了LiteLLM 能做的只是尽快切换到备选并不能凭空变出模型。也不要指望它帮你优化 prompt它保证的是“接口稳定、路由可靠、账单清楚”prompt 工程是另一门功课。2. 五分钟跑通安装、密钥与首次调用2.1 安装与版本选择LiteLLM 是个 Python 库安装非常简单干净的环境里一条命令就够pip install --upgrade litellm如果你后面要用代理模式给团队提供 HTTP 接口建议直接装带 proxy 依赖的版本省得后面补包pip install litellm[proxy]我建议所有项目都用虚拟环境管理依赖别直接往系统 Python 里装。原因很简单LiteLLM 依赖比较多升级 SDK 或系统包时很容易把版本搞乱而大版本升级时有些配置项会改名有一个隔离环境方便你随时重建。有一点提醒这个项目迭代速度很快几乎每周都有版本更新。不要盲目追最新先读一下当前版本的发布说明再决定要不要升。特别是你已经在生产环境跑了代理服务的情况下升级前务必在测试环境先验证一遍 YAML 配置和路由行为。2.2 用 Python SDK 完成第一次请求装好后第一件事就是配密钥。LiteLLM 约定每家供应商的 API 密钥通过对应的环境变量读取。你不需要在代码里写密钥只要在启动前设置好环境变量export PROVIDER_A_API_KEYsk-你的密钥然后写一段最简单的调用import litellm response litellm.completion( modelprovider-a/model-alpha-v1, messages[ {role: user, content: 用一句话介绍你自己} ], ) print(response.choices[0].message.content)看到没有不管背后是哪家供应商返回的对象结构都是统一的choices→message→content跟业界标准兼容格式完全一致。你不需要关心 A 家返回的是text还是generated_text也不需要手动解析tool_callsLiteLLM 全帮你处理好了。这里关键的model参数格式是供应商前缀/模型名。前缀由 LiteLLM 统一规定模型名必须和上游供应商实际提供的模型标识保持一致。比如provider-a/model-alpha-v1就表示调用供应商 A 的某个具体版本。2.3 模型前缀与别名代码稳定的关键很多第一次用 LiteLLM 的人会忽略一个设计上的好处模型前缀把“供应商”和“模型名”两层信息组织在了一起切换供应商时你只需要改配置不必改业务代码。更推荐的做法是给模型起别名。业务代码里从头到尾只写smart-model这种业务语义的名字具体映射到哪家供应商的哪个模型全部放在配置层。后面 A 家涨价了你想换成 B 家的模型只需要改一个配置项代码一行不动。代理模式下你可以在 YAML 配置文件里定义model_name作为对外暴露的名字内部通过litellm_params.model指向真实的上游模型。纯 SDK 模式下也有对应的别名机制但实际开发中我建议大家直接用代理模式管理别名后面第 4 节会详细讲。除了一般的补全调用嵌入向量的用法也差不多response litellm.embedding( modelprovider-a/embedding-model-x, input[需要嵌入的文本], )这样一套接口风格从对话到向量检索全项目都能统一写。做 AI 应用的同学会发现代码里再也不用维护 N 套供应商封装了。3. 网关级能力回退、重试与负载均衡3.1 故障回退怎么配才可靠按上一节的写法每次调用都直连某一家供应商这只能算“统一接口”还没体现出网关的价值。真正让你省心的是路由策略尤其是故障回退。我用一个例子说清楚。假设主模型是供应商 A 的model-alpha-v1备用模型是供应商 B 的model-beta-v2希望当主模型报错或超时时请求自动打到备用模型上from litellm import Router router Router( model_list[ { model_name: smart, litellm_params: { model: provider-a/model-alpha-v1, api_key: os.environ/PROVIDER_A_API_KEY, }, }, { model_name: smart, litellm_params: { model: provider-b/model-beta-v2, api_key: os.environ/PROVIDER_B_API_KEY, }, }, ], fallbacks[ { model_name: smart, fallbacks: [provider-b/model-beta-v2], } ], timeout30, num_retries2, ) response router.completion( modelsmart, messages[{role: user, content: 你好}], )这段代码里Router是 LiteLLM 提供的核心路由对象。model_list里有多条记录它们共享同一个对外名字smartfallbacks则声明了回退顺序。当第一条记录对应模型调用失败Router 会按配置自动尝试备用模型。回退配置有几个细节需要记住。第一回退目标是供应商前缀/模型名不是model_name别写反了。第二触发回退的条件包括上游返回限流429、服务不可用5xx、超时和网络错误LiteLLM 默认帮你判断不需要逐个枚举。第三不同版本对 fallbacks 在 YAML 里的写法有过调整升级大版本后务必对照官方文档看看配置项是否改名。3.2 负载均衡与重试的心得负载均衡稍微进阶一点但理解了模型列表的写法就很简单同一个model_name对应多个上游部署LiteLLM 会把请求分发到不同部署上。典型场景有两个。一个是同一个模型在多家供应商都有你想把流量按比例分开降低单家限流风险另一个是同一家供应商开通了多个账号想提高整体并发。这两种情况在model_list里都会表现为多行配置router Router( model_list[ { model_name: smart, litellm_params: {model: provider-a/model-alpha-v1}, model_info: {rpm: 1000}, }, { model_name: smart, litellm_params: {model: provider-a/model-alpha-v1}, model_info: {rpm: 1000}, }, ], routing_strategysimple-shuffle, )routing_strategy决定分发策略。默认的simple-shuffle是随机打散适合大多数场景如果希望根据实时负载选择最空闲的部署可以用基于使用量的策略。这里要注意基于负载的策略依赖model_info里的rpm每分钟请求数和tpm每分钟 token 数配置不填的话无法准确评估负载。重试参数num_retries建议设为 2 到 3 次。设置太多会导致整体延迟明显上升设置太少又容易在限流尖峰时直接失败。我一般把cooldown_time一起配了比如设在 30 秒某个部署连续失败后会被临时冷却避免每次请求都往一个已经出问题的目标上撞。3.3 流式输出场景下的取舍聊天应用基本都离不开流式输出。LiteLLM 对流式支持得不错写法也很直觉response litellm.completion( modelsmart, messagesmessages, streamTrue, ) for chunk in response: delta chunk.choices[0].delta if delta and delta.content: print(delta.content, end)值得提醒的是流式场景下做故障回退是有代价的。主模型已经吐了一部分内容才报错这时候切到备用模型备用模型会从头开始生成客户端会看到内容“前面一段没了又重新说一遍”体验上会有明显割裂。我的习惯是非流式场景放心开 fallback流式场景要评估用户能否接受这种割裂。如果接受不了就在流式接口上单独配置不启用回退或者只在请求刚发出去的前几秒内允许回退这个策略目前不是默认行为需要你自己额外控制。另外一个容易踩的坑是流式调用超时时间设置很多供应商流式场景首次返回延迟较长固定 30 秒超时往往不够建议单独调大。4. 代理模式给团队开一个统一 API 入口4.1 启动代理与基础配置只在自己代码里用 SDK那叫自给自足真正把 LiteLLM 的价值放大一定要用它的代理模式。代理就是一个运行中的 HTTP 服务对外暴露一个和业界标准兼容格式一致的接口团队里所有应用只要配一个base_url和api_key就能接入完全不用关心背后接了几家供应商。启动代理前先准备一个 YAML 配置文件比如config.yamlmodel_list: - model_name: smart litellm_params: model: provider-a/model-alpha-v1 api_key: os.environ/PROVIDER_A_API_KEY - model_name: smart litellm_params: model: provider-b/model-beta-v2 api_key: os.environ/PROVIDER_B_API_KEY然后设置主密钥并启动export LITELLM_PROXY_MASTER_KEYsk-123456 litellm --config config.yaml --port 4000看到日志里出现 health check 通过之类信息后代理就起来了。用 curl 验证一下curl http://localhost:4000/v1/chat/completions \ -H Authorization: Bearer sk-123456 \ -H Content-Type: application/json \ -d {model: smart, messages: [{role: user, content: 你好}]}团队里其他服务接入时直接用任意标准 SDK 指向这个地址就行。以 Python 为例from openai import OpenAI client OpenAI( api_keysk-123456, base_urlhttp://localhost:4000/v1, ) resp client.chat.completions.create( modelsmart, messages[{role: user, content: 你好}], )你有没有发现团队成员根本不需要安装 LiteLLM也不需要知道供应商细节他们只知道“公司有一个统一的模型网关”这比每个项目自己维护一套 SDK 封装舒服太多了。4.2 虚拟密钥与权限隔离代理模式最大的福利之一是虚拟密钥。你可以用主密钥生成一批带权限限制的虚拟密钥发给不同团队或不同应用使用。生成一个限定额度的密钥curl -X POST http://localhost:4000/key/generate \ -H Authorization: Bearer sk-123456 \ -H Content-Type: application/json \ -d {max_budget: 50, models: [smart], metadata: {team: 客服组}}返回结果里会有一个key字段把它当成普通 API 密钥发给对应团队即可。这样做的价值不只是安全隔离更重要的是成本归因。每个人、每个团队用的都是独立密钥谁花了多少钱一目了然出了异常调用也能直接定位到具体密钥。还可以限制虚拟密钥能访问哪些模型。比如客服团队只能调smart搜索团队只能调embed不让一个密钥拥有全部模型权限这在多团队共用网关时非常重要。4.3 成本统计与预算控制成本统计是 LiteLLM 吸引很多团队的关键功能。代理模式下每次请求的 token 消耗和费用都会被记录下来你可以通过内置接口查询/spend/logs按请求维度查看费用日志/key/info查看某个密钥的累计消费和剩余配额/global/spend看整个网关的总花费。预算控制更直接生成密钥时设置max_budget这只密钥的消费一旦超过预算后续请求会被网关直接拒绝返回 429。这个机制对团队管理特别有用比如给外部客户开放的试用密钥设置 10 美元预算用完就停完全不用人工盯。成本统计还有一个前提要注意只有通过代理发起的请求才会自动计费。如果你只是把 LiteLLM 当 Python 库在代码里直接用没有走代理默认不会记录费用需要额外配置回调。所以我前面才反复强调团队化使用一定要走代理。5. 进阶配置与可观测性5.1 一个可落地的完整 YAML 配置模板这里给一份经过我实际验证的配置模板可以直接抄走再改model_list: - model_name: chat-main litellm_params: model: provider-a/model-alpha-v1 api_key: os.environ/PROVIDER_A_API_KEY timeout: 30 model_info: mode: completion - model_name: chat-backup litellm_params: model: provider-b/model-beta-v2 api_key: os.environ/PROVIDER_B_API_KEY timeout: 60 model_info: mode: completion - model_name: embed-main litellm_params: model: provider-a/embedding-model-x api_key: os.environ/PROVIDER_A_API_KEY model_info: mode: embedding router_settings: routing_strategy: simple-shuffle fallbacks: - model_name: chat-main fallbacks: - provider-b/model-beta-v2 retry_policy: TimeoutError: 2 RateLimitError: 3 cooldown_time: 30 litellm_settings: drop_params: true set_verbose: false几个关键点解释一下api_key: os.environ/变量名是 LiteLLM 推荐的安全写法它会从环境变量读取值密钥不落盘、不进 Git 仓库。绝对不要直接写成明文。model_info.mode用来区分补全和嵌入模型写错了会导致嵌入模型在补全接口下被调用而报错。router_settings.fallbacks的层级关系是“fallbacks 列表里每一项对应一个需要保护的 model_name”后面接的具体是供应商前缀/模型名。litellm_settings.drop_params开启后如果某个模型不支持某个参数比如嵌入模型不支持 temperatureLiteLLM 会自动把参数丢掉而不是报错这在多模型混用时非常实用。5.2 接入自建模型服务很多团队会内部部署开源模型这类模型服务只要提供标准兼容接口LiteLLM 也能统一纳管。做法是把模型前缀写成openai/再指定api_base指向你自己的服务地址model_list: - model_name: local-llm litellm_params: model: openai/local-model api_base: http://127.0.0.1:8000/v1 api_key: any-value model_info: mode: completion这种写法相当于告诉 LiteLLM这个模型的协议是业界标准兼容格式但访问地址是内网自建的别往公网发。自建模型的优势和公网供应商完全不同但路由、回退、计费这些能力可以完全复用同一套配置。比如公网供应商限流时可以把请求回退到自建模型成本低还稳定。接入自建模型后建议设置偏大的timeout因为本地 GPU 推理速度受硬件影响明显高峰期可能比公网还慢超时设太短会误判失败。5.3 把调用日志接入已有监控LiteLLM 提供了回调机制可以把每次调用的元数据推给外部系统。我常用的做法是自定义一个回调把请求延迟、模型名、token 数、费用推送到团队现有的监控平台或日志系统。在配置里可以这样挂回调litellm_settings: success_callback: [custom_callback] failure_callback: [custom_callback]然后在代码里注册对应的回调函数。回调里能拿到的信息很完整包括请求模型、响应延迟、输入输出 token 数、费用等。有了这些数据你就能做几件非常实际的事情给不同业务线做费用分摊、监控模型延迟的 P95 走势、对下游频繁限流的模型自动告警。我一直觉得网关类组件必须和监控打通否则就像在家里装了一个不带电表的配电箱电是从这里过的但用了多少、哪个房间用的完全不知道。回调机制就是给网关装电表的过程。6. 常见问题与排查实录6.1 高频报错对照表整理了一份我在实际使用中遇到的高频问题对照表遇到报错可以先来这里找找答案现象可能原因解决方案返回 401/403供应商密钥错误或密钥环境变量没设置成功检查启动代理的进程里是否真的 export 了对应变量打印环境变量做一次确认返回 404 model not found模型名写错或前缀不是 LiteLLM 认识的前缀确认供应商前缀/模型名的格式先在官方模型列表里查一遍频繁 429触发了供应商限流或者虚拟密钥超预算配置 fallback 和重试检查密钥的 max_budget 是否已用完400 且提示上下文超长prompts 超过了模型上下文窗口对输入做截断或压缩或切换到上下文更大的模型代理启动失败端口被占用或 YAML 里 model_list 为空换端口确认 YAML 语法和模型配置完整调用成功但 /spend/logs 没数据没走代理模式费用统计没有自动启用检查请求是否打到代理地址代理模式下检查数据库连接是否正常流式输出中途断开供应商流式接口异常或超时设置太短调大流式超时确认网络环境稳定性6.2 我踩过的几个坑说实话LiteLLM 文档写得很全但真正上手时还是有几个坑不容易绕过这里分享给各位避免重蹈覆辙。第一个坑密钥明文写进了 YAML。团队里有人直接把api_key: sk-xxxx写在配置文件里然后整个仓库推到代码托管平台半天后密钥就被人盗刷了。这不是危言耸听如果密钥泄露引发大量调用账单会非常难看。解决办法只有一个配置文件里永远用os.environ/变量名的形式密钥只出现在部署环境的变量里。第二个坑回退目标配了同一个供应商的同一个账号。有次我给两个部署配了回退结果上线后发现限流时回退也没用因为两个部署本质上用同一个套餐额度一个限流另一个也限。回退的意义是“鸡蛋别放一个篮子里”所以回退目标最好选不同供应商至少也要不同账号、不同套餐。第三个坑升级版本没看配置变更。LiteLLM 大版本升级时路由配置的写法改过不止一次我就吃过一次亏升级后 fallbacks 没生效花了很久排查才发现是配置格式变了。建议在正式升级前先在测试环境把原配置完整跑一遍仔细核对启动日志里的报警。第四个坑环境变量设置时机不对。即使你在终端里 export 了变量如果代理是通过 nohup 或进程管理器启动的很可能根本没有继承当前终端的环境变量。我建议在启动脚本里显式加载环境变量并加一道保护启动时检查关键变量是否存在不存在就立刻报错退出省得启动成功但所有请求都 401。第五个坑对自建模型打开了 drop_params。drop_params虽然好用但过度使用会掩盖配置错误。上次某个本地模型明明不支持某个能力参数开了 drop_params 后参数被静默丢弃导致生成结果完全不符合预期排查了很久才发现是参数被丢了。建议调试阶段关掉 drop_params上线前再按需开启。按照我个人的经验LiteLLM 最适合的定位是团队级模型网关而不是个人项目里顺手调用的工具库。一旦把多供应商调度、密钥管理、预算控制集中到一个网关里后面接新模型、切换供应商、给团队分配额度都会省心很多。最后再分享一个小技巧接任何一个新模型之前先写一条带 timeout 的最小测试脚本把非流式、流式、嵌入三种模式都跑一遍确认接口通畅这才把它加进正式配置后面排查问题的时间能省一半。