☰
Litellm 统一大模型 API 调用:OpenAI 兼容网关配置与生产实践
2026/10/21 4:59:43 网站建设 项目流程

先从我自己的一段经历说起。某个做内部知识问答的模拟项目X,上线前要同时调用三家不同厂商的大模型接口,还要兼容一个私有化部署的开源模型。代码里硬编码了三套不同的 SDK、两套鉴权逻辑、四套返回格式解析。那段时间每次改模型参数都要动好几个文件,出问题根本分不清是超时、限流还是格式问题。后来我把入口全部收到一个服务上,那几个文件直接删掉了大半。那个服务,就是今天要聊的 litellm。

litellm 是一个开源的 LLM API 网关与统一代理,简单说就是把各家大模型接口全部收敛成一个标准入口,对外提供 OpenAI 兼容的调用格式。这项能力决定了它的核心定位:不是又一个模型聚合层,也不是简单的配置封装,而是把多模型接入、负载均衡、密钥管理、成本统计这类重复工作,变成一条config.yaml就能解决的问题。适合谁看?如果你正在给团队接入多个大模型、做内部 AI 中台,或者想把项目从单一模型迁移到多模型架构,这篇文章应该能帮你少踩几个坑。

1. 为什么需要统一调用层:从多SDK到API网关

1.1 直连多家模型服务的真实痛点

先说一个很常见的情况。项目最初只用了一家模型服务,直接用官方 SDK 写,速度最快,逻辑最简单。但一旦业务要求做第二家、第三家,麻烦就来了。

最直接的麻烦是接口不一致。不同服务商的/chat/completions参数命名相似但不完全一样,有的要求用system消息、有的用instructions;返回内容里有的带choices[0].message.content,有的套了两层output_text;流式输出的格式更是各家有各家的写法。你在代码里每接一个模型,就得多写一层适配函数,做字段映射、错误码翻译、重试策略。

第二个麻烦是鉴权和密钥散落。开发环境里api_key写在.env,测试环境又写一份,线上还要换一版。团队成员多了之后,谁手里有哪个 key 根本说不清楚,成本账单出来后也不知道是哪个模块、哪位同事调的。

第三个麻烦是容错。线上模型偶尔会超时、限流、报 5xx,你的代码得给每一个服务商都写重试和降级逻辑。如果哪天某家服务不稳定,你得快速把流量切到另一家,手工改代码再发版,显然不是合理选择。

1.2 litellm 的核心设计理念与优势

litellm 解决上述问题的思路,一句话概括:把“适配”这件事从业务代码中抽离出来,下沉到一个独立进程里。业务代码只认一个 OpenAI 兼容接口,底层到底调的是哪家模型、用的哪把密钥、走了什么重试策略,全部在代理层处理。

这个思路很像数据库领域的统一访问层:业务不直接连具体数据库,而是通过一个标准接口读写,底层引擎随便换。你不需要知道数据存到 MySQL 还是 PostgreSQL,只要连接串不换,业务代码就不动。litellm 做的事情异曲同工,只是对象从数据库换成了大模型。

基于这个定位,它的优势非常明确:

  • 无感迁移:现有代码用的是 OpenAI SDK,调整base_url指向 litellm 即可,其他代码基本不用动。
  • 集中治理:所有模型密钥收口到服务端,客户端只持有分配给自己的虚拟 key,可以按团队、按项目设置额度。
  • 统一观测:每次请求用了多少 token、花了多少钱,在代理层全部落账,不用各家控制台来回切换。
  • 降级与容错:主模型不可用时自动切换备用模型,业务方无感知。

这套设计在后端工程里其实是很经典的“门面模式”,但是放在大模型 API 爆发式增长的当下,价值被放大了很多。你永远不知道下个季度要接入哪家新模型,但只要提前留好这一层,未来那个“新模型”只是配置文件里的几行字。

2. 安装部署与基础配置

2.1 两种常见启动方式:源码与容器

litellm 的部署方式非常灵活,上手成本也很低。最快速的方式是直接用 pip 安装:

pip install 'litellm[proxy]'

安装完成后,写一份最小的配置文件config.yaml:

model_list: - model_name: gpt-4 litellm_params: model: openai/gpt-4 api_key: os.environ/OPENAI_API_KEY

然后执行:

litellm --config config.yaml --port 4000

一个本地代理就起来了,监听 4000 端口,对外提供/v1/chat/completions等 OpenAI 风格接口。注意model字段里的openai/前缀不是装饰,而是 litellm 用来识别 provider 的命名空间。每个 provider 都有固定前缀,比如anthropic/claude-3-5-sonnet-20241022、gemini/gemini-1.5-pro、azure/gpt-4、ollama/llama2。这个前缀表在官方文档里有完整列表,用错前缀会导致请求走错 provider 报错。

如果用容器方式部署,官方维护了公开镜像,一条命令就能跑一个由配置驱动的代理服务:

docker run -d \ --name litellm-proxy \ -p 4000:4000 \ -v $(pwd)/config.yaml:/app/config.yaml \ -e OPENAI_API_KEY=sk-xxx \ ghcr.io/berriai/litellm:main-latest \ --config /app/config.yaml

我个人更推荐容器方式,尤其是团队协作的场景。配置文件挂载在宿主机上,升级 litellm 版本只需要换镜像 tag,不需要重复处理 Python 环境的依赖。需要注意官方镜像比较大,第一次拉取会等一会儿,属于正常现象。

2.2 model_list 配置:把模型名映射到真实提供商

model_list是整个配置的核心。它解决的问题是:业务代码用model="gpt-4"去请求,代理层拿到这个名字后,知道实际该把流量送到哪里去。一个模型名可以对应一个地址,也可以对应多个地址,后者就是负载均衡的基础。

下面是一个多 provider 的典型配置,我加了注释:

model_list: - model_name: chat-main litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY - model_name: chat-main litellm_params: model: anthropic/claude-3-5-sonnet-20241022 api_key: os.environ/ANTHROPIC_API_KEY - model_name: embed-main litellm_params: model: openai/text-embedding-3-small api_key: os.environ/OPENAI_API_KEY

这里我用了两个技巧。第一,业务侧看到的模型名chat-main完全抽离了真实模型名,将来把gpt-4o换成别的型号,业务代码不需要改。第二,同一个chat-main配置了两条litellm_params,litellm 会自动在这两个模型之间做负载均衡,一个不可用时自动切换到另一个,这就是故障转移。

api_key推荐用os.environ/变量名这种写法,密钥不要直接写进 yaml 文件。配置文件经常要提交到 Git 仓库,密钥一旦进历史记录,想清理干净非常麻烦,这个坑我踩过。

2.3 验证代理是否工作

配置文件写好后,先用一个简单的 curl 验证链路再接入业务代码,可以省掉很多联调时间:

curl http://localhost:4000/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer sk-1234" \ -d '{ "model": "chat-main", "messages": [{"role": "user", "content": "你好,请简单介绍一下自己"}], "max_tokens": 100 }'

注意默认情况下,代理需要一个主密钥master_key来校验请求。上面的示例里sk-1234是我在配置里临时设置的。更规范的做法是在启动时通过环境变量传入:

export LITELLM_MASTER_KEY="sk-manage-abc123"

如果在验证阶段一直报 401,先检查请求头是否带上了正确的主密钥,以及代理启动时有没有把配置文件正确加载进来。启动日志里如果能看到Loaded config.yaml with N models这类输出,说明配置加载成功了。

3. 统一接口带来的关键能力

3.1 兼容 OpenAI 调用格式,业务代码几乎零改动

litellm 对外暴露的接口完全对标 OpenAI 的接口规范,这一点非常关键。它的实际效果是,你在代码里可以继续用 OpenAI 官方 SDK,只是把base_url指向 litellm,然后所有 provider 都被包装成了 OpenAI 格式。

from openai import OpenAI client = OpenAI( base_url="http://localhost:4000/v1", api_key="sk-从代理生成的虚拟key" ) response = client.chat.completions.create( model="chat-main", messages=[ {"role": "system", "content": "你是一个资深的运维助手"}, {"role": "user", "content": "数据库连接池耗尽怎么排查?"} ], stream=True, )

这段代码和直接用 OpenAI 的代码几乎一模一样,唯一的变化就是base_url和api_key。流式输出也完全兼容,迭代response拿每个 chunk 的delta.content。对于已经用 OpenAI SDK 写完的业务代码,即使底层换成 Anthropic 的模型,业务侧代码也是一行不用动的。

统一接口还有一个被低估的价值:它把团队的“知识面”也统一了。新同学只要会 OpenAI 接口写法,就能在公司内部的模型服务上快速开发,不用每次接新模型都去翻一份新文档。

3.2 负载均衡与故障转移:配置里的容灾方案

第 2.2 节那种同一个model_name配多个litellm_params的写法,就已经具备了最基本的负载均衡能力。litellm 默认会做轮询,但生产环境建议显式配置路由策略。

router_settings: routing_strategy: simple-shuffle fallbacks: - {"chat-main": ["chat-backup"]} num_retries: 3 timeout: 30 allowed_fails: 3 cooldown_time: 60
  • routing_strategy:可选simple-shuffle、least-busy、latency-based-routing。简单场景用随机打乱即可,追求响应速度可以用最低延迟路由,但需要足够多的流量样本才能学出稳定策略。
  • fallbacks:当chat-main对应的所有 deployment 都失败后,自动尝试chat-backup。我习惯专门留一个价格更低或更稳定的模型作为兜底。
  • allowed_fails和cooldown_time:连续失败多少次之后,把该 deployment 拉入“冷却名单”,一段时间内不再发流量给它,避免反复调用一个已经故障的服务。

这里有一个细节值得注意:litellm 的重试和降级不是在单个请求内部无限重试,而是有一套健康状态管理。某个 deployment 如果连续报错,会被临时标记为不健康,后续请求自动避开它。这个机制配合冷却时间,能让故障转移真正稳定落地。

3.3 缓存、限流、成本追踪等进阶功能

除了接口统一和负载均衡,litellm 还提供了一批运维侧高频使用的功能,挑几个最常用的:

缓存。对大模型请求做缓存,效果立竿见影。很多重复的问答请求其实是可以直接复用结果的。litellm 支持本地内存缓存和 Redis 缓存:

litellm_settings: cache: true cache_params: type: redis host: localhost port: 6379 ttl: 3600

开了 Redis 缓存后,如果多个实例共享同一个 Redis,缓存命中率会高很多。注意只在响应内容可复用、不需要实时性的场景开缓存,涉及动态数据的对谈别开。

成本追踪。litellm 自带了用量统计能力,但需要挂一个 Postgres 数据库来持久化数据。等你有几十万条请求之后,用 SQL 直接查某团队、某应用、某模型的花费,比在各家控制台来回切换靠谱太多了。

export DATABASE_URL=postgresql://user:password@localhost:5432/litellm

限流与配额。在litellm_params里可以对单个 deployment 设置速率上限:

litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY rpm: 1000 tpm: 100000

rpm是每分钟请求数,tpm是每分钟 token 数。这个功能之所以重要,是因为多家模型服务商的免费配额或包月额度都有硬性限制,超了轻则报错重则封 key。提前设好阈值,比事后被限流打断业务强得多。

3.4 虚拟密钥与多租户隔离

生产环境不应该把各家模型厂商的真实 key 直接暴露给所有业务方。litellm 的虚拟 key 机制就是为此设计的:主密钥管理系统,业务方拿的是 litellm 生成的sk-开头虚拟 key,针对这个 key 可以单独设置可用模型、预算上限、过期时间等。

curl http://localhost:4000/key/generate \ -H "Authorization: Bearer sk-manage-abc123" \ -H "Content-Type: application/json" \ -d '{ "models": ["chat-main"], "max_budget": 20, "expires": "2025-06-01" }'

生成出来的 key 就可以下发给业务团队。每个 key 的调用量、花费都能在代理里追踪到,等于给每个团队发了一张“子卡”。配合虚拟 key 和团队标签,可以很自然地做多租户隔离,这也是 litellm 在不少企业内部被当成轻量 AI 网关使用的原因。

4. 与主流框架的集成实践

4.1 OpenAI SDK 无缝替换 base_url

与 OpenAI SDK 的集成前面已经展示过了,核心就一句话:把base_url指向 litellm 代理地址,把api_key换成代理生成的虚拟 key。不仅仅 Python SDK 可以这么干,Node.js 的openai包同样支持:

import OpenAI from "openai"; const client = new OpenAI({ baseURL: "http://localhost:4000/v1", apiKey: "sk-从代理生成的虚拟key" }); const stream = await client.chat.completions.create({ model: "chat-main", messages: [{ role: "user", content: "帮我总结一下这篇日志" }], stream: true });

这种方式对很多项目都是迁移成本最低的路径。我之前接手的一个历史项目,原来直接写死了某个模型服务的地址,后来只改了base_url和api_key两个常量,模型请求就走上了带缓存、限流、故障转移的中台服务,改完之后心里踏实很多。

4.2 LangChain 与 LlamaIndex 接入

LangChain 生态里的ChatOpenAI其实也是 OpenAI 接口的封装,同样可以直接指向 litellm:

from langchain_openai import ChatOpenAI llm = ChatOpenAI( model="chat-main", base_url="http://localhost:4000/v1", api_key="sk-虚拟key", temperature=0.7, ) response = llm.invoke("介绍一下这个项目的架构")

LangChain 的OpenAIEmbeddings也一样,把base_url指过去就能同时使用不同的 embedding 模型。LlamaIndex 的OpenAI类也是同样的套路,没有特殊适配逻辑。如果你是做 Agent 应用,底层模型的切换变得非常轻松,前后端逻辑完全解耦。

4.3 本地模型与多服务统一管理

很多团队会有私有化部署的模型服务,比如用 vLLM、Ollama 在内部 GPU 服务器上跑开源模型。这类模型同样可以接入 litellm,配置时使用ollama/、vllm/、openai/之类的命名空间:

model_list: - model_name: local-llama litellm_params: model: ollama/llama2:13b api_base: http://192.168.1.50:11434

接入后,业务代码对这个“本地模型”的调用方式与调用云端模型完全一致。统一入口的好处在这里体现得尤为明显:你可以用同一个 API 网关,把花钱的付费模型和跑在自有机器上的开源模型管理起来,按场景灵活路由。比如简单任务走开源小模型,复杂推理走 GPT 级大模型,这是很多做成本优化的团队在走的一条路。

5. 常见问题与排查实录

5.1 典型故障速查表

我在实际使用中积累了一些高频问题,整理成表格方便对照排查:

现象大概率原因排查方向
401 Unauthorized请求头没有携带有效 key,或 key 已被删除检查Authorization头,确认使用的是master_key或虚拟 key
404 Model Not Foundmodel_name不在model_list配置中核对配置里的模型名,注意区分业务名与真实模型名
400 Bad Request 参数错误给 Claude/Gemini 发送了 OpenAI 风格的max_tokens等参数冲突检查litellm_params是否有drop_params: true,或参数名是否正确
请求超时上游服务响应慢,代理层等待时间不够调整配置文件里的timeout,支持按 deployment 单独配置
某个 provider 频繁报错限流或密钥异常查看代理日志中的上游原始错误,配合冷却时间观察
成本数据为 0没有配置database_url,数据只存在内存中挂 Postgres,并确认请求是否走代理
流式输出中断上游流式格式与代理预期不一致确认请求带stream: true,检查网络代理对 SSE 的支持

5.2 三个容易忽略的配置细节

第一,drop_params开关。各家模型对参数的支持范围不一样,OpenAI 可以用frequency_penalty,Anthropic 则不一定认。如果不希望代理把不支持的参数硬传给上游,可以在litellm_params里设置drop_params: true,让代理把上游不认识的字段静默丢弃,而不是直接报错。这个开关对多模型混跑的场景非常重要,代价是可能会丢掉部分参数效果。

第二,按 deployment 配置独立超时。很多团队只在全局设置了一个timeout,但不同模型服务的响应速度差异很大。开源模型跑在自家 GPU 上,处理速度可能比云端慢很多,一个全局超时很容易误杀。我习惯单独给每个模型配置超时:

litellm_params: model: ollama/llama2:13b api_base: http://192.168.1.50:11434 timeout: 120

第三,内部模型的 SSL 校验。如果接入的是公司内网模型服务,经常是自签名证书或裸 HTTP。此时需要在litellm_params里显式关闭证书校验:

litellm_params: model: openai/custom-model api_base: https://internal-model.example.internal/v1 ssl_verify: false

不设置的话,代理会默认校验证书,导致连接直接失败。这个配置在官方文档里不够显眼,踩坑率很高,大家留意一下。

5.3 从日志里定位问题

litellm 的日志输出非常详细,基本能还原每个请求从进入到转发到上游的完整路径。排查问题时我建议按先后顺序关注三处:请求是否到达代理、代理选择哪个 deployment、上游返回什么内容。如果日志显示请求已经到了代理,但上报的 model 与你配置的model_name对不上,先看请求参数里有没有覆盖配置值。如果上游返回了明确的错误码,比如 429、503,则去对应的模型服务商那里核实配额和负载情况。

6. 生产环境部署建议

6.1 用 docker-compose 搭一个可用服务

一个能上线的 litellm 服务,至少要包含三块:代理服务本身、Postgres 数据库(用于成本与虚拟 key 持久化)、Redis(用于缓存和限流)。如果只跑单机测试,下面这个docker-compose.yml就够用了:

version: "3.8" services: litellm: image: ghcr.io/berriai/litellm:main-latest ports: - "4000:4000" volumes: - ./config.yaml:/app/config.yaml environment: LITELLM_MASTER_KEY: sk-manage-abc123 DATABASE_URL: postgresql://litellm:litellm@db:5432/litellm REDIS_URL: redis://redis:6379 command: --config /app/config.yaml depends_on: - db - redis db: image: postgres:16-alpine environment: POSTGRES_USER: litellm POSTGRES_PASSWORD: litellm POSTGRES_DB: litellm volumes: - pgdata:/var/lib/postgresql/data redis: image: redis:7-alpine volumes: pgdata:

启动之后记得先看日志,确认数据库迁移是否自动执行。litellm 首次连接数据库会建一批表,用于管理 key、记录请求日志,这些表是后续成本统计和虚拟 key 管理的基础。如果数据库连接失败,代理能启动但大部分管理功能会异常,这个顺序问题我遇到过几次。

6.2 安全与监控的几点忠告

关于安全,第一原则是:master_key绝不能泄露给业务方。这个 key 拥有管理端所有权限,包括生成新 key、修改配置。尤其是如果配置里还有各家厂商的真实 API key,一旦 master key 泄露,半个模型资产都没了。我在内部使用时,会把 master key 存在专门的密钥管理服务里,只有负责维护代理的少数人知道。

监控方面,litellm 暴露了/metrics端点,可以接入 Prometheus 抓取请求量、延迟、错误率等指标。生产环境建议至少关注三块:上游错误率、P95 延迟、虚拟 key 的预算消耗速度。前两个问题关乎业务稳定性,第三个问题关乎成本失控。

还有一个在多人协作场景容易踩的坑:不要把每个开发者的本地环境都指向同一个线上代理。至少要在config.yaml里区分好开发和生产配置入口,或者在测试环境单独起一套代理。否则开发阶段的调试请求会把生产环境的成本统计和限流数据搅浑,后续做容量评估都不准。

7. 写在最后:几个实际使用体会

关于 litellm,我最后的体会是:它并不改变你用哪个模型,也不提高模型本身的回答质量,但它能大幅降低“多模型工程化接入”的摩擦成本。真正让它有价值的场景,是当一个团队开始认真考虑多模型策略、成本治理和故障容灾的时候。

我实际用下来,最舒服的地方是切换模型的成本几乎降到零。某个模型服务商政策调整、价格变动,或者新出了效果更好的模型,我只需要改配置文件,业务代码完全不感知。这种底层能力带来的稳定性,比任何单点模型的能力提升都更让人安心。这也是我从最初的“接一个模型调一个 SDK”,到现在所有模型调用都统一走代理的根本原因。

如果你打算在生产环境上它,建议不要一上来就把所有功能都打开。先从最小可用的模型转发开始,确认链路通畅之后,再逐步打开缓存、虚拟 key、成本统计。每加一个功能就测试一轮,这样即使出了问题,也能快速定位到是哪个环节引入的。最后再分享一个小技巧:配置文件里多写注释。你维护的这个代理,半年后大概率不只你一个人在用,把每个模型命名的用途、备选策略写清楚,会省掉未来很多沟通成本。

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

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

立即咨询