☰
统一大模型API网关:用LiteLLM解决多模型接入与运维难题
2026/10/12 3:16:12 网站建设 项目流程

前段时间接手了一个内部工具平台的改造,被十几个大模型 API 的接入折腾得够呛。各家 SDK 有自己的请求格式,认证方式五花八门,token 计费单位还不一样,今天这家更新了接口,明天那家报了个新错误码。团队里每个开发都在自己封装 HTTP 调用,重复代码一堆,出了问题谁也说不清是模型的问题还是自己代码的问题。后来我把 litellm 作为统一代理网关接了进去,整个接入流程才算理顺。这篇就聊聊这个项目,以及我在实际部署和运维中摸出来的一些经验。

litellm 本质是一个大模型 API 的代理网关,把市面上主流的大模型服务商接口统一成 OpenAI 兼容格式。你只要按照 OpenAI 的规范去请求它,它负责把请求翻译成目标模型真正能识别的格式,再把响应转回 OpenAI 结构返回给你。除了协议转换,它还内置了 API Key 管理、成本追踪、限流、负载均衡、多模型 fallback 这些生产环境必须要有的能力。适合谁用?如果你手里有多个模型要接,或者团队里有多个人在调模型 API,又或者你被各家的 SDK 版本搞到头大,litellm 都能直接上手。

1. 为什么我没继续让团队直接调各家 SDK

1.1 多模型接入的混乱,远不止“换个接口地址”

先还原一下我最早遇到的问题。项目里需要同时用三个不同家的模型:一个做对话,一个做 embedding,还有一个做长文本总结。刚开始大家各自写代码,A 同学封装了甲家的 Python SDK,B 同学直接拿 HTTP 工具调乙家的接口,C 同学因为丙家的文档不全,干脆用了一个第三方包装库。到了联调阶段就乱了:请求参数命名不一样,有的叫max_tokens,有的叫max_new_tokens;错误处理逻辑也不一样,有的返回 200 加错误码,有的直接 500;计费口径更乱,有的按字符,有的按 token,有的按请求次数。

更麻烦的是模型升级。某家把老模型下线了,我们需要把线上流量切到新模型。如果是直连各家 SDK,就得逐个改代码、重新发版。有了 litellm 之后,这个切换只是在网关的配置文件里改一个模型映射,服务本身不用动。这个价值在频繁调整模型选型的时候特别突出。

1.2 litellm 到底在请求链路的哪一层

litellm 走的是“客户端 -> litellm 网关 -> 各家模型服务”的链路。客户端只需要认识 OpenAI 的接口协议,也就是base_url指向 litellm 的地址,api_key用 litellm 生成的虚拟 key,然后像调用ChatCompletion.create()一样发请求。网关拿到请求后,根据你配置的model_name找到对应的上游模型,把请求体做一次字段映射和格式转换,然后转发给真正的模型服务商。

可以把它理解成公司前台。所有访客不用关心你要找的人在几号楼几层哪个工位,只要告诉前台“我要找技术部”,前台帮你把人带过去。技术部内部怎么组织,跟访客无关。网关也一样,上游是哪家服务商、模型怎么命名、认证用什么方式,对客户端全部不可见。

1.3 它和直接调 SDK 或者用 LangChain 的区别

有朋友问我,LangChain 不也能切模型吗?LangChain 确实可以做模型抽象,但它更偏向应用层的编排,你的代码里还是需要装一堆 provider 的依赖包,而且它更多解决的是“不同的链怎么串起来”的问题,不太关心 API Key 管理、预算控制、统一审计这些运维层面的事。

litellm 的定位更接近基础设施。它只做一件事:把上游模型 API 统一成一个标准的 OpenAI 格式接口。你不一定非要用 LangChain,但你一定需要一个统一的出口。就算你最终不用 OpenAI 的模型,只要你的代码是按 OpenAI SDK 写的,换到 litellm 代理的任意模型上,代码基本不用改。我在实际项目里就是把一个基于 OpenAI SDK 写的老服务直接改了base_url,下游模型换成了别的家,请求照常跑通。

2. 从一个最小配置开始,先跑通再谈优化

2.1 安装环节没有那么多花活

litellm 是基于 Python 的,安装用pip直接装。需要注意的是,它区分两个安装目标:单独的 SDK 安装和带代理的安装。如果只是想在 Python 代码里调用 litellm 的客户端能力,装基本包就行;如果要跑网关服务,必须装带proxy的版本。

pip install 'litellm[proxy]'

国内网络环境下建议指定国内镜像源加速。装完之后可以看下版本:

litellm --version

我遇到过一个坑:如果机器上之前装过比较老版本的 openai 库,litellm 启动时可能会报依赖冲突。建议在干净的环境里装,或者用虚拟环境隔离。我自己习惯用uv管理环境,创建环境然后装依赖,干净利落。

2.2 写第一份 config.yaml

litellm 网关的启动核心是配置文件。第一次用不需要搞得很复杂,先把两家模型配置进去看看效果。下面这份配置是个可以直接抄的模板,我把敏感信息全部用环境变量占位:

model_list: - model_name: gpt-4o-mini litellm_params: model: openai/gpt-4o-mini api_key: os.environ/OPENAI_API_KEY api_base: https://api.openai.com/v1 - model_name: claude-3-5-sonnet litellm_params: model: anthropic/claude-3-5-sonnet api_key: os.environ/ANTHROPIC_API_KEY - model_name: embedding-all litellm_params: model: openai/text-embedding-3-small api_key: os.environ/OPENAI_API_KEY litellm_settings: drop_params: true set_verbose: false

注意这里的model_name是暴露给客户端的名字,可以随便起,客户端请求的时候就用这个名字。而litellm_params.model里的openai/或anthropic/前缀是 litellm 内部用来判断走哪家 provider 路由的标识。比如openai/gpt-4o-mini表示调 OpenAI 的模型,anthropic/claude-3-5-sonnet表示调 Anthropic 的模型。

drop_params: true这个配置建议从第一天就打开。它的作用是:如果客户端传了一个参数是当前模型不支持的,直接丢弃而不是报错。比如 Claude 不接受某些 OpenAI 特有的参数,开着这个开关,网关就自动把多余参数吃掉,避免请求失败。这个开关我在生产环境一直开着,帮我省了不少事。

2.3 启动网关并验证连通性

配置文件写好之后,启动命令很简单:

litellm --config config.yaml --port 4000 --host 0.0.0.0

--host 0.0.0.0很关键,默认情况下网关可能只监听本机回环地址,如果不开这个参数,其他机器访问不到。我第一次部署就是没加这个参数,结果本机 curl 正常,另外一台服务器的请求死活连不上,排查了半天才发现是监听地址的问题。

启动之后,看到类似Uvicorn running on http://0.0.0.0:4000的日志就说明起来了。验证方式可以直接用 curl,也可以写一段 Python 脚本。

curl http://localhost:4000/health/live

返回正常的话,再用 OpenAI SDK 测一下真实调用。我用的是 1.x 版本的 openai 库,写法如下:

from openai import OpenAI client = OpenAI( api_key="sk-anything", base_url="http://localhost:4000" ) resp = client.chat.completions.create( model="gpt-4o-mini", messages=[ {"role": "user", "content": "你好,介绍一下你自己"} ] ) print(resp.choices[0].message.content)

api_key随便填一个非空字符串就能过认证,因为 litellm 默认在没有配置master_key的情况下,不对虚拟 key 做校验。当然这只是本地测试用,真上生产必须把 key 体系建起来,这个在后面讲。

2.4 模型路由和 fallback 配置

模型路由是 litellm 比较实用的能力。客户端可以只请求一个逻辑模型名,网关根据策略把请求分发到多个物理模型上。比如你希望对话请求主要走便宜快速的模型,但允许一个备选模型在失败时顶上,可以这样配置:

model_list: - model_name: chat-main litellm_params: model: openai/gpt-4o-mini api_key: os.environ/OPENAI_API_KEY rpm: 300 - model_name: chat-main litellm_params: model: azure/gpt-4o api_key: os.environ/AZURE_API_KEY api_base: os.environ/AZURE_API_BASE api_version: "2024-06-01"

同一个model_name配多个条目,litellm 会自动做负载均衡。压力大的时候把请求分摊到多个模型上,某个模型挂了就自动重试到下一个可用模型。你可以在router_settings里控制重试次数和超时。实际效果是,有一次我把主模型配错了环境变量,请求自动 fallback 到了备选模型,客户端无感,直到我看监控日志才发现主模型一直是失败的。

3. 核心功能逐个拆解:Key 管理、成本追踪、限流

3.1 虚拟 Key 管理,权限边界一次说清

如果你的网关只给自己用,不配 key 也能跑。但只要团队超过两个人,或者你不想让所有人的请求都“裸奔”在公网上,强烈建议把虚拟 key 机制用起来。

虚拟 key 就是由 litellm 自己生成的 key,客户端请求时带着它,网关校验通过才放行。它跟真实的上游 API Key 完全隔离,客户端永远不知道真正的 key 是什么。生成方式有几种,命令行、HTTP 接口、管理后台都可以。

curl -X POST http://localhost:4000/key/generate \ -H "Authorization: Bearer sk-1234" \ -H "Content-Type: application/json" \ -d '{"models": ["gpt-4o-mini"], "max_budget": 20, "duration": "30d"}'

这里Authorization里的sk-1234是你在启动 litellm 时通过--master_key或环境变量LITELLM_MASTER_KEY配置的管理员 key。上面的示例里max_budget表示这个 key 在有效期内的总花费上限,duration表示有效期 30 天,models限制了它能访问的模型范围。

生成成功后返回一个api_key,这个 key 只会显示这一次,后面再想看也看不到了,所以要妥善保存。客户端拿到这个 key 之后,就把api_key换成它,base_url还是指向网关。这样团队里每个人都有自己的 key,谁的调用量异常、谁超预算了,一目了然。

3.2 成本追踪的真实用法

litellm 默认记录每次请求的 token 消耗和预估费用,存在本地 SQLite 数据库里。你可以在管理后台页面看到实时数据,也能通过 API 查询。

查询某个 key 的花费:

curl http://localhost:4000/usage/key?api_key=your-virtual-key

查询全量记录:

curl http://localhost:4000/spend/logs -H "Authorization: Bearer sk-1234"

这里有个细节:litellm 内置了一张各模型的价格表,但它也有没收录的模型。如果某次请求完成后,发现 spend 统计数据不对,或者很多请求没统计到成本,大概率是这个模型的价格没被识别。这时候需要你在配置里手动指定模型价格,在model_list的条目里加上cost_per_token或max_tokens_per_request之类的字段。我第一次接一个第三方私有化部署的模型时,查了半天文档,最后才发现 litellm 不知道这个模型的价格,请求是通了但成本全是 0。后面手动加了价格字段才统计上。

成本追踪这个功能对开发环境尤其重要。很多团队不限制开发环境的用量,结果有人在测试代码里写了死循环,一晚上调了几万次大模型接口,月底账单数字吓人。上了 litellm 之后,给每个开发环境 key 设好预算,超了就自动拒绝,这个事故直接被扼杀在摇篮里。

3.3 限流和负载均衡,生产环境不能跳过

限流配置可以从两个维度做:模型维度和 key 维度。模型维度是指某个模型每秒最多接收多少请求或多少 token,key 维度是指某个虚拟 key 每秒最多请求多少。

模型维度在model_list里配置rpm(requests per minute,每分钟请求数)和tpm(tokens per minute,每分钟 token 数):

model_list: - model_name: gpt-4o litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY rpm: 500 tpm: 60000

key 维度在/key/generate时传入rpm和tpm字段。当请求超过限制时,litellm 会返回 429 状态码。建议客户端对 429 做指数退避重试,这是标准做法。

负载均衡前文已经提过,同一个model_name配多组上游就能自动实现。litellm 的默认策略是每次从可用列表中随机选一个,也可以通过设置routing_strategy改成round-robin或者least-busiest。这个能力在应对大流量场景时非常有用,但前提是你对模型服务的并发能力有真实了解,别把限流数值拍脑袋。

3.4 流式输出和额外参数透传

很多人用大模型 API 都会开流式输出,litellm 完整支持stream=True的请求转发,响应也是标准的 SSE 流。我测试过中文长文生成,客户端按 OpenAI 流式格式解析没有问题。如果你在日志里看到响应卡住不结束,多半是上游模型服务超时了,需要在配置里调大timeout。默认超时时间不长,生产环境建议至少给到 300 到 600 秒。

litellm 还允许透传一些 OpenAI 标准之外的参数。比如某家模型支持top_k,OpenAI 格式里没有这个字段,你可以在请求体的extra_body里带上,网关会把它透传给上游。这一点在对接国产模型时尤其好用,各家总有自己独特的采样参数,不能因为统一协议就把它们丢掉。

4. 部署上线时我踩过的几个关键坑

4.1 SQLite 还是 PostgreSQL,这是个选择

litellm 默认用 SQLite 存数据。单机、小团队用完全没问题。但当你有多个网关节点的需求,或者虚拟 key 数量超过几千、日志量上来之后,SQLite 会成为瓶颈,尤其并发写入时会出现锁冲突。

生产环境建议接 PostgreSQL。配置方式是在环境变量里指定数据库连接串:

export DATABASE_URL="postgresql://user:password@host:5432/litellm"

litellm 自身有数据库迁移能力,启动时会自动建表。我后来把仓库里所有 key、日志、预算都搬到了 PostgreSQL,查询速度和稳定性明显提升。如果你一开始就用 SQLite,后期数据量大了想迁移,litellm 官方也提供了迁移脚本,不过最好还是决策早一点,免得后面推倒重来。

4.2 用 systemd 跑网关,比 nohup 靠谱得多

我见过很多同学用nohup litellm --config ... &启动服务,进程一挂就没人知道,机器重启后服务也不会自动起来。生产环境建议直接用 systemd。下面给一份可以直接改的 unit 文件:

[Unit] Description=LiteLLM Proxy After=network.target [Service] User=litellm Group=litellm WorkingDirectory=/opt/litellm Environment="DATABASE_URL=postgresql://..." Environment="LITELLM_MASTER_KEY=sk-你的管理key" ExecStart=/usr/local/bin/litellm --config /opt/litellm/config.yaml --port 4000 --host 0.0.0.0 Restart=always RestartSec=5 [Install] WantedBy=multi-user.target

写好之后,systemctl daemon-reload,然后systemctl enable litellm,systemctl start litellm。Restart=always 保证了进程挂了自动拉起。我遇到过上游 DNS 解析临时出问题导致网关崩溃的情况,由于配置了自动重启,服务在半分钟内就恢复了,客户端受到影响的时间很短。

4.3 Docker 部署方案

如果你用的是 Docker Compose 管理集群,litellm 官方仓库里有镜像可以直接用。下面是一个简化版的 compose 配置:

version: "3.9" services: litellm: image: ghcr.io/berriai/litellm:main-latest ports: - "4000:4000" volumes: - ./config.yaml:/app/config.yaml environment: - DATABASE_URL=postgresql://... - LITELLM_MASTER_KEY=sk-... command: ["--config", "/app/config.yaml", "--host", "0.0.0.0"]

注意镜像里的入口命令可能和本地安装的litellm命令行为不完全一致,启动参数用--host 0.0.0.0以数组形式传进去更稳当。这个方案适合已经上了容器编排的团队,配好一次之后,扩展节点只是加个副本的事。

4.4 密钥管理要有点洁癖

配置文件里尽量不要出现明文真实 API Key。那些上游服务的 key 和你的 master key,都通过环境变量或者密钥管理服务注入。litellm 的os.environ/XXX语法就是为了配合环境变量设计的,可以用得很彻底。

另外,如果你的上游是各类云厂商的模型服务,尽量把网关部署在靠近服务商的区域内网,减少公网绕行的延迟。如果公司有合规要求,也可以把 litellm 放在私有子网里,客户端通过内网访问。毕竟网关手里攒着多个云厂商的 key,一旦这台机器被打穿,风险不小。做好安全组规则、只放行必要的端口,是基本操作。

4.5 监控和日志,别等出了事才看

litellm 自带一个管理页面,默认地址是/ui,如果你配置了 master key,页面登录时需要填。在这个页面里可以看到请求量、模型调用分布、失败率、花费这些关键指标。我平时看的最多的就是/spend和/usage,每次给老板汇报 AI 成本,直接截这个页面的图,比什么都直观。

日志方面,默认是控制台输出。日志级别可以在litellm_settings里通过set_verbose: true打开比较详细的输出,但生产环境这个开关一般不建议开,日志量会很大,磁盘容易被打满。建议把日志重定向到日志采集系统,比如 Loki 或者 ELK,再把关键字告警接上。我第一次上线时没接监控,某天下午模型服务商大面积故障,网关日志里全是超时重试,我愣是过了半个小时才从聊天里得知系统变慢了。后面接上告警,5 分钟之内就能发现问题。

5. 常见问题排查与应急预案

5.1 请求返回 401 但 key 明明是对的

出现这个情况,先检查请求头里的Authorization是不是真的带上了。如果客户端用的是 OpenAI SDK,api_key参数传成None可能会让 SDK 自动尝试读环境变量里的某个 key,结果那个 key 是无效的,也会报 401。另一个原因是网关启动了--master_key,而你没有给客户端分配虚拟 key,相当于拿了一个不存在的 key 去访问,当然会被拒绝。解决办法就是调用/key/generate生成一个可用的 key。

5.2 模型提示不存在

如果你按照文档配置了模型,但请求时报模型不存在,先确认请求里的model字段是不是和你配置的model_name完全一致,注意大小写和连字符。之前有同学把配置里的模型名写成gpt-4o-mini,客户端请求时传的是gpt-4O-mini,一个大写 O 的差异让网关找不到对应项,报错跟模型不存在一模一样。这种问题在本地测试时不太容易暴露,因为从日志里看比较难一眼发现。

另外,如果你用了环境变量语法os.environ/XXX,要确认这个环境变量在 litellm 进程里真的存在。我遇到过 systemd 环境下环境变量没配全的情况,配置里引用了一个不存在的变量,litellm 启动时并不一定报错,但调用时就会失败。排查方式也很简单,在服务里打一个测试请求,然后看日志里日志级别为 error 的具体信息。

5.3 响应格式兼容问题

所有模型经过 litellm 转换后都会尽量对齐 OpenAI 的响应结构,但不同模型的字段总有一些细微差异。比如某些国产模型可能不返回usage字段,或者finish_reason的取值不完全一致。客户端代码不要假设所有字段都存在,解析时要做容错。一个比较实用的技巧是在 litellm 配置里给某个模型加上response_format相关的参数,或者让客户端不要过度依赖某个响应字段。

如果你在开发时发现某个模型经过 litellm 后返回的内容和你直连时不一致,可以先停掉 litellm,直接用原生 SDK 或 API 请求一次,对比差异点。大多数情况下是请求参数被drop_params丢掉了,或者是响应字段的兼容映射问题。litellm 社区对常见模型的兼容性维护得很勤快,升级到最新版本往往能解决这类问题。

5.4 网关本身成为瓶颈怎么办

litellm 是 Python 写的,单进程性能虽然不能跟 Go 写的高性能网关比,但在日常百分之几十 QPS 的场景下完全够用。如果你的并发量真的非常大,可以做多实例部署,前置一个负载均衡器,把请求分发给多个 litellm 实例。因为 litellm 的配置和 key 数据都放在独立的数据库里,多实例之间状态可以共享,扩容是很直接的事。

我实测过一个比较典型的场景:内部系统同时有几十个用户在调用,每个用户都在持续流式生成内容,litellm 的 CPU 占用基本稳定在单核 20% 以下。所以对绝大多数团队来说,litellm 的性能不会是短板,真正需要关注的是上游模型服务的稳定性。

5.5 遇到奇怪问题时的通用排查路径

整理一套我自己的排查顺序:

  1. 看 litellm 启动日志里有没有 warn 或 error 级别信息。
  2. 用 curl 直接请求 litellm 接口,排除客户端代码原因。
  3. 看数据库里有没有对应请求的记录,如果有,说明网关收到并处理了请求。
  4. 把set_verbose: true临时打开,重放一次请求,看完整链路日志。
  5. 对照 litellm 官方文档排查配置字段是否有拼写错误。
  6. 升到最新版本,很多兼容性坑都是老版本才有。

这套流程帮我解决了至少八成的问题。剩下的两成,基本都和上游模型服务商最近更新有关——原因是它们改了些接口行为,而 litellm 还没来得及做兼容。这种时候先降级到已知稳定的模型,或者在配置里针对那个模型单独调整参数,不必死磕。

6. 落地推广时的一点体会

litellm 这类工具,最大的价值不在于它有多炫酷,而在于它把团队里“每个人各自对接模型”的混乱局面,收敛成一个清晰的边界。开发不需要关心模型供应商是谁、SDK 是什么版本、价格怎么算,只管像调用 OpenAI 一样调用就行了;管理员只需要在一个地方配置模型、控制预算、查看消耗。这种“上游变化对下游透明”的架构方式,在模型更新换代极快的当下,非常实用。

如果你的团队还在被多模型接入折磨,与其写一堆封装代码,不如直接部署一个 litellm 网关试试。先跑最小配置,再逐步解锁虚拟 key、成本追踪这些能力。有个小建议:尽早把虚拟 key 的管理接入到你现有的权限系统里,比如通过脚本调用/key/generate接口,在用户开通权限时自动发放一个 key,这样整个接入流程会更顺滑,也不会出现 key 满天飞没人管的情况。

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

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

立即咨询