Skip to content

필사 모드: LiteLLM 实战指南 — 用一个接口调用 100+ 个 LLM

中文
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.

概述

做 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

最小的调用形式如下。只需把 modelmessages 传给 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 前缀示例环境变量
OpenAIopenai/gpt-4oOPENAI_API_KEY
Anthropicanthropic/claude-3-5-sonnet-20241022ANTHROPIC_API_KEY
Gemini (AI Studio)gemini/gemini-1.5-proGEMINI_API_KEY
Vertex AIvertex_ai/gemini-1.5-proGCP 凭证
AWS Bedrockbedrock/...AWS 凭证
Azure OpenAIazure/...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)。可以按失败类型分别配置三种回退。

回退类型触发条件备注
fallbacks429/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 平台时,自然会走向这个方向。

再整理几条实战中有用的心得。

  1. 响应解析代码只写一次:不管调用哪个供应商,resp.choices[0].message.content 这个形状都保持不变,响应解析逻辑不需要按供应商各写一份。
  2. 密钥走环境变量:无论是 SDK 还是 proxy 的 config,都不要把密钥写死在代码里,而是通过环境变量注入。在 proxy 里用 os.environ/ 引用。
  3. model 字符串就是切换开关:切换供应商无非是替换前缀、设置环境变量这两件事。按部署环境只改 model 字符串的策略很管用。
  4. 把 OpenRouter 放在身边:常用的供应商直连,实验性、多样化的模型用 openrouter/ 前缀接入,就能在不增加集成成本的前提下拓宽选择面。
  5. 从小处起步,再逐步扩展:先从 SDK 开始,等团队扩张、需要集中管理时,把同一套 model_list 的思路原样搬进 Proxy 的 config 就行。

总结一下,LiteLLM 把供应商的碎片化推出了代码之外。第一次调用只需要几行,而在需要的那一刻,可以用 Router 加上稳定性,用 Proxy 加上组织层面的管控。更深入的内部机制和生产环境细节配置,可以接着看 LiteLLM 完整指南

参考资料

현재 단락 (1/164)

做 LLM 应用做得久了,很快就会撞上同一堵墙。每个供应商的 SDK 不一样,请求参数不一样,响应格式也不一样。用 OpenAI 的代码起步,想换成 Anthropic 时,从客户端初始化到消息解析全...

작성 글자: 0원문 글자: 7,043작성 단락: 0/164