- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 概述
- 1. 安装与第一次调用
- 2. 用同一份代码调用多个供应商
- 3. 通过 LiteLLM 使用 OpenRouter
- 4. 流式输出与异步
- 5. Router — 负载均衡与回退
- 6. Proxy Server(AI 网关)
- 7. SDK 还是 Proxy,以及一些实战心得
- 参考资料
概述
做 LLM 应用做得久了,很快就会撞上同一堵墙。每个供应商的 SDK 不一样,请求参数不一样,响应格式也不一样。用 OpenAI 的代码起步,想换成 Anthropic 时,从客户端初始化到消息解析全都要重写一遍。LiteLLM 正是要消除这个摩擦点。
LiteLLM(由 BerriAI 打造)由两部分组成。一是 Python SDK,二是 Proxy Server(AI 网关)。两者有一个共同目标:把 100 个以上的 LLM API 统一成 OpenAI 请求/响应格式 来调用。在这层统一表面之上,再叠加成本追踪、重试、负载均衡、回退(fallback)、护栏(guardrails)、日志等运维能力。
这篇文章是一份快速上手的 实战速成指南。安装、发出第一次调用、切换供应商,再以最短路径过一遍流式输出、Router 和 Proxy。这个博客里已经有一篇深入讲 LiteLLM 内部结构与生产级运维模式的 LiteLLM 完整指南,如果需要原理和生产环境的细节配置,可以配合那篇一起看。这篇文章刻意保持轻量。
先把一个核心视角定下来。LiteLLM 不是「又一个供应商」,而是架在多个供应商之上的 单一统一层。而在它下面,甚至还可以再放一层像 OpenRouter 这样、本身就整合了数百个模型的路由器。也就是说,一套 LiteLLM 配置就能用同一份代码,同时调用直连的供应商和经由 OpenRouter 接入的供应商。
1. 安装与第一次调用
安装只需要一行。用 pip 还是 uv 没有区别。
pip install litellm
# 使用 uv 时
uv add litellm
最小的调用形式如下。只需把 model 和 messages 传给 completion 函数,响应会按 OpenAI 的格式原样返回。
from litellm import completion
import os
os.environ["OPENAI_API_KEY"] = "sk-..."
resp = completion(
model="openai/gpt-4o",
messages=[{"role": "user", "content": "Hello"}],
)
print(resp.choices[0].message.content)
值得留意的是访问响应的方式。resp.choices[0].message.content 正是用过 OpenAI SDK 的人熟悉的那套结构。因为不管调用哪个供应商,这个形状都保持不变,处理响应的代码只需要写一次。
在 SDK 这一层就能直接传入简单的稳定性选项。用 num_retries 指定重试次数,用 timeout 指定等待响应的时长,就能让单次调用对临时性错误多一分韧性。这些选项在不经过 Router 的单次调用里也照样有效。
from litellm import completion
resp = completion(
model="openai/gpt-4o",
messages=[{"role": "user", "content": "Hello"}],
num_retries=2,
timeout=30,
)
print(resp.choices[0].message.content)
2. 用同一份代码调用多个供应商
切换供应商只需要两步:改 model 字符串的 前缀(prefix),再设置该供应商对应的 环境变量。仅此而已。消息结构和响应解析都原样不变。
| 供应商 | model 前缀示例 | 环境变量 |
|---|---|---|
| OpenAI | openai/gpt-4o | OPENAI_API_KEY |
| Anthropic | anthropic/claude-3-5-sonnet-20241022 | ANTHROPIC_API_KEY |
| Gemini (AI Studio) | gemini/gemini-1.5-pro | GEMINI_API_KEY |
| Vertex AI | vertex_ai/gemini-1.5-pro | GCP 凭证 |
| AWS Bedrock | bedrock/... | AWS 凭证 |
| Azure OpenAI | azure/... | Azure 配置 |
| Ollama(本地) | ollama/llama3 | 无(本地运行) |
比如切换到 Anthropic,就是这样。
from litellm import completion
import os
os.environ["ANTHROPIC_API_KEY"] = "sk-ant-..."
resp = completion(
model="anthropic/claude-3-5-sonnet-20241022",
messages=[{"role": "user", "content": "Hello"}],
)
print(resp.choices[0].message.content)
想用本地模型试验,启动 Ollama 后把前缀改成 ollama/ 就行,连 API 密钥都不需要。
from litellm import completion
resp = completion(
model="ollama/llama3",
messages=[{"role": "user", "content": "Hello"}],
)
print(resp.choices[0].message.content)
得益于这个结构,「开发用本地 Ollama、预发布用 Gemini、生产用 Bedrock」这类切换,不需要改任何代码,只靠环境变量和 model 字符串就能完成。
3. 通过 LiteLLM 使用 OpenRouter
这是本文特别想强调的组合。OpenRouter 本身就是一项把 300 多个模型整合进单一 API 的服务。把 LiteLLM 架在它上面,就能同时获得 OpenRouter 广泛的模型覆盖面,以及 LiteLLM 统一的接口和运维能力(重试、回退、成本追踪)。
方法和前面的模式一致。设置 OPENROUTER_API_KEY,再把 model 字符串以 openrouter/ 开头,后面接上 OpenRouter 的模型 id。
from litellm import completion
import os
os.environ["OPENROUTER_API_KEY"] = "sk-or-..."
resp = completion(
model="openrouter/openai/gpt-4o",
messages=[{"role": "user", "content": "Hello"}],
)
print(resp.choices[0].message.content)
拆开这个前缀就好理解了。前面的 openrouter/ 是在告诉 LiteLLM「经由 OpenRouter 发送」,后面的 openai/gpt-4o 则是 OpenRouter 能识别的模型 id。也就是说,openrouter/ 后面可以接上 OpenRouter 支持的任何模型 id。
这个组合的实用价值很清楚。把直接签约的几个供应商用 LiteLLM 直连,把其余实验性、多样化的模型经由 OpenRouter 接入,而应用代码始终保持同一个 completion 调用。增加一个模型所需的集成成本几乎趋近于零。
4. 流式输出与异步
要实时流式输出 token,只需加上 stream=True 并遍历返回值,从 delta 里取出片段拼接起来即可。
from litellm import completion
resp = completion(
model="openai/gpt-4o",
messages=[{"role": "user", "content": "Write a haiku about the sea"}],
stream=True,
)
for chunk in resp:
print(chunk.choices[0].delta.content or "", end="")
有些 chunk 的 delta.content 会是 None,所以惯例是用 or "" 做防护,这样空片段就不会抛出异常。
在异步代码里用 acompletion。签名和 completion 一样,只需加上 await。
import asyncio
from litellm import acompletion
async def main():
resp = await acompletion(
model="anthropic/claude-3-5-sonnet-20241022",
messages=[{"role": "user", "content": "Hello"}],
)
print(resp.choices[0].message.content)
asyncio.run(main())
流式输出和异步可以组合使用。在 FastAPI 这类异步 Web 框架里,把 token 以 server-sent events 的形式流式发出时,通常就会把两者一起用上。
5. Router — 负载均衡与回退
一旦调用量增长、稳定性变得重要,SDK 的 Router 类就该登场了。Router 把多个部署(deployment)归到同一个别名(alias)下,分散请求并自动吸收失败。
先定义 model_list。每一项都有对外可见的名字 model_name,以及实际调用参数 litellm_params。把同一个 model_name 挂到多个部署上,Router 就会把发往这个别名的请求分散到这几个部署里。
from litellm import Router
model_list = [
{
"model_name": "my-gpt",
"litellm_params": {
"model": "openai/gpt-4o",
"api_key": "sk-...",
},
},
{
"model_name": "my-gpt",
"litellm_params": {
"model": "azure/gpt-4o-deployment",
"api_key": "...",
"api_base": "https://your-resource.openai.azure.com",
},
},
]
router = Router(model_list=model_list)
resp = router.completion(
model="my-gpt",
messages=[{"role": "user", "content": "Hello"}],
)
print(resp.choices[0].message.content)
Router 真正的价值在于回退(fallback)。可以按失败类型分别配置三种回退。
| 回退类型 | 触发条件 | 备注 |
|---|---|---|
fallbacks | 429/500 类错误 | 转发到其他模型 |
context_window_fallbacks | 超出上下文长度 | 需要 enable_pre_call_checks=True |
content_policy_fallbacks | 内容政策拒绝 | 绕道到其他模型 |
同时配置这三种的例子如下。唯一要留意的是,要用上下文回退,就得打开事前检查。
from litellm import Router
router = Router(
model_list=model_list,
fallbacks=[{"my-gpt": ["claude"]}],
context_window_fallbacks=[{"my-gpt": ["claude-long"]}],
content_policy_fallbacks=[{"my-gpt": ["safe-model"]}],
enable_pre_call_checks=True,
)
除此之外,Router 还一并管理重试(retries)、冷却(cooldowns)、超时(timeouts)。如果某个部署持续失败,就会先把它放进冷却名单、暂时不发流量过去,等过一段时间后再恢复。应用代码依旧只需要一行:router.completion(model="my-gpt", ...)。
6. Proxy Server(AI 网关)
如果多个团队和多个应用需要共享同一个网关,答案就是 Proxy Server。Proxy 以独立进程的形式启动,充当能接纳任意 OpenAI 兼容客户端的网关。
先在 config.yaml 里写 model_list。让 API 密钥通过 os.environ/ 引用环境变量,是更安全的做法。
model_list:
- model_name: gpt-4o
litellm_params:
model: openai/gpt-4o
api_key: os.environ/OPENAI_API_KEY
- model_name: claude
litellm_params:
model: anthropic/claude-3-5-sonnet-20241022
api_key: os.environ/ANTHROPIC_API_KEY
接着指定配置文件启动 proxy。默认监听在 http://0.0.0.0:4000。
litellm --config config.yaml
现在,任意 OpenAI 兼容客户端只要把 base URL 指向这个 proxy、传一个占位/基础密钥,就能直接工作。真正的供应商密钥由 proxy 从 config 里持有,不会暴露给客户端。
from openai import OpenAI
client = OpenAI(
base_url="http://0.0.0.0:4000",
api_key="anything", # 代理管理的虚拟密钥/占位密钥
)
resp = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello"}],
)
print(resp.choices[0].message.content)
Proxy 这层带来的远不止单纯的代理转发。按团队发放虚拟密钥(virtual keys)、预算(budgets)上限、成本追踪看板、请求日志,全都在网关这一层集中管理。应用不需要知道真正的供应商密钥,运维团队也能在一个地方看到谁用了多少。
7. SDK 还是 Proxy,以及一些实战心得
该用哪一个,取决于规模。
- 适合用 SDK 的情况:单一应用或脚本。把库 import 进来在代码里直接调用即可,不需要额外的基础设施。适合个人项目、批处理任务、单一服务。
- 适合用 Proxy 的情况:多个团队或多个应用需要共享同一个网关。如果需要集中式密钥管理、预算、成本看板,Proxy 就是正解。搭建组织级 LLM 平台时,自然会走向这个方向。
再整理几条实战中有用的心得。
- 响应解析代码只写一次:不管调用哪个供应商,
resp.choices[0].message.content这个形状都保持不变,响应解析逻辑不需要按供应商各写一份。 - 密钥走环境变量:无论是 SDK 还是 proxy 的 config,都不要把密钥写死在代码里,而是通过环境变量注入。在 proxy 里用
os.environ/引用。 - model 字符串就是切换开关:切换供应商无非是替换前缀、设置环境变量这两件事。按部署环境只改 model 字符串的策略很管用。
- 把 OpenRouter 放在身边:常用的供应商直连,实验性、多样化的模型用
openrouter/前缀接入,就能在不增加集成成本的前提下拓宽选择面。 - 从小处起步,再逐步扩展:先从 SDK 开始,等团队扩张、需要集中管理时,把同一套
model_list的思路原样搬进 Proxy 的 config 就行。
总结一下,LiteLLM 把供应商的碎片化推出了代码之外。第一次调用只需要几行,而在需要的那一刻,可以用 Router 加上稳定性,用 Proxy 加上组织层面的管控。更深入的内部机制和生产环境细节配置,可以接着看 LiteLLM 完整指南。