1. 从一个真实困境说起:多模型调用的碎片化之痛
如果你最近半年在折腾大模型应用,大概率会遇到这样一个场景:产品原型阶段用某家云服务商的API跑得挺顺,结果老板说“咱们得支持国产模型,成本要降下来”,于是你开始接入第二家、第三家。每家的SDK不一样,鉴权方式不一样,返回格式不一样,流式输出的解析逻辑也不一样。你写了一套适配层,勉强跑通,结果测试同学跑过来告诉你:“同一个提示词,A模型返回的是JSON,B模型返回的是带Markdown代码块的文本,C模型直接给你截断了。”
这不是个别现象。我在过去一年里帮三个不同规模的团队做过大模型应用落地,几乎每个团队都在“多模型适配”这件事上浪费了至少两周的纯开发时间。而litellm这个项目,就是冲着这个痛点来的。它的核心价值用一句话概括:用一套OpenAI风格的调用接口,统一访问上百种大模型服务。你不需要为每个模型写适配代码,不需要维护多套鉴权逻辑,甚至不需要改业务代码就能在不同模型之间切换。
这篇文章适合三类人看:第一类是做AI应用开发但被多模型适配折磨的工程师;第二类是想快速对比不同模型效果、但不想写一堆胶水代码的算法同学;第三类是对LLM应用架构感兴趣、想了解“统一网关”这个思路的技术负责人。我会从实际使用角度出发,把litellm的核心机制、配置细节、踩坑经验和进阶玩法都讲清楚,尽量让你看完就能上手,少走弯路。
2. litellm到底解决了什么问题:拆解统一调用层的核心逻辑
2.1 没有litellm之前,多模型调用有多麻烦
先还原一个典型场景。假设你要同时调用三家不同厂商的模型服务,代码大概长这样:
# 厂商A的调用方式 import vendor_a_sdk client_a = vendor_a_sdk.Client(api_key="xxx", region="cn-north") resp_a = client_a.chat(model="model-a-v2", messages=[...], temperature=0.7) text_a = resp_a["choices"][0]["message"]["content"] # 厂商B的调用方式 import vendor_b_sdk client_b = vendor_b_sdk.Client(token="yyy", endpoint="https://api.vendor-b.com/v1") resp_b = client_b.generate(prompt=..., max_tokens=1024) text_b = resp_b["data"]["output"]["text"] # 厂商C的调用方式 import requests resp_c = requests.post("https://api.vendor-c.cn/infer", headers={"Authorization": "Bearer zzz"}, json={"model_name": "model-c-large", "input": ..., "params": {"top_p": 0.9}}) text_c = resp_c.json()["result"]["content"]三套代码,三种鉴权方式,三种参数命名,三种返回结构。这还只是三家,如果要做模型效果对比测试,每换一个模型就要改一次代码。更麻烦的是流式输出——有的用SSE,有的用WebSocket,有的返回chunk格式完全自定义。你写一个流式解析器,换一家模型就得重写。
litellm的做法是:把所有模型的调用都抽象成OpenAI的ChatCompletion接口。你只需要记住一套参数名(model、messages、temperature、max_tokens、stream),剩下的适配工作交给litellm。
2.2 统一接口背后的映射机制
litellm的核心是一个“模型名到提供商”的路由表。当你调用completion(model="gpt-4o", messages=[...])时,它内部做的事情大致分四步:
第一步,解析model字段。litellm支持两种写法:一种是直接用模型名(如gpt-4o、claude-3-5-sonnet、deepseek-chat),它会根据内置的映射表找到对应的提供商;另一种是显式指定提供商前缀(如openai/gpt-4o、anthropic/claude-3-5-sonnet、azure/gpt-4-deployment),这种方式在模型名有歧义时更稳妥。
第二步,参数转换。不同厂商对同一个概念的叫法不同。比如“最大生成token数”,OpenAI叫max_tokens,Anthropic叫max_tokens_to_sample,某国产模型叫max_new_tokens。litellm在内部做了一层参数名映射,你统一传max_tokens,它会自动转成目标厂商需要的字段名。
第三步,鉴权适配。OpenAI用Authorization: Bearer,Anthropic用x-api-key,Azure用api-key。litellm根据提供商类型自动选择正确的鉴权头。你只需要在环境变量或配置里把各家的key准备好。
第四步,响应归一化。不管底层返回什么结构,litellm都会把它包装成OpenAI风格的响应对象,包含choices[0].message.content、usage.prompt_tokens、usage.completion_tokens等标准字段。这样你的业务代码只需要处理一种响应格式。
这里有一个容易被忽略的细节:litellm的响应对象是类OpenAI格式,但不是完全一致。某些厂商特有的字段(比如Anthropic的
stop_reason)会被放在response._hidden_params或额外的属性里。如果你需要访问这些原生字段,得用response._hidden_params或者直接拿原始响应。
2.3 支持的模型范围与更新节奏
litellm目前支持的提供商数量在持续增长,覆盖了主流云服务商、开源模型托管平台、以及自部署推理框架。大致可以分成几类:
| 类别 | 代表提供商 | 接入方式 |
|---|---|---|
| 闭源商业API | OpenAI、Anthropic、Google Gemini、Mistral | 官方API key |
| 云平台托管 | Azure OpenAI、AWS Bedrock、Google Vertex AI | 云凭证或API key |
| 国产模型API | DeepSeek、通义千问、智谱、月之暗面 | 各家API key |
| 开源托管平台 | Together AI、Fireworks、Groq、Replicate | 平台API key |
| 自部署推理 | Ollama、vLLM、HuggingFace TGI | 本地endpoint地址 |
这个列表几乎每个月都在更新。我实测下来,主流模型基本都能覆盖,但一些小众或刚发布的模型可能需要等社区提交PR。如果你用的模型不在列表里,litellm也提供了自定义提供商的扩展接口,后面会讲到。
3. 从零跑通第一个调用:环境准备与最小可用示例
3.1 安装与版本选择
litellm的安装非常简单:
pip install litellm但这里有个版本选择的坑。litellm的迭代速度非常快,几乎每周都有新版本发布。新版本会加入新模型支持,但也可能引入不兼容的改动。我的建议是:生产环境锁定版本号,比如pip install litellm==1.40.0,不要用pip install --upgrade无脑升级。测试环境可以跟最新版,但升级前先跑一遍你的核心调用链路。
另外,litellm有一个[proxy]扩展包,如果你要用它的代理网关功能,需要:
pip install 'litellm[proxy]'这个扩展包会额外安装FastAPI、uvicorn等依赖,用于启动HTTP代理服务。如果你只是用Python SDK做库调用,不需要装这个。
3.2 API Key的配置方式
litellm读取API key的方式有两种:环境变量和运行时传参。推荐用环境变量,因为这样代码里不用硬编码密钥,也方便在不同环境切换。
各家提供商的环境变量名不一样,常见的有:
export OPENAI_API_KEY="sk-..." export ANTHROPIC_API_KEY="sk-ant-..." export DEEPSEEK_API_KEY="sk-..." export AZURE_API_KEY="..." export AZURE_API_BASE="https://your-resource.openai.azure.com/" export AZURE_API_VERSION="2024-02-01"如果你用Azure OpenAI,除了key还需要配base和version,这三个缺一不可。我见过有人只配了key,结果调用一直报404,排查半天才发现是base地址没设对。
一个实用技巧:如果你在本地开发,可以把这些环境变量写进
.env文件,然后用python-dotenv加载。但记得把.env加入.gitignore,别把密钥提交到代码仓库。
3.3 第一个可运行的调用示例
配置好key之后,最小可用代码是这样的:
from litellm import completion response = completion( model="gpt-4o", messages=[ {"role": "system", "content": "你是一个简洁的助手。"}, {"role": "user", "content": "用一句话解释什么是统一调用层。"} ], temperature=0.7, max_tokens=200 ) print(response.choices[0].message.content) print(f"消耗token: {response.usage.total_tokens}")把model换成claude-3-5-sonnet、deepseek-chat、gemini-1.5-pro,代码其他部分完全不用改。这就是litellm最核心的价值——模型切换零成本。
如果你用的是自部署的Ollama,写法稍微不同:
response = completion( model="ollama/llama3.1", messages=[{"role": "user", "content": "你好"}], api_base="http://localhost:11434" )注意api_base要指向你的Ollama服务地址。如果是vLLM部署的OpenAI兼容接口,可以写成openai/your-model-name,然后把api_base指向vLLM的地址。
3.4 流式输出的正确打开方式
流式输出是多模型调用里最容易出问题的环节。litellm的流式接口设计成和OpenAI一致:
response = completion( model="claude-3-5-sonnet", messages=[{"role": "user", "content": "写一段200字的产品介绍"}], stream=True ) for chunk in response: delta = chunk.choices[0].delta if delta.content: print(delta.content, end="", flush=True)这里有个细节要注意:不同厂商的流式chunk结构在litellm里被归一化了,但首个chunk和末尾chunk的处理逻辑可能不同。有些厂商的首个chunk只包含role信息,content为空;末尾chunk可能包含finish_reason和usage统计。如果你要做token计数,不能简单累加每个chunk的content长度,得看最后一个chunk的usage字段(如果提供商支持的话)。
我实测下来,Anthropic和OpenAI的流式usage统计比较完整,部分国产模型的流式接口不返回usage,这时候你只能自己用tiktoken之类的工具估算。
4. 进阶配置:路由、重试与成本控制
4.1 用Router实现多模型负载均衡
当你同时配置了多个API key或者多个同能力模型时,litellm的Router组件可以帮你做负载均衡和故障转移。基本用法:
from litellm import Router router = Router( model_list=[ { "model_name": "gpt-4", "litellm_params": { "model": "gpt-4o", "api_key": "sk-key1" } }, { "model_name": "gpt-4", "litellm_params": { "model": "gpt-4o", "api_key": "sk-key2" } }, { "model_name": "gpt-4", "litellm_params": { "model": "claude-3-5-sonnet", "api_key": "sk-ant-key" } } ], routing_strategy="simple-shuffle" ) response = router.completion( model="gpt-4", messages=[{"role": "user", "content": "你好"}] )这里model_name是你自定义的逻辑名称,litellm_params里才是真正的模型和key。Router会把请求按策略分发到不同的后端。simple-shuffle是随机轮询,还有least-busy(选当前负载最低的)、usage-based-routing(按token消耗做路由)等策略。
这个机制在两种场景下特别有用:一是你有多个同模型的key,想分摊速率限制;二是你想做A/B测试,把一部分流量切到新模型上。
4.2 重试与降级策略
API调用失败是常态,尤其是高峰期。litellm内置了重试机制:
from litellm import completion response = completion( model="gpt-4o", messages=[...], num_retries=3, timeout=30 )num_retries控制重试次数,timeout是单次请求超时时间(秒)。litellm默认会对速率限制错误(429)和服务器错误(5xx)做指数退避重试。
但光有重试还不够,如果主模型持续不可用,你需要降级到备用模型。这个用Router的fallbacks配置:
router = Router( model_list=[...], fallbacks=[{"gpt-4": ["claude-3-5-sonnet", "deepseek-chat"]}] )意思是当gpt-4这个逻辑模型的所有后端都失败时,自动尝试claude-3-5-sonnet,再失败就试deepseek-chat。这个降级链路在线上环境非常关键,我经历过一次某厂商API大面积故障,全靠降级配置撑过了那两小时。
4.3 成本追踪与预算控制
litellm内置了成本计算功能,它会根据模型名和token用量估算费用:
response = completion(model="gpt-4o", messages=[...]) print(f"本次调用成本: ${response._hidden_params.get('response_cost', 0):.6f}")不过这个估算依赖litellm内置的价格表,如果厂商调价了而litellm还没更新,数字会不准。更可靠的做法是自己在业务层记录token用量,然后按自己的价格表计算。
如果你用代理模式,litellm还支持设置预算上限:
# config.yaml model_list: - model_name: gpt-4o litellm_params: model: gpt-4o api_key: os.environ/OPENAI_API_KEY litellm_settings: max_budget: 100 # 总预算100美元 budget_duration: 30d # 30天周期超过预算后,后续请求会被拒绝。这个功能在多团队共用一套key的场景下很有用,能防止某个团队把额度跑爆。
5. 代理模式:把litellm变成团队级统一网关
5.1 什么时候需要代理模式
Python SDK适合个人开发或单个服务内部使用。但如果你的团队有多个服务、多种语言(比如Java服务、Go服务也想调模型),或者你想在网关层统一做鉴权、限流、日志,那就需要litellm的代理模式。
代理模式本质上是启动一个HTTP服务,对外暴露OpenAI兼容的/v1/chat/completions接口。任何能调OpenAI接口的客户端,把base_url改一下就能用。
启动方式:
litellm --config /path/to/config.yaml --port 4000然后你的业务代码这样调:
from openai import OpenAI client = OpenAI( base_url="http://localhost:4000", api_key="any-string" # 代理层可以配置自己的鉴权 ) response = client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": "你好"}] )注意这里用的是原生openai库,不是litellm。这就是代理模式的好处——对客户端完全透明。
5.2 配置文件的关键字段
代理模式的核心是配置文件。一个典型的配置长这样:
model_list: - model_name: gpt-4o litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY rpm: 1000 # 每分钟请求限制 - model_name: claude litellm_params: model: anthropic/claude-3-5-sonnet api_key: os.environ/ANTHROPIC_API_KEY general_settings: master_key: sk-your-master-key # 代理层鉴权 database_url: postgresql://... # 可选,用于记录日志 litellm_settings: drop_params: true # 自动丢弃目标模型不支持的参数 set_verbose: falsedrop_params这个设置值得单独说。不同模型支持的参数集不一样,比如你传了top_p但某个模型不支持,如果不设drop_params,请求会直接报错。设为true后,litellm会自动过滤掉不支持的参数,提高兼容性。但这也意味着你传的参数可能被静默丢弃,调试时要注意。
5.3 代理层的鉴权与多租户
代理模式支持虚拟key机制。你可以在数据库里创建多个虚拟key,每个key绑定不同的预算、模型权限、速率限制。这样不同团队用不同的key,互不影响。
创建虚拟key的方式:
curl -X POST http://localhost:4000/key/generate \ -H "Authorization: Bearer sk-your-master-key" \ -H "Content-Type: application/json" \ -d '{ "models": ["gpt-4o", "claude"], "max_budget": 50, "rpm_limit": 100 }'返回的key就可以发给对应团队使用。他们只能访问被授权的模型,超出预算或速率限制会被拒绝。这套机制在中小团队里基本够用,不需要额外搭一套鉴权系统。
6. 踩坑实录:那些文档里没写的细节
6.1 参数传递的隐性陷阱
litellm虽然做了参数名映射,但不是所有参数都能正确转换。我遇到过几个典型问题:
第一个是stop参数。OpenAI的stop接受字符串或字符串列表,但某些厂商只接受列表。如果你传单个字符串,litellm可能不会自动包装成列表,导致请求报错。稳妥做法是始终传列表:stop=["\n\n"]。
第二个是response_format。OpenAI支持{"type": "json_object"}来强制JSON输出,但很多其他模型不支持这个参数。如果你设了drop_params: true,它会被静默丢弃,模型可能返回非JSON内容,导致你的解析代码崩溃。所以用这个参数时,要么确认目标模型支持,要么在业务层做容错解析。
第三个是seed参数。部分模型支持固定随机种子来复现结果,但支持范围有限。如果你做效果对比测试,不要依赖seed来保证可复现性,最好把temperature设为0。
6.2 流式场景下的异常处理
流式调用最怕的是中途断流。网络抖动、服务端超时、模型生成被截断,都会导致你的for chunk in response循环提前结束。如果不做处理,用户看到的就是半句话。
我的做法是在循环外层包一层异常捕获,并记录已生成的内容:
full_content = "" try: response = completion(model="gpt-4o", messages=[...], stream=True) for chunk in response: delta = chunk.choices[0].delta if delta.content: full_content += delta.content yield delta.content except Exception as e: # 记录异常,决定是否重试或返回已生成内容 print(f"流式中断: {e}, 已生成{len(full_content)}字")另外,litellm的流式响应对象在某些版本里不支持直接break后自动关闭连接。如果你在循环中提前退出,最好显式调用response.close(),否则可能留下未关闭的HTTP连接。
6.3 模型名冲突与版本歧义
litellm的模型映射表里,有些模型名是模糊的。比如gpt-4可能指向gpt-4-0613,也可能指向gpt-4-turbo,取决于litellm版本和你的配置。如果你需要精确控制版本,始终用提供商前缀加完整模型名,比如openai/gpt-4-0613。
还有一个坑是Azure的部署名。Azure OpenAI的模型名是你自己起的部署名,不是官方模型名。如果你写azure/gpt-4,litellm会把它当成部署名去调,但你的部署名可能叫my-gpt4-deployment。这时候要么在配置里做映射,要么直接用部署名作为model参数。
6.4 超时与并发控制的平衡
litellm默认的超时时间比较短,对于长文本生成任务可能不够。我建议根据任务类型设置不同的超时:
| 任务类型 | 建议超时 | 说明 |
|---|---|---|
| 短文本分类 | 10s | 输入输出都短,快速失败 |
| 常规对话 | 30s | 平衡响应速度和成功率 |
| 长文生成 | 120s | 给模型足够时间 |
| 流式输出 | 60s | 首token超时,后续不限 |
并发控制方面,litellm本身不做限流,需要你在业务层或用代理模式的rpm/tpm参数来控制。如果并发太高,提供商会返回429,litellm会重试,但重试次数用完后还是会失败。所以在客户端做并发限制比依赖重试更可靠。
7. 自定义提供商:当内置支持不够用时
7.1 什么情况下需要自定义
litellm的内置提供商列表虽然长,但总有覆盖不到的情况。比如你们公司内部部署了一个私有模型服务,接口格式是自研的;或者某个小众云平台刚上线了模型API,litellm还没收录。这时候就需要自定义提供商。
自定义提供商的核心是实现一个转换类,把litellm的标准请求转成目标服务的格式,再把目标服务的响应转回标准格式。
7.2 自定义提供商的基本步骤
litellm提供了CustomLLM基类,你需要实现completion和streaming两个方法。简化后的代码结构:
from litellm import CustomLLM, ModelResponse from litellm.types.utils import Choices, Message, Usage import requests class MyCustomProvider(CustomLLM): def completion(self, model, messages, **kwargs): # 把messages转成目标服务的格式 payload = { "prompt": self._convert_messages(messages), "max_length": kwargs.get("max_tokens", 512) } resp = requests.post( "https://my-internal-api/generate", json=payload, headers={"X-Token": "my-token"} ) data = resp.json() # 把响应转回litellm标准格式 return ModelResponse( choices=[Choices( message=Message(content=data["text"], role="assistant") )], usage=Usage( prompt_tokens=data.get("input_len", 0), completion_tokens=data.get("output_len", 0), total_tokens=data.get("input_len", 0) + data.get("output_len", 0) ) ) def streaming(self, model, messages, **kwargs): # 流式实现,逐chunk yield ...然后在调用时指定custom_llm_provider:
response = completion( model="my-custom-model", messages=[...], custom_llm_provider="my-provider" )7.3 自定义提供商的调试技巧
自定义提供商最容易出问题的地方是响应格式转换。litellm内部对响应对象有严格的类型检查,如果你构造的ModelResponse缺少必要字段,会报一些很难懂的错。
我的调试方法是:先用内置提供商跑一个正常调用,把返回的ModelResponse对象打印出来,看它的完整结构。然后照着这个结构构造自定义响应。重点关注choices、usage、model这几个字段,它们是最常被引用的。
另外,自定义提供商的流式实现要特别注意chunk的格式。每个chunk必须是ModelResponse对象,且choices[0].delta要有正确的role和content字段。如果格式不对,客户端解析会出错。
8. 性能与稳定性:生产环境的实战经验
8.1 连接池与HTTP客户端复用
litellm底层用httpx发请求。默认情况下,每次调用会创建新的连接。在高并发场景下,这会导致大量TIME_WAIT连接,影响性能。
解决办法是复用HTTP客户端。litellm支持传入自定义的httpx客户端:
import httpx from litellm import completion client = httpx.Client( limits=httpx.Limits(max_connections=100, max_keepalive_connections=20), timeout=httpx.Timeout(30.0) ) response = completion( model="gpt-4o", messages=[...], client=client )这样连接会被复用,减少握手开销。我实测下来,在QPS 50以上的场景,复用连接能降低约30%的延迟。
8.2 日志与可观测性
生产环境必须记录每次调用的关键信息:模型名、输入输出token数、延迟、是否成功、错误类型。litellm提供了回调机制:
from litellm import completion from litellm.integrations.custom_logger import CustomLogger class MyLogger(CustomLogger): def log_success_event(self, kwargs, response_obj, start_time, end_time): # 记录成功调用 print(f"模型: {kwargs['model']}, 延迟: {(end_time - start_time).total_seconds():.2f}s") def log_failure_event(self, kwargs, response_obj, start_time, end_time): # 记录失败调用 print(f"失败: {kwargs['model']}, 错误: {response_obj}") completion( model="gpt-4o", messages=[...], logger=MyLogger() )你可以把日志写到文件、数据库或监控系统。关键是记录足够的上下文,出问题时能快速定位是哪个模型、哪个key、什么参数导致的。
8.3 缓存策略减少重复调用
如果你的应用有大量重复或相似的查询,加缓存能显著降低成本。litellm支持内置缓存:
from litellm import completion from litellm.caching import Cache litellm.cache = Cache(type="redis", host="localhost", port=6379) response = completion( model="gpt-4o", messages=[...], caching=True )缓存key默认基于模型名和messages内容生成。相同请求会直接返回缓存结果,不消耗token。但要注意:缓存对temperature大于0的调用可能不合适,因为同样的输入本来就应该有不同的输出。缓存更适合temperature=0的分类、抽取类任务。
9. 模型对比测试:用litellm做效果评估的实操方法
9.1 设计一个可复现的对比测试
litellm最大的价值之一,就是让模型对比测试变得极其简单。你可以写一个循环,遍历模型列表,用同一套提示词跑测试:
from litellm import completion models = ["gpt-4o", "claude-3-5-sonnet", "deepseek-chat", "gemini-1.5-pro"] test_prompts = [ "用一句话解释什么是机器学习。", "把'今天天气真好'翻译成英文。", "写一个Python函数,判断一个数是否为质数。" ] results = {} for model in models: results[model] = [] for prompt in test_prompts: try: resp = completion( model=model, messages=[{"role": "user", "content": prompt}], temperature=0, max_tokens=500 ) results[model].append({ "prompt": prompt, "output": resp.choices[0].message.content, "tokens": resp.usage.total_tokens, "cost": resp._hidden_params.get("response_cost", 0) }) except Exception as e: results[model].append({"prompt": prompt, "error": str(e)})跑完之后,你可以从输出质量、token消耗、成本、延迟四个维度做对比。我建议把结果导出成表格,方便横向比较。
9.2 评估维度的量化方法
光看输出文本很难做客观对比。我通常会用几个量化指标:
| 维度 | 测量方式 | 说明 |
|---|---|---|
| 延迟 | 记录start_time和end_time | 首token延迟和总延迟分开记 |
| Token效率 | usage.total_tokens | 同样任务消耗越少越好 |
| 成本 | response_cost | 结合token单价计算 |
| 格式合规 | 正则或JSON解析 | 检查是否按要求格式输出 |
| 内容质量 | 人工评分或LLM打分 | 1-5分,多人交叉评 |
其中“LLM打分”是一个实用技巧:用一个强模型(比如GPT-4o)给其他模型的输出打分,虽然不完全客观,但比人工快得多,适合大规模初筛。
9.3 对比测试中的常见偏差
做模型对比时,有几个偏差要注意:
提示词偏差:同一套提示词对不同模型的友好度不同。有些模型对系统提示词敏感,有些对few-shot示例敏感。如果你只用一种提示词风格,结论可能有偏。
版本偏差:模型服务商经常静默更新模型版本。你今天测的gpt-4o和下个月测的可能不是同一个版本。所以测试报告要标注日期和模型版本号。
采样偏差:temperature大于0时,同一输入多次调用结果不同。做对比时要么设temperature=0,要么每个测试用例跑多次取平均。
成本偏差:不同模型的计费方式不同,有的按输入输出分开计费,有的按调用次数。litellm的成本估算基于内置价格表,可能和实际账单有出入。精确对比要用厂商的账单数据。
10. 我个人的使用体会与几个实用建议
用了大半年litellm,最大的感受是它确实把“多模型调用”这件事的复杂度降了一个数量级。以前切换模型要改代码、改配置、改解析逻辑,现在改一个字符串就行。但也不是没有代价——抽象层意味着你对底层细节的控制变弱了,某些厂商特有的高级功能(比如Anthropic的tool_use、Google的grounding)可能无法通过litellm直接使用,需要绕过抽象层直接调原生SDK。
我的建议是:把litellm当作默认调用层,但保留直接调原生SDK的能力。对于标准对话、文本生成、分类抽取这类任务,用litellm统一调用;对于需要厂商特有功能的任务,直接调原生SDK。两者并不冲突,可以在同一个项目里共存。
另外几个实用建议:
第一,始终在配置里显式指定提供商前缀。虽然litellm能自动推断,但显式指定能避免模型名冲突,也让代码更易读。
第二,生产环境一定要配降级链路。不要依赖单一模型或单一key,Router的fallbacks配置能帮你扛过大部分服务波动。
第三,记录每次调用的原始响应。litellm的归一化响应会丢失一些原生字段,如果你需要做深度调试或效果分析,把原始响应也存一份。
第四,关注版本更新日志。litellm的更新频率很高,新版本可能修复了你正遇到的bug,也可能引入了新的不兼容。升级前先在测试环境跑一遍核心链路。
第五,不要过度依赖成本估算。litellm的成本计算是估算值,实际账单以厂商为准。如果成本敏感,自己在业务层做精确的token计数和计费。
这个项目后续还可以这样扩展:结合LangChain或LlamaIndex做更复杂的编排,用litellm做底层模型调用层;或者在代理模式基础上加一层自定义中间件,做请求预处理和响应后处理。litellm的定位是“统一调用层”,它不解决编排问题,但把编排框架最头疼的模型适配问题解决了。两者配合使用,效果更好。