最开始有这个需求,是因为我在模拟项目X里接了三套大模型服务:一套官方GPT接口、一套Claude兼容接口、还有一套自建的本地模型服务。它们的数据格式完全不同,鉴权方式也不同,结果就是业务代码里全是if/else分支,今天调这个、明天调那个,日志还混在一起,成本也算不清楚。后来我把litellm作为统一的网关层放在前面,所有模型请求都先走它,由它来负责格式转换、负载均衡、密钥管理和成本统计。这篇文章就从一个实际使用者的角度,把这套工具的搭建过程、核心能力、真实测出来的表现,以及一批配置和运行阶段的坑,完整地写一遍。
1. litellm解决的问题:与其改代码,不如在代码前面加一层
1.1 多模型接入的真实困境
假设你的项目需要同时使用三个供应商的模型接口:OpenAI格式、Anthropic格式、Google格式。你很快会发现三件事:
第一,请求结构不一样。OpenAI用messages数组,Anthropic要system字段单独拆出来,Google的contents里又是另一套结构。同样的“用户和助手多轮对话”,在三个SDK里要写三套构造逻辑。
第二,响应解析不一样。有的返回choices[0].message.content,有的返回content[0].text,流式输出时字段名也不统一。你不得不在主业务逻辑里写一堆关于“字段取哪里”的判断,这套东西跟业务毫无关系,纯属磨人。
第三,出错了各报各的。超时的错误码不同,限流的返回结构不同,重试策略也得针对不同接口单独调。我在项目里一度有超过四分之一的代码是在处理“接口格式适配”,这显然是架构上有问题。
1.2 网关层的思路
litellm做的事情用一句话概括:在你业务代码和多个模型服务之间,加一个统一网关。所有模型请求发给它,它负责按目标服务的格式做转换,转发出去,把响应再转回OpenAI格式返回。
这个“OpenAI兼容”的定位很关键。OpenAI格式事实上有两重价值:一是它是全网公开格式里文档最齐全的,二是大量开源生态(很多组件、SDK、工具链)都把OpenAI兼容作为默认标准。用了litellm之后,业务侧客户端不用换SDK,所有代码围绕一个固定格式写,后面要换模型或者新增模型,只改服务端配置,不动代码。
做个类比:你不希望每次出差都重学当地插座的形状,于是随身带了个转换插头。litellm就是那个转换插头,连接的是业务代码和各类模型服务。
1.3 它到底是什么形态
很多第一次接触litellm的人会把它当成“Python库”,因为装的时候就是pip install litellm,而且它确实提供litellm.completion()这种函数直接调用。但这只是一个“库模式”。
它还有更重要的“服务模式”:启动一个本地服务进程,监听8000端口,提供/v1/chat/completions这样的接口。这种模式下,你的前端、后端、测试脚本、低代码平台、第三方工具,都可以像调用OpenAI一样调用它,由它内部再去路由到真正的大模型。
所以准确地说,litellm是一个可嵌入的大语言模型网关。它既能当SDK用,也能当独立服务部署。我在实际项目里用的是服务模式,这也是我最推荐的方式,因为业务代码里可以直接配一个base_url就能切换到任意后端模型。
2. 搭建与配置:从安装到一次真实可用的请求
2.1 最简安装与启动
先把环境准备好。建议使用Python 3.9以上版本,最好准备一个独立虚拟环境,不要直接装到系统里:
python -m venv lm_gateway source lm_gateway/bin/activate pip install 'litellm[proxy]'[proxy]这个附加依赖会装齐所有跑代理服务需要的组件。如果你只拿它当SDK用,直接pip install litellm就够,但那样很多已有功能(比如UI管理、数据库记录)用不上。
安装完成后,可以先跑一个空配置启动一下:
litellm --port 8000如果能在浏览器里看到管理页面,说明基本环境正常。查对应端口是litellm什么时候开始提供内置管理端的,这个我们要到文章第三部分再展开。
2.2 第一份配置文件的结构
litellm的核心配置是一个YAML文件,比较常见的启动方式是指定配置:
litellm --config config.yaml --port 8000一份最基础、能跑通的配置大概是这样的:
model_list: - model_name: gpt-sample litellm_params: model: openai/gpt-4o-mini api_key: os.environ/OPENAI_API_KEY - model_name: claude-sample litellm_params: model: anthropic/claude-sonnet-4-20250514 api_key: os.environ/ANTHROPIC_API_KEY这里有两个名字容易搞混:
model_name:这是对外暴露的名字。你的业务代码里传的model参数,写gpt-sample,litellm就看到这个名字,然后去匹配内部配置。litellm_params.model:这是真正要调用的模型完整名。格式是“提供商/模型名”,比如openai/gpt-4o-mini、anthropic/claude-sonnet-4-20250514、google/gemini-2.0-flash。
所以实际的意义是:你可以对外暴露一个gpt-sample,后端偷偷换成别的模型,业务代码完全不用动。这个设计在厂商迁移、灰度切换的时候非常省事。
2.3 密钥管理方式
配置文件里不要直接写明文key。litellm支持从环境变量读取,写法是os.environ/变量名,启动前在系统里导入即可:
export OPENAI_API_KEY="sk-xxx" export ANTHROPIC_API_KEY="sk-ant-xxx" litellm --config config.yaml --port 8000也支持本地.env文件,如果同时存在,推荐用环境变量导入的方式在容器编排里更容易管理。我在本地开发时用一个.env文件,生产环境直接在部署平台配置环境变量,原理一样。
2.4 用curl做第一次连通性验证
服务启动后,模拟一个用户请求,确认路由和密钥都配置正确:
curl http://localhost:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-sample", "messages": [{"role": "user", "content": "你好,帮我做一下自我介绍"}] }'如果一切正常,你会收到一个OpenAI格式的响应,里面包含choices字段、model字段显示的是你对外暴露的名字,usage字段则记录token消耗。到这一步,你的业务代码就已经可以用一个统一的OpenAI SDK指向http://localhost:8000了。
一个很小的但容易忽略的点:默认情况下,litellm代理不校验调用者身份,谁拿到8000端口的地址都能调用配置里的模型。正式环境里一定要开启master_key(下面会讲)或者用Apikey管理模块。
3. 路由、预算、成本追踪:litellm真正值钱的三个能力
3.1 多模型路由策略
如果你的服务背后挂了多个相同能力的模型,litellm可以做路由控制,支持权重、优先级和fallback三种方式。
权重轮询适用于“多个模型能力接近、希望按比例分摊流量”的场景:
model_list: - model_name: mix-model litellm_params: model: openai/gpt-4o-mini api_key: os.environ/OPENAI_API_KEY routing_strategy: weight: 70 - model_name: mix-model litellm_params: model: anthropic/claude-sonnet-4-20250514 api_key: os.environ/ANTHROPIC_API_KEY routing_strategy: weight: 30fallback则解决“主模型不可用/限流时自动换备用模型”的需求。注意fallback不是靠配置完成的,而是在每次请求时指定:
from litellm import completion resp = completion( model="openai/gpt-4o-mini", messages=[{"role": "user", "content": "你好"}], fallbacks=[{"model": "anthropic/claude-sonnet-4-20250514"}] )当主模型返回5xx、429、超时等情况时,litellm会自动尝试备用模型。我在实际项目中把主模型设成走已训练私有化的模型,备用模型设成通用云API。效果非常明显:上游一抖动,自动就兜底了,业务方几乎感知不到。
判断参数还有个priority,它和权重是两套独立机制。权重只是分配流量比例,priority则是在“该用哪条路由”这一排序问题上起作用,比如同样一个对外model名配了多个主备模型,按优先级顺序尝试。两套可以同时用,但刚开始建议只用一个,避免行为不符合预期。
3.2 预算和配额管理:给每个用户、每个项目一把独立的尺子
如果litellm只做“多模型统一转发”,那它跟普通的反向代理没太大区别。真正拉开差距的是它在“API Key管理”和“预算控制”上做得很完整。
启动代理时加上--master_key,并开启数据库记录:
litellm --config config.yaml --master_key sk-master-123456 --port 8000然后可以通过管理API创建分发给特定用户或项目的虚拟Key:
curl http://localhost:8000/key/generate \ -H "Authorization: Bearer sk-master-123456" \ -H "Content-Type: application/json" \ -d '{"models": ["gpt-sample"], "max_budget": 5, "duration": "30d"}'这里生成的Key是litellm自己的虚拟Key,业务侧拿它来调用litellm,litellm再转用真实模型密钥。好处是:你不需要把OpenAI的Key发给每个内部用户,谁的Key超预算了就直接失效,即使泄露了也只影响一个有限范围。
预算控制可以分为几个维度:
- Key级别:给每个Key设置最大消费金额。
- User级别:针对最终使用者的唯一标识。
- Team级别:以团队或项目为单位限制总额。
- IP级别:限制某个来源IP的调用量。
我做模拟项目X的对外接口时,只开放了key级别限制和一个30天过期时间,所有内部调用都打在一个虚拟Key上,月底一拉消费列表就能查出哪个业务线开销最大。
3.3 成本追踪:让每一笔token花销都有据可查
成本追踪有两种很典型的用法:
实时查询:每次请求完成后,litellm会把spend(本请求花费)和total_tokens等参数写进数据库。通过/spend/logs接口,输入一个Key,就能看到这个Key的所有请求记录、模型、token数、消费金额、响应时间。
定期报表:通过/global/spend可以拿到所有Key在某个时间窗口内的总消费。做月度对账的时候,我一般是把数据拉出来,按model维度或者按key维度分组,很快就知道钱主要花在哪块。
价格数据来源上,litellm内置了大量模型的价格信息,也会定期更新。如果某个模型的价格没覆盖到,可以在litellm_params里手动指定input_cost_per_token、output_cost_per_token,或者在config里定义一个自有价格表。它在成本跟踪上的精细度,对需要做内部结算和成本归因的团队很实用。
3.4 模型别名与配置文件热加载
除了路由、预算和成本,另一个实际很有用的小功能叫“模型别名管理”。
比如,你内部约定一个别名叫fast-answer,希望它背后的实际模型优先用低延迟模型,如果效果不够好再切到更强模型。配置里可以这样:
model_list: - model_name: fast-answer litellm_params: model: openai/gpt-4o-mini - model_name: strong-answer litellm_params: model: anthropic/claude-sonnet-4-20250514然后业务侧永远传fast-answer。今天你想把fast-answer指向别的模型,改配置,重启全部归一。不改业务一行代码。当然,要不要重启这件事得看你的部署方式。litellm支持通过管理API动态新增、修改、删除模型配置,不需要重启进程;但这个功能在需要持久化数据库的情况下才比较顺手。
4. 实测记录:在模拟项目X里的真实表现与数据
4.1 跨厂商模型切换的测试效果
我在模拟项目X里搭了一个简单的AI客服DEMO:用户提问,系统调模型回答,同时记录token消耗。第一次配置时,我故意在config里同时放了一个国内厂商模型和一个国外商用模型,并让业务侧用同一个OpenAI SDK调用。
效果是:所有请求都通过http://localhost:8000/v1/chat/completions发进去,请求体完全一样,只是model字段不一样。服务端根据不同model名分别路由到不同厂商,返回结构始终一致。整个切换过程中,业务代码零改动。
比较直观的体验是:过去如果我从模型A切到模型B,往往要改请求构造、改响应解析、改错误处理代码;现在只需要在litellm配置里增删一条litellm_params,然后测试一次,就能继续用了。
4.2 流式输出和工具调用的兼容情况
模型在聊天场景和工具调用场景下,返回格式稍有差异。litellm的默认目标是“看起来完全是OpenAI”,所以它对不同厂商响应做了不少适配。
流式输出:把OpenAI SDK的stream=True传给litellm,litellm会把上游流式响应转成OpenAI的data: [DONE]格式。这样前端用EventSource就能无痛对接。实测中,一个接入Gemini流式响应的请求,到了业务侧看到的字段和直接调OpenAI流式接口几乎没有差别。
工具调用(function calling):主流模型现在都支持工具调用,但参数结构略有差异。litellm在转换后,会把工具调用的相关信息放在OpenAI格式的tool_calls里。实际测了一个用Claude模型做“天气查询工具调用”的流程,业务侧完全按OpenAI的tool_calls标准解析,没有改任何代码。
不过在工具调用场景里有个要注意的点:模型自身支持的工具域差异仍然存在。litellm能统一的是“传输和格式”,不是“每个模型都有一模一样的原生能力”。比如某个模型限制了单次请求最大工具数量,它在litellm转换后仍然受这个限制。业务侧最好还是对“传多个工具”的场景做好降级方案。
4.3 成本追踪的实际数据
我在这套测试跑了两周,大概处理了6000多次请求,总token消耗约4200万。最后拉成本报表时,能看到:
- 按日期的消费分布,哪天的调用量异常高。
- 按模型汇总,哪个模型实际占比最大。
- 按虚拟Key维度,哪个具体业务线消耗最多。
有一次我发现某一类请求延迟突然升高,查数据库日志看到是某个模型返回了429限流,而我配置的fallback模型没有生效,因为fallback只在completion()函数指定的时候才触发,代理模式的模型路由则需要配置更细一层的routing_strategy。这个坑我会在下一节详细讲。
4.4 延迟与稳定性分析
延迟主要取决于三块:litellm本身的转发开销、上游模型的响应速度、网络链路质量。
在局域网内自测,大部分请求从业务发起到业务收到完整响应,litellm自身带来的额外耗时在50毫秒以内。对于一次动辄几秒钟的大模型推理来说,这点开销基本无感。
稳定性上,litellm做对了一件事:它默认维护了连接池,上游断连时能快速重试。只要不是配置写错,服务本身可以长期保持稳定,我更推荐在生产环境用Docker容器来跑:
docker run -d --name litellm-gateway \ -e OPENAI_API_KEY=$OPENAI_API_KEY \ -e ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY \ -v $(pwd)/config.yaml:/app/config.yaml \ -p 8000:8000 \ ghcr.io/某个镜像仓库/litellm:main-latest如果是从官方镜像拉,拉下来后启动命令里指定--config /app/config.yaml。Docker化的最大价值不是节省安装时间,而是让你能同时管理多个环境配置。
5. 配置与运行阶段的常见坑
5.1 最经典的混淆:model_name和litellm_params.model
很多人拿着文档学习的时候都会犯同一个错——把model_name当成“要调用的真实模型名”写进业务代码,但业务代码向litellm发送请求时,model字段必须填配置文件里的model_name,而不是litellm_params.model里的完整名。
举个例子,如果你在业务代码里传了anthropic/claude-sonnet-4-20250514,但配置里只定义了claude-sample,你会收到一个“模型不存在”的错误。正确做法是:业务侧只用model_name,配置文件里才知道它背后映射到谁。
一开始不习惯,踩过一次之后就再也不容易忘记:对外名称是配置自由定义的,对内名称带提供商前缀。
5.2 环境变量没有正确加载导致的重试风暴
我在二次修改配置后,出现过一次很隐蔽的问题:key一直鉴权失败。查日志发现,每次请求都触发litellm自动重试,重试又在同一个问题上反复。原因就是我在config里写了api_key: os.environ/OPENAI_API_KEY,但启动服务的那条终端没加载这个环境变量。
更隐蔽的是,服务启动时os.environ/OPENAI_API_KEY如果为空,litellm不一定会立刻报错,因为它可能自动尝试从别的地方找key。最终请求被转发到上游之后才失败,失败后又重试,整个链路看起来就是慢、不稳定。
排查定位方法很简单:启动前先确认能否在终端里直接用Python读取到对应环境变量结构。确保环境变量真的生效之后,再启动代理服务。
5.3 负载均衡权重和fallback行为上的误判
有些配置看起来能用,实际不会按预期走。比如你给同一个model_name配了两个模型,一个权重90,一个权重10,你可能会以为“流量按90:10分”。结果最近突然发现,90这个模型返了4xx错误,另一条模型却没有自动接管。原因正如前文所说:代理模式下“负载均衡”和“故障备援”是两回事。
代理模式要实现自动故障转移,可以在litellm_params里配置:
model_list: - model_name: primary-gpt litellm_params: model: openai/gpt-4o-mini api_key: os.environ/OPENAI_API_KEY routing_strategy: fallback_model: anthropic/claude-sonnet-4-20250514配置后,当主模型返回某种特定错误时,litellm会根据配置满足条件地切到fallback模型。初学阶段建议先把“轮询”和“故障备援”分开测试,确认每种配置下各自的触发条件,再组合使用。
5.4 非对话模型与自定义API地址的接入
litellm支持的不只是对话补全(/v1/chat/completions),还有/v1/completions、/v1/embeddings、/v1/moderations等接口。我在做检索增强生成里的向量化环节时,直接用/v1/embeddings来调通embedding模型,OpenAI SDK的embedding.create()不用改,带一个模型名就能命中litellm配置。
如果你要接本地或者自定义AI服务,比如一个不通公网的自建推理服务,可以在配置里指定api_base:
model_list: - model_name: local-llm litellm_params: model: openai/custom-model api_key: fake-key api_base: http://127.0.0.1:8888/v1注意模型前缀要写成openai/custom-model,引导litellm走OpenAI兼容协议的解析方式。实际请求会转发到api_base指定地址。这个接法测试本地模型非常方便。
5.5 日志与监控:没日志的时候排查是最耗时的
litellm默认的请求日志覆盖了每一次调用的完成时间、总token、状态码、缓存命中情况。如果你在容器里跑,建议把日志挂出来,用日志采集工具统一收集。暴露指标以后,可以在Grafana里直接看到延迟趋势和费用趋势。
我遇到过接口偶尔超时的问题,单独调接口是好的,就是某些时段慢。这种问题没有日志基本上只能靠猜。后来把平均响应时间和分位数响应时间都拉出来,才定位到是上游模型服务在高峰期排队。litellm的日志在排查这类问题上帮助很大,建议第一天上手的时候就养成看日志的习惯。
6. 升级到生产环境的几个建议
6.1 开数据库,用好持久化能力
本地测试时可以不接数据库,重启后就丢了一些统计信息。但生产环境建议用Postgres作为存储,这样虚拟Key、预算信息、消费记录都能持久化。配置里加一行database_url即可启动;首次启动会自动建表。
我的经验是:一旦挂上数据库,就相当于你拥有了一个内部所有模型调用的“审计日志库”。不管从成本角度还是稳定性排查角度,价值都很直接。
6.2 缓存策略,减少重复开销
针对重复提问,litellm支持在网关层做缓存,命中后不重新请求上游模型。可以在请求里带上caching: True,并通过cache_args控制参数:
from litellm import completion resp = completion( model="gpt-sample", messages=[{"role": "user", "content": "今天的天气怎么样"}], caching=True )实测中,对于完全相同的消息,第二次响应时间从原来的两三秒降到了几十毫秒,费用也变成了0。代价是缓存如果设置不当会给出过时答案,所以只建议对“固定知识类、不强调时效性”的问题开。
6.3 多环境管理
dev、staging、prod三套环境,建议用不同配置文件,通过部署时传入不同config路径来切换。不要在同一个配置文件里用条件注释控制多套环境,那会越来越难维护。规范做法是把config文件作为环境配置的一部分,和代码一起做版本管理。
6.4 监控告警与应用集成
litellm的网关层天然能看到所有大模型调用的状态。如果出现特定错误码(比如429限流)、成本突然飙升、某个模型连续多次失败,可以接入告警。个人小团队用简单的方式就可以:轮询接口,记录阈值,触发就推提醒。大团队则建议直接接入现有监控体系,配合自带的指标导出能力。
这些告警在业务量上来之后尤其重要。因为大模型服务的SLA“看起来”由供应商保障,但配置错误、Key失效、紧急限流这类问题,在网关层反而是最容易提前发现和止损的。
我在模拟项目X里跑通这套方案之后,最大的体会是:litellm并没有让任何一类模型变得“更强”,它只是把“同时用多少个模型”这件事的成本从“改代码”变成了“改配置”。如果你现在还在代码里硬编码多个供应商的请求和解析逻辑,建议尽早把网关层加上。刚开始会多一点服务要维护,但一旦模型多起来、调用方多起来,这笔投入的回报会非常明显。另外提醒一句,每次升级litellm版本前,记得看一眼变更日志,这个项目迭代快,偶尔会有配置字段调整,养成“先查后升”的习惯能省不少事。