几个月前我在一个内部工具项目里被模型调用搞到焦头烂额。业务上要同时接好几家主流的模型接口每家的请求格式、密钥认证、超时机制、限流语义都不一样代码里全是if/else分支换个模型要改半天。后来同事把一个叫litellm的开源网关推到仓库里我抱着试试看的心态部署了一版结果一晚上就把散落的调用全部收敛到统一网关后面。如果你也在为多模型接入头疼或者想让算法同学屏蔽底层API差异这篇文章应该能帮你少走很多弯路。1. 为什么需要litellm多模型调用的痛点1.1 被多个SDK拆散的代码早期项目里模型只有一两家事情很简单。请求封装成一个函数传入模型名调对应的SDK。随着模型数量增加代码开始变味。A厂商的SDK要求用某个client对象发请求B厂商的参数叫model_id而不是modelC厂商的流式返回格式又完全不一样。于是业务层不得不写一堆适配代码每接一个新模型都要重新理解它的认证方式和频率限制。最难受的是这些适配代码往往落在业务模块里排查问题的时候要在Model层和Service层来回跳。用生活里的例子来说每个模型API都像一种专用插座而你的业务代码是一堆需要同时供电的设备。如果每台设备都配一个专用插头你就要在桌面上摆满变电器。litellm做的事是在所有插座前面放一个统一的转换排插业务设备只认一种插头具体插到哪个插座由排插去处理。1.2 代理网关的核心价值我第一次用litellm的时候理解的只是一个“格式转换器”。后来才发现它的核心价值远不止转换而是把模型调用从业务代码里彻底剥离出去。业务侧只需要知道“我要调哪个逻辑模型”不需要关心这个逻辑模型背后是哪个厂商的哪套接口。逻辑模型到物理模型的映射全部放在网关的配置文件里。这个设计带来的直接好处是换模型从“改代码发版”变成“改配置重启”。之前我们灰度一个新模型需要业务代码传不同模型名还要保证两个分支逻辑一致非常容易漏。现在只要在config.yaml里调整model_list的映射关系甚至可以用同一个model_name指向不同上游按路由策略分流。第二个好处是集中治理。密钥、预算、限流、日志这些横切关注点不用在每个业务系统里各做一套网关统一管。对平台型团队来说这意味着算法同学可以自助申请虚拟key后台能看到每个key花了多少钱、调了多少次不用再追着运维要账单。2. litellm核心能力拆解2.1 兼容层把一切变成主流格式litellm最容易被感知的能力是兼容层。不管上游是哪种协议网关对外统一暴露/chat/completions、/embeddings、/completions等端点请求体和响应体尽量贴近目前业界最常见的LLM接口格式。客户端直接用标准SDK把base_url指到litellm地址就行。这里有个细节要说明litellm的前缀路由机制。当你配置litellm_params.model时如果写成openai/your-model它会走OpenAI兼容协议如果写成anthropic/your-model会走对应厂商的协议。前缀不是给客户端用的而是告诉litellm“上游是哪条生态”。所以客户端永远不用改协议需要改的是网关配置里的前缀。兼容层的实现并不是简单透传请求。它要处理不同厂商API在系统提示词、消息格式、工具调用、流式事件上的差异。一个典型例子是某厂商的流式返回把usage放在最后一条消息而另一个厂商要求额外参数开启才会返回usage。litellm在内部做了归一化客户端拿到的流式响应结构是统一的。这个归一化过程偶尔会有边界问题比如某些模型的特殊参数传不进去后面我会在踩坑部分细说。2.2 模型路由与负载均衡当同一个逻辑模型背后挂了多个物理模型时路由策略就派上用场了。litellm支持几种策略简单的随机打散、轮询、最少连接数、基于延迟、基于使用量、基于成本等。默认是随机打散适合试验环境生产环境我更常用轮询或最少连接数让请求尽量均匀地分散到多个上游。路由配置在router_settings里修改可以针对全局设置也可以每个模型单独覆盖。比如某个高优先级模型我希望它优先被选到就把路由策略设为priority模型列表的顺序就是优先级顺序。靠前的模型先被使用只有不可用时才往后找。还有一层是模型间的降级关系。除了负载均衡litellm支持显式配置fallback当主模型返回限流、超时或者5xx时自动把请求转给备用模型。这对保证线上可用性很有用。我们之前遇到过某厂商凌晨升级导致偶发超时配置了fallback之后用户几乎没有感知。需要提醒的是fallback不是银弹它依赖对“可重试”的判断后面我会专门讲。2.3 预算与密钥管理如果litellm只是纯代理其实价值有限。它真正的优势在于把API key做成了两层。第一层是上游厂商key只保存在litellm环境变量或config里业务方永远接触不到。第二层是litellm生成的虚拟key业务方拿到的是一把加过前缀的网关key。这把key可以在网关后台配置能访问哪些模型、每分钟/每天最多多少请求、总预算上限是多少还能设置有效期。一旦超出网关直接返回限流或鉴权错误不会把请求打到上游。预算管理适合内部多个团队共享一个网关的场景。比如A团队做原型验证预算设为50元B团队做生产预算更高但绑定固定模型。每把虚拟key的用量都会被记录后台能看到“哪个团队用了多少token、花了多少钱”。这个功能帮我们省掉了另外开发一套计费面板的工作。2.4 日志与可观测性网关天然是日志的汇聚点。litellm默认会把每次请求的关键信息记录下来请求的模型、虚拟key、客户端信息、prompt和response的大致内容、token用量、延迟、费用估算、状态码等。在开发模式写SQLite生产模式可以接Postgres或者通过回调把日志推到自己的监控系统。可观测性的意义不仅仅是排查故障。它还能用来做容量规划和成本分摊。比如有一段时间我们发现某个模型的token消耗突然涨了一倍但业务量没涨查日志发现是某个新上线的定时任务把上下文窗口开得特别大顺手优化掉了。如果没有统一网关这类问题可能要等月底账单出来才能发现。litellm还暴露了指标端点可以接入Prometheus等监控体系把请求量、延迟、错误率、token消耗变成指标。配合告警规则比纯看日志要高效很多。到这里litellm的能力轮廓已经清楚了下面进入实际操作。3. 从零部署litellm网关3.1 安装与启动先说明一下litellm本身是一个Python包但为了管理多实例和配置通常以代理模式启动。安装很简单pip install litellm[proxy]这样会把网关依赖和数据库驱动一起装好。如果你用Docker也可以直接拉镜像跑不过我更推荐本地先跑一遍方便看日志。最小启动方式是直接命令行指定模型但生产环境不推荐因为配置分散。强烈建议用config.yaml管理。第一步先建一个配置文件里面至少包含model_list和litellm_settings。然后在项目目录执行litellm --config config.yaml --port 4000首次启动时litellm会打印一个master key。这个key是网关超级管理员密钥用来调用管理接口和生成虚拟key千万别泄露。如果没有打印或者忘了可以通过/key/generate配合已保存的数据库重新生成具体后面会提到。启动成功后访问http://localhost:4000/health应该能看到状态正常。3.2 用config.yaml管理模型下面给一个最简配置两位提供方各一个模型并且用环境变量引用密钥避免把明文密钥写进仓库model_list: - model_name: gpt-main litellm_params: model: openai/your-model-id api_key: os.environ/LLM_PROVIDER_A_KEY - model_name: claude-backup litellm_params: model: anthropic/your-model-id api_key: os.environ/LLM_PROVIDER_B_KEY litellm_settings: drop_params: true request_timeout: 60这里有几个容易踩的点。model_name是客户端请求时要传的模型名它可以是任何字符串不一定和上游模型名一样。litellm_params.model里的openai/和anthropic/是路由前缀告诉litellm走哪种上游协议。drop_params: true很关键它会忽略上游不认识的参数。比如某厂商接口不支持某个采样参数设置了这个选项后litellm会在转发前把这类非法参数丢掉而不是直接报错。request_timeout建议按业务调大一点默认值在一些长思考模型场景下容易超时。如果模型响应很慢可以单独为litellm_params加timeout覆盖全局值避免所有模型共用一个超时。3.3 用标准SDK接入配置写好之后接入方式比想象中简单。以Python客户端为例你不需要引入litellm的client直接用常见的主流兼容SDK把base_url指向网关即可from openai import OpenAI client OpenAI( api_keysk-litellm-虚拟key, base_urlhttp://localhost:4000, ) resp client.chat.completions.create( modelgpt-main, messages[ {role: system, content: 你是一个助手}, {role: user, content: 帮我总结一下这段文本}, ], ) print(resp.choices[0].message.content)这个客户端请求发出后litellm会拿着虚拟key做鉴权查到它允许访问gpt-main然后根据model_list里gpt-main对应的上游配置发起真实请求再把响应转成统一格式返回。整个过程业务代码不感知后端是哪个厂商以后哪怕把gpt-main换成任何其他供应商客户端代码一行都不用动。其他语言也类似只要是能设置base_url的兼容客户端都可以接入。比如JS里把baseURL指到网关地址Java里把apiHost指过去。如果团队里有老项目用的是原始HTTP调用也可以直接请求POST /chat/completions传JSON即可。3.4 生产环境部署建议本地跑通之后别急着把单进程放到线上。litellm本身是无状态网关可以多实例横向扩展。实例之间需要共享配置和状态所以生产环境建议把默认的SQLite换成Postgres并且开启Redis作为限流存储。一个可用的部署拓扑是前置负载均衡器后面挂两到三个litellm实例数据库用PostgresRedis保存虚拟key维度的速率计数。启动时可以加--database_url和--redis_host参数。实例数根据请求量调整初始阶段两个足够。还有一点生产环境建议通过环境变量指定主密钥比如LITELLM_MASTER_KEY这样密钥不会打印在日志里也方便容器平台注入。配置文件的密钥统一用os.environ/变量名引用生产密钥放在密钥管理服务里提交到仓库的只是占位符。这样即使配置仓库泄露也不会直接泄露上游厂商的key。4. 路由策略与成本优化进阶4.1 按优先级路由很多团队并不是单纯想“多模型轮询”而是希望有一个稳健的主备关系。比如主力模型能力更强但价格贵、偶尔限流备用模型便宜能力稍弱只在主力不可用时才调用。要实现这个效果把列表顺序当作优先级并把路由策略设为prioritymodel_list: - model_name: chat-default litellm_params: model: openai/your-main-model api_key: os.environ/LLM_PROVIDER_A_KEY - model_name: chat-default litellm_params: model: anthropic/your-backup-model api_key: os.environ/LLM_PROVIDER_B_KEY router_settings: routing_strategy: priority num_retries: 1 retry_after: 0.2注意这里两个条目的model_name都是chat-default客户端只要调用这个名网关会优先选择第一个条目。当第一个条目连续失败或触发限流时litellm会在重试过程中自动落到第二个条目。num_retries控制重试次数retry_after控制重试间隔间隔不宜过大否则用户等待时间会累积。这种主备模式的适用场景很明显核心链路需要一个高可用兜底。我们实测过主模型因为账号余额问题返回403时网关在几百毫秒内降级到备用模型下游业务拿到的是正常响应没有感知到故障。不过要注意403如果是鉴权失败可能是密钥配置有误这时候fallback会掩盖配置错误排查时要结合日志看清楚。4.2 按延迟与成本路由当多个上游模型能力接近时可以进一步做动态路由。litellm支持基于延迟的路由和基于成本的路由。前者会记录每个模型实例的历史响应延迟把请求优先分配给当前最快的一个后者优先选择估算成本更低的模型。这两个策略适合对响应时间敏感或对成本敏感的批量任务不适合需要固定模型能力的场景。按延迟路由有个前提就是多个上游确实都能完成同一类任务否则每次效果差异会很大。我们做过一次小规模对比两个模型都开流式响应延迟路由策略下p95延迟比固定路由低了约三成。但要注意延迟数据是有窗口的刚开始没有足够样本时litellm会退化为默认策略所以不要在冷启动阶段就依赖它。按成本路由要结合计费模型理解。litellm内置了常见模型定价表配置成本路由后它会根据输入输出token估算成本并优先选便宜的上游。如果上游是私有化部署或自定义计费可以在模型参数里维护输入输出单价让成本计算更准确。4.3 失败降级的正确姿势凡是涉及自动降级都要先想清楚一个问题请求能否安全重放如果业务是文本生成重放通常是安全的但如果是工具调用、订单查询、状态变更重放可能产生副作用。litellm的fallback发生在请求层它默认会重试同样的请求。所以我建议在设计上游接口时尽量让业务逻辑对重复请求保持幂等否则降级策略要谨慎开启。来看一个具体配置示例litellm_settings: fallbacks: [ { openai/your-main-model: [anthropic/your-backup-model] } ] cooldown_time: 30 allowed_fails: 3fallbacks定义主模型失败后转向哪些备用模型。cooldown_time表示某个上游连续失败后进入冷却的秒数冷却期内不会再把流量分给它。allowed_fails是触发冷却前允许的失败次数。这几个参数要一起调不然可能出现上游只是抖了一下就被冷却半小时的情况。还要注意fallback和重试的叠加关系。如果num_retries设置得比较大一个失败请求可能会先在同模型上重试多次然后再fallback。我一般会把num_retries控制在1次把主要可靠性放在fallback上这样整体延迟更可控。5. 常见问题与排查实录5.1 报错速查表实际使用litellm过程中我遇到最多的问题都集中在配置和权限上。整理一个小表方便你直接对照。报错/现象常见原因处理方式AuthenticationError虚拟key不存在或无权访问该模型用master key重新生成key并检查模型范围NotFoundErrormodel_name没有在config里注册检查model_list重启网关RateLimitError超出上游限流或虚拟key配额增加重试/fallback或调整key的速率限制TimeoutError上游响应慢全局超时太短调大request_timeout或按模型单独设置timeoutContextWindowExceededError请求token超长检查消息长度必要时分段或改用更长上下文的模型流式响应缺少用量信息上游需额外参数才能返回在模型参数中开启对应选项或在litellm配置中补齐这里特别想提醒的是NotFoundError。它不一定是你客户端模型名写错很可能是网关启动后修改了配置文件但没重启。litellm的热加载能力有限修改model_list后最好手动重载或重启实例。我们曾在线上改配置没重启新模型一直404排查了半天才发现配置没生效。5.2 密钥生成与配额管理litellm的master key和虚拟key概念容易混淆。简单说master key是管理员的能调管理接口虚拟key是给业务用的自身带限制。第一次启动时自动生成的master key可以在日志里找也可以手动指定环境变量LITELLM_MASTER_KEY。生成虚拟key的常见姿势是用管理接口curl -X POST http://localhost:4000/key/generate \ -H Authorization: Bearer sk-你的-master-key \ -H Content-Type: application/json \ -d { models: [gpt-main], max_budget: 10, rpm_limit: 60, duration: 1d }返回体里会包含生成的key。注意虚拟key只显示一次过后拿不到明文所以生成后要立刻保存到自己的密钥系统里。max_budget的单位是美元如果你的上游是其他货币计费可以结合自己的成本模型换算别让预算形同虚设。在实际运营中我还习惯给每个环境用不同的master key开发环境一套生产环境一套。这样即使开发环境的key泄露也不会影响生产。配合网关的团队管理接口还能按团队维度配置预算和模型白名单比单把key更灵活。5.3 性能与稳定性优化最后聊聊上线后容易忽略的细节。第一是数据库连接池默认SQLite扛不住多实例并发生产务必切Postgres并关注连接数。第二是日志量如果每个请求都落全量prompt数据库会很快膨胀。我们后来改成只保留metadata和token统计prompt脱敏后存对象存储需要复盘时再回放。第三是流式响应的处理。litellm转发流式内容时会做事件解析和重组这个过程的CPU开销比普通非流式要高。如果并发量很大建议把网关实例CPU核数配足并监控p95延迟。第四是健康检查。负载均衡器最好配置好存活探针和就绪探针这样实例升级时流量能平滑摘除。还有一个小技巧如果某些上游API很不稳定可以在litellm_settings里配置allowed_fails和cooldown_time让网关自动把坏实例摘掉。我们早期没有配冷却导致一个异常模型被持续轮询到拖慢了整体可用性。加上冷却后故障模型会被临时隔离整体成功率明显回升。litellm用下来我最强烈的感受是“换模型不再是一场发布事故”。以前改一个模型要协调算法、后端、运维代码评审加回归测试跑一个下午现在只是在config里加一行映射然后重启网关。踩过几次坑之后我现在做任何新项目的模型接入都会先问一句能不能走litellm如果团队已经有网关就直接复用如果没有我会建议花半天搭一个而不是继续在每个服务里写各自的SDK适配。模型这个领域变化太快把底层差异收敛在一个代理层是我目前觉得性价比最高的做法。