最近在做一个内部 AI 功能模块需要同时接入好几家大模型服务有闭源商用模型、有开源的自我托管模型还有国内各家云厂商的托管版本。一开始倒是简单每个服务商都给了 SDK照着文档调就行。但等做到第二个、第三个的时候就开始不对劲了——每个 SDK 的初始化方式不一样、参数命名对不上、鉴权头放的字段不同、流式输出的结构更是五花八门。最头疼的是切换模型做效果对比时业务代码要跟着改一圈光对接和联调就占了好几天。后来一个同事给我提了个思路把 Litellm 作为统一网关插在业务代码和所有模型服务之间。它做的事其实很朴素——对外暴露一套统一的 HTTP 接口和 SDK 调用方式对内去适配各家模型服务的差异同时把路由、负载均衡、重试、降级、预算和用量统计全收拢到一层里。项目里跑下来业务代码只认一套规范之后再接新模型基本只是改配置的事。如果你正在做多模型接入、Agent 应用、或者想在微服务里统一管理大模型调用成本这个项目值得花半天时间了解一下。这篇就把我实际搭建和踩坑的过程完整记录下来包括配置怎么写、代理模式和 SDK 模式怎么选、生产环境要注意哪些问题。1. 为什么需要统一网关一套接口对接所有模型服务1.1 多个服务商接口之间的割裂感先说说没有网关时的真实体验。假设一个应用要支持三家模型服务商你在代码里可能要写三套对接逻辑。第一家的消息格式是这样的{prompt: 你好, max_tokens: 100}鉴权走 Header第二家要求{messages: [{role: user, content: 你好}]}鉴权参数藏在 URL 里第三家更特别它的工具调用和流式事件格式跟另外两家完全不是一个风格。这还是表面上的差别实际联调起来连错误码都不通用。这种割裂带来的麻烦不止是“多写几段代码”那么简单。最痛的是做模型评估和效果对比的时候你想让同一个业务请求分别打到三个模型上看看哪个回答质量更好。如果没有统一层你得把请求组装成三种格式分别发送再把三份不同结构的响应各自解析后拉平。这个工作量叠加到真实的业务场景里往往会吃掉大量本来该花在 Prompt 调优上的时间。我当时的处理方式是写了一个自研的“适配器集合”把各家 SDK 包了一层。可维护性很差任何一个服务商升级了接口规范或者你的代码里新加了一个参数适配层和业务逻辑的耦合就开始失控。所以方向是对的但重复造轮子没必要直接用成熟的 Litellm 反而更省心。1.2 Litellm 的定位和设计理念Litellm 不是某个具体模型它是一层“中间翻译层 代理服务 路由控制器 监控统计系统”。它的设计理念非常明确你在业务代码里只跟一套统一接口打交道其他事情全部交给它。具体来说Litellm 提供了三种使用模式分别适配不同场景。第一种是 SDK 内嵌模式。你在 Python 代码里直接import litellm调用litellm.completion()内部由它完成协议转换。这种模式适合你不想再额外启动一个独立服务的情况把模型访问能力直接打进应用进程里。第二种是 CLI 启动模式。用一行命令把 Litellm 跑成一个本地代理监听某个端口然后你的代码往这个端口发普通的 HTTP 请求就行。第三种是服务化部署模式。这也是生产环境里最常用的方式——把 Litellm 部署成一个独立的网关服务用一份 YAML 配置文件管理所有模型路由所有业务服务通过 HTTP 访问这个网关。要理解这套设计为什么好用可以拿家里的遥控器做类比。没有统一遥控器之前电视一个遥控器、空调一个遥控器、机顶盒又一个遥控器每个遥控器按钮布局还不一样。Litellm 就是那个万能遥控器你只按“音量”这一个按钮不管背后是电视还是音响它帮你翻译成对应设备能听懂的红外信号。从接口兼容性上说Litellm 对外暴露的接口风格很接近行业通用的 Chat 风格规范所以很多能对接“标准 Chat 接口”的工具链比如一些开源的 Agent 框架和低代码平台可以直接把地址指向 Litellm 网关无缝迁移。2. 核心功能拆解与关键参数2.1 模型注册与路由配置Litellm 的核心配置是一份 YAML 文件。初次使用时第一个要理解的概念是“模型逻辑名”和“真实模型路径”的区分。看下面这段配置model_list: - model_name: assistant-main litellm_params: model: provider-a/llm-model-name api_key: os.environ/A_KEY temperature: 0.7 - model_name: assistant-express litellm_params: model: provider-b/llm-model-name api_key: os.environ/B_KEY这里的model_name是你在业务代码里使用的逻辑名比如assistant-main。而litellm_params.model是服务商内部真实的模型标识。为什么要搞两层命名关键作用是解耦。假设今天业务用的主模型是 A 服务商的某个版本跑了一段时间觉得效果不好想换成 B 服务商能力更强的模型。正常情况下你需要把代码里的 model 名字改掉同时可能还要换 Key、改超时参数。但在 Litellm 里你只需要把 YAML 里assistant-main对应的真实模型路径从provider-a/xxx改成provider-b/yyy业务代码一行都不用动。这层抽象在多人协作的项目里价值尤其明显。前后端联调时前端同学只需要知道“主模型叫 assistant-main 就够了”不需要关心背后今天用的是哪家、明天会不会换。配置里的api_key也支持从环境变量读取这是我最推荐的方式。不要在 YAML 里明文写密钥否则配置文件一进仓库就等于把密码交出去了。模型列表可不是简单的一对一映射同一个逻辑名还可以挂多份真实模型实例这就引出了负载均衡。2.2 负载均衡、重试与降级机制多实例配置大概是这样的model_list: - model_name: assistant-main litellm_params: model: provider-a/llm-model-name api_key: os.environ/A_KEY model_info: mode: completion weight: 3 - model_name: assistant-main litellm_params: model: provider-b/llm-model-name api_key: os.environ/B_KEY model_info: mode: completion weight: 1同一个逻辑名assistant-main对应了两个真实模型实例weight表示权重。默认情况下 Litellm 会按权重做轮询分流权重为 3 的实例被选中的概率是权重为 1 的三倍。这个设计很适合灰度切流先给新模型一个很低的权重比如 1:9线上大量请求还是走老模型你观察新模型在真实流量下的表现确认没问题后再把权重慢慢调上来。真正能救命的是降级配置。生产环境最怕的就是正在用的模型服务商突然限流或宕机这时候如果网关能自动把请求切换到备用模型上用户体验不会中断。配置方式是在 YAML 里增加fallbacksrouter_settings: fallbacks: [ {assistant-main: [assistant-fallback]} ] num_retries: 3 timeout: 30 cooldown_time: 60含义是当assistant-main这个逻辑名对应的所有真实实例都不可用时自动把请求转发给assistant-fallback。cooldown_time的意思是某个实例失败后先让它冷却 60 秒再重新尝试避免对一个已经宕机的服务反复打请求。关于超时设置我要特别提醒不要把这几个参数当成摆设。不同模型服务商的实际响应速度差异非常大尤其是大模型场景一个稍复杂的生成任务可能本身就要跑 10 秒以上。超时设太短正常的请求会被误判为失败设太长又可能在服务商真正卡死时拖住整个业务链路。我的经验是先按业务可接受的最长等待时间设一个值比如 30 秒然后混用重试策略来兜底。2.3 预算管理与用量追踪大模型调用是有成本的而且成本很容易失控。尤其是团队里多个人共用一套 Key 的时候月底账单出来之后才追责往往已经晚了。Litellm 内置的预算控制和用量统计可以把这件事前置化。它可以从三个维度做限制全局总预算、每个 Key 的预算、具体到某个用户的预算。配置大概是这样general_settings: max_budget: 5000 budget_duration: 30d litellm_settings: max_budget: 3000 budget_duration: 30d这个配置的含义是网关整体每 30 天最多消耗 5000 个配额单位单个 Gateway 层面再兜一层双保险。用量统计更细。Litellm 会为每次请求记录 Token 数、服务商、模型、耗时、费用估算等信息并且在内部维护一套类似关系数据库的表结构方便做查询和汇总。你可以在管理界面上按模型维度看消耗排行也可以按 Key 维度分析是哪个业务方消耗最大。这里要说一个容易误解的点费用估算不是服务商账单只是一个近似值。因为各家的计价规则存在差异Litellm 是拿“Token 数 × 单价”的方式估算的。它用来做趋势分析和异常预警足够了但真要跟服务商出账对账还是以服务商后台的账单为准。3. 实操过程从零搭一个统一入口3.1 环境准备与安装搭建一个 Litellm 网关的前置条件很简单一台能联网的服务器或开发机装好 Python 3.8 以上环境即可。如果只是想本地快速体验直接在一台普通的笔记本上就能跑。安装有两种方式。第一种是用 Python 包管理工具安装适合开发环境pip install litellm装好之后命令行里就有了litellm这个命令。第二种是用容器方式部署适合生产环境docker pull ghcr.io/xxx/litellm:main docker run -d \ --name litellm-gateway \ -p 4000:4000 \ -v /path/to/config.yaml:/app/config.yaml \ ghcr.io/xxx/litellm:main \ --config /app/config.yaml关于端口Litellm 默认监听 4000。这个端口选得比较讲究跟常见的前端开发端口 3000、后端 8080 都不冲突能少很多麻烦。如果你所在的环境 4000 被占用也可以用--port参数显式指定其他端口。安装完成后的第一件事自然是准备模型接入信息。你需要知道自己要用哪些模型服务商的 AccessKey把 Key 配到环境变量里。3.2 代理模式不改业务代码就能接模型代理模式是 Litellm 最没有侵入性的使用方式。你不需要修改任何业务代码只需要启动代理然后把原来发给模型服务商的请求地址改成一个统一的代理地址。启动代理的命令litellm --config ./config.yaml --port 4000启动日志里会输出一个本地地址看到类似“Uvicorn running on http://0.0.0.0:4000”的提示就代表网关起来了。验证网关是否正常工作用 curl 是最快的curl --location http://localhost:4000/v1/chat/completions \ --header Content-Type: application/json \ --header Authorization: Bearer sk-any-string \ --data { model: assistant-main, messages: [ {role: user, content: 用一句话介绍你自己} ] }需要注意的是代理模式下发请求时业务方携带的鉴权信息是一个虚拟 Key。Litellm 内部会校验这个虚拟 Key确认它有权限后再用配置里对应的真实上游 Key 去请求真正的模型服务。所以你在 curl 里随便带一个 Bearer Token 在网关内部也是可以过的——如果你没有开虚拟 Key 校验的话。如果只是在本地快速验证随便传一个字符串能通但生产环境必须开启虚拟 Key 校验每个业务团队分配一个独立的虚拟 Key这样才能把用量和费用分摊下去。3.3 SDK 集成在代码里直接用如果你不想额外跑一个代理服务或者在 Python 程序里希望通过函数调用方式直接访问模型可以选择 SDK 模式。安装完成后在 Python 代码里这样用import litellm response litellm.completion( modelassistant-main, messages[ {role: user, content: 你好介绍一下你自己} ], temperature0.3 ) print(response.choices[0].message.content)对比代理模式SDK 模式少了一层网络开销响应延时会更低一些。缺点是业务代码和 Litellm 的库强耦合升级 Litellm 版本时可能要同步回归测试。两种模式怎么选我的建议很直接场景推荐模式原因快速原型验证CLI/代理模式不写代码配置即用微服务多团队共用模型能力服务化代理模式统一出入口方便控制权限和预算单个 Python 应用不想多维护一个服务SDK 模式部署简单延时低需要精细的路由和降级策略服务化代理模式配置管理更集中实际操作中我经常是两种混用开发阶段用 SDK 模式方便调试等到要部署到测试或生产环境时就切到服务化代理模式统一管理 Key 和预算。3.4 一份可以直接抄的完整最小配置最后给一份我在本地方便复现的最小配置。它注册了两个逻辑模型开了虚拟 Key 校验加了基础预算控制。model_list: - model_name: main-model litellm_params: model: provider-a/gpt-style-chat api_key: os.environ/SERVICE_A_KEY temperature: 0.5 - model_name: aux-model litellm_params: model: provider-b/llm-v2 api_key: os.environ/SERVICE_B_KEY router_settings: fallbacks: - {main-model: [aux-model]} num_retries: 2 timeout: 30 cooldown_time: 60 general_settings: master_key: sk-master-key database_url: sqlite:///litellm_budget.db max_budget: 200 budget_duration: 30d配好后启动代理测试调用时带上Authorization: Bearer sk-master-key。如果要给某个团队分配一个子 Key可以后续在管理端生成然后限定它只允许调用main-model并给一个独立的预算额度。4. 常见问题与排查技巧实录4.1 鉴权失败和模型名找不到这是新手最容易遇到的两类报错我把它们放一起说。第一类是 401 鉴权失败。日志里通常直接显示“Authentication Fails”或者“Invalid API key”。排查顺序是这样的先检查环境变量名是否跟 YAML 配置里读取的一致。比如 YAML 里写的是os.environ/SERVICE_A_KEY那么操作系统环境变量里就必须存在SERVICE_A_KEY。我自己踩过坑YAML 里写对了但 shell 环境变量没 export然后花了十分钟看日志。再检查上游服务商的账号是否还有余额。有些免费额度用完后再调用服务商会返回鉴权失败类的提示看似是 Key 的问题实际是欠费了。第二类是 404 或者“Unknown model”的报错说明配置里litellm_params.model的值不匹配真实模型标识。这里最常见的原因是把逻辑名和实际模型名搞混了。逻辑名是main-model真实模型标识应该像provider-a/具体版本这样的格式。Litellm 不会自动帮你“纠正”名字它只是按照你给的字符串去上游查找。4.2 超时、流式中断与限流在生产环境跑了一段时间后我遇到最多的问题集中在超时和流式中断上。大模型生成内容本来就慢如果配置里的timeout设得太小比如 10 秒一个正常的超过 500 字的回答很容易被打断重试。重试本身又增加了上游的并发压力。我最终设成了 30 秒并且把num_retries控制在 2 次以内。另一个值得注意的点是流式输出。启用流式响应之后网络链路的稳定性要求更高因为请求已经被客户端打开了网关需要持续推送数据。如果客户端是关掉网页或者断开连接网关这边要能感知并停止上游调用不然会白白消耗 token。Litellm 在处理流式断开时相对智能但你在对接时也要注意服务端的超时设置比如前端的请求超时时间不能小于网关的超时时间。限流问题主要出现在模型服务商侧。当上游返回 429 限流错误时Litellm 默认会触发重试但如果上游限流是持续性的重试只会把问题放大。合理的做法是设置较短的冷却时间让请求先转移到备用模型或者直接返回限流提示给前端由用户决定是否重试。4.3 成本数据对不上用量统计对不上的问题基本上集中在三个原因。一是统计时间窗口和账单周期不一致。Litellm 的预算周期是按你配置的budget_duration计算的比如从首次调用后开始计时 30 天而服务商账单可能是自然月。两者本来就不是一个时间口径。二是流式请求的 token 统计。流式输出是分批返回的Litellm 需要把所有分片加起来才能得到完整 token 数。如果应用中途断流部分 token 可能没被记录完整。三是缓存命中。Litellm 支持缓存机制同样的请求如果命中了缓存就不会真正发到上游自然也就不会产生新的费用。但从成本估算上看那部分 token 数不需要被重复计费这反而说明缓存是起了作用的。遇到成本对不上的情况我通常先按模型维度筛选再按时间范围对比服务商后台数据能对上 90% 的问题。5. 高级用法与生产落地建议5.1 多租户与虚拟 Key 管理当团队规模变大以后不能再让所有人都用同一个 Master Key。Litellm 的解决方案是虚拟 Key。每个虚拟 Key 可以关联到特定的用户或团队并且可以被绑定这些规则team_settings: - team_id: team-a team_alias: 平台组 max_budget: 500 budget_duration: 30d models: [main-model]这样做的好处是每一笔调用都知道是哪个团队在消耗月底归因的时候非常清楚。同时也能在某个团队调用量暴涨时单独给这个团队设置上限不让它拖垮全局预算。分发虚拟 Key 时建议把 Key 的权限设置成最小够用原则——只能调它需要的模型而不是整个网关所有模型都能调。这样某团队的 Key 即使泄露影响面也是可控的。5.2 结合可观测性与审计日志网关是流量的必经之地天然适合做可观测性数据的收集点。Litellm 每次请求都会记录请求模型、上游服务商、响应耗时、token 数、费率、状态码。这些数据可以导出到日志系统或监控大盘做实时监控和告警。实际落地时我至少会关注这三个指标请求成功率、P95 响应耗时、每分钟运行费率。成功率掉到 95% 以下就要开始排查P95 耗时突然翻倍很可能是某个模型服务质量劣化分钟级费率可以做成告警防止账单一夜暴涨。审计日志在合规要求比较严的场景里尤其重要。谁在什么时间调了哪个模型、传了什么参数、返回是什么都留痕。Litellm 可以对接数据库存储这些记录方便事后回溯。5.3 高可用与多实例部署单实例网关撑不住的时候就需要横向扩展了。Litellm 是支持多实例部署的配置层面可以做这些事情把配置文件放在共享存储或配置中心所有网关实例加载同一份配置。数据库依赖集中化不要让每个实例用自己的本地 SQLite改成共享关系型数据库。在网关实例前面挂一个负载均衡器业务请求先打到负载均衡再分发到不同 Litellm 实例。多实例部署后虚拟 Key 的管理和用量统计的数据都在共享数据库里所以在用户视角整个集群仍然像一个统一的网关。关于容量评估一个很粗略的参考普通配置下单实例处理每秒十几次请求问题不大更精确的数字要结合模型上下文长度和上游响应速度来压测。如果无法确认瓶颈建议先把限流和队列做好避免瞬时洪水把网关打垮。最后分享一个我在实际项目中很受用的经验接第一个模型服务时Litellm 的价值还不明显接第二个模型时你会觉得“好像省了一点事”真正接入到第三个、第四个时你会庆幸当初做了这个决策。因为此时你的业务代码已经完全稳定新增模型只是在 YAML 里加几行再也不用担心每个服务商的 SDK 差异了。还有一个细节是配置文件的命名规范最好统一一下包括逻辑模型名、团队名、Key 前缀这些小事看起来不起眼等运维和后续接手的同学处理问题时就知道有多重要了。