1. 从一个“模型调用中间层”说起
第一次接触 litellm 是在一个多模型混用的项目里。当时的需求很朴素:同一个业务逻辑,今天调 A 家的模型,明天可能要换成 B 家的,后天又得接一个本地部署的开源模型做兜底。如果每换一次都要改一遍业务代码,那维护成本会高到让人崩溃。litellm 就是在这个背景下进入视野的——它本质上是一个统一的模型调用中间层,用一套 OpenAI 风格的接口去适配几十种不同的模型服务,让上层业务代码只写一次,底层换模型只改配置。
这个定位听起来简单,但真正用起来之后会发现它解决的问题远不止“换模型不改代码”这么表面。它把多模型路由、成本追踪、失败重试、密钥管理、流式输出、日志回调这些原本需要自己手写一堆胶水代码的事情,收敛到了一个库里面。对于做 AI 应用的人来说,这意味着你可以把精力放在业务逻辑上,而不是天天跟各家 SDK 的差异较劲。
这篇文章适合几类人看:一是正在做多模型接入、被各家 API 差异折磨的开发者;二是想给现有应用加一层模型抽象、方便后续切换或做 A/B 测试的工程师;三是想搞清楚“统一接口”这件事到底怎么落地、有哪些坑的人。我会从设计思路、核心机制、实操步骤、常见问题几个角度,把 litellm 拆开讲透,尽量做到看完就能上手抄作业。
2. 为什么需要统一模型调用层
2.1 多模型接入的真实痛点
先说清楚问题,才能理解 litellm 的价值。假设你手头有三个模型服务要接:一个 OpenAI 风格的云端接口、一个本地部署的开源模型、一个第三方厂商的推理服务。这三家的 SDK 各不相同,认证方式不一样,请求体结构不一样,返回体结构更不一样,连流式输出的分片格式都可能对不上。
如果不用中间层,你的代码里会充斥大量 if-else 分支,每个分支处理一家的调用逻辑。更麻烦的是,当你想加一个“失败自动切换备用模型”的功能时,得在每个分支里都写一遍重试逻辑。想统计每个模型的 token 消耗和费用时,又得在每个分支里埋一遍埋点。这种代码写出来能跑,但几乎没法维护,加一个新模型就是一次小型重构。
litellm 的思路是把这些差异全部吃掉,对外只暴露一套接口。你调用的时候传一个模型名,比如gpt-4o或者claude-3-5-sonnet或者ollama/llama3,它内部根据前缀和配置去路由到对应的适配器。上层代码完全不用关心底层是谁。
2.2 统一接口的核心设计取舍
这里有个关键的设计选择值得说:litellm 没有自己发明一套全新的请求格式,而是直接对齐 OpenAI 的 Chat Completions 格式。这个决定非常聪明,原因有几个。
第一,OpenAI 的接口格式事实上已经成了行业通用语。绝大多数模型服务商都提供了兼容 OpenAI 的接口,或者至少有社区适配。对齐它意味着学习成本几乎为零,你原来怎么调 OpenAI,现在就怎么调 litellm。
第二,生态兼容性好。大量现成的工具、框架、示例代码都是围绕 OpenAI 格式写的,litellm 对齐之后可以直接复用这些生态。比如你想用一个基于 OpenAI 格式的评测工具,直接指向 litellm 就行。
第三,迁移路径平滑。如果你原本就在用 OpenAI,接入 litellm 只需要改 base_url 和 api_key,代码几乎不动。这种“无痛迁移”是它被广泛采用的重要原因。
当然,对齐 OpenAI 格式也有代价。有些模型服务有自己独特的能力,比如特殊的函数调用格式、多模态输入的特殊字段,这些在统一格式下可能需要额外的适配层来处理。litellm 的做法是在保持核心格式一致的前提下,通过额外的参数和 provider-specific 的透传机制来支持这些特性。
2.3 它到底解决了哪些具体问题
把价值说得再具体一点。用了 litellm 之后,下面这些事情从“需要自己写”变成了“配置一下就行”。
- 模型切换:改一个字符串,从
gpt-4o换成claude-3-5-sonnet,业务代码零改动。 - 失败重试与降级:配置一个 fallback 列表,主模型挂了自动切备用,不用写重试逻辑。
- 成本与用量追踪:内置了各模型的计价表,调用后自动算出花了多少钱、用了多少 token。
- 密钥管理:多个模型的密钥统一在配置里管理,不用散落在代码各处。
- 流式输出统一:不管底层是什么格式,对外都是统一的流式分片。
- 可观测性:通过回调机制把每次调用的日志、耗时、结果送到你指定的地方。
这些能力单拎出来都不算黑科技,但组合在一起,就构成了一个相当扎实的工程基础设施。尤其是当你的应用开始规模化、开始在意成本和稳定性的时候,这些东西的价值会成倍放大。
3. 核心机制拆解:路由、适配与回调
3.1 模型名到适配器的路由逻辑
litellm 最核心的机制是基于模型名前缀的路由。当你传入一个模型名,它内部会解析这个名字,决定用哪个适配器、走哪个 API 端点、用什么认证方式。
规则大致是这样的:如果模型名里带有 provider 前缀,比如anthropic/claude-3-5-sonnet、ollama/llama3、azure/gpt-4,它会根据前缀选择对应的适配器。如果没有前缀,它会根据模型名的特征去猜测,比如gpt-开头默认走 OpenAI,claude-开头默认走 Anthropic。
这个设计的好处是显式且可预测。你写ollama/llama3就明确知道走本地 Ollama,不会因为环境变量配错而跑到别的地方去。对于生产环境来说,这种确定性很重要。
实操中我建议始终带前缀,哪怕默认能猜对。原因很简单:显式前缀让代码可读性更好,别人一看就知道这个调用走的是哪家,排查问题时也少一层猜测。而且当你想做批量替换时,带前缀的写法更容易用正则处理。
3.2 请求与响应的标准化过程
路由确定之后,litellm 会把你的请求“翻译”成目标服务需要的格式。这个过程包括几个层面。
参数映射是最基础的一层。比如 OpenAI 用的max_tokens,在某些服务里叫max_output_tokens,litellm 会帮你转换。temperature、top_p、stop这些通用参数也会做归一化处理。
消息格式的转换是另一层。OpenAI 的 messages 数组里,每条消息有 role 和 content,content 可以是字符串也可以是数组(多模态)。litellm 会把这个结构转换成目标服务能理解的格式,比如某些服务需要把 system 消息单独拎出来,某些服务对图片输入的字段名不一样。
响应标准化则是反向的过程。目标服务返回的结果会被转换成统一的 OpenAI 风格响应对象,包含choices、usage、model等字段。这样你的上层代码拿到的永远是同一种结构,不用为每家写不同的解析逻辑。
注意:标准化不是万能的。有些服务特有的字段在转换过程中可能会丢失。如果你依赖某个服务的独有能力,需要确认 litellm 是否支持透传,或者用
extra_body之类的机制手动传递。
3.3 回调机制与可观测性
litellm 的回调系统是我个人觉得最实用的功能之一。它允许你在调用的各个生命周期节点挂上自定义逻辑,比如请求前、请求后、成功时、失败时。
常见的用法有这么几种。一是成本追踪,每次调用后把 usage 和计算出的费用写到一个数据库或日志系统里,方便后续做成本分析。二是日志记录,把完整的请求和响应存下来,用于调试和审计。三是监控告警,当失败率或延迟超过阈值时触发通知。
回调的配置方式很灵活,可以全局配置,也可以针对单次调用配置。全局配置适合做统一的日志和成本追踪,单次配置适合做特定场景的埋点。
这里有个实操心得:回调函数里不要做耗时操作。因为回调是在调用链路上同步执行的,如果你在里面做网络请求或者复杂计算,会直接拖慢整体响应。正确的做法是把数据丢到一个队列里,由后台任务异步处理。
4. 从零搭建一个多模型调用服务
4.1 环境准备与依赖安装
先把环境搭起来。litellm 是一个 Python 库,安装很直接。
pip install litellm如果你需要用到某些特定 provider 的 SDK,可能还需要额外安装。比如走 Azure 的话需要azure-identity,走某些云服务可能需要对应的 SDK。不过 litellm 的设计是尽量用 HTTP 直连,减少对各家 SDK 的依赖,所以大部分情况下一个 litellm 就够了。
版本选择上,建议用较新的稳定版。litellm 迭代比较快,新版本通常会支持更多模型、修复一些适配问题。但生产环境不要盲目追最新,先在测试环境验证过再上。
环境变量是配置密钥的主要方式。litellm 会读取一系列约定好的环境变量名,比如OPENAI_API_KEY、ANTHROPIC_API_KEY、AZURE_API_KEY等。把密钥放在环境变量里而不是代码里,是最基本的安