做AI应用开发这几年,我踩过最多的坑,就是各家模型API不统一:这家用prompt,那家用messages;这家叫max_tokens,那家叫max_tokens_to_sample;返回结构更是千奇百怪,换一个模型就要重写一遍客户端。后来我用LiteLLM把这堆事情全部收编了,一个接口接所有模型,省下来的时间足够我多调好几轮prompt。如果你也在被多模型接入折磨,或者想给团队搭一个统一的模型网关,这篇分享应该能给你省下不少弯路。
LiteLLM本身是一个开源项目,核心就一句话:把市面上主流大模型API全部转成OpenAI兼容接口。它有两种用法,一种是作为Python库直接嵌进你的代码里,另一种是起一个代理服务,让整个团队或所有后端服务都通过这一个网关去访问不同模型。配合上密钥管理、成本追踪、负载均衡、自动重试这些能力,它基本就是一个轻量级的LLM网关。
我在实际项目里同时用到了这两种形态:本地脚本和快速验证用SDK,线上服务统一走代理。这篇就把我的使用经验、踩过的坑和关键配置都整理出来,希望能给你一个可参考的落地路径。
1. 为什么需要LiteLLM:多模型接入的切肤之痛
在聊配置和代码之前,先得搞明白一个问题:市面上已经有那么多模型服务商和封装工具,为什么我还要专门维护一个LiteLLM?说白了,是因为多模型接入这件事,远比你想象的更折磨人。
1.1 各家的API从来就没有统一过
先说最直观的:请求格式。OpenAI系的接口用messages数组传对话历史,每条消息有role和content;有些平台则用prompt直接塞字符串;还有些偏学术的部署框架,喜欢用inputs或者text作为字段名。你以为只是字段名不同?参数名也不一样,OpenAI叫temperature,有的平台叫temperature但取值范围不同,还有的干脆叫top_p却不支持temperature。
这些还只是接口层的问题。往下挖,鉴权方式也各有各的脾气:有的是Authorization: Bearer,有的要求x-api-key,还有的要你在请求体里单独塞一个api_key字段。返回结构更不用说,OpenAI的choices[0].message.content是一个固定的访问路径,但别家返回的长得完全不一样,有的是data.choices,有的把内容放在output.text里。
这种差异带来的直接后果就是:你每接入一个新模型,就要写一套新的请求构造逻辑、响应解析逻辑、错误处理逻辑。如果只是自己跑个Demo还好,一旦在上生产环境,把这些写进业务代码里,后面每换一次模型就要动一次代码、发一次版、回归一轮测试。我见过不少项目,半年之后代码里躺着四五套互不兼容的模型客户端,维护成本高得吓人。
打个比方,这就跟你家里的电器一样,每个厂家都用自己的插座标准,你要么给每个电器配一个转接头,要么干脆装一个万能插座。LiteLLM干的就是这个"万能插座"的活儿——你只需要写一套OpenAI格式的代码,它帮你把请求翻译成各平台能听懂的语言,再把各平台返回的数据翻译回OpenAI格式。
1.2 统一网关的定位与设计思路
LiteLLM选择把所有模型都"翻译"成OpenAI兼容格式,这个设计决策非常聪明。原因有两个:第一,OpenAI的API格式是事实上的行业标准,生态最成熟,几乎所有的开源工具、框架、SDK都原生支持OpenAI格式;第二,对开发者来说,学习成本最低,你会了OpenAI SDK,就等于会了LiteLLM。
整个项目的定位可以理解为"LLM请求的路由器兼翻译器"。你往它里面塞配置,告诉它哪个虚拟模型名对应哪家平台的哪个模型,然后所有请求都打到这个统一入口,由它来决定:这个请求应该转发给谁、用哪个key、要不要重试、要不要记录成本。
这个思路的好处是,业务代码和模型提供商彻底解耦了。你的业务代码只认识"gpt-4o"这个名字,今天它可能真的在调用OpenAI的gpt-4o,明天你把这个虚拟模型名重新映射到另一个平台的同类模型,业务代码不用动一行,只要改配置、重启服务就行。对于需要频繁对比不同模型效果、或者担心被单一平台绑定的团队来说,这个灵活性非常值钱。
不过也要说句公道话,LiteLLM不是万能的。各家模型的特殊参数它虽然大部分都转发了,但极个别独特的、不常见的参数可能没法完全兼容,需要你在虚拟模型配置里用extra_body之类的字段手动透传。所以它解决的是80%的通用场景,剩下20%的个性化需求还是要有Backup方案。
2. 架构与核心功能拆解
想把这个工具用好,光知道"能接很多模型"不够,还得理解它的整体结构。LiteLLM的架构核心其实就两层:入口统一,出口多样。入口永远是一个OpenAI风格的API,出口则通过配置决定。
2.1 SDK与Proxy两种工作模式
LiteLLM提供两种工作模式,适用场景完全不同。
第一种是SDK模式。你在Python代码里直接import litellm,然后调用litellm.completion()方法,传入model参数和messages参数就行。SDK模式下面,LiteLLM库本身承担了翻译、鉴权、重试、成本统计这些工作。这种方式的好处是轻量、灵活,适合在本地脚本、数据分析、模型对比测试这类场景里用,代码部署起来最简单,不依赖额外的服务进程。
第二种是Proxy模式。LiteLLM起一个独立的HTTP服务,监听一个端口(默认4000),所有请求都通过HTTP发到这个服务,再由它转发到底层模型平台。这个模式更接近企业级网关的用法:部署一次,团队共享;前端、后端、测试脚本都通过这个网关访问模型。密钥集中管理,不需要把各家平台的key发给每个开发人员;成本统一统计,方便核算;还可以在网关层做限流、配额、负载均衡。
我的建议是:个人项目或者初期探索期,用SDK模式足够了,简单直接;一旦进入团队协作或者生产环境,果断切到Proxy模式。理由很简单,SDK模式把逻辑都打进业务代码里,换模型要改代码、发版;Proxy模式把模型接入做成一个独立服务,换模型只改配置文件。生产环境追求的是变更频率越低越好,Proxy模式天然更适合。
2.2 核心功能模块:模型注册、密钥路由、成本追踪、负载均衡
LiteLLM代理能做的事远不止"格式翻译"这一项。我在生产环境实际用得最频繁的,是下面这四个模块:
第一,模型注册与映射。在config.yaml里设置model_list,每个条目定义一个"虚拟模型名"和它对应的真实模型。比如虚拟名gpt-4o,映射到openai/gpt-4o,带上api_key。之后所有请求都只提虚拟名,网关负责查表、翻译、转发。你甚至可以把gpt-4o映射到一个完全不同的平台模型,只要你想,虚拟名而已,不绑定任何厂商。
第二,密钥路由与轮询。一个模型可以有多个API key,比如你注册了多个账号,每个账号都有额度。LiteLLM可以在这一组密钥之间自动做负载均衡,一个key触发限流了就自动切到下一个key。这个功能对高频调用场景来说简直是续命神器,直接绕开了单个账号的速率限制。
第三,成本追踪。LiteLLM会记录每次请求的输入token数和输出token数,再结合模型单价算出费用。在代理模式下,它还提供了一个/spend接口,可以按key、按用户、按模型维度查询历史花费。做预算管理或者给客户做计费报表,这个功能非常关键。
第四,负载均衡与重试回退。当多个模型都能完成同一个任务时,可以在配置里定义一个模型组,LiteLLM会根据你设置的策略(轮询、随机、优先级等)自动分发请求。某个模型返回错误或超时,它会自动尝试组里的另一个模型,对业务方完全透明。这种容灾设计在依赖大模型的生产链路里至关重要,毕竟任何一家平台的稳定性都不是百分之百。
这四个模块单独拎出来,每个都有对应的专业产品可以做,但LiteLLM把它们整合到了一个工具里,而且和模型接入这件事本身紧耦合。这就是它的核心价值:不是解决一个点,而是把"接入模型这段路上你能遇到的所有通用问题"打包处理了。
3. 从零搭建LiteLLM的完整实操
理论说再多,不如跑一遍。这一章我带你从安装开始,一步步搭出一个能用的LiteLLM代理服务,验证它能转发请求到真实模型平台。
3.1 安装与环境准备
环境要求其实很宽松,我用的是Python 3.10,理论上3.8以上都能跑。安装命令很简单:
pip install 'litellm[proxy]'这里注意,[proxy]这个扩展必须装,它才会带上代理服务所需的依赖,比如FastAPI、uvicorn这些。如果你只用SDK模式,直接pip install litellm就够了。
装完之后,设置环境变量。LiteLLM约定每种模型平台的API key都通过特定的环境变量名读取,比如某主流平台的key,默认读OPENAI_API_KEY;另一个主流对话模型平台的key,默认读ANTHROPIC_API_KEY。如果你是在Linux或macOS上:
export OPENAI_API_KEY="sk-你的key" export ANTHROPIC_API_KEY="sk-ant-你的key"Windows下就用set命令,或者干脆写到.env文件里,用export $(cat .env)加载。这一步非常关键,我在刚开始用的时候经常忘记设置环境变量,结果所有请求都报401,还以为是自己代码写错了,排查半天才发现是环境变量没加载。
3.2 config.yaml的模型映射详解
代理模式的灵魂全在这个配置文件里。下面是一份我常用的最小配置:
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 api_key: os.environ/ANTHROPIC_API_KEY - model_name: llama3-70b litellm_params: model: ollama/llama3:70b api_base: http://localhost:11434这个配置文件里面有几个重要细节,一定要理解了再上手:
model_name是虚拟模型名,也就是你对外暴露的名字,业务方只认这个名字。litellm_params.model是真实模型标识,格式是"提供商/模型名"。openai/gpt-4o表示走OpenAI标准接口,anthropic/claude-3-5-sonnet表示走Anthropic接口,ollama/llama3:70b表示走本地Ollama服务。前缀决定了LiteLLM用什么协议去访问,写错了它就会按错误的协议去请求,大概率报错。
api_key这里可以直接放明文,但更好的是用os.environ/VAR_NAME这种写法,让LiteLLM从环境变量读取。这样你的key不会明文暴露在配置文件里,安全性高很多,也方便在不同环境之间切换。对于本地模型(比如Ollama),通常不需要api_key,但可能需要指定api_base,告诉LiteLLM本地服务监听在哪里。
模板还有个隐藏功能:model_name可以和真实模型不一样。你可以故意把所有模型都映射到同一个真实模型,比如A/B测试时避免业务方感知;也可以把一个真实模型映射成多个虚拟名,给不同业务线分别配额计费。灵活性很高。
3.3 启动代理服务
配置文件写好了,启动服务就一条命令:
litellm --config config.yaml --port 4000看到类似Uvicorn running on http://0.0.0.0:4000的日志,说明服务起来了。这时候先别急着写代码,用curl探探路:
curl http://localhost:4000/health如果返回一个正常的JSON状态,说明网关活着。接下来发一个真正的对话请求:
curl http://localhost:4000/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer sk-你的代理密钥" \ -d '{ "model": "gpt-4o", "messages": [{"role": "user", "content": "你好,介绍一下你自己"}] }'这里要特别注意两个地方。第一个是URL路径:LiteLLM兼容OpenAI的/v1/chat/completions路径,你不用自己拼路径,直接按OpenAI的习惯来。第二个是请求头:代理默认需要一个key才能访问,这个key可以通过环境变量LITELLM_MASTER_KEY设置,如果没设,LiteLLM会在启动日志里打印一个临时key。我之前没设master key,结果发现测试客户端一直连不上,日志里才看到临时key,早知道就不用白折腾了。
如果你是用Python的OpenAI SDK访问这个代理,写法也几乎不用改,只需要把base_url和api_key指向你自己的服务:
from openai import OpenAI client = OpenAI( base_url="http://localhost:4000", api_key="sk-你的代理密钥" ) response = client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": "讲个冷笑话"}] ) print(response.choices[0].message.content)这段代码的要点在于,除了base_url和api_key,其他东西跟直接调OpenAI完全一样。你换模型的时候,只需要改model字段,比如改成claude-3-5-sonnet,代码其他地方一行都不用动。这种"偷懒"带来的好处,在你同时接十个模型的时候体会最深。
4. 生产环境关键配置:成本、限流与重试
开发环境通了只是第一步,真上生产,你会发现另外三件事特别重要:成本要能看到,流量要能控制,失败要能自愈。这一章我聊聊这三个方面的配置实践。
4.1 成本追踪与预算管控
记账这件事,别看简单,做不好很头疼。LiteLLM默认会对大部分主流模型预设单价,所以请求进来之后,它自动就能算出这轮对话花了多少钱。每次请求的日志里会带上spend字段,精确到小数后四位。
如果你用的是比较新的模型,或者自己部署的开源模型,LiteLLM可能不认识它的价格,这时候需要手动在配置里补充价格信息。在model_list里给对应的模型条目加上model_info,比如:
model_list: - model_name: my-custom-llm litellm_params: model: openai/my-custom-llm api_base: http://your-endpoint api_key: os.environ/CUSTOM_API_KEY model_info: input_cost_per_token: 0.000002 output_cost_per_token: 0.000006input_cost_per_token和output_cost_per_token按你的实际成本填,单位是美元/token。这里有个坑:成本单位极其容易记错。有的平台文档给的是"每千token的价格",LiteLLM要的是"每token的价格",换算差了1000倍的话,账本会离谱到没法看。我在一次项目里就因为这个,成本统计比实际高了几十倍,排查了半天才发现是单位没换算。
成本数据看哪里?代理模式下,LiteLLM启动时会打印各key的使用情况,你也可以调它的/spend接口拿历史聚合数据。我自己的习惯是写一个定时任务,每小时调一次/spend接口,把数据落到自己的监控面板里,这样团队看到的花费永远是最新的。至于预算管控,可以在配置文件里设置litellm_settings,比如每月总预算、单key预算,超过阈值直接拒绝请求,避免半夜有人跑了个大循环把额度烧光。
4.2 速率限制与多Key轮询
生产环境的高频调用,几乎必然撞上平台的速率限制(Rate Limit)。LiteLLM为此准备了两种武器:限制和轮询。
先看限制。你可以在配置里给每个key或每个虚拟模型设置请求速率限制,比如每分钟最多200个请求,超过的直接返回429给调用方,而不是傻乎乎地继续往平台冲。这个配置在litellm_settings里定义,具体字段可以按官方文档配。我一般会按"模型"和"用户"两个维度设置限制:按模型限制是为了保护平台配额,按用户限制是为了防止某个使用方把资源都占了。
再看多Key轮询。如果你有多个API key,可以在模型条目的litellm_params里传一个key列表,LiteLLM会在这些key之间自动做轮询和故障转移。这个功能解决的是单账号速率限制问题:一个key每秒只能打那么多次,那就用10个key轮流打,等效频率直接乘以10。不过这里有个前提,你的多个key得来自同一个平台账号体系,而且平台允许你这种用法,别违反人家的服务条款。
我在一个真实项目里,用4个key轮询同一个模型,把每天能处理的请求量硬生生翻了4倍,而且全程几乎不需要改代码。这个操作执行起来非常简单,但效果立竿见影,推荐有高频调用需求的团队都试试。
4.3 重试、超时与模型回退
模型服务的稳定性从来不是100%的,今天你可能碰见超时,明天可能碰上5xx错误。LiteLLM在代理层帮你把这些失败逻辑做了兜底。
先说超时。我通常会在配置里设置一个合理的请求超时时间,默认值可能偏长或偏短,你得根据自己的场景调。比如跟用户交互的场景,超过10秒用户就受不了,那超时时间就设成10秒;如果是离线批量处理任务,可以设到120秒甚至更长。
再看重试。当请求因为瞬时故障失败时,LiteLLM可以自动重试。重试次数和重试间隔都可以配置,但这里有个经验教训:重试一定要配合指数退避,否则你的服务刚恢复,所有重试请求同一时间涌过来,直接把平台打到限流,反而更糟。LiteLLM在这方面有内置的退避策略,默认行为还算合理,你自己不要额外写一个"失败就疯狂重试"的循环,那是自找麻烦。
最后说模型回退(Fallback),这个功能我是真的很喜欢。比如我有一个"主力模型出问题就切备用模型"的需求:正常情况下用贵一点的强模型,一旦它报错或超时,自动降级到便宜一点的模型,保证业务不中断。在LiteLLM里,这可以通过模型分组和回退配置实现。我配置过一个场景:主力模型挂了,自动切到备用模型,再不行就切到本地模型兜底。三层保障,那之后我的服务因为模型供应商故障导致的线上事故,基本绝迹了。
5. 常见问题与排查技巧实录
配置和代码写得再顺,也免不了在实际运行中遇到各种诡异问题。这一章我把自己和身边同事踩过的坑整理成一份速查清单,每个问题的症状、原因和解决办法都写清楚。
5.1 模型返回401或403鉴权失败
这个问题的典型症状是:请求到了LiteLLM,但返回401 Unauthorized或者403 Forbidden。
排查思路按顺序来。先确认代理本身有没有启动成功,如果代理需要用master key,而你落了LITELLM_MASTER_KEY环境变量,那代理会打印一个临时key,你用临时key说不定就好了。接着确认目标平台的key是不是有权限、有没有过期。最后,也是最多人踩的坑:环境变量没加载。你明明在config.yaml里写了os.environ/OPENAI_API_KEY,但当时Shell里根本没这个变量,LiteLLM读到的是空值,自然鉴权失败。
我现在的习惯是,任何新环境部署完LiteLLM,首先在命令行里printenv | grep API_KEY,确认所有用到的环境变量都存在再启服务。别嫌麻烦,这一步能帮你省掉后面一小时的排查时间。
5.2 提示模型不存在或模型名错误
症状是请求报错,大概意思是"Model xxx does not exist"。这通常不是说你调的模型在平台上不存在,而是LiteLLM的配置里没有你要用的那个虚拟模型名。
比如你在配置文件里定义的是gpt-4o,请求里却写gpt-4,那LiteLLM当然找不到映射关系,直接报错。解决办法很简单:要么请求方改成配置里存在的虚拟名,要么在配置里把gpt-4也加上映射。这里我建议把虚拟模型名设计得跟业务语义相关,比如叫chat-main、chat-backup,这样就算背后真实模型换了好几次,虚拟名都不需要变。
还有一种情况:你在litellm_params.model里写错了平台前缀。比如把openai/gpt-4o写成anthropic/gpt-4o,LiteLLM就会用Anthropic的协议去请求OpenAI的模型名,返回的报错会很莫名其妙。遇到这种报错,先回头看一眼前缀对不对。
5.3 成本数据不准确或统计不到
这个问题我前面提过一嘴,最常见的原因是模型价格没配置或者配置错了。LiteLLM对不认识的模型不会自动记账,你必须在model_info里手动填价格。填的时候千万注意单位,是按token算还是按千token算,差了1000倍账就废了。
第二种情况是,你的自定义API端点返回的token用量字段跟标准格式不一致,导致LiteLLM解析不出来。这种就属于模型的兼容性问题,需要在配置里调整响应解析逻辑,或者在上游先把响应格式规范化。
5.4 日志太多刷屏、性能变慢
代理模式的日志默认会打印每一个请求的完整信息,包括输入输出。流量一大,日志文件膨胀得很快,磁盘满了服务直接就挂了。这个问题我踩过一次,后续学乖了:配置日志轮转,控制日志级别,生产环境只输出WARNING以上的日志。
另外,如果你发现代理服务的性能变慢,先别怀疑LiteLLM本身。检查一下是不是把大模型调用都压在一个网关进程上,如果是,要么考虑给LiteLLM加并发配置,要么在网关前面再加一层负载均衡,把一个实例拆成多个实例。
5.5 调用OpenAI SDK时连接被拒绝
症状很直接:Connection refused。原因通常就是代理服务没启动,或者你填的base_url不对。很多人在本地测试时填了localhost:4000,但代理服务跑在容器或远程服务器上,那当然连不上。还有一个常见错误:地址里漏了端口号,或者多了个/v1。比如base_url填成http://localhost:4000/v1,而LiteLLM的路由本身已经带了/v1,结果拼起来变成/v1/v1/chat/completions,照样404。
我建议统一约定:base_url只填到主机和端口(http://localhost:4000),后面的/v1/chat/completions让OpenAI SDK自己拼。这样最不容易出问题。
6. 写在最后:一点个人体会
实际操作下来,LiteLLM给我的最大帮助不是"少写代码"这么简单,而是把"模型接入"这件事从"每个项目重复造轮子"变成了"一次配置、到处复用"。团队里新来的同学要接一个新模型,我只需要告诉他:在config.yaml里加一段映射,然后请求里换个模型名,五分钟搞定,完全不需要理解各家API的差异。这省下来的沟通成本和维护成本,只有经历过的人才知道有多值。
如果你打算上手,我的建议是:先在本地用SDK模式跑一遍你常用的两三个模型,确认效果和成本都满意;再把它包装成代理服务,接进你的统一开发环境;最后再逐步加入限流、预算、回退这些生产配置。这个路径平滑,踩坑最少。
最后再分享一个小技巧:很多团队不是从零开始接LiteLLM,而是已经有一堆调用各种模型的代码。这时候别急着重写,利用LiteLLM的OpenAI兼容接口,可以先把一个最常用的模型切换过去,跑通之后再慢慢把其它模型也迁移进来,风险小很多。真正的生产系统,从来不是靠一次大重构赢的,而是靠一次次小步快跑稳下来的。