☰
litellm实战:统一大模型API与网关部署全解析
2026/10/13 21:30:15 网站建设 项目流程

1. 多家大模型API来回切换的痛苦,才是litellm真正的用武之地

过去一年,我先后在几个项目里接入了不同的大模型服务商。说实话,最让人头疼的不是模型效果本身,而是API的调用方式五花八门。有的用messages数组传对话历史,有的用input字段;有的返回choices[0].message.content,有的返回completions[0].text;流式输出的格式更是各家有各家的规矩。每换一家供应商,就要重写一遍调用层,再写一堆适配代码,心情极其烦躁。

后来我注意到GitHub上这个叫litellm的开源项目,star数涨得很快。它的思路很直接:把市面上主流大模型供应商的API格式全部统一成OpenAI的格式,这样上层业务只需要维护一套调用代码,底层想换哪家就换哪家。

简单说,litellm做的事情有三层:

  • 统一调用接口:用OpenAI的Python SDK或Node SDK,去调Anthropic、Gemini、Cohere、Bedrock、Azure OpenAI等几十家服务商的模型。
  • 代理服务器模式:本地起一个兼容OpenAI接口的网关服务,所有请求打到这个网关,由它负责转发到真正的模型供应商。
  • 工程化配套能力:包括成本追踪、限流、重试、负载均衡、多key管理、预算控制等,相当于把生产环境调用大模型的脏活累活一并解决了。

如果你只是写个脚本调一次模型,litellm确实帮不上什么大忙——直接装个原生SDK更省事。但如果你要在真实项目里接入多个模型、要切换供应商、要控制成本、要处理限流和重试,litellm几乎是把这些事打包成了一个标准答案。这篇文章我想从原理到部署,再到我实际用下来的踩坑记录,完整聊一遍。

2. litellm的工作原理:一个翻译层加一个网关

2.1 它本质上做的是协议转换

要理解litellm,我建议先抛开“框架”“平台”这些大词,抓住一个核心:它是个API翻译层。

各家模型服务商的请求格式、响应格式、鉴权方式、错误码都不一样。litellm在中间做了一层映射,把OpenAI格式的请求翻译成目标服务商的要求,再把目标服务商的响应翻译回OpenAI格式。你拿到手里的永远是OpenAI风格的response["choices"][0]["message"]["content"]。

我用一个非常生活化的类比:litellm像个同声传译。你和他说中文,他去跟说英语、法语、日语的人交流,回来再用中文告诉你结果。你不需要学英语、法语和日语,只需要会说中文。

这种设计的直接好处是:业务代码的稳定性提高了。供应商A的SDK升级了、废弃了某个参数、改了返回字段,只要litellm跟上适配,你的业务代码一行都不用动。

2.2 两种使用方式:SDK直连和代理网关

litellm提供两种接入方式,对应不同的使用场景。

第一种是SDK方式。

from litellm import completion response = completion( model="claude-3-5-sonnet-20240620", messages=[ {"role": "user", "content": "用一句话解释什么是API网关"} ] ) print(response["choices"][0]["message"]["content"])

你看,completion函数和OpenAI的ChatCompletion.create几乎一模一样,但model参数传的是Anthropic的模型名。litellm内部根据模型名路由到对应供应商,自动处理鉴权和格式转换。这种方式适合在脚本、函数、后端服务里直接集成。

第二种是代理网关模式。

litellm --model gpt-4o --port 4000

这条命令会在本地4000端口起一个OpenAI兼容的代理服务。然后你的代码里只需要把base_url指向http://localhost:4000:

from openai import OpenAI client = OpenAI( api_key="anything_you_want", base_url="http://localhost:4000" ) response = client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": "你好"}] )

注意,这里用的是OpenAI官方SDK,但实际请求会被litellm网关转发到配置好的模型供应商。网关模式的好处在于:业务方拿到的就是一个标准的OpenAI兼容endpoint,不管后端接的是哪家模型、接了几家模型、怎么做负载均衡,业务方完全无感知。

生产环境我建议用网关模式。原因有三个:

  • 业务代码完全和具体供应商解耦,供应商切换只改网关配置。
  • 可以在网关层统一做限流、预算、日志、缓存,代码只写一遍。
  • 多个服务共享同一个网关,不用每个服务各自管理API key。

2.3 支持几百家供应商背后的路由逻辑

litellm支持几百家供应商,靠的是一个命名约定:模型名的前缀即供应商。

比如gpt-4o是OpenAI,claude-3-5-sonnet-20240620是Anthropic,gemini-1.5-pro是Google,bedrock/claude-3-haiku是AWS Bedrock,ollama/llama3.1是本地Ollama。litellm解析模型名里的provider/前缀来匹配路由规则。

这个设计有个好处是心智负担小。你不需要额外传一个provider参数,模型名里自带了。bedrock/前缀的意思是:模型本身是claude-3-haiku,但走的是Bedrock的通道。

生产中如果不确定模型名前缀怎么写,直接做一次空的completion调用,报错信息里通常会列出目前支持的供应商列表和正确的模型名格式。

3. 从零部署一个litellm代理网关:环境准备、配置管理与API key体系

3.1 安装与最小化启动

litellm是纯Python项目,安装很简单:

pip install litellm

装完先验证一下:

litellm --help

看到版本号之后,可以先用最简单的方式起一个代理:

litellm --model gpt-4o --port 4000

如果环境变量里配了OPENAI_API_KEY,这个代理就能直接转发请求。测试一下:

curl http://localhost:4000/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer test-key" \ -d '{ "model": "gpt-4o", "messages": [{"role": "user", "content": "你好"}] }'

返回的JSON结构和OpenAI官方接口一致。到这里,一个最小可用的代理网关已经跑起来了。

3.2 config.yaml才是生产环境的正确玩法

直接用命令行参数起服务适合测试,生产环境必须用配置文件。litellm的配置文件是YAML格式,逻辑很简单:定义哪些模型可以被访问,以及每个模型走哪个供应商、用什么key。

model_list: - model_name: gpt-4o litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY - model_name: claude-3-5-sonnet litellm_params: model: anthropic/claude-3-5-sonnet-20240620 api_key: os.environ/ANTHROPIC_API_KEY - model_name: llama-3-70b litellm_params: model: ollama/llama3.1:70b api_base: http://localhost:11434

用这个配置启动:

litellm --config config.yaml --port 4000

这里model_name是暴露给使用方的模型别名,litellm_params里的model才是真实的供应商模型名。这样设计的价值在于:你可以在不通知业务方的情况下,把model_name: gpt-4o背后从OpenAI换成Azure OpenAI,甚至换成某个自部署的开源模型。

3.3 API key体系:主key与虚拟key的隔离

网关本身也需要鉴权,不然谁拿到端口都能白嫖你的模型额度。litellm提供虚拟key机制,相当于在真实供应商API key前面再加一层。

设置管理员key:

export LITELLM_MASTER_KEY="sk-1234" litellm --config config.yaml --port 4000 --master_key sk-1234

然后可以通过管理接口创建只能访问特定模型的虚拟key:

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

返回的key就是你发给业务方使用的虚拟key。这个key只能调用gpt-4o,且总预算10美金。这样即便key泄漏了,损失也限制在10美金以内。

生产环境中,我强烈建议为每个业务线单独生成虚拟key,配上独立的预算和限流阈值。出了任何费用问题,看key就能定位到是哪个业务、哪个服务、哪个时间段冒的尖。

4. 接入实战:统一SDK、流式输出、多供应商切换与成本追踪

4.1 SDK接入的具体写法

网关跑起来之后,业务侧接入是很舒服的。Python侧用OpenAI SDK:

from openai import OpenAI client = OpenAI( api_key="sk-virtual-key-xxx", base_url="http://localhost:4000" ) def chat(prompt: str) -> str: resp = client.chat.completions.create( model="claude-3-5-sonnet", messages=[{"role": "user", "content": prompt}], temperature=0.7 ) return resp.choices[0].message.content

Node.js侧也一样:

import OpenAI from "openai"; const client = new OpenAI({ apiKey: "sk-virtual-key-xxx", baseURL: "http://localhost:4000", }); const resp = await client.chat.completions.create({ model: "gpt-4o", messages: [{ role: "user", content: "你好" }], }); console.log(resp.choices[0].message.content);

只要团队里约定好base_url和虚拟key,所有服务都按OpenAI的标准写。以后模型从Claude换成GPT,代码里改一个model参数字符串就完事。

4.2 流式输出的坑

大模型应用几乎离不开流式输出。litellm对OpenAI格式的流式透传做得不错,但有几个细节必须留意。

Python侧流式调用:

stream = client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": "写一篇800字的短文"}], stream=True ) for chunk in stream: if chunk.choices[0].delta.content: print(chunk.choices[0].delta.content, end="")

Node侧也类似,用for await遍历。第一个容易踩的坑是:litellm某些模式下,流式响应里第一个chunk可能带role字段但没有content,如果你的解析逻辑只处理choices[0].delta.content没问题,但如果你习惯性读choices[0].delta整体判断,要注意做空值保护。

第二个坑是finish_reason的兼容性。不同供应商对流结束的标记有细微差别,litellm虽然统一成了OpenAI格式,但个别供应商在你stop之后还会多推一个空chunk。这需要你自己做幂等处理。

4.3 切换模型供应商的完整示例

假设业务里原本用GPT-4o,现在想部分流量切到Anthropic的Claude测试效果。整个过程只动配置,不改代码。

先在config.yaml里加上Claude的模型:

model_list: - model_name: gpt-4o litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY - model_name: claude-3-5-sonnet litellm_params: model: anthropic/claude-3-5-sonnet-20240620 api_key: os.environ/ANTHROPIC_API_KEY

重启网关,业务方调用时把model参数从gpt-4o换成claude-3-5-sonnet,完事。如果你想做灰度,还可以利用litellm的负载均衡,让同一模型名随机路由到多个后端供应商。这个后面展开讲。

4.4 成本追踪:不看报表的成本控制都是空谈

litellm内置了一套成本追踪机制,可以自动按模型、按key、按天、按用户维度记录token消耗和费用。它维护了一个模型价格表,大部分主流模型的价格已经内置了,不需要手动配置。

查看网关运行统计:

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

还可以按月看总花费:

curl http://localhost:4000/spend?start_date=2025-01-01&end_date=2025-12-31 \ -H "Authorization: Bearer sk-1234"

如果接入了Prometheus,litellm也暴露了/metrics端点,token用量、请求延迟、错误率这些指标都能直接抓。我自己习惯在Grafana里配一个按小时聚合的token消耗面板——大模型项目的成本失控从来不是某一天突然爆的,而是每天涨一点你没注意,月底一看傻眼。

5. 生产环境必须考虑的工程化配置:负载均衡、重试、限流与预算

5.1 多key负载均衡

当你单个模型的调用量上来了,一个API key可能触发供应商限流。litellm允许给同一个模型配多个API key,轮询使用。

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

注意写法:同一个model_name配了两条,每条对应一个key,litellm收到gpt-4o请求后在两个key之间做轮询。这种配置在开源模型自托管场景下更有意思——你可以把同一模型部署在多台机器上,通过api_base指到不同实例,litellm帮你做流量分发。

5.2 重试策略与退避

大模型接口偶尔会返回5xx,或者429限流。litellm在litellm_params里支持重试配置:

model_list: - model_name: llama-3-70b litellm_params: model: ollama/llama3.1:70b api_base: http://192.168.1.10:11434 num_retries: 3 retry_after: 5 fallbacks: ["gpt-4o"]

这里num_retries是重试次数,retry_after是重试间隔秒数。fallbacks更有意思——如果这个本地模型挂了,自动降级到gpt-4o。这个机制对稳定性要求高的服务来说价值极大。

有一点需要提醒:重试要配合幂等设计。如果你的请求里有非幂等操作(比如让模型生成之后直接扣费),重试可能造成重复扣费或重复业务动作。这种情况建议在业务侧做请求ID去重,而不是完全依赖网关层重试。

5.3 限流与预算控制

litellm的限流配置在key层面:

curl http://localhost:4000/key/generate \ -H "Authorization: Bearer sk-1234" \ -H "Content-Type: application/json" \ -d '{ "models": ["gpt-4o"], "max_budget": 50.0, "rpm_limit": 100, "tpm_limit": 50000 }'

rpm_limit是每分钟请求数,tpm_limit是每分钟token数。配置后,超过阈值的请求会被网关拒绝并返回429。这套机制能够防止单个调用方因为代码bug疯狂循环调用,把整个项目的成本拉爆。

5.4 生产部署:systemd与Docker

真实服务不可能用一个前台进程挂着。我建议用Docker起网关:

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

多个供应商的API key通过-e传进去,config.yaml里用os.environ/XXX引用。这样key不会写死在文件里,也方便在CI/CD里做密钥管理。

内存方面要特别留意。litellm会为每个请求分配一些临时数据,高并发场景下内存上涨比较明显,建议给容器至少512MB内存,并且做内存上限限制。

6. 实测中的高频问题与排查思路

6.1 请求超时的定位与调整

前几天一个服务反馈说流式输出经常"卡住"。我去看litellm日志,发现一个现象:请求转发到了后端,后端也正常返回了,但客户端过了很久才收到第一个token。

问题出在litellm的timeout配置上。默认的超时时间对某些供应商来说偏长,导致在超时未触发时看起来像卡死。解法是显式配置:

response = client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": "你好"}], timeout=30 )

网关侧也可以通过环境变量调整:

export LITELLM_REQUEST_TIMEOUT=30

还有一次是上游供应商自身响应慢,网关已经在等,但客户端那边read timeout设置了5秒。两边超时时间不匹配,会造成客户端先放弃、网关还在等上游的情况。建议客户端读超时设得比网关整体超时略长,链路里就统一了。

6.2 模型名解析失败

又一个高频问题:提示模型不存在。

litellm.exceptions.BadRequestError: litellm.provider_not_found: provider not found

这种基本就是模型前缀写错了。litellm能自动识别的是带正确供应商前缀的模型名,比如anthropic/claude-3-5-sonnet-20240620。如果你直接写claude-3-5-sonnet-20240620,它可能识别不了。注意:在litellm的config.yaml里,除非你配了model_name作为别名,否则真实模型名必须带供应商前缀。

排查这类问题,最快的办法是把报错信息完整贴出来,看它提示的provider not found指的是哪个字段。如果确认模型名没问题,就检查环境变量里对应的key是否设置了,很多"provider not found"其实是"API key not found"的连带报错。

6.3 前后端不一致:流式模式下finish_reason的坑

我在做某个聊天应用时发现,部分响应结束后客户端没有收到finish_reason为stop的chunk,导致前端一直显示"生成中"。

逐个对比了多家供应商的原始流式输出后发现:Anthropic的流式响应里,message_stop事件的形态和OpenAI的格式差异较大。litellm虽然做了映射,但个别版本里对stream_options: {"include_usage": true}的支持不够完整。如果你用了这个参数,建议确认litellm版本是否支持,不支持就升级。

6.4 日志排查的实用技巧

litellm的日志默认是打到标准输出的,能看到每一次请求的目标模型、供应商、耗时和token数。排查问题时,我一般直接过滤关键字:

journalctl -u litellm.service | grep "model="

model=后面跟着的就是实际路由到的模型和供应商。如果发现路由结果和预期不一致,问题多半出在config.yaml里model_list的匹配逻辑上。

还可以用debug模式看更详细的内部请求:

litellm --config config.yaml --port 4000 --detailed_debug

这个模式下,日志里会打印litellm发送给上游供应商的完整请求体,方便确认请求在翻译层有没有被改坏。

7. 总结一些我实际用下来的体会

这套方案在我们这里稳定跑了快一年,我最大的感受是:litellm解决的不只是API格式统一的问题,它把大模型接入从"每换一家供应商就要重新适配一次"变成了"改配置、重启、验证"三个动作。这个改变对团队效率的提升是很直观的——原来开发侧要专门留一个同学维护各种SDK适配层,现在这些工作被吸收掉了,大家可以把精力放到业务逻辑上。

两件我觉得值得注意的事:

第一,不要一上来就全量迁移。litellm的很多高级功能(比如负载均衡、预算控制、多key轮询)需要一定的理解成本。建议先让一个团队用一个模型跑通链路,确认稳定和收益之后再推广。

第二,关注版本迭代。litellm迭代速度极快,三天一个小版本、两周一个大版本很常见。升级前一定要先看changelog,特别是涉及路由规则和配置格式的变更。我这边就遇到过升级后旧配置兼容性出问题的情况,好在都有备份,回滚很快。

有人可能会说:"我直接写个适配层不就完了,何必引入一个框架?"如果只接两三家供应商,自己写适配层确实够用。但当你后面要接的模型越来越多、要处理的问题从"格式转换"上升到"成本、限流、预算、灰度、可观测性"这些工程问题时,自己写的适配层会变得越来越重。这时候litellm这种社区活跃、更新频繁、踩坑人多的方案,反而更省事。

以上就是我个人在litellm上从了解到落地使用的完整经历。如果你们团队也在纠结多模型接入怎么搞,希望这篇能帮上忙。

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

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

立即咨询