☰
用Litellm统一大模型API调用:从OpenAI格式到代理网关实战
2026/10/14 8:54:04 网站建设 项目流程

1. 为什么 Litellm 值得专门写一篇

先亮明态度:如果你正在做 AI 应用落地,或者手里攒了好几个大模型 API 的调用代码,Litellm 这个名字值得你停下来看五分钟。这个开源项目解决的是一个非常具体、又让很多人都头疼的问题——不同模型供应商的接口风格不统一,导致每次接入一个新模型都要重写一遍请求逻辑、错误处理、重试策略。Litellm 做的事情,用一句话说就是:用一套 OpenAI 风格的 SDK 调用几乎所有主流大模型服务,不管是国外的还是国内的,不管是闭源 API 还是本地开源的推理服务。

我第一次接触这个项目是在做一个多模型聚合 Demo 的时候。当时手里有四个不同来源的大模型接口,每个的鉴权方式不一样,超时时间不一样,返回格式也有细微差别。为了统一封装,我花了两天写适配层,结果没过两周又来了一个新接口,适配代码差点把项目撑爆。后来在技术社区里看到 Litellm,才发现这东西把我那两天的活儿全干了,而且干得比我自己写的稳定得多。

这篇文章适合谁?正在做 AI 应用开发、需要对接多家模型 API 的工程师,刚接触 LLM 应用、想省去重复封装工作量的新手,以及想了解业界这类统一网关工具是怎么设计的人。文章会从核心设计思路、实际用法、典型问题和底层原理几个角度展开,尽量做到既能让新手照着抄,也能让有经验的朋友看到一些值得关注的细节。

这个项目的目标很明确:让所有大模型调用层的代码长得一样。你不需要关心背后到底是 Google 的接口还是阿里云的接口,也不需要关心请求是发到了云上还是发到了本地显卡,Litellm 给你一个统一的入口和出口。它的另一个身份是代理服务,你可以把它部署成一个 API Gateway,让团队里的所有服务都走这一个网关去访问模型,这样权限管理、成本统计、流量控制就都有了落脚点。

2. 核心设计拆解:为什么需要这样一层“翻译官”

2.1 各家模型 API 的割裂现状

做 AI 应用的人大多经历过这种痛苦:某个模型的能力不错,但它的 API 请求格式和主流标准差得很多。比如有的平台要求鉴权放在 Header 的自定义字段里,有的平台要求必须带上某个渠道 ID,还有的对上下文格式的要求非常特殊。如果不做一层统一封装,那每接入一个模型,就需要写一份针对性的对接代码。

这种割裂不仅体现在请求格式上,还体现在返回内容的差异上。有的模型正常返回时会有固定的包装结构,有的模型在流式输出时给的是不同的增量格式,有的模型遇到内容审核不通过时的报错码都不一样。如果你在业务代码里直接调用这些接口,那每一处调用都要处理这些差异,业务逻辑和技术细节就会纠缠在一起,代码很快变成了没人愿意维护的状态。

Litellm 的思路就是在这中间加一层“翻译官”。它对内实现每个模型供应商的适配器,对外统一暴露成 OpenAI 风格的接口格式。这样业务代码永远只需要面向一套 API 编程,不管底层接了多少个模型,代码都不用动。

2.2 核心入口统一到 OpenAI 格式的取舍

有人可能会问:为什么不统一成别的格式,偏偏是 OpenAI 格式?这个问题我觉得有三种原因:

一是事实标准。因为 OpenAI 推出的 Chat Completions 接口使用范围太广,很多模型服务商本身就在兼容这套格式,或者提供了兼容模式。Litellm 把它作为统一出口,学习成本最低,社区适配资源也最多。

二是生态成熟。OpenAI 格式的客户端 SDK 非常多,不管是什么语言,都能找到现成的官方库或社区库。Litellm 统一成这个格式之后,你就可以直接用这些库去连 Litellm,等于把整个生态都接到了模型层。

三是对齐很多开源模型的消费端使用习惯。比如很多本地部署的推理框架,本身就参考了 OpenAI 协议设计接口,天然容易对齐。

不过这里要提醒一下:统一格式不等于底层模型的全部特性都能透传。比如某些模型有特殊的采样参数,或者某些平台有自己独有的功能开关,这些在统一封装里要么不支持,要么需要通过额外参数透传。Litellm 对很多模型做了一部分高阶参数映射,但遇到特别冷门的功能,最好还是看下它的官方文档里有没有支持说明。

2.3 普通 SDK 和代理网关两条使用路径

Litellm 给人最大的意外是,它不只是 SDK,还可以直接作为代理服务运行。这两条路径解决的是不同阶段的问题。

第一条路径是只用 SDK。你在代码里引入 litellm 的 Python 包,然后直接调用统一接口,传入模型名和消息内容。它内部会去识别你传入的模型名属于哪个供应商,然后自动选择合适的适配逻辑。这种用法适合单体项目、脚本工具,以及不想额外部署服务的场景。

第二条路径是把它跑成代理网关。你启动一个服务,让它监听某个端口,然后所有业务客户端都把请求发到这个地址。服务内部根据你配置的模型名和密钥,决定转发到哪一家真实提供商。这种用法适合团队开发、多服务共用模型资源的场景,因为它能把密钥集中在服务端管理,避免把各家服务的密钥散落在各个客户端里。

我实际体验下来,这两条路径可以混合使用。本地调试用 SDK 直接调,部署到测试环境后改成走网关,代码层面几乎不需要改动,因为网关暴露的也是同样的接口风格。这个平滑迁移的设计确实省了不少事。

3. 实操要点:安装、配置与三种典型调用方式

3.1 安装与最小配置

Litellm 的安装非常常规,就是一个 Python 包。推荐在虚拟环境里装,避免污染全局 Python 环境。官方推荐用 uv 或者 pip 安装,我一般在项目里加一行依赖即可:

pip install 'litellm[proxy]'

注意这里我加上了方括号里的 proxy 附加组件。如果你只打算用 SDK 模式,不打算起代理服务,那直接装基础包就够了。但如果想体验网关功能,建议把 proxy 相关依赖一起装上,不然启动服务的时候会报缺依赖。

最小配置其实连配置文件都不用写。SDK 模式下,你只需要在代码里设置一下模型对应的 API Key 环境变量,然后直接调用。比如要调一个某国内厂商的模型,代码大致长这样:

import os import litellm os.environ["OPENAI_API_KEY"] = "你的key" # 这里用统一的模型标识 response = litellm.completion( model="gpt-4o-mini", messages=[{"role": "user", "content": "你好"}], ) print(response.choices[0].message.content)

如果你要把某家特殊模型映射成 OpenAI 的统一格式,那就需要在环境变量或配置文件里指定它的 base_url 和 api_key。比如某些兼容接口的地址不是标准地址,需要额外指定。

3.2 统一 completion 接口调用不同厂商模型

刚才的示例是调用默认的 OpenAI 接口。现实中更常见的情况是,你手里还有一个国内模型、一个本地部署的开源模型,想在同一个函数里根据业务逻辑切换。

Litellm 的模型命名规则一般是这样:供应商前缀/模型名。例如调用某厂商的模型就是某厂商/模型名,调用本地 Ollama 上的模型就是ollama/模型名。本地推理框架如 vLLM 部署的模型也可以类似方式指定。

下面这段示例展示了如何用同一个函数调用三个完全不同的模型来源:

import litellm def chat_with_any_model(model_name: str, user_input: str): messages = [{"role": "user", "content": user_input}] response = litellm.completion(model=model_name, messages=messages) return response.choices[0].message.content print(chat_with_any_model("某厂商/某模型", "你好")) print(chat_with_any_model("ollama/llama3.1", "你好")) print(chat_with_any_model("gpt-4o-mini", "你好"))

这里每个模型对应的 API Key 从哪里来?Litellm 会按一个约定顺序去寻找。如果你的模型名带上了供应商前缀,它会去读取对应供应商的 Key 环境变量。你可以提前在虚拟环境配置好,也可以写个启动脚本统一设置。

在使用统一接口时,有几个不太容易被发现的细节值得注意。一是返回结构虽然统一了,但某些字段可能为空。比如有些国产模型不返回 usage 中的 prompt_tokens,或者流式输出的结束符号有细微差别。二是一些模型的上下文窗口差异比较大,如果你在消息里塞了很长的历史记录,可能某家模型能接受,另一家直接报错。统一接口不会帮你截断,它只是负责格式转换,控制权仍然在你手上。

3.3 流式输出与异步调用场景

聊天机器人类的应用几乎离不开流式输出。Litellm 对流的支持做得比较自然,设置stream=True之后,返回值变成一个生成器对象。

response = litellm.completion( model="某厂商/某模型", messages=messages, stream=True, ) for chunk in response: delta = chunk.choices[0].delta.content if delta: print(delta, end="")

这段代码里,每个 chunk 的结构在不同供应商内部可能差异很大,但 Litellm 会把它们都统一成 delta.content 的形式。这一点对业务层非常友好,因为不管背后是哪个模型,前端流的逻辑完全一致。

异步场景下,Litellm 提供了acompletion方法。这个方法配合 asyncio 使用就能实现并发请求的聚合。比如你在做一个内容处理工具,需要同时向两个模型发请求来做交叉验证,就可以用异步简化代码:

import asyncio import litellm async def main(): tasks = [ litellm.acompletion(model="某模型A", messages=messages), litellm.acompletion(model="某模型B", messages=messages), ] results = await asyncio.gather(*tasks) return [r.choices[0].message.content for r in results] asyncio.run(main())

这里要强调一点:异步并发在业务系统里是有收益的,因为多次串行调用模型会让单次请求的耗时累加得很夸张,比如一次串行三次 4 秒的调用,总耗时可能超过 12 秒。改并发后虽然响应时间不一定稳定,但整体吞吐能提升不少。

3.4 代理模式部署与团队共享接入

如果只是个人项目,SDK 模式完全够用。但在团队环境里,我更推荐把 Litellm 部署成一个内部服务。原因不复杂:密钥集中管理、接入统一、接口可观测。

启动代理服务很简单,写一个配置文件,指定模型的虚拟名称和真实后端映射,然后运行命令。一个精简的配置示例值得贴一下:

model_list: - model_name: main-llm litellm_params: model: openai/某模型 api_key: os.environ/OPENAI_API_KEY - model_name: local-fast-model litellm_params: model: ollama/llama3.1 api_base: http://localhost:11434

然后启动服务:

litellm --config config.yaml

启动后,服务会监听在本地 4000 端口。客户端可以直接用 OpenAI SDK 把 base_url 指向这个地址:

from openai import OpenAI client = OpenAI(base_url="http://localhost:4000", api_key="任意值") response = client.chat.completions.create( model="main-llm", messages=[{"role": "user", "content": "你好"}], )

注意,客户端填的模型名是你在配置文件里定义的虚拟名称,不是真实模型名。这样做的好处是,以后底层换模型或者切换供应商,团队内同学只需要知道别名变了,不用关心新模型的鉴权和网络参数怎么配。

从我实际使用的体验来说,代理模式最大的价值体现是在多服务多服务的场景中。因为配置集中了,后续给某个模型加限流、加日志、加成本统计都非常方便,不需要在每一条业务链路里重复写这些逻辑。

4. 常见问题与排错实录

4.1 模型名映射错了还一直报 404

我遇到过好几次,SDK 模式下用某个模型名发起请求,返回 404 或者 401。排查到最后发现问题出在模型名的前缀识别上。Litellm 依赖供应商前缀去定位适配器,如果你的模型确实是某家的,但名字写成了openai/xx,那适配器就会去 OpenAI 的后端找这个模型,结果自然找不到。

这类问题其实很容易排查。看报错信息里的日志,一般会打印它最终请求的地址和鉴权信息。如果地址不对,八成就是映射写错了。解决办法是去官方文档的模型列表里查一下,复制完整正确的模型标识来用。

4.2 抛异常和网络重试策略不合适

不同厂商服务的稳定性天差地别。有的服务偶尔超时,有的服务在高峰期直接 429 限流。Litellm 内置了重试机制,但是默认参数不一定适合每一个厂商。

我一般会单独设置超时时间。比如对某些服务,我把单次请求超时设为 120 秒,因为长上下文生成确实可能超过默认的 60 秒。重试次数我也会调整,因为有的厂商接口幂等性不太好,盲目重试可能出现重复扣费。更安全的做法是写一个外层业务重试逻辑,而不是完全依赖 SDK 的自动重试。

4.3 流式输出中途断了怎么办

流式生成过程中最容易遇到的问题就是连接中断。这在网络环境不稳定或者模型推理较慢时偶尔出现。Litellm 的流式对象不会自动续传,它只会让迭代器结束。这时候如果业务上需要完整的输出,就得在业务层做缓存拼接,并在迭代器意外结束时重新发起请求或者提示用户。

我遇到过的一次情况是,本地模型推理速度太慢,客户端设置的读取超时比推理时间短,导致流中途断掉但是服务端其实还在生成。后来我把客户端的超时参数调大,并且在日志里增加了一条流结束原因判断,问题才稳定解决。这个教训是:流式输出不只是链路通不通的问题,还牵扯全链路的超时配置一致性。

4.4 成本统计和 Quota 管理怎么配

如果大家共用同一个代理网关,很容易出现某个测试同学的脚本把本月额度跑光的情况。Litellm 代理模式里可以配置几种简单的预算控制。虽然它的能力不如专业网关那么完备,但对于中小团队足够了。

配置预算时要注意单位。有些场景下按美元计费,有些按 token 计费,有些按请求次数计费。混合使用的时候要提前约定口径,不然团队内看到的数据互相矛盾,统计就失去了意义。

4.5 本地模型接入后显存不稳定

本地模型接入后,我遇到的另一类问题不是 Litellm 本身的问题,而是网关到本地推理服务的连接稳定性。比如 vLLM 或 Ollama 偶尔会因为显存不足导致一段时间内无法接收新请求。Litellm 不会帮你重启推理服务,但它会把这个连接错误原样抛出。这时候调大上游服务的队列长度,或者给代理配置健康检查,可能比在请求层做重试更有效。

一个可用的小技巧是给本地推理服务也配置别名,并用 Flush 和 /health 接口做定期探测。如果服务不健康,就在网关处对应标记不可用,让业务请求自动转向其他模型。这虽然不如完整的高可用方案精细,但能有效缓解偶发性不可用的影响。

5. 交互设计与方案中的细节决策

这一节我想聊聊,用 Litellm 搭建方案时几个容易忽略的决策点。这些点初看是小事,落在实际工程里却非常重要。

首先是模型别名和版本管理。很多团队直接在配置中写死模型名,一旦供应商升级版本,就要通知所有客户端改名。更好的做法是,在网关配置里定义一个逻辑别名,比如chat-v2,底层指向某厂商的某版本。升级时就只改一处配置文件,所有客户端无感知。这个思路在 API 网关领域很经典,在模型网关这里同样适用。

其次是全局和请求级别的参数覆盖关系。Litellm 支持在配置里设定默认参数,例如 temperature 的默认值、最大生成长度等。但请求时可以传入同名参数覆盖它。理解这个优先级关系很重要,因为如果你的统一服务想要强制某个模型固定使用某个采样参数,那就需要在上层或者网关层把客户端的覆盖能力关掉,或者忽略客户端的传入值。否则总有人会传一个奇怪的高 temperature 值,让结果稳定性变差。

第三是用户身份传递。如果你把 Litellm 代理服务放在内部系统中间,那么上游系统和下游模型的调用链中,用户身份的透传是一个容易忽略但很重要的问题。Litellm 允许你在请求中带上自定义信息或元数据,这样下游的审计和成本分析可以追踪到具体的使用方。设计中如果没有提前预留这个字段,后面补起来成本很高。

还有一种常见的决策是选择 SDK 模式还是网关模式。我的建议是:个人脚本工具,直接 SDK 即可,省心;但只要是多人协作或长期系统,一定要走代理模式。因为把配置集中起来,后续的维护成本和迭代效率天差地别。尤其是当业务发展,模型从两三个变成十几个的时候,这种优势会体现得非常明显。

6. 扩展玩法:基于 Litellm 还可以做些什么

Litellm 解决的是统一接入问题,但它的价值不局限于此。我在实际项目中还看到过一些有趣的扩展玩法,也自己动手试过其中一部分。

一个是模型自动容灾切换。很多服务需要一个高可用策略,即主模型挂了或超时了,自动切到备用模型。Litellm 本身没有提供很成熟的自动切换策略,但你可以利用它统一接口的优势,在业务侧或网关侧写一个判断逻辑:主模型出错后,用同样的 messages 换备用模型重新请求。这比在业务代码里硬编码多个模型的判断逻辑要干净得多。

另一个是基于它做统一日志审计。不管接入多少模型,所有请求最终都通过 Litellm,这意味着你能在统一的位置记录请求时间、模型名、Token 消耗、响应状态等数据。这就等于拥有了一份全链路模型调用台账。后续做成本归因、容量规划、甚至模型质量对比分析,都有据可查。

还有人用它来做模型评估平台的底层能力。假设你要做一个自动评测系统,需要把同一个测试问题发给多个模型然后对比结果,Litellm 的异步并发能力就能派上用场。你只需要维护一个模型名列表,然后用循环加 gather 发起并发请求,就能得到一个横向对比结果。评测逻辑本身和模型来源完全解耦。

再往前一步,如果把 Litellm 代理服务嵌入到公司内部已有的网关体系里,它就可以作为一个“模型路由子模块”存在。前端由公司网关治理流量,后端由 Litellm 处理多供应商适配。这个分层设计非常清晰,适用场景也比较广泛,技术团队内部引入 LiTElLM 不需要做伤筋动骨的改动,只需要在链路上加一个转发节点。

7. 个人实操中的几点心得与提醒

工具看了再多文档,不如动手跑一遍。我自己的实操经验是,第一次用 Litellm 时不需要追求把所有配置都吃透。先从最简单的 SDK 调用开始,把三家不同的模型跑通。跑通之后,再尝试流式输出,然后尝试代理模式。每往前一步,都能对这套工具的边界有更深理解。

从设计思想上讲,Litellm 给我最大的启发是:将“接口适配”和“业务逻辑”彻底分开,是一个成本非常低的架构决策。很多项目早期觉得直接调模型 API 很快,写两行代码就完事,但当模型数量多起来,那些隐藏的成本就会以异常、兼容性调试、重复代码的形式找回来。而 Litellm 这类工具的价值,就是把这个问题提前消灭在架构层面。

在使用过程中也踩过不少坑,比如环境变量没配好导致某厂商的 Key 串门到另一个厂商的请求上,排查了很久;还有一次配置文件写错了模型名前缀,导致所有请求都转发到了一个不存在的后端。这些问题的共性特点是,出问题时表面现象都是模型返回错误,很难一眼看出是模型的问题还是网关配置的问题。建议团队里把日志链路打完整,尤其是让 Litellm 在转发时打印真实的请求目标。

最后想分享一个真实建议:如果你是第一次接触这个项目,不要只看 README,建议直接跑一遍官方文档里的 Quick Start。有很多细节(比如某些模型字段映射的差异)是只有在真实调用中才会暴露出来的。跑通了三个不同模型,你对这套工具的信心才会有真正的底子。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询