LiteLLM深度解析:统一调用100+大模型的AI网关SDK架构设计与实战
一、背景:大模型API的碎片化困局
2026年的AI开发圈,一个不得不面对的现实是——大模型API的碎片化已经严重影响了工程效率。
当你的项目需要同时调用 GPT-4o、Claude Sonnet 4、Gemini 2.5 Pro、DeepSeek V3 以及本地部署的 Qwen3 时,你的代码库里会堆满这样的东西:
# 痛点:每个厂商一套API,不同的调用方式、参数格式、错误处理
# OpenAI
from openai import OpenAI
openai_client = OpenAI(api_key="sk-xxx")
response = openai_client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello"}],
temperature=0.7,
max_tokens=1024
)
# Anthropic
import anthropic
anthropic_client = anthropic.Anthropic(api_key="sk-ant-xxx")
response = anthropic_client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}]
)
# Google Gemini
import google.generativeai as genai
genai.configure(api_key="AIzaXXX")
model = genai.GenerativeModel('gemini-2.5-pro')
response = model.generate_content("Hello")
# DeepSeek(OpenAI兼容但base_url不同)
deepseek_client = OpenAI(api_key="sk-xxx", base_url="https://api.deepseek.com")
response = deepseek_client.chat.completions.create(
model="deepseek-chat",
messages=[{"role": "user", "content": "Hello"}]
)
这不是危言耸听,而是每个AI工程师的真实日常。不同厂商的API设计各不相同:
| 厂商 | 参数命名 | 响应格式 | 流式处理 | Embedding接口 | 函数调用 |
|---|---|---|---|---|---|
| OpenAI | max_tokens | choices[0].message | SSE | /v1/embeddings | tools |
| Anthropic | max_tokens | content[0].text | SSE(不同格式) | 不支持 | tool_use |
generationConfig | candidates[0].content | Streaming API | embedContent | functionDeclarations | |
| DeepSeek | max_tokens | OpenAI兼容 | SSE | OpenAI兼容 | tools |
每接入一个新模型,就要学习一套新的SDK、适配不同的参数格式、处理不同的错误码、编写不同的流式解析逻辑。更麻烦的是,当你要做模型切换——比如从GPT-4o切换到Claude做A/B测试——改动量可能涉及几十个文件。
LiteLLM 就是为了解决这个问题而生的。 它的核心承诺很简单:一套代码,调用100+大模型。 无论底层是OpenAI、Anthropic、Google、AWS Bedrock、Azure OpenAI,还是本地Ollama,上层代码完全不变。
二、核心概念:LiteLLM的设计哲学
2.1 OpenAI格式统一:业界的事实标准
LiteLLM选择OpenAI的Chat Completions API作为统一接口格式,这不是随意的选择,而是基于一个关键判断:OpenAI格式已经成为大模型API的事实标准。
就像HTTP之于网络通信、SQL之于数据库查询,OpenAI的/v1/chat/completions接口已经成为了大模型调用的"通用语言"。绝大多数新进入者(DeepSeek、Moonshot、智谱、百川等)都选择了兼容OpenAI格式,因为这降低了用户的迁移成本。
LiteLLM的统一策略是:
你的代码(OpenAI格式)
↓
LiteLLM 转换层
↓
┌────┼────┬────────┬──────────┐
↓ ↓ ↓ ↓ ↓
OpenAI Anthropic Google Bedrock Ollama...
2.2 双引擎架构:SDK + Proxy
LiteLLM不是简单的SDK封装,它提供了两种使用模式:
模式一:Python SDK(轻量级,适合应用内嵌)
from litellm import completion
import os
# 设置API密钥
os.environ["OPENAI_API_KEY"] = "sk-xxx"
os.environ["ANTHROPIC_API_KEY"] = "sk-ant-xxx"
# 调用OpenAI——和直接用openai库一样的体验
response = completion(
model="openai/gpt-4o",
messages=[{"role": "user", "content": "解释量子计算"}]
)
# 切换到Claude——只改model参数,其他代码不变
response = completion(
model="anthropic/claude-sonnet-4-20250514",
messages=[{"role": "user", "content": "解释量子计算"}]
)
# 切换到本地Ollama——依然只改model参数
response = completion(
model="ollama/qwen3:32b",
messages=[{"role": "user", "content": "解释量子计算"}]
)
模式二:Proxy Server(AI网关,适合团队/企业级)
# 安装Proxy依赖
pip install 'litellm[proxy]'
# 启动网关服务
litellm --host 0.0.0.0 --port 4000 --config config.yaml
启动后,所有客户端只需要指向这个网关,使用标准OpenAI SDK即可:
import openai
# 所有模型统一走Proxy,用一个base_url
client = openai.OpenAI(
api_key="anything", # Proxy自行管理密钥
base_url="http://localhost:4000"
)
# 用model参数指定实际模型
response = client.chat.completions.create(
model="gpt-4o", # Proxy根据配置路由到真实模型
messages=[{"role": "user", "content": "Hello"}]
)
这两种模式的区别是什么时候该用哪个?简单总结:
| 维度 | SDK模式 | Proxy模式 |
|---|---|---|
| 部署方式 | import即用 | 需启动服务 |
| 密钥管理 | 代码中设置 | Proxy集中管理 |
| 适用规模 | 个人/小项目 | 团队/企业 |
| 负载均衡 | 不支持 | 支持 |
| 速率限制 | 不支持 | 支持 |
| 费用追踪 | 基础支持 | 完整支持 |
| 模型回退 | 手动 | 自动配置 |
三、架构深度分析
3.1 模型路由机制
LiteLLM最精妙的设计是它的模型路由系统。当你传入 model="openai/gpt-4o" 时,它需要完成以下工作:
- 解析provider前缀:
openai/→ 映射到OpenAI的调用逻辑 - 构建请求参数:将统一的OpenAI格式参数转换为Anthropic/Google等各自的格式
- 处理认证:从环境变量或配置中获取对应provider的API密钥
- 发送请求:调用对应provider的API
- 转换响应:将provider特有的响应格式统一转换为OpenAI格式
让我们深入看看路由是怎么工作的。LiteLLM内部维护了一个provider映射表:
# LiteLLM核心路由逻辑简化版
def get_llm_provider(model: str):
"""根据model字符串解析出provider和实际模型名"""
# 显式前缀模式:provider/model_name
if "/" in model:
provider, model_name = model.split("/", 1)
return provider, model_name
# 隐式推断模式:根据模型名自动识别
model_lower = model.lower()
if model_lower.startswith("gpt-") or model_lower.startswith("o1-") or model_lower.startswith("o3-"):
return "openai", model
elif model_lower.startswith("claude-"):
return "anthropic", model
elif model_lower.startswith("gemini-"):
return "vertex_ai", model # 或 gemini
elif model_lower.startswith("command-"):
return "cohere", model
elif model_lower.startswith("deepseek"):
return "deepseek", model
else:
# 默认走OpenAI兼容端点
return "openai", model
3.2 参数转换:核心难点
统一接口说起来简单,实现起来最难的是参数转换。不同provider的参数设计差异巨大,以函数调用(Function Calling/Tool Use)为例:
# OpenAI的函数调用格式
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取天气信息",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "城市名"}
},
"required": ["city"]
}
}
}]
# Anthropic的函数调用格式(完全不同的结构)
tools = [{
"name": "get_weather",
"description": "获取天气信息",
"input_schema": { # 注意:不是parameters,是input_schema
"type": "object",
"properties": {
"city": {"type": "string", "description": "城市名"}
},
"required": ["city"]
}
}]
LiteLLM的转换层需要处理这些差异。让我们看看它内部是怎么做的:
# LiteLLM参数转换核心逻辑(简化版)
def translate_openai_to_anthropic(kwargs):
"""将OpenAI格式参数转换为Anthropic格式"""
translated = {}
# 1. messages转换:Anthropic要求system消息单独提取
messages = kwargs.get("messages", [])
system_content = None
anthropic_messages = []
for msg in messages:
if msg["role"] == "system":
system_content = msg["content"]
elif msg["role"] == "assistant":
# Anthropic的assistant消息格式不同
content_blocks = []
if msg.get("content"):
content_blocks.append({"type": "text", "text": msg["content"]})
if msg.get("tool_calls"):
for tc in msg["tool_calls"]:
content_blocks.append({
"type": "tool_use",
"id": tc["id"],
"name": tc["function"]["name"],
"input": json.loads(tc["function"]["arguments"])
})
anthropic_messages.append({"role": "assistant", "content": content_blocks})
elif msg["role"] == "tool":
# OpenAI的tool role需要转为Anthropic的tool_result
anthropic_messages.append({
"role": "user",
"content": [{
"type": "tool_result",
"tool_use_id": msg.get("tool_call_id"),
"content": msg["content"]
}]
})
else:
anthropic_messages.append(msg)
if system_content:
translated["system"] = system_content
translated["messages"] = anthropic_messages
# 2. tools转换:function → input_schema
if "tools" in kwargs:
anthropic_tools = []
for tool in kwargs["tools"]:
if tool["type"] == "function":
func = tool["function"]
anthropic_tools.append({
"name": func["name"],
"description": func.get("description", ""),
"input_schema": func.get("parameters", {})
})
translated["tools"] = anthropic_tools
# 3. 参数映射
if "max_tokens" in kwargs:
translated["max_tokens"] = kwargs["max_tokens"]
if "temperature" in kwargs:
translated["temperature"] = kwargs["temperature"]
if "stop" in kwargs:
translated["stop_sequences"] = kwargs["stop"] if isinstance(kwargs["stop"], list) else [kwargs["stop"]]
# 4. 不支持的参数需要丢弃或警告
unsupported = {"n", "presence_penalty", "frequency_penalty", "logprobs"}
for param in unsupported:
if param in kwargs:
# 记录警告但不报错,保证调用不中断
import warnings
warnings.warn(f"Anthropic不支持参数 {param},已忽略")
return translated
3.3 响应标准化
请求发出去了,响应回来了,但每个provider的响应格式又不一样。LiteLLM需要把所有响应统一成OpenAI的 ChatCompletion 格式:
# Anthropic原始响应
{
"id": "msg_01XFDUDYJgAACzvnptvVoYEL",
"type": "message",
"role": "assistant",
"content": [{"type": "text", "text": "量子计算是..."}],
"model": "claude-sonnet-4-20250514",
"stop_reason": "end_turn",
"usage": {"input_tokens": 25, "output_tokens": 100}
}
# LiteLLM转换后的标准OpenAI格式
{
"id": "chatcmpl-abc123",
"object": "chat.completion",
"created": 1745390400,
"model": "claude-sonnet-4-20250514",
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": "量子计算是..."
},
"finish_reason": "stop" # end_turn → stop
}],
"usage": {
"prompt_tokens": 25, # input_tokens → prompt_tokens
"completion_tokens": 100, # output_tokens → completion_tokens
"total_tokens": 125
}
}
这种标准化让上层代码完全不需要关心底层provider的变化。
3.4 流式响应处理
流式响应(Streaming)是另一个技术难点。不同provider的SSE格式差异很大:
# OpenAI的SSE格式
data: {"id":"chatcmpl-abc","object":"chat.completion.chunk","choices":[{"delta":{"content":"量"},"index":0}]}
data: {"id":"chatcmpl-abc","object":"chat.completion.chunk","choices":[{"delta":{"content":"子"},"index":0}]}
data: [DONE]
# Anthropic的SSE格式(完全不同的event类型)
event: message_start
data: {"type":"message_start","message":{"id":"msg_abc"}}
event: content_block_delta
data: {"type":"content_block_delta","delta":{"type":"text_delta","text":"量"}}
event: content_block_delta
data: {"type":"content_block_delta","delta":{"type":"text_delta","text":"子"}}
event: message_stop
data: {"type":"message_stop"}
LiteLLM在流式模式下做了逐chunk的格式转换,确保上层代码收到的SSE事件格式完全一致:
# 统一的流式调用,无论底层provider
from litellm import completion
response = completion(
model="anthropic/claude-sonnet-4-20250514",
messages=[{"role": "user", "content": "写一首关于编程的诗"}],
stream=True
)
for chunk in response:
# 所有provider返回统一的delta格式
content = chunk.choices[0].delta.content or ""
print(content, end="", flush=True)
四、代码实战:从入门到生产级
4.1 基础用法:5分钟上手
pip install litellm
import litellm
import os
# 配置API密钥(推荐用环境变量,不要硬编码)
os.environ["OPENAI_API_KEY"] = "sk-xxx"
os.environ["ANTHROPIC_API_KEY"] = "sk-ant-xxx"
# 最简调用
response = litellm.completion(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello, world!"}]
)
print(response.choices[0].message.content)
# 流式调用
response = litellm.completion(
model="claude-sonnet-4-20250514",
messages=[{"role": "user", "content": "解释微服务架构"}],
stream=True
)
for chunk in response:
print(chunk.choices[0].delta.content or "", end="")
4.2 函数调用实战:跨模型统一
这是LiteLLM真正展现价值的地方。同一个tools定义,无缝切换模型:
import litellm
import json
import os
os.environ["OPENAI_API_KEY"] = "sk-xxx"
os.environ["ANTHROPIC_API_KEY"] = "sk-ant-xxx"
# 定义工具(OpenAI格式,LiteLLM自动转换给其他provider)
tools = [
{
"type": "function",
"function": {
"name": "get_stock_price",
"description": "获取股票实时价格",
"parameters": {
"type": "object",
"properties": {
"symbol": {
"type": "string",
"description": "股票代码,如 AAPL, GOOGL"
}
},
"required": ["symbol"]
}
}
},
{
"type": "function",
"function": {
"name": "calculate_portfolio",
"description": "计算投资组合的总价值",
"parameters": {
"type": "object",
"properties": {
"holdings": {
"type": "array",
"items": {
"type": "object",
"properties": {
"symbol": {"type": "string"},
"shares": {"type": "number"}
}
},
"description": "持仓列表"
}
},
"required": ["holdings"]
}
}
}
]
# 工具执行函数
def execute_tool(name, args):
"""模拟工具执行"""
if name == "get_stock_price":
prices = {"AAPL": 198.5, "GOOGL": 176.3, "MSFT": 425.2}
return json.dumps({
"symbol": args["symbol"],
"price": prices.get(args["symbol"], 0),
"currency": "USD"
})
elif name == "calculate_portfolio":
total = 0
for h in args["holdings"]:
total += h["shares"] * 200 # 简化计算
return json.dumps({"total_value": total, "currency": "USD"})
# Agentic Loop:模型调用工具 → 执行工具 → 返回结果 → 继续推理
def agent_loop(model: str, user_message: str, max_steps: int = 5):
"""一个简化的Agent循环,展示LiteLLM的函数调用统一性"""
messages = [{"role": "user", "content": user_message}]
for step in range(max_steps):
print(f"\n--- Step {step + 1} (model: {model}) ---")
response = litellm.completion(
model=model,
messages=messages,
tools=tools,
tool_choice="auto"
)
assistant_message = response.choices[0].message
# 检查是否需要调用工具
if assistant_message.tool_calls:
# 将assistant消息加入历史
messages.append(assistant_message.json())
for tool_call in assistant_message.tool_calls:
func_name = tool_call.function.name
func_args = json.loads(tool_call.function.arguments)
print(f" 调用工具: {func_name}({func_args})")
# 执行工具
result = execute_tool(func_name, func_args)
print(f" 工具返回: {result}")
# 将结果加入消息历史
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": result
})
else:
# 模型给出了最终回答
print(f" 最终回答: {assistant_message.content}")
return assistant_message.content
return "达到最大步数限制"
# 同一段代码,切换模型只需改model参数
result_openai = agent_loop("gpt-4o", "我持有100股AAPL和50股GOOGL,现在的投资组合价值多少?")
result_claude = agent_loop("claude-sonnet-4-20250514", "我持有100股AAPL和50股GOOGL,现在的投资组合价值多少?")
4.3 Proxy Server部署实战
SDK模式适合应用内嵌,但当你需要团队协作、密钥集中管理、费用追踪时,Proxy Server才是正解。
配置文件详解
# config.yaml - LiteLLM Proxy核心配置
model_list:
# GPT-4o 配置
- model_name: gpt-4o # 对外暴露的模型名
litellm_params:
model: openai/gpt-4o # 实际调用的provider/model
api_key: os.environ/OPENAI_API_KEY # 从环境变量读取
# GPT-4o 备用节点(负载均衡)
- model_name: gpt-4o
litellm_params:
model: azure/gpt-4o # Azure OpenAI作为备用
api_key: os.environ/AZURE_API_KEY
api_base: https://your-resource.openai.azure.com
# Claude配置
- model_name: claude-sonnet
litellm_params:
model: anthropic/claude-sonnet-4-20250514
api_key: os.environ/ANTHROPIC_API_KEY
# 本地Ollama模型
- model_name: qwen3-local
litellm_params:
model: ollama/qwen3:32b
api_base: http://localhost:11434 # Ollama本地地址
# DeepSeek(OpenAI兼容端点)
- model_name: deepseek-v3
litellm_params:
model: openai/deepseek-chat
api_key: os.environ/DEEPSEEK_API_KEY
api_base: https://api.deepseek.com
# 通用设置
litellm_settings:
# 请求超时(秒)
request_timeout: 60
# 降级策略:主模型失败时自动切到备选
fallbacks:
- gpt-4o: ["claude-sonnet", "deepseek-v3"]
- claude-sonnet: ["gpt-4o", "deepseek-v3"]
# 重试策略
num_retries: 3
retry_after: 0.5 # 重试间隔(秒)
# Proxy Server设置
general_settings:
# 主数据库(存储请求日志、费用等)
database_url: postgresql://user:pass@localhost:5432/litellm
# 主密钥(客户端连接Proxy时使用)
master_key: sk-your-master-key
# 最大并行请求
max_parallel_requests: 100
# 全局速率限制
tpm_limit: 1000000 # tokens per minute
rpm_limit: 10000 # requests per minute
启动与健康检查
# 启动Proxy
litellm --host 0.0.0.0 --port 4000 --config config.yaml
# 健康检查
curl http://localhost:4000/health
# 查看可用模型
curl -H "Authorization: Bearer sk-your-master-key" \
http://localhost:4000/v1/models
客户端调用
import openai
# 所有客户端统一连接Proxy
client = openai.OpenAI(
api_key="sk-your-master-key",
base_url="http://your-proxy-host:4000"
)
# 用法和直接调用OpenAI完全一致
response = client.chat.completions.create(
model="gpt-4o", # Proxy根据config路由到实际模型
messages=[{"role": "user", "content": "分析一下2026年AI趋势"}]
)
# 甚至LangChain也能直接接入
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="gpt-4o",
api_key="sk-your-master-key",
base_url="http://your-proxy-host:4000"
)
4.4 多模型负载均衡
这是Proxy模式最强大的功能之一。当你在 model_list 中为同一个 model_name 配置多个provider时,LiteLLM会自动做负载均衡:
model_list:
# 三个GPT-4o节点,自动轮询
- model_name: gpt-4o
litellm_params:
model: openai/gpt-4o
api_key: os.environ/OPENAI_API_KEY_1
- model_name: gpt-4o
litellm_params:
model: azure/gpt-4o
api_key: os.environ/AZURE_API_KEY
api_base: https://your-resource.openai.azure.com
- model_name: gpt-4o
litellm_params:
model: azure/gpt-4o
api_key: os.environ/AZURE_API_KEY_2
api_base: https://your-resource-2.openai.azure.com
客户端只需要 model="gpt-4o",Proxy会自动在三个节点间分发请求。如果某个节点失败(如Azure某个区域宕机),自动切换到其他节点。
4.5 模型降级(Fallback)
在生产环境中,模型降级是必备能力。当主模型不可用时,自动切到备选模型:
# SDK模式的手动降级
import litellm
from litellm import completion
models_to_try = ["gpt-4o", "claude-sonnet-4-20250514", "deepseek/deepseek-chat"]
for model in models_to_try:
try:
response = completion(
model=model,
messages=[{"role": "user", "content": "分析这段代码"}],
timeout=10 # 设置超时,避免长时间等待
)
print(f"成功使用 {model}")
break
except litellm.AuthenticationError:
print(f"{model} 认证失败,尝试下一个")
continue
except litellm.RateLimitError:
print(f"{model} 限流,尝试下一个")
continue
except litellm.Timeout:
print(f"{model} 超时,尝试下一个")
continue
except Exception as e:
print(f"{model} 未知错误: {e}")
continue
Proxy模式更简单,配置文件里写好fallbacks就行:
litellm_settings:
fallbacks:
- gpt-4o: ["claude-sonnet", "deepseek-v3", "qwen3-local"]
- claude-sonnet: ["gpt-4o", "deepseek-v3"]
4.6 费用追踪与预算控制
LiteLLM内置了精确的token计数和费用计算,支持主流100+模型的定价数据:
import litelll
# 开启回调追踪
litellm.success_callback = ["langfuse"] # 接入Langfuse观测平台
litellm.failure_callback = ["langfuse"]
response = litellm.completion(
model="gpt-4o",
messages=[{"role": "user", "content": "写一篇技术博客"}],
)
# 直接获取本次调用的费用
cost = litellm.completion_cost(completion_response=response)
print(f"本次调用费用: ${cost:.6f}")
# 获取token使用详情
print(f"输入tokens: {response.usage.prompt_tokens}")
print(f"输出tokens: {response.usage.completion_tokens}")
print(f"总tokens: {response.usage.total_tokens}")
Proxy模式下可以设置团队预算和用户预算:
# 在Proxy配置中设置预算
general_settings:
# 全局月预算
max_budget: 1000 # $1000/月
budget_duration: 30d
# 通过API创建带预算的API Key
# POST /key/generate
# {
# "max_budget": 50, # 该Key月预算$50
# "budget_duration": "30d",
# "models": ["gpt-4o", "claude-sonnet"],
# "tpm_limit": 50000
# }
五、安全事件复盘:PyPI投毒攻击
2026年3月,LiteLLM遭遇了一次严重的供应链攻击,这个事件值得深入分析。
5.1 事件回顾
2026年3月24日,LiteLLM在PyPI官方仓库发布了两个带有后门的版本:v1.82.7和v1.82.8。这两个版本被植入了恶意代码,在安装时执行远程代码注入。
关键数据:
- 月安装量约9500万次,影响面极大
- 受影响版本:1.82.7、1.82.8
- 攻击方式:供应链投毒(PyPI包劫持)
- 影响:数千家使用LiteLLM的企业AI架构
5.2 供应链攻击的防护策略
这次事件给整个Python生态敲响了警钟。作为开发者,我们应该如何防护?
策略一:版本锁定与哈希校验
# 永远不要 pip install litellm 不带版本号
# 正确做法:锁定版本号 + 哈希校验
pip install litellm==1.82.6 \
--require-hashes \
-r requirements.txt
# requirements.txt 内容:
# litellm==1.82.6 \
# --hash=sha256:abc123...
策略二:私有镜像与审核
# 使用私有PyPI镜像,手动审核每个版本
# devpi 或 Nexus 搭建私有仓库
pip install litellm==1.82.6 \
--index-url https://your-private-pypi.com/simple/ \
--trusted-host your-private-pypi.com
策略三:运行时安全监控
# 检测异常网络请求
import litellm
# 检查版本是否在受影响范围内
import importlib.metadata
version = importlib.metadata.version("litellm")
affected_versions = ["1.82.7", "1.82.8"]
if version in affected_versions:
raise RuntimeError(
f"当前LiteLLM版本 {version} 存在安全漏洞,"
f"请立即升级到安全版本!"
)
策略四:Proxy模式的安全优势
Proxy模式在安全方面有一个重要优势:密钥隔离。API密钥只存在于Proxy服务端,客户端只需要知道Proxy的地址和master_key。即使客户端被攻破,攻击者也无法获取原始的API密钥。
六、性能优化:生产级调优
6.1 连接池与并发优化
import litellm
import asyncio
from litellm import acompletion # 异步版本
# 开启缓存(相同请求直接返回缓存结果)
litellm.cache = litellm.Cache(type="redis", host="localhost", port=6379)
async def batch_call(prompts: list[str], model: str = "gpt-4o"):
"""并发调用多个提示词"""
tasks = [
acompletion(
model=model,
messages=[{"role": "user", "content": prompt}],
temperature=0.3,
max_tokens=500
)
for prompt in prompts
]
return await asyncio.gather(*tasks, return_exceptions=True)
# 批量处理100个请求
prompts = [f"总结以下文章的要点:{article}" for article in articles]
results = await batch_call(prompts)
6.2 缓存策略
LiteLLM支持多种缓存后端,对于重复查询场景效果显著:
import litellm
# Redis缓存(推荐生产环境)
litellm.cache = litellm.Cache(
type="redis",
host="localhost",
port=6379,
namespace="litellm_cache", # 命名空间隔离
ttl=3600 # 缓存1小时
)
# 相同请求第二次直接返回缓存
response1 = litellm.completion(
model="gpt-4o",
messages=[{"role": "user", "content": "什么是Docker?"}]
)
# → 实际调用API
response2 = litellm.completion(
model="gpt-4o",
messages=[{"role": "user", "content": "什么是Docker?"}]
)
# → 直接返回缓存,0延迟0费用
6.3 超时与重试配置
import litellm
# 全局超时设置
litellm.request_timeout = 30 # 30秒超时
# 针对特定模型的超时
response = litellm.completion(
model="gpt-4o",
messages=[{"role": "user", "content": "分析代码"}],
timeout=60, # 这次调用给60秒
num_retries=3, # 失败重试3次
retry_strategy="exponential_backoff" # 指数退避
)
6.4 Proxy模式的高可用部署
# docker-compose.yml - 生产级LiteLLM部署
version: '3.8'
services:
litellm-proxy:
image: ghcr.io/berriai/litellm:main-latest
ports:
- "4000:4000"
volumes:
- ./config.yaml:/app/config.yaml
environment:
- OPENAI_API_KEY=${OPENAI_API_KEY}
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
- DATABASE_URL=postgresql://litellm:password@postgres:5432/litellm
- REDIS_HOST=redis
- STORE_MODEL_IN_DB=True # 持久化模型配置
depends_on:
- postgres
- redis
restart: always
deploy:
resources:
limits:
memory: 2G
cpus: '2'
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:4000/health"]
interval: 30s
timeout: 10s
retries: 3
postgres:
image: postgres:16
environment:
POSTGRES_DB: litellm
POSTGRES_USER: litellm
POSTGRES_PASSWORD: password
volumes:
- pgdata:/var/lib/postgresql/data
restart: always
redis:
image: redis:7-alpine
volumes:
- redisdata:/data
restart: always
volumes:
pgdata:
redisdata:
6.5 Prometheus监控集成
# 在config.yaml中添加
litellm_settings:
# 开启Prometheus指标
prometheus_enabled: true
prometheus_port: 9090
关键监控指标:
| 指标 | 含义 | 告警阈值 |
|---|---|---|
litellm_request_total | 请求总数 | - |
litellm_request_duration_seconds | 请求延迟 | P99 > 30s |
litellm_request_errors_total | 错误数 | 错误率 > 5% |
litellm_tokens_total | Token消耗 | 接近预算 |
litellm_cost_total | 费用累计 | 接近预算 |
# Prometheus告警规则
groups:
- name: litellm
rules:
- alert: LiteLLMHighErrorRate
expr: rate(litellm_request_errors_total[5m]) / rate(litellm_request_total[5m]) > 0.05
for: 5m
annotations:
summary: "LiteLLM错误率超过5%"
- alert: LiteLLMHighLatency
expr: histogram_quantile(0.99, rate(litellm_request_duration_seconds_bucket[5m])) > 30
for: 5m
annotations:
summary: "LiteLLM P99延迟超过30秒"
- alert: LiteLLMBudgetApproaching
expr: litellm_cost_total > 900 # $1000预算的90%
annotations:
summary: "LiteLLM月度费用接近预算上限"
七、高级应用场景
7.1 多模型并行调用:模型仲裁
在某些场景下,我们需要同时调用多个模型,取最佳结果。这是一种"模型仲裁"模式:
import asyncio
from litellm import acompletion
async def model_arbitration(prompt: str, models: list[str]) -> str:
"""多模型并行调用,投票选最佳结果"""
async def call_model(model: str):
try:
response = await acompletion(
model=model,
messages=[{"role": "user", "content": prompt}],
temperature=0.1 # 低温度,更确定性
)
return {
"model": model,
"content": response.choices[0].message.content,
"tokens": response.usage.total_tokens,
"cost": response._hidden_params.get("response_cost", 0)
}
except Exception as e:
return {"model": model, "error": str(e)}
# 并行调用所有模型
results = await asyncio.gather(*[call_model(m) for m in models])
# 过滤掉失败的
valid_results = [r for r in results if "content" in r]
if not valid_results:
raise RuntimeError("所有模型调用失败")
# 简单策略:取最长的回答(更详细)
best = max(valid_results, key=lambda x: len(x["content"]))
print(f"仲裁结果:选用 {best['model']} 的回答")
print(f"Token消耗:{sum(r.get('tokens', 0) for r in valid_results)}")
print(f"总费用:${sum(r.get('cost', 0) for r in valid_results):.4f}")
return best["content"]
# 使用示例
result = await model_arbitration(
"用Rust实现一个高性能的HTTP服务器,要求支持异步IO和连接池",
["gpt-4o", "claude-sonnet-4-20250514", "deepseek/deepseek-chat"]
)
7.2 Embedding统一接口
RAG系统中,Embedding模型的调用也需要统一。LiteLLM同样支持:
from litellm import embedding
import os
os.environ["OPENAI_API_KEY"] = "sk-xxx"
# OpenAI Embedding
response = embedding(
model="openai/text-embedding-3-large",
input=["这是第一段文本", "这是第二段文本"]
)
print(f"维度: {len(response.data[0]['embedding'])}")
print(f"用量: {response.usage}")
# 切换到本地Ollama的Embedding
response = embedding(
model="ollama/nomic-embed-text",
input=["这是第一段文本", "这是第二段文本"]
)
# 切换到Cohere Embedding
response = embedding(
model="cohere/embed-english-v3.0",
input=["这是第一段文本", "这是第二段文本"]
)
7.3 结构化输出(Structured Output)
from litellm import completion
from pydantic import BaseModel
class CodeReview(BaseModel):
quality_score: int # 1-10
issues: list[str]
suggestions: list[str]
security_concerns: list[str]
# 通过response_format约束输出格式
response = completion(
model="gpt-4o",
messages=[{
"role": "user",
"content": f"审查以下代码并返回结构化结果:\n```python\n{code}\n```"
}],
response_format=CodeReview # Pydantic模型直接传入
)
review = CodeReview.model_validate_json(response.choices[0].message.content)
print(f"代码质量: {review.quality_score}/10")
print(f"问题: {review.issues}")
7.4 自定义Provider扩展
如果你的模型不在LiteLLM支持的100+之列,可以自定义Provider:
import litellm
class CustomProvider(litellm.CustomLLM):
"""自定义LLM Provider示例"""
def completion(self, model: str, messages, **kwargs):
"""实现同步调用"""
import requests
# 你的自定义API调用逻辑
response = requests.post(
"https://your-api-endpoint.com/v1/chat",
json={
"model": model,
"messages": messages,
**kwargs
},
headers={"Authorization": f"Bearer {self.api_key}"}
)
# 转换为LiteLLM标准格式
return litellm.ModelResponse(
id=response.json()["id"],
choices=[{
"index": 0,
"message": {
"role": "assistant",
"content": response.json()["output"]
},
"finish_reason": "stop"
}],
usage={
"prompt_tokens": response.json().get("input_tokens", 0),
"completion_tokens": response.json().get("output_tokens", 0),
"total_tokens": response.json().get("total_tokens", 0)
}
)
async def acompletion(self, model, messages, **kwargs):
"""实现异步调用"""
# 类似同步版本,但用httpx异步请求
pass
# 注册自定义Provider
litellm.custom_provider_map = [
{"provider": "my-custom", "class": CustomProvider}
]
# 使用自定义Provider
response = litellm.completion(
model="my-custom/my-model-v1",
messages=[{"role": "user", "content": "Hello"}]
)
八、踩坑指南:实际项目中的经验
8.1 Provider前缀规范
LiteLLM支持隐式推断和显式前缀两种模型指定方式。生产环境强烈建议使用显式前缀:
# ❌ 不推荐:隐式推断,可能出错
response = litellm.completion(
model="gpt-4o", # 会被自动推断为openai/gpt-4o
messages=[...]
)
# ✅ 推荐:显式前缀,清晰明确
response = litellm.completion(
model="openai/gpt-4o",
messages=[...]
)
# 特别是对于OpenAI兼容端点,一定要显式指定
response = litellm.completion(
model="openai/deepseek-chat", # 通过openai兼容模式调用
api_base="https://api.deepseek.com",
api_key="sk-xxx",
messages=[...]
)
8.2 Anthropic的特殊处理
Anthropic有一些独特的API设计,LiteLLM虽然做了转换,但有些坑仍需注意:
# 坑1:Anthropic必须设置max_tokens
response = litellm.completion(
model="anthropic/claude-sonnet-4-20250514",
messages=[{"role": "user", "content": "Hello"}],
max_tokens=1024 # ← 不设置会报错!OpenAI可以不设置,Anthropic不行
)
# 坑2:system消息必须作为独立参数
response = litellm.completion(
model="anthropic/claude-sonnet-4-20250514",
messages=[
{"role": "system", "content": "你是一个代码审查专家"}, # LiteLLM自动提取
{"role": "user", "content": "审查这段代码"}
],
max_tokens=4096
)
# 坑3:Anthropic不支持presence_penalty和frequency_penalty
response = litellm.completion(
model="anthropic/claude-sonnet-4-20250514",
messages=[...],
# presence_penalty=0.5, # ← 会报错或被忽略
# frequency_penalty=0.3, # ← 同上
max_tokens=4096
)
8.3 流式响应的边界情况
# 流式调用时,某些provider的chunk可能缺少content字段
response = litellm.completion(
model="gpt-4o",
messages=[{"role": "user", "content": "写一篇长文"}],
stream=True
)
full_content = ""
for chunk in response:
# 安全的content提取方式
delta = chunk.choices[0].delta
if delta.content: # ← 一定要判空,有些chunk的content是None
full_content += delta.content
# 检测结束
if chunk.choices[0].finish_reason:
print(f"\n生成结束,原因: {chunk.choices[0].finish_reason}")
8.4 错误处理最佳实践
import litellm
def safe_completion(model: str, messages: list, **kwargs) -> str:
"""带完整错误处理的LiteLLM调用"""
try:
response = litellm.completion(model=model, messages=messages, **kwargs)
return response.choices[0].message.content
except litellm.AuthenticationError as e:
# API密钥无效
print(f"认证失败: {e}")
raise
except litellm.RateLimitError as e:
# 触发了速率限制
print(f"限流: {e}")
# 指数退避重试
import time
time.sleep(5)
return safe_completion(model, messages, **kwargs)
except litellm.ContextWindowExceededError as e:
# 上下文窗口超限
print(f"上下文超限: {e}")
# 尝试截断消息或换用更大窗口的模型
fallback_model = "claude-sonnet-4-20250514" if "gpt" in model else "gpt-4o"
return safe_completion(fallback_model, messages[-5:], **kwargs) # 只保留最近5条
except litellm.Timeout as e:
print(f"超时: {e}")
raise
except litellm.APIConnectionError as e:
print(f"网络错误: {e}")
raise
except litellm.BadRequestError as e:
# 参数错误
print(f"请求参数错误: {e}")
raise
except Exception as e:
print(f"未知错误: {type(e).__name__}: {e}")
raise
九、与其他方案的对比
9.1 LiteLLM vs 直接调用各SDK
| 维度 | 直接调用SDK | LiteLLM |
|---|---|---|
| 代码量 | 每个provider一套 | 一套代码通用 |
| 模型切换 | 修改多处代码 | 只改model参数 |
| 密钥管理 | 分散在代码中 | 统一管理 |
| 错误处理 | 每个SDK不同 | 统一异常类型 |
| 费用追踪 | 手动计算 | 自动追踪 |
| 负载均衡 | 自行实现 | 内置支持 |
| 额外依赖 | 无 | litellm包 |
9.2 LiteLLM vs OpenRouter
OpenRouter是一个SaaS服务,提供类似的API统一能力,但两者有本质区别:
| 维度 | LiteLLM | OpenRouter |
|---|---|---|
| 部署方式 | 自托管 | SaaS |
| 数据隐私 | 完全自控 | 经过第三方 |
| 费用 | 按各API原价 | 加价约10-20% |
| 密钥管理 | 自持各API密钥 | 只需OpenRouter密钥 |
| 可定制性 | 高(可改源码) | 低 |
| 运维成本 | 需自行维护 | 零运维 |
9.3 LiteLLM vs One API
One API是另一个国内流行的API统一方案:
| 维度 | LiteLLM | One API |
|---|---|---|
| 语言 | Python | Go |
| 部署 | pip install | Docker部署 |
| SDK集成 | Python原生 | 需走HTTP |
| 缓存 | 内置Redis | 需外部配置 |
| 费用追踪 | 内置精确计费 | 基础计费 |
| 社区活跃度 | GitHub 25k+ stars | GitHub 18k+ stars |
十、总结与展望
核心价值总结
LiteLLM解决的核心问题是大模型API的碎片化。在一个需要频繁切换模型、进行模型对比、实现模型降级的时代,LiteLLM提供了一套标准化的解决方案:
- 统一接口:100+模型,一套代码
- 无缝切换:只改model参数,代码零改动
- Proxy模式:团队级密钥管理、负载均衡、费用追踪
- 降级容灾:自动fallback,保障服务可用性
- 可观测性:内置费用追踪、Langfuse集成、Prometheus指标
技术趋势
从2026年GitHub Trending的走势来看,AI网关/统一调用层正在成为AI基础设施的标配。LiteLLM月安装量9500万次,说明市场需求确实旺盛。
未来几个值得关注的方向:
- 模型路由智能化:基于请求内容自动选择最合适的模型(代码问题→GPT-4o,创意写作→Claude,数学→Gemini)
- 成本优化:根据SLA要求自动在性能和成本之间权衡,小问题用小模型,复杂问题用大模型
- 多模态统一:将图像、音频、视频输入也纳入统一接口
- 边缘部署:在边缘节点部署LiteLLM Proxy,减少网络延迟
- 安全加固:PyPI投毒事件后,供应链安全将成为重点
最后的话
如果你正在做多模型集成,LiteLLM是目前最成熟的开源方案。它不是银弹——参数转换的边界情况、provider特有的功能差异、PyPI供应链风险——这些都是现实存在的问题。但在"不统一就混乱"和"统一但受限"之间,LiteLLM找到了一个相当好的平衡点。
一句话总结:LiteLLM是大模型时代的API适配器,它让多模型管理从"每人一套"变成了"统一标准",在AI工程化的道路上,这是一个重要的基础设施级项目。