做 AI 应用后端的人大概率都遇到过这个场景上午刚接完 OpenAI 的接口下午产品又提需求说要支持 Anthropic 的模型再过两天客户要求换成 Azure 的部署实例或者试用一下开源模型的兼容端点。每家 API 都有自己的鉴权方式、报文结构、错误码SDK 也各写各的。你只能被迫维护一层又一层适配代码越堆越多。我最早处理这个问题的方式很粗暴写一个内部中转服务把各家 API 的差异“捂”在自己的工具函数里。直到后来用了 LiteLLM才意识到这类问题其实有更省心的解法。LiteLLM 是一个开源的 LLM API 网关 / 统一代理层核心能力是让你用一套接口、一套 SDK、一套鉴权逻辑去调用市面上主流的大模型服务商同时还能做负载均衡、故障回退、预算控制、密钥管理和调用观测。它不是某个模型本身的封装而是站在你业务系统和各家模型 API 之间的“中间层”。这个定位决定了它适合的场景非常集中后端服务、平台型产品、需要给多个内部团队开放模型能力的中小型公司以及那些今天换模型、明天换供应商、后天又要做成本分摊的开发者。这篇文章我会从原理讲到实操再用生产环境踩过的坑来收尾。内容偏工程向但我也尽量把关键概念解释得直白一些方便新手把整个逻辑串起来。1. LiteLLM 到底是什么为什么这类工具会冒出来1.1 一个代理层解决“模型碎片化”问题先看最原始的矛盾。OpenAI 的 Chat Completions 接口和 Anthropic 的 Messages 接口看起来都是在“发消息、拿返回”但实际请求体差异很大模型名写法不同、系统提示词的位置不同、工具调用的结构不同、流式输出的数据格式也不完全相同。更别提各家对 JSON 模式、视觉输入、结构化输出的支持等级参差不齐。业务系统如果直接接这些 API代码里就会长满 if-else。今天判断“如果是 OpenAI 就走 OpenAI SDK”明天判断“如果是 Claude 就走 Anthropic SDK”。这种逻辑一旦多了就会开始出现奇怪的 bug同一个 prompt 在 A 模型上没问题在 B 模型上因为字段结构问题频频报错。你很难抽象出一个统一的接口层因为每一家 SDK 的“个性”太强了。LiteLLM 做的事情简单说就是把这些差异吞掉。它对外提供一套和 OpenAI SDK 兼容的接口格式对内再把你的请求翻译成各家模型真正需要的样子。你的业务代码永远只针对一个接口地址做调用至于后面是 Azure 还是 Bedrock是开源模型还是商业模型由代理层自己判断。这个思路很像后端开发里的 API 网关客户端不直接面对微服务集群里的每个节点而是先经过一层网关联动路由、鉴权、限流和监控。LiteLLM 对你的大模型调用做的正是这件事。1.2 它和“直接调各家 SDK”的本质区别很多人一开始会问我直接调官方 SDK 不是更简单吗模型能力是官方给的参数文档也是官方的何必中间多一层代理这个问题本身没错但它前提是“你只服务一个模型供应商、只服务一个业务方、不需要做任何成本管控”。一旦你的系统需要面对多个供应商直接调官方 SDK 的维护成本会迅速上升。举个例子你给客户 A 开了 Anthropic 的模型给客户 B 开了 OpenAI 的模型两个客户都要通过同一套后台去调用那你如何统一计费如何限制某个客户不能调用贵模型如何做到模型出了故障自动切换到备用模型这些能力官方 SDK 通通不提供你得自己写。LiteLLM 的价值就在于把这些“业务工程问题”提到代理层统一解决。它在技术上并不复杂但设计目标很明确让你不必为每家供应商各写一套调用逻辑也不必为了“多租户成本分摊”去另起炉灶。对比之下官方 SDK 更像是“把某个 API 封装好给你用”而 LiteLLM 是“把一群 API 变成一个可运营的系统”。1.3 这套思路适合谁不适合谁以我接触过的项目来看最适用的人群有三类做 SaaS 平台需要让外部用户通过统一的接入密钥调用不同模型。公司内部有多个算法团队、后端团队每个人申请模型密钥都要走审批领导还希望看每个团队花了多少钱。业务需要多模型轮询或回退比如主模型挂了自动切备用或者某些请求分给便宜的模型处理。不适合的情况也有。比如你只需要固定调一个模型没有任何成本管控需求那么上 LiteLLM 完全是多此一举直接写 SDK 半小时就搞定。又比如你在边缘设备或资源受限环境内跑不希望中间再塞一个 Python 服务那直接用轻量 SDK 也更合适。LiteLLM 的定位非常明确它解决的是“多模型、多租户、可观测”的组织级问题而不是“帮我少写几行调用代码”的个人便利问题。2. 核心功能拆解这些能力决定了它值不值得引入2.1 统一格式转换与模型路由LiteLLM 最底层的功能是格式转换。你发一个 OpenAI 风格的请求体过来它会根据你声明的模型提供商把消息内容重新组装成对应 API 的格式。这个过程对使用者透明你不需要知道 Claude 的 system prompt 要单独放一个字段也不需要担心 Gemini 的 roles 和 OpenAI 不完全一致。模型路由主要靠 config 文件里的model_list来实现。每一个条目定义一个对外暴露的模型名model_name并映射到某个真实模型的调用参数litellm_params。调用方只需要记住“这个系统里叫gpt-4o-mini的模型”不需要关心它背后是从 OpenAI 调、从 Azure 调还是经过某个兼容协议转发到自建模型服务。这里有个容易混淆的点如果你不写model_list直接用model: openai/gpt-4o-miniLiteLLM 也能工作它会根据前缀猜测该走哪家供应商。但生产环境建议把所有模型显式声明在配置里因为这样你才能控制路由权重、给它绑定密钥、加预算限制出了问题也能一眼看清配置。2.2 负载均衡、重试与回退这是 LiteLLM 的第二个核心价值。同一个对外模型名可以配置多个上游实例比如你在 OpenAI 和 Azure 都部署了同一个模型LiteLLM 会在它们之间分配请求。分配策略支持简单的轮询也支持自定义权重——比如某个供应商稳定性高就给它的权重调大一些。重试机制也比较实用。当上游返回 429 限流、5xx 错误或者超时的时候LiteLLM 可以自动重试。它知道哪个供应商现在大概率不可用会优先把请求切到其他实例。更高级的用法是配置fallbacks主模型失败时整个请求自动转发给备用模型。这个功能做客服机器人、做稳定性要求高的服务时非常有用。你不需要在业务代码里写一堆 try-catch 再手动切模型代理层会把失败请求消化掉。但我要提醒一点回退机制虽然省心不是没有任何副作用。备用模型能力和主模型不一定是完全对齐的同一个 prompt 可能会得到不同风格的结果。业务上如果要保证“非某个模型不可”那建议别配 fallback宁可失败也要透明如果只是追求“别让用户看到报错”那 fallback 就很香。2.3 预算控制、限流与密钥管理我见过很多团队用 LiteLLM最大的诉求反而是成本管控。AI 应用最怕一件事情某个测试脚本忘了关循环一夜之间把预算烧光。官方控制台虽然有 usage 页面但那是整个账号的你没法针对某个业务线、某个客户做独立限制。LiteLLM 的解决方案是引入“虚拟密钥”概念。管理员有一个 Master Key然后通过这个 Master Key 创建一堆子密钥。每个子密钥可以设置允许调用的模型范围。单个请求上限、每分钟请求次数上限、每分钟 token 上限。总预算额度比如“这个密钥一个月只能花 50 块钱”。过期时间到点自动失效。子密钥分发给不同团队谁花了多少钱一目了然。这比直接给每个人发官方密钥安全得多哪怕某个子密钥泄漏了也不会影响到主账号还能立刻吊销。按我的经验只要系统开始有“第三方接入”的需求虚拟密钥这个功能基本是刚需。2.4 观测、日志与缓存大模型应用和传统接口有个很大区别调用结果不是事务性的你很难用数据库状态去判断一次调用成功没成功。因此观测就显得格外重要。LiteLLM 内置了日志回调机制可以把每次调用的模型、token 消耗、延迟、错误信息统一转发到你自己的日志系统或者可观测平台。它还支持缓存配置。如果业务里有大量重复请求——比如多个用户问同一个知识库问题——缓存命中之后就可以省掉一次真实模型调用。缓存支持内存、Redis也有语义缓存选项能将相似问题映射到同一个答案。这个功能对降低成本很显著但对一致性要求高的场景需要谨慎模型输出本来就不是确定性的缓存可能让用户觉得“系统不会变”。3. 从零搭建一套 LiteLLM 网关部署与配置实操3.1 配置文件到底怎么写LiteLLM 的核心配置是一个 YAML 文件里面主要包含model_list、litellm_settings、general_settings这几个大块。我先把一个最小可用的示例贴出来之后逐个解释。model_list: - model_name: gpt-4o-mini litellm_params: model: openai/gpt-4o-mini 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 - model_name: mixed-azure-openai litellm_params: model: azure/gpt-4o-mini api_key: os.environ/AZURE_API_KEY api_base: os.environ/AZURE_API_BASE litellm_settings: drop_params: true request_timeout: 60 general_settings: master_key: sk-your-master-key-change-me database_url: os.environ/DATABASE_URL第一眼看上去model_name和下面litellm_params.model的关系最容易搞混。model_name是对外暴露的名字你的业务代码请求时用的就是它litellm_params.model是真正上游模型标识。带openai/、anthropic/、azure/这类前缀是为了告诉 LiteLLM 应该用哪套协议去解析这个上游模型。如果你在litellm_params.api_key里直接写明文密钥也可以但用os.environ/XXX的方式读取环境变量更安全避免配置文件被推送到 Git 里泄露。这里有一个常见误区drop_params: true表示“当某个上游模型不支持传入的某些参数时自动丢弃而不是报错”。例如 OpenAI 可能接受response_format但某些兼容端点不支持drop 掉之后请求还能继续。这个开关很实用但也会掩盖掉一些你想保留的行为所以我建议只在确实有多模型混用需求时开启。3.2 Docker 部署与启动流程我个人最推荐的部署方式是 Docker Compose原因很简单LiteLLM 的依赖比较多直接 pip 装容易把系统环境搞乱而容器化之后升级、回滚、扩副本都很方便。先准备一个最简单的docker-compose.ymlversion: 3.9 services: litellm: image: ghcr.io/berriai/litellm:main-latest container_name: litellm ports: - 4000:4000 volumes: - ./config.yaml:/app/config.yaml environment: - OPENAI_API_KEY${OPENAI_API_KEY} - ANTHROPIC_API_KEY${ANTHROPIC_API_KEY} - DATABASE_URL${DATABASE_URL} command: [--config, /app/config.yaml, --port, 4000, --num_workers, 4]启动命令其实就是一个docker compose up -d。启动完成后默认会监听 4000 端口。然后你可以直接发一个请求测试curl http://localhost:4000/v1/chat/completions \ -H Content-Type: application/json \ -H Authorization: Bearer sk-your-master-key-change-me \ -d { model: gpt-4o-mini, messages: [{role: user, content: 你好请用一句话介绍自己}] }这个接口路径和 OpenAI 的规范基本一致/v1/chat/completions、/v1/models这些都能直接用。如果你的业务代码用的就是 OpenAI SDK那把base_url指过来即可模型名换成配置里声明的model_name。--num_workers这个参数值得认真调。默认数值可能比较小而在高并发场景下worker 数量不够会表现为“延迟忽高忽低”或者“CPU 明明没跑满但请求就是上不去”。但我也不建议无限加大worker 太多会带来额外的内存开销通常和 CPU 核数保持一个合适比例比较稳妥。3.3 虚拟密钥、多租户和数据库配置要让虚拟密钥功能真正跑起来你需要接一个数据库。LiteLLM 支持 PostgreSQL、MySQL 等常见数据库推荐直接用 PostgreSQL 实例。配置里写上database_url后启动时它会自动建表。创建虚拟密钥的请求长这样curl http://localhost:4000/key/generate \ -H Content-Type: application/json \ -H Authorization: Bearer sk-your-master-key-change-me \ -d { models: [gpt-4o-mini, claude-3-5-sonnet], max_budget: 50, budget_duration: 30d, max_parallel_requests: 10 }请求成功后会返回一个key字符串或者你直接在/ui管理界面上创建也可以。这个 key 分给某个团队之后它的所有调用都会计入预算。max_parallel_requests限制并发防止某一个调用方把网关打满。实际使用中我认为一个比较好的组织方式是每个业务线或每个客户一套 key模型白名单控制在它真正会用到的模型上。这样做的好处是即使某个 key 泄露你能快速定位到影响范围并且可以把损失限定在单个租户内而不是整个平台挂掉。3.4 用 OpenAI SDK 接入的完整示例部署好网关之后业务侧接入只需要改两处base_url和api_key。下面是一个 Python 示例from openai import OpenAI client OpenAI( base_urlhttp://localhost:4000/v1, api_keysk-your-virtual-key, ) resp client.chat.completions.create( modelgpt-4o-mini, messages[{role: user, content: 讲个段子}], temperature0.7, ) print(resp.choices[0].message.content)Node.js、Java 这些语言也都一样只要是 OpenAISDK 兼容的客户端改一下 base_url 就能接入。这也是 LiteLLM 一个很聪明的设计它没有自定义一套全新协议而是选择兼容已有生态这样迁移成本极低。很多团队从直连 OpenAI 迁到网关改动量只有环境变量里的几百字符。有一点要强调当你在代码里传modelgpt-4o-mini时它指的是你在 LiteLLM 配置里定义的名字而不是 OpenAI 官方模型名。如果你通过 LiteLLM 调用官方模型但配置里没声明也可以用modelopenai/gpt-4o-mini这种带前缀的形式直接传LiteLLM 会按前缀去匹配供应商。4. 生产环境踩坑记录这些问题我排查了一整晚4.1 流式输出延迟或直接不返回我刚把 LiteLLM 部署好时第一个遇到的大坑就是流式调用。业务端用streamTrue请求LiteLLM 也把响应流式返回但某些模型就是偶尔卡住表现为前端收到一句半句就停住直到超时。排查了很久后发现问题出在request_timeout和上游模型本身的输出节奏上。流式模式下如果第一个 token 等了很久才到或者两个 token 之间间隔较长LiteLLM 默认的超时策略可能会误判为超时。后来我把request_timeout调大并且给流式请求单独做配置情况就好很多。另一个原因是上游模型本身延迟高LLM 首 token 时间普遍比普通 HTTP 接口长不能拿传统 API 的超时标准来套。4.2 预算数据不刷新显示一直不准虚拟密钥控制预算量其实分两个阶段请求进入时先做一次“预检查”请求结束后再异步上报实际 token 消耗。如果你在数据库里看成本数据可能会有延迟。尤其在高并发下异步任务的积压可能让某个 key 的实际消费额看起来很低但后面突然跳变。遇到这个问题的正确做法不是去改数据库而是提高后台处理任务的并发能力并且确认部署了足够多的 worker。LiteLLM 文档里对这类任务队列也有说明。总之预算功能能做“事后结算”和“事前拦截”的双重保障但如果你只依赖它做实时强管控需要把上报延迟考虑进去。4.3 权重路由不生效请求总是打到同一个上游配置了多个上游实例、也配置了权重后我一度发现所有请求还是被打到第一台上游。后来细看才发现问题在于我配置了某种“会话亲和性”策略。在很多网关里如果开启了基于用户或会话的粘滞路由同一个调用方会一直被路由到同一个实例这是故意的而不是 bug。如果业务不要求“同一用户必须走同一模型实例”那这类亲和策略最好关掉否则负载均衡形同虚设。另外还要检查一个点如果上游实例的模型名完全相同LiteLLM 默认情况下可能会把它们当成一个模型做轮询但前提是配置里确实写了多条litellm_params而不是写在了同一条里。4.4 模型参数传不过去报“不支持该参数”这是多模型网关最容易出现的兼容性问题。OpenAI 支持response_format、tools、seed这些参数但转成其他厂家模型时LiteLLM 必须决定怎么处理参数。有些参数它实现了转换有些参数它直接不支持。当你在请求里带了一个 LiteLLM 无法映射的参数时默认行为是报错。我当时用drop_params: true解决了大部分问题但也引出了新问题某些希望严格的校验场景里参数被静默丢弃后模型输出质量明显下降。现在我的习惯是分模型写配置支持度高的大模型不开 drop兼容性差的小模型才开。这不是标准答案但更符合实际业务需要。4.5 连续请求导致内存涨个不停有一次生产环境跑了一周后容器内存越涨越高。起初以为是内存泄漏后来在日志里发现我打开了过多的日志回调而回调里又把完整请求体、响应体都塞到了消息队列里。请求吞吐一高队列消费不过来内存就上去了。解决思路很简单生产环境只保留必要字段比如 token 数、延迟、模型名、状态码不要记录完整 prompt 和响应。一方面是内存开销另一方面也是隐私安全考虑。大模型应用最忌讳把用户输入原封不动写进日志出了问题责任很大。5. 和其他方案对比什么时候不一定选 LiteLLM5.1 自研网关 vs 现成代理很多团队会纠结要不要干脆自研一个统一调用层。如果你们的核心人力很充足自研确实能最大化贴合业务。但自研的隐性成本往往被低估格式转换规则要自己维护各家 API 更新了你得跟着改重试、限流、成本统计等一堆“周边功能”都要自己造轮子。除非团队有持续投入否则做到后面很容易变成一个没人敢动的“祖传模块”。LiteLLM 这类现成方案的最大优点是社区和版本迭代帮你在追各家 API 变动。你不需要关心 Anthropic 最近改了某个响应字段只要升级版本即可。缺点则是它本身的配置体系也有学习成本而且更新过快某些参数在不同版本里行为不完全一致升级前需要仔细看 changelog。5.2 托管型统一 API 服务 vs 自托管网关现在市面上也有一些托管的统一模型 API 服务直接把各家模型聚合在一个域名后面。这类服务上手极快不需要部署也有完善的计费体系。如果你不想维护任何基础设施只想一个 key 调用所有模型那托管服务是更好的选择。代价是请求会经过第三方的中转链路延迟和稳定性受制于人。另外模型输入输出也会暴露给中转方企业内部如果对数据隐私有严格要求那这一条基本一票否决。自托管 LiteLLM 虽然要维护服务器但数据链路完全在自己手里合规上更可控。5.3 什么时候可以直接放弃它如果你只是在自己电脑上跑实验偶尔换模型写个 Demo那装一个 LiteLLM 纯属给自己增加负担。对于没有多模型、多租户、成本管控需求的项目直接用官方 SDK 是最干净的做法。另外如果团队的主要技术栈不在 Python也不想额外维护一个 Python 服务那 LiteLLM 的引入成本就要重新评估。虽然它对外暴露了标准 HTTP 接口你最终只需要 HTTP 调用但运维层面还是多了一个服务要管理这点要想清楚。6. 一些值得留意的配置细节和运维经验6.1 环境变量和密钥管理LiteLLM 的配置里可以用os.environ/XXX引用环境变量。实际运维时我会把这些环境变量放到容器编排工具里统一管理而不是塞进 YAML。尤其注意master_key绝对不要用默认值很多公开示例里的默认 key 一旦暴露任何人都能访问你的网关。部署完成后第一件事就是改掉默认 master key并请确认它没有出现在公网可访问的页面里。6.2 关闭遥测选项LiteLLM 默认会收集一些匿名使用数据用于改进项目。如果公司内部对数据外发有严格限制部署时最好主动关闭。配置里有个telemetry相关设置或者直接设环境变量LITELLM_TELEMETRYFalse。我建议在内部部署时一律关掉省得后面被安全部门问起来说不清楚。6.3 UI 调试和健康检查LiteLLM 自带一个简单的管理后台可以看模型列表、密钥列表、调用日志。生产环境我会让/health接入监控系统同时定期看一下/model/info确认配置的每个模型是否健康。曾有一次 Azure 的密钥过期了但/health仍然返回正常直到调用量上升才暴露问题。所以不要只依赖健康检查要多看模型状态。6.4 升级版本前先看兼容性变更这个项目迭代速度很快社区版发布频繁。我从一个旧版本升级到新版本时遇到过配置文件格式不兼容的情况原来model_name对应的字段要改某些默认行为也变了。建议在测试环境完整跑一遍回归把请求、回退、预算校验三块重点测一下再上生产。我个人现在的习惯是把所有配置代码化、版本化。config.yaml 放到配置仓库里升级前 diff 配置差异这样即使行为变了也能快速定位是哪项配置导致。最后再分享一点我的使用体感用了 LiteLLM 大半年最大的体会是它的核心价值不在“省事”而在于把模型调用从“代码问题”变成了“配置问题”。以前换模型要改代码、发版、重新部署现在只需要在配置里加一个模型条目然后调一下路由权重。业务团队和基础设施团队的协作方式也变了算法团队不再关心密钥和网关细节而平台团队能清楚地看到每个模型、每个租户的成本结构。如果你正准备上 LiteLLM我的建议是先别追求功能齐备而是从最小配置开始一个模型、两个 key、一张成本报表。把基础链路跑通再把多模型回退、预算控制、缓存逐个加进去。你会发现当模型成为可配置的资源之后整个系统的灵活性强很多。当然它也不是万能的自治性和稳定性之间永远需要权衡。但至少在“多模型统一接入”这件事上LiteLLM 现阶段是我用过的综合成本最低的方案。