Fork me on GitHub

2025年11月

实战 LiteLLM 与外部日志系统的集成

在前一篇文章中,我们学习了 LiteLLM 的内置日志系统,包括请求日志、会话日志和审核日志。这些日志为我们提供了完整的 API 调用追踪、成本分析和合规审计能力。然而,在企业级部署场景中,我们往往需要将这些宝贵的数据集成到现有的可观测性生态系统中,比如与 Elasticsearch 进行日志分析、通过 Datadog 进行性能监控,或者利用 Langfuse 进行 LLM 专业化的可观测性管理。

LiteLLM 支持与 30 多种外部日志和可观测性系统 的集成,包括传统的云存储(S3、GCS、Azure Blob)、专业的可观测性平台(Langfuse、OpenTelemetry、Datadog)、以及企业级的数据分析工具(Elasticsearch、BigQuery、DynamoDB),为我们构建完整的监控和分析体系提供了强有力的支持。

今天这篇文章,我们就来深入学习 LiteLLM 的外部日志集成能力。

支持的外部日志系统

LiteLLM 的日志集成能力非常丰富,支持多达 30+ 种不同类型的外部系统:

LLM 专业可观测性平台

  • Langfuse - LLM 专业可观测性平台,提供完整的 LLM 应用监控、分析和优化
  • Langsmith - LangChain 官方的 LLM 开发和监控平台,专为 LangChain 生态设计
  • Lunary - LLM 监控和分析平台,提供对话流程可视化和性能分析
  • Langtrace - LLM 应用的可观测性和监控平台,提供详细的追踪分析
  • Helicone - 开源的 LLM 可观测性平台,简化 LLM 应用监控
  • DeepEval - Confidential AI 的 LLM 评测平台,专注模型质量评估
  • Athina - LLM 应用的质量评估和监控平台,提供实时质量检测
  • Braintrust - AI 产品开发平台,提供评估、监控和数据管理
  • Humanloop - LLM 应用开发平台,集成提示工程和监控功能
  • Literal AI - 对话式 AI 监控平台,专注用户体验优化
  • Promptlayer - 提示工程和监控平台,帮助优化 LLM 提示效果

通用监控和可观测性平台

  • OpenTelemetry - 开源的可观测性框架,支持分布式追踪和监控
  • Datadog - 综合性能监控平台,提供全栈监控和告警能力
  • Sentry - 错误监控和性能追踪平台,帮助快速定位应用问题
  • Logfire - Pydantic 团队开发的现代可观测性平台
  • PostHog - 开源的产品分析平台,提供用户行为跟踪和 A/B 测试

机器学习和实验管理

  • MLflow - 机器学习实验管理平台,支持模型版本控制和部署
  • Arize AI - 专注于 ML 可观测性的企业级平台,提供模型漂移检测
  • Arize Phoenix OSS - Arize 的开源版本,专注 ML 模型监控
  • Galileo - AI 模型质量监控平台,专注于数据和模型性能评估
  • Weights & Biases - 机器学习实验跟踪和可视化平台
  • Comet Opik - 机器学习实验管理和模型监控平台

数据标注和质量管理

  • Argilla - 开源数据标注和质量管理平台,支持 LLM 训练数据优化
  • AgentOps - AI Agent 运行监控平台,专注 Agent 行为分析

使用量计量和费用管理

  • OpenMeter - 开源的使用量计量和计费平台,支持 API 使用监控
  • Greenscale - 云成本优化平台,帮助降低 AI 基础设施成本
  • CloudZero's AnyCost API - 企业级云成本分析和分配平台
  • Lago - 开源计费平台,支持基于使用量的灵活计费模式

云存储服务

  • AWS S3 - AWS 的对象存储服务,适合大规模日志归档
  • AWS SQS - AWS 的消息队列服务,适合实时日志处理
  • Google Cloud Storage Buckets - 谷歌云的对象存储服务
  • Google Cloud Storage PubSub Topic - 谷歌云的消息队列服务,可以被 BigQuery 消费
  • Azure Blob Storage - 微软云的存储解决方案

数据库和分析

  • Elasticsearch - 分布式搜索和分析引擎
  • DynamoDB - AWS 的 NoSQL 数据库
  • BigQuery - 谷歌云的大数据分析平台
  • Supabase - Firebase 开源替代

下面将以 Langfuse 和 OpenTelemetry 为例,实际体验下集成的详细步骤。

实战 Langfuse 集成

Langfuse 是专为 LLM 应用设计的开源可观测性平台,提供了完整的链路追踪、性能分析、成本监控和质量评估能力。

langfuse.png

作为专业的 LLM 可观测性平台,Langfuse 具有以下核心特性:

  • 追踪(Tracing):记录 LLM 应用的完整执行过程
  • 观测(Observability):提供实时的性能监控和可视化
  • 评估(Evaluation):支持多种评估指标和人工标注
  • 数据集管理:管理测试数据和历史记录
  • 成本追踪:监控 Token 使用和费用

获取 Langfuse 的 API Key

我们首先访问 Langfuse 官网,注册账号并登录,然后创建一个组织:

langfuse-new-org.png

然后在组织下创建一个项目:

langfuse-new-project.png

创建成功后,接着为项目创建 API Key:

langfuse-new-apikey.png

点击创建按钮,获取以下三个重要参数:

  • Public Key:公开密钥,用于客户端身份验证
  • Secret Key:私钥,用于服务端 API 调用
  • Host:Langfuse 服务器地址

langfuse-new-apikey-2.png

Langfuse 是开源项目,我们也可以本地部署它。

在 LiteLLM 中配置 Langfuse

首先安装依赖:

$ pip install langfuse==2.59.7

注意,如果使用最近版本的 Langfuse 可能会报错,可以使用 Langfuse OTEL 集成方案。

然后配置环境变量:

export LANGFUSE_PUBLIC_KEY="pk_xxx"
export LANGFUSE_SECRET_KEY="sk_xxx"
export LANGFUSE_HOST="https://cloud.langfuse.com"  # 可选,默认为云版本

接着在 config.yaml 中添加 Langfuse 回调:

litellm_settings:
  success_callback: ["langfuse"]
  failure_callback: ["langfuse"]

最后重新启动 LiteLLM 并发送测试请求:

$ curl -X POST 'http://127.0.0.1:4000/chat/completions' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "gpt-4o",
    "messages": [{"role": "user", "content": "介绍下 Langfuse"}]
  }'

进入 Langfuse 的 Trace 页面,应该能看到详细的追踪数据:

langfuse-trace.png

元数据传递

Langfuse 支持传递丰富的元数据信息,用于更精确的分析:

$ curl -X POST 'http://127.0.0.1:4000/chat/completions' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "gpt-4o",
    "messages": [{"role": "user", "content": "介绍下 Langfuse"}],
    "metadata": {
      "generation_name": "knowledge-qa",
      "trace_id": "trace-001",
      "trace_user_id": "user-123",
      "session_id": "session-456"
    }
  }'

这些元数据在 Langfuse 中显示如下:

langfuse-trace-metadata.png

自定义标签

我们还可以使用标签对不同类型的请求进行分类:

$ curl -X POST 'http://127.0.0.1:4000/chat/completions' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "gpt-4o",
    "messages": [{"role": "user", "content": "写一个 Python 函数来计算斐波那契数列"}],
    "metadata": {
      "tags": ["code-generation", "python", "algorithms"]
    }
  }'

这些标签可以在 Langfuse 的 Tags 一栏看到:

langfuse-trace-tags.png

注意,这个功能可能和标签路由冲突,如果开启了标签路由,tags 就不能随便传了。

除了在请求中自定义标签,LiteLLM 也内置了很多特有的字段作为标签,可以在配置文件中启用:

litellm_settings:
  success_callback: ["langfuse"]
  failure_callback: ["langfuse"]
  # 配置要作为标签记录的 LiteLLM 字段
  langfuse_default_tags: [
    "cache_hit",               # 缓存命中状态
    "cache_key",               # 缓存键
    "user_api_key_alias",      # 用户API密钥别名
    "user_api_key_user_id",    # 用户ID
    "user_api_key_user_email", # 用户邮箱
    "user_api_key_team_alias", # 团队
  ]

这样在 Langfuse 中就能看到这些额外的标签信息,方便进行更细粒度的分析:

langfuse-trace-litellm-tags.png

实战 OpenTelemetry + Elasticsearch 集成

OpenTelemetry 简称 OTEL,是 CNCF 的开源可观测性框架,提供了统一的遥测数据收集标准。它的核心优势在于:

  • 标准化:使用业界标准的遥测数据格式
  • 灵活性:可以同时导出到多个不同的监控系统
  • 可扩展性:Collector 可以水平扩展处理大量数据
  • 厂商中立:不依赖特定的监控平台

otel.png

OpenTelemetry 的主要组件包括:

  • SDK:各种语言的客户端库,负责收集遥测数据
  • Collector:数据收集、处理和导出的中间件
  • Exporter:将数据导出到不同的后端系统

其实现架构如下:

otel-graph.png

结合 Elasticsearch 的强大搜索和分析能力,我们可以构建一个企业级的日志分析系统。

环境搭建

第一步,创建一个 Docker 网络:

$ docker network create otel-network

在该网络中启动一个单节点的 Elasticsearch 服务:

$ docker run -d \
  --name elasticsearch \
  --network otel-network \
  -p 9200:9200 \
  -e "discovery.type=single-node" \
  -e "xpack.security.enabled=false" \
  elasticsearch:8.18.2

第二步,创建 otel_config.yaml 配置文件:

receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318

processors:
  batch:
    timeout: 1s
    send_batch_size: 1024

exporters:
  debug:
    verbosity: detailed
  elasticsearch:
    endpoint: "http://elasticsearch:9200"

service:
  pipelines:
    metrics:
      receivers: [otlp]
      exporters: [debug, elasticsearch]
    traces:
      receivers: [otlp]
      exporters: [debug, elasticsearch]
    logs: 
      receivers: [otlp]
      exporters: [debug, elasticsearch]

然后启动 OpenTelemetry Collector 服务,注意它和 Elasticsearch 共用一个网络,确保可以使用 elasticsearch:9200 这个地址访问 Elasticsearch 服务:

$ docker run -d \
  --name otel-collector \
  --network otel-network \
  -p 4317:4317 \
  -p 4318:4318 \
  -v $(pwd)/otel_config.yaml:/etc/otel-collector-config.yaml \
  otel/opentelemetry-collector-contrib:latest \
  --config=/etc/otel-collector-config.yaml

另一点值得注意的是,这里我使用的是 otel/opentelemetry-collector-contrib 镜像,该镜像包含大量的接收器导出器处理器连接器 和其他可选组件,包括我们这里要使用的 elasticsearch 导出器。

第三步,修改 LiteLLM 的配置文件,添加 OTEL 回调:

litellm_settings:
  callbacks: ["otel"]

并安装 OTEL 相关的依赖:

$ pip install \
  opentelemetry-api \
  opentelemetry-sdk \
  opentelemetry-exporter-otlp

然后设置环境变量:

$ export OTEL_EXPORTER=otlp_http
$ export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318"

重启 LiteLLM 服务:

$ litellm -c config.yaml

测试验证

发送测试请求:

$ curl -X POST 'http://127.0.0.1:4000/chat/completions' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "gpt-4o",
    "messages": [{"role": "user", "content": "你好"}]
  }'

稍等片刻,搜索 Elasticsearch 验证数据是否正确写入:

# 搜索最近的一条跟踪数据
$ curl "localhost:9200/_search?pretty&size=1" | jq '.'

如果一切顺利,应该能看到类似这样的 OpenTelemetry 跟踪数据:

{
  "took": 119,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 15,
      "relation": "eq"
    },
    "max_score": 1.0,
    "hits": [
      {
        "_index": ".ds-traces-generic.otel-default-2025.11.25-000001",
        "_id": "AZq5FFC45Ve33J9AiHVu",
        "_score": 1.0,
        "_source": {
          "@timestamp": "2137173047.194915",
          "data_stream": {
            "type": "traces",
            "dataset": "generic.otel",
            "namespace": "default"
          },
          "trace_id": "af20113fb91ba1e2893b1c0e3a6d20e7",
          "span_id": "f8b94554ab20692f",
          "parent_span_id": "f5cf57a86811be6d",
          "name": "router",
          "kind": "Internal",
          "duration": 823751,
          "attributes": {
            "call_type": "async_get_available_deployment",
            "service": "router"
          },
          "links": [],
          "status": {
            "code": "Ok"
          },
          "resource": {
            "attributes": {
              "telemetry.sdk.language": "python",
              "telemetry.sdk.name": "opentelemetry",
              "telemetry.sdk.version": "1.38.0",
              "service.name": "litellm",
              "deployment.environment": "production",
              "model_id": "litellm"
            }
          },
          "scope": {
            "name": "litellm"
          }
        }
      }
    ]
  }
}

Kibana 可视化

我们还可以启动 Kibana 进行数据可视化,注意和 Elasticsearch 共用一个网络:

$ docker run -d \
  --name kibana \
  --network otel-network \
  -p 5601:5601 \
  kibana:8.18.2

访问 http://localhost:5601,进入 探索(Discover) 页面,创建一个新的 数据视图(Data View)

kibana-create-data-view.png

其中 索引模式(Index pattern) 填写 traces-generic.otel-default,OTEL 的 trace 数据默认会写入该 数据流(Data Stream) 中。然后选择该视图,就可以看到 LiteLLM 推送过来的日志了:

kibana-logs.png

小结

今天我们学习了 LiteLLM 与外部日志系统的集成能力,对其中的两种集成方案进行了实战演示:

  • Langfuse 集成:专业的 LLM 可观测性平台,提供了完整的链路追踪、成本分析和质量评估能力,特别适合需要深度 LLM 应用监控的场景
  • OpenTelemetry + Elasticsearch 集成:基于开源标准的企业级日志分析方案,利用 OTEL 的标准化数据收集和 Elasticsearch 的强大搜索分析能力

除了本文介绍的这两种方案,LiteLLM 还支持 30 多种其他日志系统的集成,具体内容可参考官方文档:

通过统一的回调机制和标准化的日志格式,我们可以将 LiteLLM 的日志数据与现有的可观测性生态系统无缝整合,实现全面的性能监控、成本优化和问题诊断。


学习 LiteLLM 的日志系统

对于一个 LLM 网关来说,日志系统扮演着至关重要的角色:它不仅能帮我们追踪每一笔 API 调用的成本和性能;当模型回复异常或请求失败时,还能提供详细的上下文信息来定位问题;它还确保所有管理操作都有迹可循,以满足合规性要求。

我们今天就来学习下 LiteLLM 的日志体系,主要包括 请求日志(Spend Logs)会话日志(Session Logs)审核日志(Audit Logs)

logging.png

请求日志

请求日志(Spend Logs) 是整个日志系统的核心,它记录了每一次 API 调用的详细信息,包括调用者、消耗成本、token 使用量、延迟等关键指标,能够用于成本分析和性能监控。

可以进入 Admin UI,点击 Logs 菜单,查看请求日志:

![](./images/requests-logs.png)

在这里,LiteLLM 记录了所有成功和失败的请求日志。考虑到 隐私保护存储成本,默认情况下,LiteLLM 只记录元数据信息,而不存储具体的请求和响应内容。如果业务需要进行内容分析或调试,可以通过下面的配置显式开启:

general_settings:
  store_prompts_in_spend_logs: true

注:开启此选项会增加数据库的存储压力,并且可能涉及敏感数据的合规问题,请根据实际情况谨慎开启。

开启后,你就能在 UI 界面中看到完整的对话内容:

requests-logs-request-response.png

日志保存逻辑

LiteLLM 的请求日志保存在 Postgre 数据库的 LiteLLM_SpendLogs 表中,在高并发场景下,如果每一笔请求都同步写入数据库,会对性能造成巨大影响。为了最小化对主要请求路径的性能影响,它采用了 异步队列和批量处理 的优化手段:

![](./images/requests-logs-flow.png)

这里有几个值得学习的点:

  1. 异步处理:日志记录不会阻塞主要的 API 响应路径
  2. 批量提交:多个日志记录会被聚合后批量写入数据库
  3. 内存缓冲:使用内存队列减少数据库 I/O 频次
  4. 事务安全:通过数据库事务确保数据一致性

高级配置选项

除了 store_prompts_in_spend_logs 选项之外,LiteLLM 还提供了很多其他的配置选项来控制日志行为:

general_settings:
  # 完全禁用错误日志
  disable_error_logs: true

  # 完全禁用支出日志
  disable_spend_logs: true

  # 存储详细的请求/响应内容
  store_prompts_in_spend_logs: true

  # 配置日志保留期
  maximum_spend_logs_retention_period: "30d"  # 30天后自动删除
  maximum_spend_logs_retention_interval: "1d"  # 每天执行一次清理

其中日志的自动删除功能属于企业特性。此外,在多实例部署环境中,LiteLLM 使用 Redis 分布式锁 确保清理任务不会重复执行,因此需要开启 Redis 缓存。

会话日志

会话日志(Session Logs) 在请求日志的基础上,提供了 会话级别的聚合视图,它通过 session_id 将相关的请求进行逻辑分组,让你能够跟踪用户的完整交互流程。

可以在发起请求时增加一个 litellm_session_id 参数:

response = client.chat.completions.create(
  model="gpt-4o",
  messages=[
    {"role": "user", "content": "你好,我是张三"}
  ],
  extra_body={
    "litellm_session_id": session_id
  }
)
print(response.choices[0].message.content)

然后将后续请求也关联到这个会话:

response = client.chat.completions.create(
  model="gpt-4o",
  messages=[
    {"role": "user", "content": "你好,我是张三"},
    {"role": "assistant", "content": response.choices[0].message.content},
    {"role": "user", "content": "我是谁"}
  ],
  extra_body={
    "litellm_session_id": session_id
  }
)
print(response.choices[0].message.content)

在 LiteLLM 的 UI 中,可以看到生成的两条请求日志 Session ID 是相同的:

session-logs.png

你可以通过 Session ID 筛选出该会话下的所有交互记录,这对于复现 Bug 或分析用户行为模式非常有帮助:

session-logs-details.png

使用 Responses API

使用 Chat Completions API 进行多轮对话时,每一次都要带上完整的上下文,这是非常不方便的。可以考虑使用 OpenAI 的 Responses API 接口,LiteLLM 也对该接口做了兼容。

第一次请求如下:

response = client.responses.create(
  model="gpt-4o",
  input="你好,我是张三"
)
print(response.output_text)

第二次请求时通过 previous_response_id 参数带上前一次请求的响应 ID 即可:

response = client.responses.create(
    model="gpt-4o",
    input="我是谁",
    previous_response_id=response.id
)
print(response.output_text)

LiteLLM 内部对 Chat Completions API 接口做了一层封装,使得我们也可以通过 Responses API 调用 Anthropic、Gemini 等模型。不过需要注意的是,它是根据会话 ID 查询数据库获取历史对话,因此需要开启 store_prompts_in_spend_logs: true 保存请求和响应的日志。

另一点需要注意的是,由于日志存储是异步的,因此第二次请求不能太快,太快的话可能还查不到历史对话,两次请求中间要等待个 10 秒左右。这个特性目前还是 beta 状态,后面应该会优化。

审核日志

审核日志(Audit Logs) 则专注于记录所有的管理操作,包括用户创建、权限变更、配置修改等。这类日志对于企业的合规要求、安全审计和问题追踪具有关键作用。

审核日志是企业级特性,需要显式启用:

litellm_settings:
  store_audit_logs: true

然后我们通过 /key/generate 接口生成一个 Key:

$ curl 'http://127.0.0.1:4000/key/generate' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "models": ["gpt-4o"],
    "metadata": {"user": "audit-test@example.com"}
  }'

进入 Admin UI,点击 Logs 菜单,查看审核日志如下:

audit-logs.png

LiteLLM 会自动为以下管理操作创建审核日志:

用户管理:
- ✅ 用户创建、更新、删除
- ✅ 用户权限变更
- ✅ 用户状态变更(激活/禁用)

API 密钥管理:
- ✅ 密钥创建、更新、删除
- ✅ 密钥轮换(regenerate)
- ✅ 密钥权限修改

团队管理:
- ✅ 团队创建、更新、删除
- ✅ 团队成员添加/移除
- ✅ 团队预算调整

模型配置:
- ✅ 模型添加、更新、删除
- ✅ 模型权限配置变更

小结

今天的内容比较简单,主要学习了 LiteLLM 的三大日志系统:

  • 请求日志(Spend Logs) 精确记录每一次 API 调用的详细信息,可以通过 store_prompts_in_spend_logs 参数开启存储具体的请求和响应内容;
  • 会话日志(Session Logs) 在请求日志基础上提供了会话级别的聚合视图,通过 Session ID 分组,支持跨多个请求的用户行为追踪和对话模式分析;
  • 审核日志(Audit Logs) 专注于管理操作的完整记录,确保每一个关键操作都有迹可循;

这套完整的日志系统,作为 LiteLLM 的核心能力,直接存储在 Postgre 数据库中。其实,LiteLLM 还支持对接很多外部日志系统或可观测平台,并基于这些丰富的日志数据构建完善的监控体系,我们将在下一篇文章中继续学习。


学习 LiteLLM 的缓存系统

随着我们的 LLM 网关承载的流量越来越大、接入的模型越来越多,除了稳定性和可靠性,成本和性能 也成为了关键的考量因素。实际上,我们的应用每天都在处理很多相似的查询,比如客服系统中的常见问题、代码生成中的重复模式、文档摘要中的相似内容。如果每次都调用真实的 LLM API,不仅延迟高、成本昂贵,还可能触发供应商的速率限制。而且,对于相同或相似的查询,LLM 的回答往往是一致的或高度相似的,这就为缓存的应用提供了天然的基础。

LiteLLM 提供了一套完整的缓存解决方案,它不仅能够缓存完全相同的请求(精确缓存),还能够基于语义相似性缓存相似的请求(语义缓存),从而显著降低成本,并大幅提升性能,同时减轻对上游 API 的压力,提高了系统稳定性。

今天这篇文章,我们就来深入了解一下 LiteLLM 的缓存系统。

缓存类型一览

LiteLLM 支持 8 种不同的缓存后端,每种都针对特定的使用场景:

传统缓存

  • 内存缓存(In-Memory):最快的访问速度,适合单机部署和开发测试
  • 磁盘缓存(Disk):持久化存储,适合单机长期缓存
  • Redis 缓存:分布式缓存,适合多实例部署和生产环境

云存储缓存

  • S3 缓存:利用 AWS S3 进行大规模、低成本的缓存存储
  • GCS 缓存:基于 Google Cloud Storage 的缓存解决方案
  • Azure Blob 缓存:微软 Azure 的对象存储缓存

智能缓存

  • Redis 语义缓存:基于向量相似度的语义匹配缓存
  • Qdrant 语义缓存:专业向量数据库的语义缓存解决方案

基本使用

首先我们来体验下最简单的内存缓存,在 config.yaml 文件中添加如下配置:

litellm_settings:
  cache: true
  cache_params:
    type: local

然后重启 LiteLLM Proxy 服务。发送第一次请求:

$ curl -X POST 'http://127.0.0.1:4000/chat/completions' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "gpt-4o",
    "messages": [{"role": "user", "content": "给我讲个笑话"}]
  }'

第一次请求会调用真实的 API,耗时可能在 1-3 秒。再发送完全相同的请求(加了 -v 选项用于打印响应头):

$ curl -v -X POST 'http://127.0.0.1:4000/chat/completions' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "gpt-4o",
    "messages": [{"role": "user", "content": "给我讲个笑话"}]
  }'

第二次请求从缓存返回,耗时通常在 50-200 毫秒,响应头中会包含缓存相关信息:

x-litellm-cache-key: 6b86d8cb3ab300d7cbe071f93176e28cc25d9da7f2db95dd8ad078176faddc94

这个 Key 是根据请求内容生成的,相同的请求参数生成的 Key 也是相同的。

Redis 缓存

内存缓存适合单机部署和开发测试,生产环境一般使用 Redis 作为缓存后端。可以用 Docker 在本地快速启一个 Redis 示例:

$ docker run -d \
  --name redis-stack \
  -p 6379:6379 \
  -p 8001:8001 \
  redis/redis-stack:latest

注意我这里使用的是 Redis Stack 镜像,它是一个包含多个模块的集成软件套件,在 Redis 的基础上,扩展了 搜索(RedisSearch)JSON(RedisJSON)图数据库(RedisGraph)时间序列(RedisTimeSeries)布隆过滤器(RedisBloom) 等功能,提供了更丰富的数据处理能力,适用于构建复杂应用。相对于 Redis Server 只是核心的内存数据结构存储,更侧重于缓存和消息队列等场景。

最简单的 Redis 缓存配置如下:

litellm_settings:
  cache: true
  cache_params:
    type: redis
    host: localhost          # Redis 服务器地址
    port: 6379               # Redis 端口
    password: your_password  # Redis 密码(可选)
    ttl: 600                 # 默认缓存时间(秒)

对于大规模部署,LiteLLM 支持配置 Redis 集群或哨兵。

验证方法和内存缓存一样,第二次请求从缓存返回,并且在 Redis 中应该能找到 x-litellm-cache-key 对应的缓存键:

redis-key.png

Redis 语义缓存

Redis 不仅可以用来做普通缓存,还可以用来做向量数据库。我们可以将文本、图像等非结构化数据转换为向量,存储到 Redis 中,并利用 Redis 的内存优势实现毫秒级的向量相似性搜索。

LiteLLM 基于 Redis 向量数据库实现了语义缓存功能,语义缓存 不同于传统的精确匹配缓存,它能够理解查询的语义含义,并返回语义相似查询的缓存结果。即使这些查询的字面表达完全不同,语义缓存也能识别它们的相似性并返回相同的结果,大大提高了缓存命中率。

Redis 语义缓存基于 Redis Vector Library (RedisVL) 实现,首先需要安装依赖:

$ pip install redisvl==0.4.1

然后在 LiteLLM 的配置文件中开启 Redis 语义缓存:

litellm_settings:
  cache: true
  cache_params:
    type: redis-semantic              # 语义缓存类型
    host: localhost
    port: 6379
    password: your_password
    ttl: 600
    similarity_threshold: 0.8                                     # 相似度阈值(0-1,1为完全匹配)
    redis_semantic_cache_embedding_model: text-embedding-3-large  # 嵌入模型名称

其中 similarity_threshold 为相似度阈值,范围 [0-1]redis_semantic_cache_embedding_model 为嵌入模型名称,必须是在 model_list 中定义。

注意,如果你的 Redis 没有密码,启动可能会报错 Missing required Redis configuration: REDIS_PASSWORD。设置一下环境变量 export REDIS_PASSWORD= 即可。

可以使用两个相似的请求来验证,第一次请求:

$ curl -X POST 'http://127.0.0.1:4000/chat/completions' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "gpt-4o",
    "messages": [{"role": "user", "content": "什么是人工智能?"}]
  }'

第二次请求:

$ curl -v -X POST 'http://127.0.0.1:4000/chat/completions' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "gpt-4o",
    "messages": [{"role": "user", "content": "AI 是什么?"}]
  }'

第二次请求的响应头中不仅包含了缓存 Key,还包含了相似度信息:

x-litellm-cache-key: 9cdf6246deaee1f8d96aa8b093029bc129f7eca32f2f8f4a9fd0352138e6ea3e
x-litellm-semantic-similarity: 0.162912428379

我们打开 Redis 管理页面,可以发现多了一个 litellm_semantic_cache_index 开头的键:

redis-sematic-key.png

它的内容包含了请求的 Prompt 和对应的响应:

redis-sematic-value.png

RedisVL 库介绍

RedisVL (Redis Vector Library) 是 Redis 官方提供的 Python 客户端库,专为 AI 应用设计,提供了高级的向量搜索抽象,主要特性包括:

  • 简化的 API:高级抽象,简化向量搜索操作
  • 强大的查询能力:支持混合查询、过滤条件、聚合等
  • 语义缓存:专门为 LLM 缓存优化的 LLMCache 组件,LiteLLM 的 Redis 语义缓存就是基于它实现的

这一节我们通过一个简单示例学习它的基本使用。

首先通过 Schema 创建索引:

from redisvl.index import SearchIndex
from redis import Redis

# 创建连接
client = Redis.from_url("redis://localhost:6379")

# 使用字典定义 Schema
schema = {
  "index": {
    "name": "product_index",
    "prefix": "product:",
  },
  "fields": [
    {"name": "title", "type": "text"},
    {"name": "brand", "type": "tag"},
    {"name": "price", "type": "numeric"},
    {"name": "category", "type": "tag"},
    {
      "name": "description_vector",
      "type": "vector",
      "attrs": {
        "dims": 3072,  # 向量维度
        "distance_metric": "cosine",  # 距离度量
        "algorithm": "flat",  # 向量索引算法
        "datatype": "float32"
      }
    }
  ]
}

# 创建索引
index = SearchIndex.from_dict(schema, redis_client=client)
index.create(overwrite=True)
print(f"索引创建成功!")

这是一个产品表,包含产品的名称、品牌、分类、价格、描述等信息,我们为描述加一个向量字段,用于语义搜索。

其中向量维度根据你使用的 Embedding 模型来定义,我这里使用的是 OpenAI 的 text-embedding-3-large 模型,维度是 3072 维。

接着定义一批示例数据,加载到 Redis 中:

import numpy as np
from litellm import embedding

# 定义产品数据
products = [
  {
    "id": "p001",
    "title": "iPhone 15 Pro Max",
    "brand": "Apple",
    "category": "smartphone",
    "price": 1199,
    "description": "最新的 iPhone,配备 A17 Pro 芯片,48MP 主摄像头,钛金属机身"
  },
  {
    "id": "p002",
    "title": "MacBook Pro 14英寸",
    "brand": "Apple",
    "category": "laptop",
    "price": 1999,
    "description": "搭载 M3 芯片的专业笔记本电脑,适合开发者和创意工作者"
  },
  {
    "id": "p003",
    "title": "AirPods Pro",
    "brand": "Apple",
    "category": "audio",
    "price": 249,
    "description": "主动降噪无线耳机,空间音频技术,透明模式"
  },
  {
    "id": "p004",
    "title": "Samsung Galaxy S24",
    "brand": "Samsung",
    "category": "smartphone",
    "price": 899,
    "description": "Android 旗舰手机,AI 摄影功能,120Hz 显示屏"
  },
  {
    "id": "p005",
    "title": "Dell XPS 13",
    "brand": "Dell",
    "category": "laptop",
    "price": 1299,
    "description": "轻薄笔记本电脑,13.3英寸 4K 触摸屏,Intel 处理器"
  }
]

# 生成向量嵌入
for product in products:
  response = embedding('text-embedding-3-large', product["description"])
  product["description_vector"] = np.array(response.data[0]['embedding'], dtype=np.float32).tobytes()

# 加载产品数据到 Redis
for product in products:
  index.load([product], id_field="id")

print(f"成功加载 {len(products)} 个产品到索引中")

我们为每个产品的描述生成对应的向量,并通过 index.load() 将产品数据加载到 Redis 中。接下来就可以执行搜索了:

from redisvl.index import SearchIndex
from redisvl.query import VectorQuery

# 使用已有索引
index = SearchIndex.from_existing('product_index', client)

# 生成查询向量
response = embedding('text-embedding-3-large', "适合程序员的电脑")
query_vector = np.array(response.data[0]['embedding'], dtype=np.float32).tobytes()

# 创建向量查询
vector_query = VectorQuery(
  vector=query_vector,
  vector_field_name="description_vector",
  return_fields=["title", "brand", "category", "price", "description"],
  num_results=3,
)

# 执行搜索
results = index.query(vector_query)

print(f"\n查询: '适合程序员的电脑'")
for doc in results:
  score = 1 - float(doc['vector_distance'])  # 转换为相似度分数
  print(f"- {doc['title']} ({doc['brand']}) - 相似度: {score:.3f}")
  print(f"  价格: ${doc['price']} | 描述: {doc['description']}")

搜索结果如下:

查询: '适合程序员的电脑'
- MacBook Pro 14英寸 (Apple) - 相似度: 0.570
  价格: $1999 | 描述: 搭载 M3 芯片的专业笔记本电脑,适合开发者和创意工作者
- Dell XPS 13 (Dell) - 相似度: 0.435
  价格: $1299 | 描述: 轻薄笔记本电脑,13.3英寸 4K 触摸屏,Intel 处理器
- iPhone 15 Pro Max (Apple) - 相似度: 0.293
  价格: $1199 | 描述: 最新的 iPhone,配备 A17 Pro 芯片,48MP 主摄像头,钛金属机身

缓存控制参数

LiteLLM 提供了灵活的缓存控制机制,允许在请求级别动态控制缓存行为。这些控制参数借鉴了 HTTP 缓存控制的设计理念,提供了细粒度的缓存管理能力。

参数类型说明使用场景
ttlint指定缓存时间(秒)短期缓存、时效性内容
s-maxageint只接受指定时间内的缓存(秒)强制刷新、数据一致性
no-cachebool跳过缓存读取,强制调用 API需要最新数据
no-storebool不存储响应到缓存敏感内容、一次性查询
namespacestr自定义缓存命名空间多租户、环境隔离

动态 TTL 控制

参数 ttl 用于控制缓存时间,我们可以为不同类型的请求设置不同的缓存时间:

# 长期缓存:百科类知识
response = client.chat.completions.create(
  model="gpt-4o",
  messages=[{"role": "user", "content": "什么是量子计算?"}],
  extra_body={
    "cache": {
      "ttl": 86400  # 缓存 24 小时
    }
  }
)

# 短期缓存:实时性要求较高的内容
response = client.chat.completions.create(
  model="gpt-4o",
  messages=[{"role": "user", "content": "今天的股市表现如何?"}],
  extra_body={
    "cache": {
      "ttl": 300  # 缓存 5 分钟
    }
  }
)

缓存年龄控制

参数 s-maxage 控制只接受指定年龄内的缓存:

response = client.chat.completions.create(
  model="gpt-4o",
  messages=[{"role": "user", "content": "最新的股票价格"}],
  extra_body={
    "cache": {
      "s-maxage": 60  # 只接受 1 分钟内的缓存
    }
  }
)

强制刷新缓存

当需要获取最新结果时,可以使用 no-cache 强制绕过缓存:

response = client.chat.completions.create(
  model="gpt-4o",
  messages=[{"role": "user", "content": "最新的股票价格"}],
  extra_body={
    "cache": {
      "no-cache": True  # 跳过缓存检查
    }
  }
)

禁用缓存存储

对于包含敏感信息的查询,可以使用 no-store 不缓存当前响应:

response = client.chat.completions.create(
  model="gpt-4o",
  messages=[{"role": "user", "content": "敏感信息查询"}],
  extra_body={
    "cache": {
      "no-store": True  # 不存储此响应
    }
  }
)

命名空间隔离

在多租户或多环境场景中,LiteLLM 支持命名空间来实现缓存隔离:

litellm_settings:
  cache: true
  cache_params:
    type: redis
    namespace: "litellm.production"  # 命名空间前缀

这样存储在 Redis 中的键将变成 {namespace}:<hash> 格式,我们也可以在请求参数中动态控制,为不同的用户或应用使用独立的缓存空间:

response = client.chat.completions.create(
  model="gpt-4o",
  messages=[{"role": "user", "content": "Hello"}],
  extra_body={
    "cache": {
      "namespace": "user:12345"  # 用户专用命名空间
    }
  }
)

默认关闭模式

对于需要严格控制的场景,可以将缓存设置为默认关闭,只在需要时显式启用:

litellm_settings:
  cache: true
  cache_params:
    mode: default_off  # 缓存默认关闭

客户端需要显式启用缓存:

response = client.chat.completions.create(
  model="gpt-4o",
  messages=[{"role": "user", "content": "Hello"}],
  extra_body={
    "cache": {"use-cache": True}  # 显式启用缓存
  }
)

小结

我们今天简单学习了 LiteLLM 的缓存系统。LiteLLM 提供了从简单的内存缓存到复杂的语义缓存等多种选择,每种缓存都有其特定的适用场景,可以根据业务需求灵活选择最合适的缓存策略。此外,LiteLLM 的缓存控制参数提供了细粒度的缓存管理能力,使开发者能够动态调整缓存行为,以适应不同场景的需求。

通过合理配置和使用这些缓存功能,应用可以更好地处理重复性和相似性的查询,有效降低对上游 LLM API 的压力,提升系统的稳定性与响应速度。


学习 LiteLLM 的路由和回退策略

在之前的系列文章中,我们学习了 LiteLLM 的基础使用,包括模型管理、用户管理、权限认证和访问控制机制等。当我们的 LLM 网关要承载越来越多的流量、接入越来越多的模型供应商时,就会面临新的挑战:某个模型供应商的 API 突然出现故障、请求量激增导致速率限制、某些模型的响应时间过长、成本控制需要在多个供应商之间进行优化选择等等。这些问题如果处理不当,会严重影响用户体验,甚至导致业务中断。

为此 LiteLLM 提供了一套完整的智能路由和容错解决方案,它通过智能的负载均衡、自动容错和多层次的回退策略,确保在复杂的多模型环境中提供稳定可靠的服务。今天这篇文章,我们就来深入学习 LiteLLM 的路由和回退策略,了解它是如何帮助我们构建一个高可用、高性能、低成本的 LLM 网关。

负载均衡

让我们从最简单的场景开始:假设你有一个 gpt-4o 模型,但是在不同的地区部署了多个实例(可能是 Azure 的不同区域,也可能是不同的云厂商),如何在这些实例之间分配请求?

LiteLLM 的路由配置非常简洁,只需要在 model_list 中将多个 model_name 配置成相同的名字即可:

model_list:
  - model_name: gpt-4o
    litellm_params:
      model: azure/gpt-4o
      api_base: https://my-endpoint-us.openai.azure.com/
      api_key: os.environ/AZURE_API_KEY
  - model_name: gpt-4o
    litellm_params:
      model: azure/gpt-4o
      api_base: https://my-endpoint-eu.openai.azure.com/
      api_key: os.environ/AZURE_API_KEY
      api_version: os.environ/AZURE_API_VERSION
  - model_name: gpt-4o
    litellm_params:
      model: gpt-4o
      api_key: os.environ/OPENAI_API_KEY

在这个配置中,三个不同的部署都映射到同一个模型名称 gpt-4o,它们被称为 模型组(Model Group),当用户请求 model="gpt-4o" 时,LiteLLM 会自动在模型组中的部署之间分配请求。

路由策略

LiteLLM 提供了多种不同的路由策略,每种策略针对不同的使用场景:

  • 简单随机策略(simple-shuffle:这是默认的路由策略,采用随机选择算法,确保请求在所有可用部署间均匀分布;其优点是实现简单,负载均匀,适用于大多数通用场景;
  • 最少忙碌策略(least-busy:开启该策略后,LiteLLM 会实时监控每个部署的活跃请求数,优先选择当前活跃请求数最少的部署;其优点是动态负载均衡,避免热点,适用于高并发场景;
  • 延迟优化策略(latency-based-routing:基于历史延迟数据,优先选择响应时间最短的部署,开启后 LiteLLM 会维护每个部署的延迟历史,并使用滑动窗口计算平均值;这种策略能优化用户体验,减少等待时间,适用于对延迟敏感的交互式应用;
  • 成本优化策略(cost-based-routing:基于模型定价信息,优先选择成本最低的部署;它的优点是控制成本,优化预算使用,适用于成本敏感的批量处理场景;
  • 使用率均衡策略(usage-based-routing:也被称为 Rate Limit Aware 策略,基于 RPM/TPM 使用率选择负载最低的部署,确保各部署的负载均衡;这种策略充分利用所有部署的配额,适用于需要精确控制流量分配的场景;不过这种策略会对性能产生影响,因为它要频繁操作 Redis 来跟踪不同部署的使用情况,从而导致延迟显著增加,不建议用于生产环境;

关于使用率策略还有一个 v2 版本(usage-based-routing-v2),它将所有 Redis 操作改为异步,有一定的性能提升。

简单随机策略

在高流量场景中,为了获得最佳性能,官方建议使用简单随机(simple-shuffle)策略,这也是 LiteLLM 的默认路由策略,它随机选择部署,性能开销最小。在 LiteLLM Proxy 中配置路由策略如下:

router_settings:
  routing_strategy: "simple-shuffle"

或者在 SDK 中通过 Router 使用:

router = Router(
  model_list=model_list,
  routing_strategy="simple-shuffle"
)

此外,简单随机策略根据配置,又分为 基于 RPM 随机(RPM-based shuffling)基于权重随机(Weight-based shuffling) 两种。下面是基于权重随机的示例:

model_list:
  - model_name: gpt-4o
    litellm_params:
      model: azure/gpt-4o
      api_base: https://my-endpoint-us.openai.azure.com/
      api_key: os.environ/AZURE_API_KEY
      weight: 9  # 90% 的概率被选中
  - model_name: gpt-4o
    litellm_params:
      model: azure/gpt-4o
      api_base: https://my-endpoint-eu.openai.azure.com/
      api_key: os.environ/AZURE_API_KEY
      api_version: os.environ/AZURE_API_VERSION
      weight: 1  # 10% 的概率被选中

跨实例的负载均衡

在生产环境中,LiteLLM Proxy 通常会部署多个实例。但多实例部署会带来一个问题:不同实例之间无法直接通信,它们无法协调已使用的 RPM/TPM。

例如,假设 OpenAI 限制我们每分钟 1000 个请求,而我们有 3 个 LiteLLM 实例:

实例 A:已用 400 个请求
实例 B:已用 300 个请求
实例 C:已用 300 个请求
总计:1000 个请求

如果没有跨实例的协调,每个实例可能还会继续发送请求,导致全局超过限制。

为了解决这个问题,LiteLLM 提供了 Redis 支持,可以将 RPM/TPM 数据存储在共享的 Redis 中:

router_settings:
  redis_host: redis.default.svc.cluster.local
  redis_port: 6379
  redis_db: 0

启用 Redis 后,所有实例都会定期同步它们的 RPM/TPM 数据到 Redis,从而实现全局的限流和负载均衡。

高级路由策略

除了基础的负载均衡,LiteLLM 还提供了多种智能化路由策略,能够根据内容、预算、标签等维度进行智能路由。

自动路由

自动路由(Auto Routing) 也被称为 语义路由 (Semantic Routing),能够根据请求内容自动选择最适合的模型。比如,你可以配置:

  • 编程相关的请求路由到代码能力强的模型
  • 创意写作请求路由到创意能力强的模型
  • 普通对话请求路由到性价比高的模型

注意,开启自动路由需要额外安装 semantic-router 依赖。

首先,需要在 router.json 文件中定义路由规则:

{
  "encoder_type": "openai",
  "encoder_name": "text-embedding-3-large",
  "routes": [
    {
      "name": "gpt-4o",
      "utterances": [
        "写一首关于春天的诗"
      ],
      "description": "通用助手",
      "score_threshold": 0.5
    },
    {
      "name": "claude-sonnet-4",
      "utterances": [
        "使用 Python 语言实现冒泡排序算法"
      ],
      "description": "代码助手",
      "score_threshold": 0.5
    }
  ]
}

然后在模型列表中配置自动路由:

model_list:
  
  # 嵌入模型(用于计算内容相似度)
  - model_name: text-embedding-3-large
    litellm_params:
      model: text-embedding-3-large
      api_key: os.environ/OPENAI_API_KEY

  # 自动路由
  - model_name: auto_router
    litellm_params:
      model: auto_router/auto_router
      auto_router_config_path: router.json
      auto_router_default_model: gpt-4o
      auto_router_embedding_model: text-embedding-3-large

  # 目标路由
  - model_name: gpt-4o
    litellm_params:
      model: openai/gpt-4o
      api_key: os.environ/OPENAI_API_KEY
  - model_name: claude-sonnet-4
    litellm_params:
      model: anthropic/claude-sonnet-4-20250514
      api_key: os.environ/ANTHROPIC_API_KEY

然后使用下面的命令进行测试:

# 这条请求会被自动路由到 gpt-4o
$ curl -X POST 'http://127.0.0.1:4000/chat/completions' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "auto_router",
    "messages": [{"role": "user", "content": "写一首关于春天的诗"}]
  }'
# 这条请求会被自动路由到 claude-sonnet-4
$ curl -X POST 'http://127.0.0.1:4000/chat/completions' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "auto_router",
    "messages": [{"role": "user", "content": "使用 Python 语言实现冒泡排序算法"}]
  }'

自动路由也可以在 Admin UI 中添加:

add-auto-router.png

自动路由的工作原理很简单:

  1. 内容嵌入:使用配置的嵌入模型将用户请求转换为向量;
  2. 相似度计算:计算请求向量与每条规则的 utterances 向量的相似度;
  3. 阈值判断:如果最高相似度超过 score_threshold,则选择对应模型;
  4. 默认回退:如果没有规则匹配,使用 auto_router_default_model 默认模型;

标签路由

标签路由(Tag Routing) 允许基于请求的标签来选择不同的模型部署,这在多租户场景下特别有用。比如:

  • 多租户隔离:不同租户使用不同的模型实例
  • 服务分级:免费用户使用廉价服务,付费用户使用真实服务
  • 团队隔离:不同团队使用不同的部署实例

它的配置也很简单:

model_list:
  - model_name: gpt-4o
    litellm_params:
      model: openai/gpt-4o-mini
      api_key: os.environ/OPENAI_API_KEY
      tags: ["free"]          # 免费用户使用
  - model_name: gpt-4o
    litellm_params:
      model: openai/gpt-4o
      api_key: os.environ/OPENAI_API_KEY
      tags: ["paid"]          # 付费用户使用
  - model_name: gpt-4o
    litellm_params:
      model: openai/gpt-4o-mini
      api_key: os.environ/OPENAI_API_KEY
      tags: ["default"]       # 默认路由

router_settings:
  enable_tag_filtering: true  # 开启标签路由

注意通过 enable_tag_filtering 配置开启标签路由功能,在这个例子中,我们定义了 gpt-4o 这个模型,当免费用户(带 free 标签)请求时将路由到 gpt-4o-mini 模型,只有付费用户(带 paid 标签)请求时才会路由到真正的 gpt-4o 模型。

客户端调用方式如下:

# 免费用户请求
$ curl -X POST 'http://127.0.0.1:4000/chat/completions' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "gpt-4o",
    "messages": [{"role": "user", "content": "Hello"}],
    "tags": ["free"]
  }'

请求入参中的 tags 也可以放在 metadata 中。

# 付费用户请求
$ curl -X POST 'http://127.0.0.1:4000/chat/completions' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "gpt-4o",
    "messages": [{"role": "user", "content": "Hello"}],
    "tags": ["paid"]
  }'

我们也可以在 Admin UI 中添加标签并关联对应的模型:

create-new-tag.png

预算路由

在企业环境中,成本控制是一个关键考虑因素。LiteLLM 支持按 供应商模型标签 三个维度设置预算限制,实现自动的成本控制。

供应商预算(Provider Budget)

为不同的 LLM 供应商设置日预算或月预算:

router_settings:
  provider_budget_config:
    openai:
      budget_limit: 100.0    # $100/day
      time_period: "1d"
    azure:
      budget_limit: 500.0    # $500/month
      time_period: "30d"
    anthropic:
      budget_limit: 200.0    # $200/10days
      time_period: "10d"

当某个供应商的预算用完后,LiteLLM 会自动将请求路由到其他预算充足的供应商。

模型预算(Model Budget)

为特定模型设置预算:

model_list:
  - model_name: gpt-4o
    litellm_params:
      model: openai/gpt-4o
      api_key: os.environ/OPENAI_API_KEY
      max_budget: 10.0         # $10/day
      budget_duration: "1d"
  - model_name: gpt-4o-mini
    litellm_params:
      model: openai/gpt-4o-mini
      api_key: os.environ/OPENAI_API_KEY
      max_budget: 100.0        # $100/month
      budget_duration: "30d"

标签预算(Tag Budget)

为特定的业务标签设置预算(企业特性):

litellm_settings:
  tag_budget_config:
    product:chat-bot:         # 客服机器人标签
      max_budget: 50.0        # $50/day
      budget_duration: "1d"
    product:internal-tool:    # 内部工具标签
      max_budget: 200.0       # $200/day
      budget_duration: "1d"

重试策略

在生产环境中,我们还需要考虑各种故障场景,LiteLLM 提供了一套完整的可靠性保障机制,包括 重试策略(Retry Policy)回退策略(Fallbacks)

当请求失败时,LiteLLM 会自动重试,可以通过下面的参数修改重试次数和重试间隔:

router_settings:
  num_retries: 2    # 全局重试次数
  retry_after: 5    # 最小重试间隔(秒)

LiteLLM 还可以针对不同类型的错误来重试:

router_settings:
  num_retries: 2    # 全局重试次数
  retry_after: 5    # 最小重试间隔(秒)
  retry_policy:
    "RateLimitErrorRetries": 3        # 速率限制错误重试3次
    "ContentPolicyViolationErrorRetries": 2  # 内容政策违规重试2次
    "TimeoutErrorRetries": 2          # 超时错误重试2次
    "BadRequestErrorRetries": 0       # 错误请求不重试
    "AuthenticationErrorRetries": 0   # 认证错误不重试

值得注意的是,针对速率限制错误,LiteLLM 使用 指数退避(Exponential Backoffs) 重试策略,每次重试的间隔时间会按照指数级增长,而非固定间隔。

回退策略

回退(Fallbacks) 是另一种可靠性保障机制,当重试仍然失败时,LiteLLM 会尝试回退到其他模型部署或模型组,它确保在部分模型不可用时系统能够优雅降级,而不是直接失败。

回退和重试的区别:重试是针对同一部署的多次尝试,通常用于应对临时性故障(网络抖动等),而回退尝试不同的部署,用于应对永久性故障(服务宕机等)。合理使用这两种机制,能够显著提高系统的可靠性。

LiteLLM 实现了三种不同的回退策略:

  1. 上下文窗口回退 (Context Window Fallbacks) - 当请求的 token 数量超过当前模型的上下文窗口限制时,自动切换到支持更大上下文的模型;
  2. 内容策略回退 (Content Policy Fallbacks) - 当请求因内容审核被拒绝时,自动切换到内容限制更宽松的模型;
  3. 通用故障回退 (General Fallbacks) - 处理网络错误、服务不可用、速率限制等各种故障情况;

回退的配置如下所示:

router_settings:
  context_window_fallbacks: [
    {"gpt-4o": ["gpt-4o-long"]}
  ]
  content_policy_fallbacks: [
    {"gpt-4o": ["gpt-4o-permissive"]}
  ]
  fallbacks: [
    {"gpt-4o": ["gpt-4o-mini", "gpt-3.5-turbo"]}
  ]

当某个部署频繁失败时,LiteLLM 会将其放入 冷却期(Cooldown),避免继续向故障部署发送请求:

router_settings:
  allowed_fails: 3  # 允许失败 3 次
  cooldown_time: 30 # 冷却 30 秒

冷却机制可以通过下面的参数关闭:

router_settings:
  disable_cooldowns: true # 关闭冷却机制

如果客户端不希望触发回退,可以在请求中传入 disable_fallbacks 参数:

$ curl -X POST 'http://127.0.0.1:4000/chat/completions' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "gpt-4o",
    "messages": [{"role": "user", "content": "Hello"}],
    "disable_fallbacks": true
  }'

小结

到这里,我们已经完整梳理了 LiteLLM 的路由与回退策略的核心逻辑,这些能力正是构建高可用 LLM 网关的基石,能帮我们从容应对多模型场景下的流量分配、成本控制与故障容错挑战。

最后我们再对今天学习的内容总结一下:

  • 负载均衡与路由策略:LiteLLM 提供了多种路由策略来应对不同场景需求。在高并发场景下,推荐使用默认的简单随机策略获得最佳性能;在需要精细控制的场景下,可以选择延迟优化、成本优化或使用率均衡策略。
  • 智能化路由功能:除了基础的负载均衡,LiteLLM 还提供了自动路由、标签路由和预算路由等高级功能。自动路由能根据请求内容语义自动选择最适合的模型;标签路由支持多租户隔离和服务分级;预算路由则从供应商、模型、标签三个维度实现精确的成本控制。
  • 可靠性保障机制:通过重试策略和回退策略的组合,LiteLLM 构建了完整的容错体系。重试策略针对临时性故障提供自动恢复能力,支持按错误类型定制重试逻辑;回退策略则处理永久性故障,包括上下文窗口限制、内容策略违规和通用故障等多种场景。

这些能力并非孤立存在,而是可以根据实际业务场景灵活组合,最终帮我们搭建出稳定、高效且成本可控的 LLM 网关,为上层业务提供可靠的模型服务支撑。


学习 LiteLLM 的访问控制

在前两篇文章中,我们深入探讨了 LiteLLM 的认证机制和用户管理体系,认证机制解决了 你是谁 的问题,用户管理则从组织、团队到用户的多层架构,以及基于角色的访问控制(RBAC)模型解决的是 你能做什么 的问题。

而今天我们要学习的访问控制机制则是用户管理的延续,从更细的粒度控制用户的行为,没有适当的访问控制,你的 LLM 网关可能会面临很多风险,比如:用户访问了不应该访问的模型,导致成本失控;恶意用户滥用 API,造成拒绝服务攻击;缺乏配额管理,导致某些用户耗尽所有资源。

LiteLLM 提供了一套完整的访问控制机制:

  1. 模型访问控制:控制用户可以使用哪些模型
  2. 接口访问控制:控制用户可以调用哪些 API 接口
  3. 配额管理:管理用户的请求频率、并发数、成本预算等资源使用限制

下面我们从最基础的模型访问控制开始,逐步深入学习。

模型访问控制

模型访问控制是 LiteLLM 访问控制的第一道防线,它决定了用户或团队是否可以使用特定的模型或模型组。

虚拟 Key 级别的模型限制

最简单的模型访问控制方式是为虚拟 Key 指定允许的模型列表。其实我们之前在创建虚拟 Key 时已经用过,通过 models 参数来限制它可以访问的模型:

$ curl -X POST 'http://127.0.0.1:4000/key/generate' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "models": ["gpt-4o"],
    "metadata": {"user": "zhangsan@example.com"}
  }'

生成的密钥只能调用 gpt-4o 这个模型,如果尝试调用其他模型,则会收到错误响应:

{
  "error": {
    "message": "key not allowed to access model. This key can only access models=['gpt-4o']. Tried to access deepseek",
    "type": "key_model_access_denied",
    "param": "model",
    "code": "401"
  }
}

团队级别的模型限制

我们还可以为团队指定允许的模型列表。首先创建一个团队,并为其指定允许的模型:

$ curl -X POST 'http://127.0.0.1:4000/team/new' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "team_alias": "demo_team",
    "models": ["gpt-4o"]
  }'

或者在 Admin UI 后台创建:

create-team.png

然后为该团队创建虚拟 Key:

$ curl -X POST 'http://127.0.0.1:4000/key/generate' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "team_id": "950db486-fa2c-46e7-bfbc-3ac39e15fad2"
  }'

此时,团队成员使用该密钥只能调用 gpt-4o 这个模型,当团队成员使用该密钥访问未授权模型时,LiteLLM 会返回错误信息:

{
  "error": {
    "message": "team not allowed to access model. This team can only access models=['gpt-4o']. Tried to access deepseek",
    "type": "team_model_access_denied",
    "param": "model",
    "code": "401"
  }
}

注意,如果使用团队级别的模型限制,调用 /key/generatemodels 参数是不生效的。

同样地,我们也可以针对组织或用户来限制模型的访问,做法基本类似,调用 /organization/new/user/new 时传入 models 参数即可,此处略过。

模型访问组

对于需要动态管理模型访问权限的场景,LiteLLM 提供了 模型访问组 的功能,允许将多个模型组织成一个逻辑组,便于批量分配权限。

首先,在配置文件中定义模型访问组:

model_list:
  - model_name: gpt-4o
    litellm_params:
      model: openai/gpt-4o
      api_key: os.environ/OPENAI_API_KEY
    model_info:
      access_groups: ["beta-models"]  # 👈 模型访问组

  - model_name: claude
    litellm_params:
      model: anthropic/claude-sonnet-4-20250514
      api_key: os.environ/ANTHROPIC_API_KEY
    model_info:
      access_groups: ["beta-models"]  # 👈 模型访问组

然后,创建虚拟 Key 时指定访问组:

$ curl -X POST 'http://localhost:4000/key/generate' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "models": ["beta-models"]
  }'

这个 Key 可以访问所有标记为 beta-models 的模型,如果后续添加了新的模型到这个组,也会自动授权。模型访问组的主要优势在于:

  • 动态管理:可以随时向访问组添加新模型,所有使用该组的用户自动获得访问权限
  • 批量操作:一次可以为多个用户分配相同的模型权限
  • 版本控制:可以创建不同的访问组用于不同环境(如 dev、staging、prod)

对于需要更灵活访问控制的场景,LiteLLM 还支持通配符模型。你可以使用模式匹配来控制对具有特定前缀或后缀的模型的访问:

model_list:
  - model_name: openai/*
    litellm_params:
      model: openai/*
      api_key: os.environ/OPENAI_API_KEY
    model_info:
      access_groups: ["default-models"]

  - model_name: openai/o1-*
    litellm_params:
      model: openai/o1-*
      api_key: os.environ/OPENAI_API_KEY
    model_info:
      access_groups: ["restricted-models"]

根据配置,default-models 访问组的用户可以访问 openai/gpt-4 但不能访问 openai/o1-mini

用户可以通过 /v1/models 接口查看自己有权访问的模型:

$ curl -X GET 'http://localhost:4000/v1/models' \
  -H 'Authorization: Bearer sk-3zO1MHhHFme9aGXfWCiMXg'

接口访问控制

除了限制用户能调用哪些模型,LiteLLM 还支持限制用户能调用哪些 API 接口。

基于角色的接口权限

在用户管理体系中,我们学习了基于角色的访问控制(RBAC),不同角色的用户自动拥有不同的接口权限:

  • 代理管理员(Proxy Admin) 拥有所有接口的访问权限,包括:

    • 用户管理接口:/user/*
    • 团队管理接口:/team/*
    • 密钥管理接口:/key/*
    • 组织管理接口:/organization/*
  • 内部用户(Internal User) 只能访问自己的密钥管理接口、自己的使用情况接口和 LLM 调用接口等
  • 团队成员(Team Member) 的接口权限由团队管理员精确控制,LiteLLM 支持对每个接口进行单独的权限配置。

限制可调用的接口

除此之外,在生成虚拟 Key 时我们还可以指定 allowed_routes 参数来限制用户能调用的接口:

$ curl -X POST 'http://127.0.0.1:4000/key/generate' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "models": ["gpt-4o"],
    "allowed_routes": ["/v1/chat/completions", "/v1/embeddings"]
  }'

这样,这个 Key 就只能调用 /v1/chat/completions/v1/embeddings 这两个接口,其他接口如获取模型列表、查询成本等都会被拒绝。

请求速率限制

LiteLLM 支持三种类型的速率限制:

  • RPM(Requests Per Minute):每分钟请求数限制
  • TPM(Tokens Per Minute):每分钟令牌数限制
  • Max Parallel Requests:最大并发请求数限制

我们可以在 config.yaml 文件中对指定模型进行全局限制:

model_list:
  - model_name: gpt-4o
    litellm_params:
      model: openai/gpt-4o
      api_key: os.environ/OPENAI_API_KEY
      rpm: 10
      tpm: 10000

或者在创建虚拟 Key 时加上这三个参数:

$ curl -X POST 'http://127.0.0.1:4000/key/generate' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "models": ["gpt-4o"],
    "rpm_limit": 3,
    "tpm_limit": 100,
    "max_parallel_requests": 1
  }'

通过上面这个命令生成的 Key 每分钟最多只能发送 3 个请求,最多只能消耗 100 个 Token,并且同时最多只能有 1 个并发请求。

值得注意的是,RPM 和 TPM 超过限制时,并不会报错,而是排队等待;只有并发数超过限制才会报 429 Too Many Requests 错误。

如果虚拟 Key 对应多个模型,也可以为每个模型单独设置速率限制:

$ curl -X POST 'http://127.0.0.1:4000/key/generate' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "models": ["gpt-4o", "gpt-3.5-turbo"],
    "model_rpm_limit": {
      "gpt-4o": 30,
      "gpt-3.5-turbo": 100
    },
    "model_tpm_limit": {
      "gpt-4o": 5000,
      "gpt-3.5-turbo": 10000
    }
  }'

没有 model_max_parallel_requests 参数,暂时无法为每个模型单独设置并发路数。

灵活的限制范围

和模型限制一样,LiteLLM 也支持在组织、团队或内部用户上配置速率限制。其中团队级别的速率限制可以是针对整个团队的,也可以是针对团队内单个成员的:

$ curl -X POST 'http://localhost:4000/team/new' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "team_alias": "demo_team",
    "rpm_limit": 100,    # 团队整体 RPM 限制
    "tpm_limit": 10000,  # 团队整体 TPM 限制
    "team_member_rpm_limit": 10,   # 单个成员 RPM 限制
    "team_member_tpm_limit": 1000  # 单个成员 TPM 限制
  }'

值得注意的是,要启用团队成员速率限制,启动 LiteLLM 之前必须要设置环境变量 EXPERIMENTAL_MULTI_INSTANCE_RATE_LIMITING=true,如果不这样做,团队成员的速率限制将不会生效。

当你部署多实例时,也需要设置这个环境变量。

另外,速率限制还可以配置在终端用户上。LiteLLM 的用户分为两种:内部用户(Internal User)终端用户(End User),内部用户是管理和使用 LiteLLM 平台的内部人员,终端用户是通过 LiteLLM 平台获得 LLM 服务的外部用户,也被称为 客户(Customer),他们没有自己的 API Key,在调用接口时通过 user 参数进行区分:

$ curl -X POST 'http://127.0.0.1:4000/chat/completions' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "user": "demo_customer",
    "model": "gpt-4o",
    "messages": [{"role": "user", "content": "你好"}]
  }'

要对终端用户进行限流,需要先创建一个配额:

$ curl -X POST 'http://127.0.0.1:4000/budget/new' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "budget_id" : "free-tier",
    "rpm_limit": 3
  }'

然后使用该配额创建一个终端用户:

# 也可以使用 /end_user/new 接口
$ curl -X POST 'http://127.0.0.1:4000/customer/new' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "user_id" : "demo_customer",
    "budget_id": "free-tier"
  }'

这样就限制了这个终端用户一分钟只能请求 3 次。

动态速率限制

在多个用户共享同一个模型部署的场景中,静态的速率限制可能导致资源分配不合理的情况。上文提到,速率限制可以配置在全局的配置文件中,假设我们给 A 模型限制了一分钟 60 次请求,如果某个用户突然疯狂发送请求,可能会导致其他用户的请求全部被限制。

为此,LiteLLM 提供了 动态速率限制 的功能,可以根据活跃密钥的数量动态分配 TPM/RPM 配额。

启用动态速率限制只需在配置文件中添加回调即可:

model_list:
  - model_name: gpt-4o
    litellm_params:
      model: openai/gpt-4o
      api_key: os.environ/OPENAI_API_KEY
      rpm: 10 # 全局 10 RPM

litellm_settings:
  callbacks: ["dynamic_rate_limiter_v3"]

它的工作原理是:

  1. 计算当前活跃密钥数量
  2. 将模型的 TPM/RPM 配额平均分配给所有活跃密钥
  3. 定期调整分配比例以适应请求模式的变化

因此,如果同时有 5 个 Key 在发送请求,每个 Key 都能得到 2 RPM 的配额(10/5)。如果只有 2 个 Key,每个能得到 5 RPM。这样就确保了资源的公平分配。

优先级预留

对于更复杂的场景,还可以为不同的优先级预留资源。比如,生产环境的应用应该获得 90% 的资源,而开发环境只有 10% 的资源:

litellm_settings:
  callbacks: ["dynamic_rate_limiter_v3"]
  priority_reservation:
    "prod": 0.9        # 生产环境:90%
    "dev": 0.1         # 开发环境:10%
  priority_reservation_settings:
    default_priority: 0  # 未指定优先级的:0%
    saturation_threshold: 0.5  # 模型使用率达到 50% 时启用严格模式(非严格模式下,使用率可以超出限制)

创建 Key 时指定优先级:

$ curl -X POST 'http://127.0.0.1:4000/key/generate' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "models": ["gpt-4o"],
    "metadata": {"priority": "prod"}
  }'

标记为 prod 的 Key 会优先获得资源,LiteLLM 会确保这个 Key 至少获得 90% 的使用率,而标记为 dev 的 Key 只能获得 10% 的使用率。

成本追踪

我们在学习 LiteLLM 的模型管理时曾经提到过,LiteLLM 维护了一个完整的模型成本映射表,每次调用都会自动计算成本。默认情况下,成本是根据 输入和输出的 Token 数 乘以 模型的单位价格 来计算的:

cost = (input_tokens × input_cost_per_token) + (output_tokens × output_cost_per_token)

如果默认的价格不符合你的情况,可以在 config.yaml 中覆盖默认价格:

model_list:
  - model_name: gpt-4o
    litellm_params:
      model: openai/gpt-4o
      api_key: os.environ/OPENAI_API_KEY
    model_info:
      input_cost_per_token: 0.00001  # 自定义价格
      output_cost_per_token: 0.00002

价格单位为 USD

或者在全局设置中配置供应商折扣:

cost_discount_config:
  openai: 0.1         # OpenAI 打 9 折
  anthropic: 0.15     # Anthropic 打 8.5 折
  vertex_ai: 0.2      # Vertex AI 打 8 折

折扣会在成本计算后自动应用,LiteLLM 会返回原始成本和折扣后的成本。

成本追踪数据存储在数据库中,你可以通过多种方式查询:

# 查询单个 Key 的成本
$ curl 'http://127.0.0.1:4000/key/info?key=sk-xyz' \
  -H 'Authorization: Bearer sk-1234'

# 查询用户的总消费
$ curl 'http://127.0.0.1:4000/user/info?user_id=user-123' \
  -H 'Authorization: Bearer sk-1234'

# 查询团队的消费
$ curl 'http://127.0.0.1:4000/team/info?team_id=team-xyz' \
  -H 'Authorization: Bearer sk-1234'

# 生成成本报告(企业版特性)
$ curl 'http://127.0.0.1:4000/global/spend/report?start_date=2025-11-01&end_date=2025-11-30&group_by=team' \
  -H 'Authorization: Bearer sk-1234'

LiteLLM 还支持与计费系统集成,比如可以自动将成本数据推送到 Lago 平台:

litellm_settings:
  callbacks: ["lago"]

预算限制

有了成本追踪,就能很容易实现预算限制了。LiteLLM 支持在多个层级设置预算限制,最直接的方式是在生成 Key 时设置 max_budget

$ curl -X POST 'http://127.0.0.1:4000/key/generate' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "models": ["gpt-4o"],
    "max_budget": 100.0
  }'

这个 Key 现在最多只能消耗 $100,一旦超过预算,后续的请求会被拒绝。

或者通过 soft_budget 参数设置软预算限制,超过这个值时发送警告但不阻止请求。

和请求速率限制类似,我们还可以为用户设置总预算,即使用户有多个 Key,这些 Key 的消费会统计到用户的总预算中;或者为团队设置总预算,团队下的所有成员使用的 Key 的消费都会累计到团队的总预算中;或者通过 model_max_budget 参数为不同模型设置不同预算;或者通过 /budget/new 创建配额,然后为终端用户设置总预算。

预算周期与自动重置

有时候我们希望用户的预算能够定期重置。比如免费用户每个月重置 $10 的额度,这就需要用到 budget_duration 参数:

$ curl -X POST 'http://127.0.0.1:4000/key/generate' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "models": ["gpt-4o"],
    "max_budget": 10.0,
    "budget_duration": "30d"
  }'

支持的时间周期包括:

  • "30s" - 30 秒
  • "30m" - 30 分钟
  • "1h" - 1 小时
  • "1d" - 1 天
  • "30d" - 30 天(一个月)

临时预算增加

有时候,用户由于突然的业务需求可能需要超出预算。对于这种场景,LiteLLM 支持临时预算增加功能:

curl -L -X POST 'http://localhost:4000/key/update' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "key": "sk-your-key",
    "temp_budget_increase": 100,
    "temp_budget_expiry": "2025-11-30"
  }'

临时预算增加也是一个企业特性,它有以下特点:

  • 固定过期时间,过期后自动失效
  • 不影响原有的预算配置
  • 支持多次临时增加
  • 只能加在 API Key 上,无法为用户、团队、组织增加临时预算

标签级别的预算

对于需要跨多个维度跟踪成本的企业场景,LiteLLM 还支持按照 标签(Tag) 来分配预算,这对于按照功能、项目、成本中心来追踪成本特别有用:

$ curl -X POST 'http://127.0.0.1:4000/tag/new' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "marketing-chatbot",
    "description": "Marketing team chatbot",
    "max_budget": 200.0,
    "budget_duration": "30d"
  }'

然后在请求时添加标签:

$ curl -X POST 'http://127.0.0.1:4000/chat/completions' \
  -H 'Authorization: Bearer sk-xyz' \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "gpt-4o",
    "messages": [{"role": "user", "content": "hello"}],
    "metadata": {
      "tags": ["marketing-chatbot", "campaign-2024"]
    }
  }'

小结

LiteLLM 的访问控制机制构成了一个多维度的安全防护体系,从三个核心维度确保平台的稳定运行和成本可控:

  • 访问范围控制:通过模型访问限制防止未授权模型使用,避免成本失控;模型访问组提供动态、批量化的权限管理能力;接口访问控制精确限制用户可调用的 API 端点;
  • 资源配额管理:通过 RPM、TPM、并发三种速率限制策略确保公平的资源分配;动态速率限制根据活跃用户数智能调整配额,避免资源浪费或抢占;优先级预留机制保障关键业务的资源需求;
  • 成本预算控制:实时成本追踪提供透明的费用可见性;多层级预算限制(Key/用户/团队/标签)满足不同场景需求;预算周期管理与临时预算增加提供灵活的额度控制;

这套完整的访问控制体系不仅保障了 LiteLLM 网关的安全性,更通过精细化的资源管理和成本控制,为企业级 AI 应用提供了可靠的治理框架。合理配置这些机制,可以在保证用户体验的同时,最大化资源利用效率并控制运营成本。


学习 LiteLLM 的用户管理体系

在上一篇文章中,我们学习了 LiteLLM 的认证机制,从基础的虚拟 Key 到企业级的 JWT/OIDC 认证,了解了如何确保 API 访问的安全性。然而,认证只是第一步,解决的是 你是谁 的问题;接下来我们需要解决的是 你能做什么 的问题,这就是 用户管理权限控制 要解决的问题。

核心概念

LiteLLM 的用户管理体系建立在四个核心概念上:

  1. 组织(Organization) 可以包含多个团队,是 LiteLLM 中最高层级的管理单位,每个组织相当于一个独立的租户;
  2. 团队(Team) 是组织内部的工作单位,可以包含多个内部用户;团队的设计非常灵活,你可以按部门划分,也可以按项目划分;
  3. 内部用户(Internal Users) 可以创建 API Key、进行 API 调用、查看使用情况等;一个用户可以拥有多个 API Key,并且可以属于多个团队;
  4. API Key 用于 LiteLLM API 的身份验证,我们在上一篇详细介绍过,它可以与团队相关联,或与用户相关联,或同时与两者相关联;

他们的关系如下:

user-heirarchy.png

三种密钥类型

正如上文所说,API Key 可以与团队或用户相关联,基于不同的组合,API Key 分为三种类型:

  1. 用户密钥(User-only Key):它关联到特定用户,跟随用户生命周期,用于个人预算和追踪,当删除用户时密钥自动失效;适用于个人用户开发测试;
  2. 团队密钥(Team Key / Service Account Key):它关联到特定团队,不绑定个人身份,团队内共享资源,用户离开团队不影响密钥有效性;适用于生产服务、CI/CD 流水线、共享服务账户等;
  3. 用户+团队密钥(User + Team Key):同时关联用户和团队,能定位个人在团队上下文中的身份,同时追踪个人+团队的使用情况,当删除用户时密钥失效;适用于团队成员在团队资源上的个人工作、个人问责制的团队项目等;

在 Admin UI 上创建密钥

当我们在 Admin UI 上为用户创建 API Key 时,可以按需选择不同的组合:

create-key-user-or-team.png

或者为团队创建 API Key,这个密钥也被称为 服务账户密钥

create-key-service-account.png

注意,团队密钥在使用时,区分不了用户,LiteLLM 提供了一个可选的配置参数:

general_settings:
  service_account_settings: 
    enforced_params: ["user"] # 强制要求所有请求包含 user 参数

要求所有通过服务账户的请求都必须包含 user 参数,以便进行用户级别的审计。

使用接口创建密钥

我们也可以直接使用接口来创建这三种密钥。创建仅用户密钥:

$ curl -X POST 'http://127.0.0.1:4000/key/generate' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "user_id": "zhangsan@example.com"
  }'

注意,这个 user_id 不必是系统已有用户,仅仅是一个标记而且。当然,你也可以先在平台上创建一个用户,然后将这里的 user_id 换成该用户的 ID。两者的区别在于创建的用户可以登录平台,查看或管理自己的 API Key 等。

创建团队服务账户密钥:

$ curl -X POST 'http://127.0.0.1:4000/key/service-account/generate' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "team_id": "<team_id>"
  }'

创建用户+团队密钥:

$ curl -X POST 'http://127.0.0.1:4000/key/generate' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "user_id": "zhangsan@example.com",
    "team_id": "<team_id>"
  }'

注意,这个 team_id 必须先在平台上创建团队获得。

基于角色的访问控制

了解了上面的层次结构之后,接下来学习 LiteLLM 的权限控制机制。LiteLLM 采用了 RBAC(基于角色的访问控制) 模型,这是业界最成熟的权限管理方式之一。RBAC 是一种将权限与角色关联,而不是与用户直接关联的访问控制方法。这种方式的优势在于:

  • 简化管理:不必为每个用户单独分配权限,只需为角色分配权限
  • 权限复用:多个用户可以共享同一个角色
  • 动态调整:调整角色权限即可影响所有相关用户

LiteLLM 定义了两类角色系统:全局代理角色(Global Proxy Roles)组织/团队特定角色(Organization/Team Specific Roles),理解这些角色是使用 LiteLLM 权限管理的基础。

全局代理角色

全局代理角色又分为 代理管理员(Proxy Admin)代理查看者(Proxy Admin Viewer)内部用户(Internal User)内部用户查看者(Internal User Viewer) 四种,这些角色在整个 LiteLLM 平台范围内生效,不受组织或团队边界限制。

代理管理员

这是最高权限角色,控制整个 LiteLLM 平台,只有运行 LiteLLM 实例的人才应该有这个角色:

✅ 创建和管理所有组织
✅ 创建和管理所有团队(跨所有组织)
✅ 创建和管理所有用户
✅ 为任何人创建/删除 API 密钥
✅ 查看整个平台的消费成本
✅ 更新团队预算、速率限制
✅ 管理团队成员

代理查看者

这是一个只读的管理员角色,可查看所有信息但不能修改,适合财务或审计人员:

可以做:
✅ 查看所有组织、团队和用户
✅ 查看整个平台的消费数据
✅ 查看所有 API 密钥信息
✅ 登录到管理面板

不能做:
❌ 创建或删除密钥
❌ 添加或删除用户
❌ 修改预算或速率限制

内部用户

这是一般用户角色,拥有基本的操作权限,如管理自己的密钥和查看自己的消费,适用于普通员工:

可以做:
✅ 创建和删除自己的 API 密钥(如果允许)
✅ 查看自己的消费成本
✅ 使用 API 密钥进行 LLM 调用

不能做:
❌ 添加新用户
❌ 查看其他用户的信息
❌ 创建或管理团队

内部用户查看者

⚠️ 注意:这个角色已经被新的组织/团队特定角色所取代。建议迁移到更灵活的 org_adminteam_admin 角色。

组织/团队特定角色

这些是 LiteLLM 企业版中的角色,提供了更细粒度的权限控制,主要分为 组织管理员(Org Admin)团队管理员(Team Admin) 以及 团队成员(User) 四种:

组织管理员

该角色拥有特定组织内的所有管理权限,适用于部门主管、组织负责人等:

可以做:
✅ 创建团队(在自己的组织内)
✅ 添加用户到团队(在自己的组织内)
✅ 查看组织的消费成本
✅ 为组织内的用户创建 API 密钥

不能做:
❌ 创建其他组织
❌ 修改组织预算和速率限制
❌ 添加全局代理级别的模型

团队管理员

该角色拥有特定团队内的所有管理权限,适用于团队负责人,比如项目经理、小组组长、产品负责人等:

可以做:
✅ 添加或删除团队成员
✅ 为团队成员创建/删除密钥
✅ 更新团队成员的预算和速率限制
✅ 修改团队设置(预算、速率限制、模型访问)
✅ 配置团队成员权限
✅ 为团队添加自定义模型(如微调模型)

不能做:
❌ 创建新团队
❌ 修改团队的全局预算和速率限制
❌ 访问其他团队的资源

团队成员

该角色对应团队内的普通成员,拥有团队内的基础权限,团队管理员可以对团队成员的权限进行精确控制,LiteLLM 支持的权限项包括:

权限请求方法描述
/key/infoGET查看密钥信息
/key/healthGET检查密钥健康状态
/key/listGET列出团队所有密钥
/key/generatePOST创建新密钥
/key/service-account/generatePOST创建服务账户密钥
/key/updatePOST修改现有密钥
/key/deletePOST删除密钥
/key/regeneratePOST轮换密钥
/key/blockPOST禁用密钥
/key/unblockPOST启用密钥

用户管理实操

创建一个名为 XYZ Corp 的组织:

$ curl -X POST 'http://127.0.0.1:4000/organization/new' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "organization_alias": "XYZ Corp"
  }'

得到组织 ID:

{
  "organization_id": "42bea353-4697-4f01-a362-25fd096aeb5a",
  "organization_alias": "XYZ Corp",
  // ...
}

为组织创建一个组织管理员:

$ curl -X POST 'http://127.0.0.1:4000/organization/member_add' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "organization_id": "42bea353-4697-4f01-a362-25fd096aeb5a", 
    "member": {
      "role": "org_admin", 
      "user_id": "desmond@example.com"
    }
  }'

注意,该接口会自动在系统中创建一个 user_iddesmond@example.com 的用户,角色为 org_admin 组织管理员。

为该用户创建 API Key:

$ curl -X POST 'http://127.0.0.1:4000/key/generate' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "user_id": "desmond@example.com"
  }'

调用结果如下:

{
  "user_id": "desmond@example.com",
  "key": "sk-xTiqwzA2xJWzac2xk8og7w",
  "key_name": "sk-...og7w",
  // ...
}

然后组织管理员就可以通过他的 API Key 去创建团队了:

$ curl -X POST 'http://127.0.0.1:4000/team/new' \
  -H 'Authorization: Bearer sk-xTiqwzA2xJWzac2xk8og7w' \
  -H 'Content-Type: application/json' \
  -d '{
    "team_alias": "engineering_team",
    "organization_id": "42bea353-4697-4f01-a362-25fd096aeb5a"
  }'

得到团队 ID:

{
  "team_alias": "engineering_team",
  "team_id": "36100710-1fb1-4d6a-abd7-1fda8d171771",
  "organization_id": "42bea353-4697-4f01-a362-25fd096aeb5a",
  // ...
}

组织管理员可以为团队创建一个团队管理员:

$ curl -X POST 'http://127.0.0.1:4000/team/member_add' \
  -H 'Authorization: Bearer sk-xTiqwzA2xJWzac2xk8og7w' \
  -H 'Content-Type: application/json' \
  -d '{
    "team_id": "36100710-1fb1-4d6a-abd7-1fda8d171771", 
    "member": {
      "role": "admin", 
      "user_id": "stonie@example.com"
    }
  }'

同样的,该接口会自动在系统中创建一个 user_idstonie@example.com 的用户,角色为 admin 团队管理员。

也为该用户创建 API Key:

$ curl -X POST 'http://127.0.0.1:4000/key/generate' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "user_id": "stonie@example.com"
  }'

调用结果如下:

{
  "user_id": "stonie@example.com",
  "key": "sk-jhSg1qFKYEIg8ndYmmmFHg",
  "key_name": "sk-...mFHg",
  // ...
}

这里看官方文档,应该使用组织管理员的 API Key 去生成团队管理的 API Key,但是我在测试时报错 User can only create keys for themselves,因此使用了代理管理员的 API Key。

团队管理员可以添加或移除团队成员、修改团队的预算和费率限制、配置团队成员的权限等,下面是添加成员的接口示例:

$ curl -X POST 'http://127.0.0.1:4000/team/member_add' \
  -H 'Authorization: Bearer sk-jhSg1qFKYEIg8ndYmmmFHg' \
  -H 'Content-Type: application/json' \
  -d '{
    "team_id": "36100710-1fb1-4d6a-abd7-1fda8d171771", 
    "member": {
      "role": "user", 
      "user_id": "zhangsan@example.com"
    }
  }'

为该用户生成 API Key:

$ curl -X POST 'http://127.0.0.1:4000/key/generate' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "user_id": "zhangsan@example.com",
    "team_id": "36100710-1fb1-4d6a-abd7-1fda8d171771"
  }'

调用结果如下:

{
  "user_id": "zhangsan@example.com",
  "key": "sk-If8su0G3z3GlgwaA6acpLg",
  "key_name": "sk-...cpLg",
  // ...
}

这里看官方文档,应该使用团队管理员的 API Key 去生成用户的 API Key,但是我在测试时报错 User can only create keys for themselves,因此使用了代理管理员的 API Key。

用户自助服务

上面创建的这些用户,无论是组织管理员、团队管理员还是团队用户,目前都无法登录平台,只能通过 API Key 来进行管理操作,这是相当繁琐的。LiteLLM 支持用户自助服务,它让用户可以在不依赖管理员的情况下管理自己的密钥和查看使用情况。

首先,为他们生成邀请链接:

$ curl -X POST 'http://127.0.0.1:4000/invitation/new' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "user_id": "desmond@example.com"
  }'

该接口生成的是邀请 ID:

{
  "id": "35186fe0-5b96-4e75-a285-f17fbf3add0d",
  "user_id": "desmond@example.com",
  // ...
}

将邀请 ID 拼接到 http://127.0.0.1:4000/ui?invitation_id= 后面,得到类似下面的链接地址:

http://127.0.0.1:4000/ui?invitation_id=35186fe0-5b96-4e75-a285-f17fbf3add0d

将链接地址发送给用户,他就可以登录平台了:

invitation-link.png

登录平台后,根据用户的角色,展示的菜单也不一样。比如普通用户可以查看或创建自己的 API Key:

user-login.png

注意上面的邮箱地址是空的,虽然也能登录,但是下次用户再登录时就麻烦了(需要管理员编辑用户邮箱)。可以使用下面的接口来创建用户,为用户设置邮箱地址:

$ curl -X POST 'http://127.0.0.1:4000/user/new' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "user_email": "stonie@example.com",
    "user_role": "internal_user"
  }'

这个接口在创建用户的同时也会为其创建一个 API Key:

{
  "user_id": "72f9e797-0e9a-41f5-a227-03a8a813c7cc",
  "key": "sk-EIKmPPTyBriwpCW1NYV8aw",
  "key_name": "sk-...V8aw",
  "user_email": "stonie@example.com",
  "user_role": "internal_user",
  // ...
}

然后使用该用户的 ID 来生成邀请链接:

$ curl -X POST 'http://127.0.0.1:4000/invitation/new' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "user_id": "72f9e797-0e9a-41f5-a227-03a8a813c7cc"
  }'

之后用户就可以通过邮箱登录平台了。

小结

通过这篇文章,我们系统地学习了 LiteLLM 的用户管理体系,主要内容包括:

  • 多层次管理架构:从组织 → 团队 → 用户的三层结构,组织层用于大型企业的多租户隔离,团队层用于项目组的资源共享和协作,用户层用于个人开发者的独立预算和追踪;
  • 灵活的权限控制:支持代理管理员、代理查看者、内部用户等全局代理角色,以及组织管理员、团队管理员、普通成员等组织/团队特定角色,还可以精确地控制每个用户能执行的操作;
  • 用户自助服务:支持为用户生成邀请链接,允许用户在不依赖管理员的情况下管理自己的密钥和查看使用情况;

在下一篇文章中,我们将学习 LiteLLM 的 访问控制机制,包括如何为不同的用户和团队分配不同的模型访问权限,如何设置和执行流量控制策略,以及如何进行成本预算管理和预警。这是用户管理体系的延伸和深化,将帮助我们构建一个完整的 LLM 网关安全体系。敬请期待!


学习 LiteLLM 的认证机制

在之前的两篇文章中,我们分别学习了 LiteLLM 的快速入门和模型管理。我们了解到,LiteLLM 不仅是一个统一的 SDK,更是一个功能强大的企业级 LLM 网关。在生产环境中,如何确保 LLM 资源的安全访问?如何为不同用户和团队分配不同的权限?如何追踪每个用户的使用情况和成本?如何精确控制成本和防止滥用?这些都是访问控制需要解决的核心问题。

LiteLLM 的访问控制系统采用多层次的安全架构,从基础的 API Key 认证到企业级的 JWT 认证,从简单的用户管理到复杂的团队权限体系,为不同规模的应用提供了灵活的解决方案:

认证层次

  • 虚拟 API Key:为每个用户或团队生成唯一的虚拟 Key
  • JWT Token:支持企业级 OpenID Connect (OIDC) 认证
  • 自定义认证:集成企业现有的身份认证系统

授权体系

  • 用户级权限:基于角色的访问控制(RBAC)
  • 团队级权限:团队成员共享模型访问权限
  • 组织级权限:大型企业的多层级管理

控制维度

  • 模型访问:控制用户可以使用的模型
  • 接口访问:限制可调用的 API 接口
  • 流量控制:请求频率和并发数限制
  • 成本控制:预算限制和消费追踪

我们今天主要关注第一部分,来学习下 LiteLLM 的认证机制。

虚拟 Key 认证

在之前的学习中,我们在调用模型接口时使用的 API Key 一直都是 sk-1234,这个是我们在配置文件中配置的 Master Key,也就是管理员密钥:

general_settings:
  master_key: sk-1234

对于个人开发者来说,只用一个简单的 API Key 可能就足够了,但是对于团队或企业来说,一个 Key 无法区分不同的用户或应用,而且 Master Key 的权限过大,这时我们就需要引入 Virtual Key 的概念了。

虚拟 Key(Virtual Key) 是 LiteLLM 最核心的认证机制,它借鉴了云服务商的 API Key 管理模式,为每个用户或应用生成独立的访问密钥。LiteLLM 的虚拟 Key 提供了一层抽象,使得:

  • 你可以为不同的用户、团队、应用生成不同的 Key
  • 每个 Key 可以独立配置访问权限和预算限制
  • 支持 Key 的轮换和撤销
  • 所有使用行为都由 Proxy 记录和追踪

接下来我们生成一个虚拟 Key 验证下。虚拟 Key 的生成需要数据库支持,因此首先配置数据库连接(昨天学习模型的动态管理时已经配过):

general_settings:
  master_key: sk-1234
  database_url: "postgresql://postgres:password@127.0.0.1:5432/litellm"

然后通过 /key/generate 接口生成 Key:

$ curl 'http://127.0.0.1:4000/key/generate' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "models": ["gpt-4o"],
    "metadata": {"user": "zhangsan@example.com"}
  }'

接口响应如下:

{    
  "key": "sk-qC5b02PjnQVdq3FPYY37wQ",
  "key_name": "sk-...37wQ",
  "models": [
    "gpt-4o"
  ],
  "metadata": {
    "user": "zhangsan@example.com"
  },
  "user_id": null,
  "team_id": null,
  "model_max_budget": {},
  "model_rpm_limit": null,
  "model_tpm_limit": null,
  "max_budget": null,
  "max_parallel_requests": null,
  "guardrails": null,
  "allowed_routes": [],
  // ...
}

可以看到,接口响应中除了 key 之外,还有一些关于用户、团队、请求频率、并发限制等信息,这些内容涉及 LiteLLM 的授权体系和访问控制机制,我们后面再具体学习。

使用这个虚拟 Key 请求 /chat/completions 接口:

$ curl -X POST 'http://127.0.0.1:4000/chat/completions' \
  -H 'Authorization: Bearer sk-qC5b02PjnQVdq3FPYY37wQ' \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "gpt-4o",
    "messages": [{"role": "user", "content": "你好"}]
  }'

接口验证正常,说明虚拟 Key 生成成功。

支持多种 Header 格式

LiteLLM 的灵活设计使其能够支持多种 Header 格式,兼容不同的客户端库和工具:

Header 名称用途优先级
x-litellm-api-keyLiteLLM 自定义 Key1 (最高)
AuthorizationOpenAI 兼容格式2
API-KeyAzure 风格3
x-api-keyAnthropic 格式4
x-goog-api-keyGoogle AI Studio5
Ocp-Apim-Subscription-KeyAzure APIM6
其他自定义 Header配置化支持7

比如像下面这样请求也是可以的:

$ curl -X POST 'http://127.0.0.1:4000/chat/completions' \
  -H 'x-litellm-api-key: sk-qC5b02PjnQVdq3FPYY37wQ' \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "gpt-4o",
    "messages": [{"role": "user", "content": "你好"}]
  }'

这样的设计让 LiteLLM 可以轻松地代理来自各种来源的请求,而无需修改客户端代码。

虚拟 Key 的存储和验证

为了保证安全性,虚拟 Key 在数据库中采用 哈希值存储,这样做的好处是,即使数据库被泄露,攻击者也无法直接使用 Key(因为数据库中只有哈希值)。

另外,LiteLLM 使用 分层缓存策略 进行虚拟 Key 的验证:

api-key-verification.png

通过分层缓存,大多数请求不需要访问数据库,大大提高了虚拟 Key 的验证性能。

客户端凭据透传

除了传统的服务器端认证,LiteLLM 还支持让客户端直接传递自己的 API Key,这在某些场景下可能有用,比如开发者使用自己的 API Key 进行测试,或者用户希望使用自己的 API Key,但又不希望配置到 LiteLLM 里。

通过下面的参数启用客户端凭据透传:

model_list:
  - model_name: gpt-4o
    litellm_params:
      model: openai/gpt-4o
      api_key: os.environ/OPENAI_API_KEY
      configurable_clientside_auth_params: ["api_key", "api_base"] # 支持透传的字段

客户端调用示例如下:

import openai

client = openai.OpenAI(
  api_key="sk-1234",
  base_url="http://localhost:4000"
)

response = client.chat.completions.create(
  model="gpt-4o",
  messages=[{"role": "user", "content": "Hello"}],
  extra_body={
    "api_key": "sk-client-xxx",  # 客户端自己的 API 密钥
    "api_base": "https://api.openai.com/v1"
  }
)

LiteLLM 会遍历 configurable_clientside_auth_params 参数,将客户端传递的参数和系统配置的参数进行合并。

有意思的,客户端不仅可以传 api_keyapi_base 等字段,甚至可以传整个 model_list,将 LiteLLM 的配置完全架空。

JWT 认证与 OIDC 集成

虽然虚拟 Key 是 LiteLLM 最核心的认证方式,但对于某些企业场景,这种认证方式可能不够灵活,企业往往已经有一套比较成熟的 身份认证系统(Identity Provider, IDP),比如:

  • Azure AD:Microsoft 的企业身份平台
  • Keycloak:开源身份和访问管理解决方案
  • Google Cloud Identity:Google 的企业 SSO
  • Okta:专业的身份管理服务

他们更希望能直接复用这套认证机制。

LiteLLM 支持通过 JWT 令牌 与这些系统集成,而无需维护独立的用户数据库。

注意,这是一个企业级特性,需要购买授权。

OIDC 简介

LiteLLM 和身份认证系统之间的交互遵循 OIDC 标准。

OpenID Connect (OIDC) 是一个基于 OAuth 2.0 的身份认证协议,它在 OAuth 2.0 的基础上增加了身份层,使得应用可以验证用户的身份,它已经成为企业级应用的标准认证方式。

OIDC 的核心优势如下:

  • 标准化:遵循 OAuth 2.0 和 OpenID Connect 规范
  • 单点登录:支持 SSO,用户一次登录,全组织访问
  • 令牌安全:JWT 令牌可以包含丰富的用户信息,支持签名和加密
  • 广泛支持:被所有主流云服务和身份提供商支持

下面是 OIDC 规范,对此感兴趣的朋友可以看看:

JWT 简介

JWT(JSON Web Token) 是一种基于 JSON 的轻量级身份认证与信息交换标准(RFC 7519),广泛用于分布式系统、API 接口、前后端分离架构中,核心作用是在客户端与服务器之间安全传递 可验证的声明(如用户身份、权限范围等),无需服务器存储会话状态。

在传统的会话认证(如 Session)中,服务器需要存储用户的会话信息,当用户量增大或服务分布式部署时,会面临会话同步复杂、服务器存储压力大等问题。而 JWT 通过 客户端存储令牌 + 服务器验证令牌 的模式,解决了这些痛点,其核心优势包括:

  • 无状态:服务器无需存储会话数据,仅通过令牌本身即可验证合法性,降低服务器存储成本,便于服务水平扩展(多台服务器可共享认证逻辑);
  • 跨域友好:JWT 基于 HTTP 头传递,天然支持跨域场景(如前后端分离、多服务间调用);
  • 轻量灵活:基于 JSON 格式,体积小、传输快,且可自定义声明字段,满足不同业务需求;
  • 自包含:令牌本身包含了用户身份、权限等核心信息,减少服务器查询数据库的次数(无需每次认证都查用户表);

一个 JWT 令牌由三部分组成,用点号分隔:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIn0.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

分别代表:

  • Header:算法和令牌类型信息
  • Payload:用户信息和声明(Claims)
  • Signature:数字签名,用于验证数据完整性

可以通过下面的网站验证和查看 JWT 令牌中的内容:

基于 Keycloak 的 JWT 认证实战

下面我使用 Keycloak 这款开源的身份认证系统来演示下如何在 LiteLLM 中实现 JWT 认证。

keycloak.png

这是一款由 Red Hat 主导开发并维护的开源 身份和访问管理(IAM) 工具,旨在为现代应用(包括 Web 应用、移动应用、API 服务等)提供统一、安全且标准化的 身份认证(Authentication)授权(Authorization) 能力,帮助开发者快速集成身份管理功能,无需重复造轮子。

Keycloak 环境准备

首先使用下面的命令启动 Keycloak 服务:

$ docker run \
  -p 8080:8080 \
  -e KC_BOOTSTRAP_ADMIN_USERNAME=admin \
  -e KC_BOOTSTRAP_ADMIN_PASSWORD=admin \
  quay.io/keycloak/keycloak:26.4.2 start-dev

服务启动成功后,在浏览器访问 http://localhost:8080/ 并使用默认的用户名和密码登录:

keycloak-admin-ui.png

点击 “Manage realms” 菜单,创建一个名为 litellm领域(Realm),这是 Keycloak 中最高级别的隔离单位,相当于 租户

keycloak-create-realm.png

创建完成后会自动切到这个领域,然后点击 “Users” 菜单,在这个领域下创建一个用户,用户名为 zhangsan

keycloak-create-user.png

创建完成后进入该用户的详情,点击 “Credentials” 菜单,再点击 “Set password” 按钮,为用户设置一个长期密码(注意将 Temporary 勾掉):

keycloak-create-user-set-password.png

然后再点击 “Clients” 菜单,创建一个客户端:

keycloak-create-client.png

其中 Client ID 命名为 litellm,点击 Next 进入 “Capability Config” 页面:

keycloak-create-client-capability.png

将 “Client authentication” 选项开启,同时在 “Authentication flow” 中将 “Direct access grants” 开启。接着,点击 Next 进入 “Login Settings” 页面,保持默认即可,点击 Save 按钮,完成客户端的创建。

开启 JWT 认证

至此 Keycloak 环境准备就绪,接下来让 LiteLLM 开启 JWT 认证。第一步,通过环境变量设置 Keycloak 的公钥端点:

# 注意 `litellm` 是领域名称
export JWT_PUBLIC_KEY_URL="http://localhost:9009/realms/litellm/protocol/openid-connect/certs"

这个 URL 是 OpenID Connect 标准的 JWKS(JSON Web Key Set) 端点,方便客户端批量获取所需密钥,里面包含了用于验证签名或加密的公钥。

第二步,在配置中启用 JWT 认证:

general_settings:
  master_key: sk-1234
  database_url: "postgresql://postgres:password@127.0.0.1:5432/litellm"
  enable_jwt_auth: true # 开启 JWT 认证

第三步,重启 LiteLLM Proxy 服务:

$ litellm -c config.yaml

第四步,使用 Client ID、Client Secret、用户名、密码,调用 Keycloak 获取 JWT 令牌:

$ curl -X POST \
  http://localhost:9009/realms/litellm/protocol/openid-connect/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=password" \
  -d "client_id=litellm" \
  -d "client_secret=0CtlgEvGHU3XNjDAmwHPn5p8wT78JGEp" \
  -d "username=zhangsan" \
  -d "password=12345678"

其中 Client Secret 可以在 Client 详情中找到:

keycloak-clients-details.png

接口返回结果如下:

{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5...",
  "expires_in": 300,
  "refresh_expires_in": 1800,
  "refresh_token": "eyJhbGciOiJIUzUxMiIsInR5...",
  "token_type": "Bearer",
  "not-before-policy": 0,
  "session_state": "dca8f2d7-eac4-d6e7-799b-f7b80da4d841",
  "scope": "profile email"
}

这个 access_token 就是 JWT 令牌,我们可以用它来调用 /chat/completions 接口:

$ curl -X POST 'http://127.0.0.1:4000/chat/completions' \
  -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5...' \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "gpt-4o",
    "messages": [{"role": "user", "content": "你好"}]
  }'

LiteLLM 会根据从 JWT_PUBLIC_KEY_URL 获取的公钥对该令牌进行验证(类似数字签名的原理),这就是 LiteLLM 的 JWT 认证流程。

自定义认证

虽然 LiteLLM 提供了虚拟 Key、JWT 等多种认证方式,但在某些高度定制化的场景中,你可能需要实现自己的认证逻辑。比如:

  • 现有系统集成:你有一套自定义的用户认证系统
  • 特殊业务规则:需要根据特定条件验证用户
  • 外部服务集成:需要调用外部服务进行认证
  • 多步认证:需要组合多个认证因素

LiteLLM 允许你提供自定义的认证函数,完全控制身份认证过程。其核心是实现一个异步函数,该函数接收请求和 API Key,然后返回一个认证对象:

from fastapi import Request
from litellm.proxy._types import UserAPIKeyAuth

async def user_api_key_auth(request: Request, api_key: str) -> UserAPIKeyAuth: 
  """
  自定义认证函数

  参数:
    request: FastAPI 请求对象,包含 HTTP 请求的所有信息
    api_key: 从请求头中提取的 API Key

  返回:
    UserAPIKeyAuth: 认证成功时返回用户认证对象

  异常:
    Exception: 认证失败时抛出异常
  """
  try: 
    if api_key.startswith("my-custom-key-"):
      return UserAPIKeyAuth(api_key=api_key)
    raise Exception("Invalid API key")
  except: 
    raise Exception("Authentication failed")

将上面的内容保存到 custom_auth.py 文件中,并放置于和 config.yaml 文件同级的目录下。在配置文件中指定自定义认证函数的位置:

general_settings:
  master_key: sk-1234
  database_url: "postgresql://postgres:password@127.0.0.1:5432/litellm"
  custom_auth: custom_auth.user_api_key_auth  # 模块路径.函数名

然后重启 LiteLLM Proxy 服务,此时,任何 my-custom-key- 开头的 Key 都能通过验证了:

$ curl -X POST 'http://127.0.0.1:4000/chat/completions' \
  -H 'Authorization: Bearer my-custom-key-888' \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "gpt-4o",
    "messages": [{"role": "user", "content": "你好"}]
  }'

值得注意的是,在认证流程中,自定义认证是最优先执行的,因此如果开启了该功能,Master Key 和 虚拟 Key 就不起作用了。为了同时兼容,企业版的 LiteLLM 支持一个更灵活的混合模式:

general_settings:
  custom_auth: custom_auth.user_api_key_auth
  custom_auth_settings:
    mode: "auto"  # 支持虚拟 Key 和自定义认证混用

当自定义认证失败后,LiteLLM 会继续沿用虚拟 Key 的验证流程。

小结

通过这篇文章,我们系统地学习了 LiteLLM Proxy 的认证机制,这是构建企业级 LLM 网关的核心基础。主要内容包括:

  • 虚拟 Key 认证:LiteLLM 最核心的认证方式,通过为每个用户或应用生成独立的 API Key,实现细粒度的权限隔离和使用追踪;采用哈希存储和分层缓存策略确保了安全性和性能的平衡;支持多种 Header 格式使其能够兼容各种客户端和工具;
  • JWT 认证与 OIDC 集成:为企业用户提供了一条与现有身份认证系统无缝集成的路径,无需在 LiteLLM 中维护独立的用户数据库,充分利用企业已有的 IAM 基础设施;
  • 自定义认证:完全开放的认证扩展机制,允许企业根据特定的业务规则实现复杂的认证逻辑,支持与任何现有系统的集成;企业版提供了混合模式,可以同时支持虚拟 Key 和自定义认证;

LiteLLM 的认证设计体现了分层的思想:从基础的虚拟 Key 面向个人开发者和小型团队,到 JWT/OIDC 面向已有 IAM 的企业,再到自定义认证面向有特殊需求的场景。这种分层的、可扩展的设计,使得 LiteLLM 能够适应从个人项目到大规模企业级应用的各种场景。

在后续的学习中,我们将继续深入 LiteLLM 的权限管理和访问控制系统,学习如何为不同的用户和团队分配不同的权限,如何追踪使用情况和成本,如何设置预算限额防止滥用。敬请期待!


学习 LiteLLM 的模型管理

在上一篇文章中,我们快速了解了 LiteLLM 的核心特性和基本用法。我们知道 LiteLLM 通过统一的 API 接口支持调用 100+ 个 LLM 服务商的模型,而 Proxy Server 可以作为一个企业级的 LLM 网关来统一管理和路由请求。

但是,当我们真正去部署和使用 LiteLLM Proxy 时,会面临一个非常实际的问题:如何有效地管理这些模型?

是否能够快速添加新模型而不需要重启服务?能否让用户清楚地了解有哪些模型可用?在使用过程中,如何追踪模型的定价和成本?怎样安全地存储和管理各个服务商的 API 凭据?这些都是模型管理需要解决的问题。

这一篇文章,我们就来深入学习 LiteLLM 的模型管理功能,看看它是如何帮助我们解决这些实际问题的。

基础配置

在前面的快速入门篇,我们已经接触过简单的模型配置,可以通过 config.yaml 文件定义模型:

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-sonnet-4-20250514
      api_key: os.environ/ANTHROPIC_API_KEY

这里的配置很直观:

  • model_name 是用户在调用 API 时使用的名称
  • litellm_params 包含了 LiteLLM 在调用该模型时需要的所有参数,包括实际的模型名称、API 密钥、URL 地址等

    • model:遵循 provider/model_id 的格式,LiteLLM 通过这个来识别实际的模型和服务商
    • api_key:支持 os.environ/KEY_NAME 的格式来从环境变量中读取,避免将密钥硬编码在配置文件中

但在实际应用中,我们往往需要更多的信息。比如,某个模型的最大 Token 数是多少?调用这个模型的成本是多少?这个模型有什么特殊的功能限制吗?这就需要用到 model_info 字段,我们可以通过 /model/info 接口了解每个模型的详细信息:

$ curl -X GET http://127.0.0.1:4000/model/info \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json'

返回结果类似下图:

model-info.png

对于一些比较常见的模型,LiteLLM 会定期维护基本信息,不过用户也可以在配置文件中进行修改,这样会覆盖默认值,用户还可以添加自定义的字段:

model_list:
  - model_name: gpt-4o
    litellm_params:
      model: openai/gpt-4o
      api_key: os.environ/OPENAI_API_KEY
    model_info:
      description: "这里是用户自定义字段"
      max_tokens: 4096
      supports_vision: true
      supports_function_calling: true

这个 /model/info 接口非常有用,可以用来在应用的 UI 中展示可用的模型列表和详细信息,帮助用户选择最合适的模型,进行成本估算和预算规划。

动态管理

通过配置文件管理模型固然简单,但是每次修改都需要重启 Proxy Server,这在生产环境下是不可接受的。LiteLLM 支持将模型信息保存到 Postgres 数据库中,从而实现动态管理功能。首先修改 config.yaml 文件,加上数据库配置并开启模型保存功能:

general_settings:
  master_key: sk-1234 # 管理员密钥
  database_url: "postgresql://postgres:password@127.0.0.1:5432/litellm"
  store_model_in_db: true # 是否将模型保存到数据库

然后重启 Proxy Server,现在我们就可以通过 API 接口的方式动态管理模型了,具体又可以分为 通过 API 管理通过命令行管理通过 Web UI 管理 几种方式。

通过 API 管理

通过 /model/new 接口添加模型:

$ curl -X POST "http://127.0.0.1:4000/model/new" \
  -H 'Authorization: Bearer sk-1234' \
  -H "Content-Type: application/json" \
  -d '{
    "model_name": "deepseek",
    "litellm_params": {
      "model": "deepseek/deepseek-chat",
      "api_key": "sk-xxx"
    }
  }'

通过命令行管理

LiteLLM 还提供了一个命令行工具 litellm-proxy,方便从命令行管理模型,这个工具在安装 Proxy Server 时会一起安装好:

$ pip install 'litellm[proxy]'

首先通过环境变量配置认证信息:

export LITELLM_PROXY_URL=http://localhost:4000
export LITELLM_PROXY_API_KEY=sk-1234

也可以使用 litellm-proxy login 登录,这会打开浏览器进行身份认证,认证后的凭据会保存在本地。

列出所有模型

$ litellm-proxy models list

添加新模型

$ litellm-proxy models add deepseek \
  --param model=deepseek/deepseek-chat \
  --param api_key=sk-xxxx

删除模型

$ litellm-proxy models delete <model-id>

通过 Web UI 管理

如果你不习惯使用命令行,LiteLLM Proxy 的 Web UI 也提供了可视化的模型管理界面,登录到管理后台后,点击 “Models + Endpoints” 菜单:

web-ui-model-management.png

这里列出了当前系统的所有模型,包括配置文件中的和数据库中的。点击 “Add Model” 标签添加新模型:

web-ui-add-model.png

填写 Provider、Model Names、Model Mappings、API Key 等参数,点击确认即可。

注意,Model Mappings 中的 Public Model Name 就对应配置文件中的 model_name 参数,LiteLLM Model Name 对应 litellm_params.model 参数。

如果有一些额外参数,可以展开 “Advanced Settings” 进行配置:

web-ui-add-model-adv.png

模型发现

手动维护模型列表可能会很繁琐,特别是对于那些有大量模型的服务商,比如 OpenAI、Anthropic 等,每次他们发布新模型时我们都要手动更新配置。为此,LiteLLM 推出了 模型发现(Model Discovery) 功能,通过 Wildcard 模型 LiteLLM 可以自动从服务商处获取最新的模型列表,无需手动更新。

其配置非常简单,只需要在 config.yaml 中使用 /* 后缀来表示 Wildcard 模型:

model_list:
  - model_name: anthropic/*
    litellm_params:
      model: anthropic/*
      api_key: os.environ/ANTHROPIC_API_KEY

litellm_settings:
  check_provider_endpoint: true  # 启用模型发现功能

注意 litellm_settings.check_provider_endpoint 必须设为 true,表示启用模型发现功能。

配置完成后,调用 /v1/models 接口就可以看到所有自动发现的模型:

$ curl -X GET http://127.0.0.1:4000/v1/models \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json'

这里我使用的是 Anthropic 服务商,因此返回的结果包含了 Anthropic 的所有可用模型:

model-discovery.png

目前 LiteLLM 的模型发现功能支持以下服务商:

  • Fireworks AI
  • OpenAI
  • Gemini
  • LiteLLM Proxy(是的,可以级联!)
  • Topaz
  • Anthropic
  • xAI
  • vLLM
  • Vertex AI

使用 Model Hub 公开模型

在团队或企业环境中,你可能希望让用户知道哪些模型是可用的,LiteLLM 提供了一个 Model Hub 功能,可以公开展示模型列表。使用 Model Hub 有以下几点优势:

  1. 自服务探索:用户可以自己浏览可用的模型,无需询问管理员
  2. 信息透明:每个模型都展示详细的信息,包括描述、能力、局限等
  3. 降低门槛:新用户可以快速了解系统中有什么,如何使用
  4. 公开演示:可以用来向客户或合作伙伴展示你的模型能力

首先,我们需要在 Web UI 中选择要公开的模型。进入 Model Hub 页面后,点击 “Make Public” 按钮,选择要公开的模型:

model-hub-make-public.png

确认后,这些模型就会出现在公开的 Model Hub 页面上,访问下面这个 URL 进行查看:

http://127.0.0.1:4000/ui/model_hub_table

这个页面是公开的,所有人都能访问,就像一个应用商店一样:

model-hub-table.png

用户可以在这里查看每个模型的详细信息以及使用文档。

模型价格同步

在上面的学习中我们了解到,可以通过 /model/info 接口查询模型的详细信息,包括模型的上下文限制以及输入输出价格等,这些信息有助于企业进行准确的成本追踪和预算控制。

LiteLLM 在 GitHub 上维护了一个完整的模型成本映射表,包含了 100+ 个模型的详细信息:

https://github.com/BerriAI/litellm/blob/main/model_prices_and_context_window.json

随着新模型的发布和价格的变化,这个映射表会定期更新。为了保持你的 Proxy Server 中的成本数据最新,LiteLLM 提供了 手动同步自动同步 的功能,可以从 GitHub 获取最新的价格信息,确保成本追踪的准确性。

如果你想立即同步最新的价格信息,可以使用以下命令:

$ curl -X POST "http://127.0.0.1:4000/reload/model_cost_map" \
  -H "Authorization: Bearer sk-1234" \
  -H "Content-Type: application/json"

对于生产环境,更推荐设置自动定期同步,比如每 6 小时同步一次:

$ curl -X POST "http://127.0.0.1:4000/schedule/model_cost_map_reload?hours=6" \
  -H "Authorization: Bearer sk-1234" \
  -H "Content-Type: application/json"

查看同步状态:

$ curl -X GET "http://127.0.0.1:4000/schedule/model_cost_map_reload/status" \
  -H "Authorization: Bearer sk-1234"

取消定时同步:

$ curl -X DELETE "http://127.0.0.1:4000/schedule/model_cost_map_reload" \
  -H "Authorization: Bearer sk-1234"

默认情况下,LiteLLM 从 GitHub 的官方仓库获取模型成本表。如果你有一些定制模型,想使用自定义的模型成本表,可以设置环境变量:

export LITELLM_MODEL_COST_MAP_URL="https://your-server.com/your-cost-map.json"

或者使用本地文件:

export LITELLM_LOCAL_MODEL_COST_MAP=True

此时 LiteLLM 会读取 litellm 目录下的 model_prices_and_context_window_backup.json 文件,不会访问网络。

凭据管理

关于模型管理的另一个话题是 凭据管理,我们知道,LiteLLM 支持 100 多个不同的模型服务商,每个服务商都有自己的 API Key 或认证方式,如何安全的管理这些服务商的凭据呢?

在前面的 config.yaml 文件中,我们配置 api_key 时使用了 os.environ/KEY_NAME 格式从环境变量中读取,这是最简单的一种凭据管理的方式,避免将密钥硬编码在配置文件中,虽然很方便,但是这种方式难以管理,而且也不够安全,在某些情况下,你可能希望在 LiteLLM 的数据库中直接存储和管理这些凭证。

LiteLLM 提供了一个专门的凭证管理界面,进入 Models -> LLM Credentials -> Add Credential,可以添加新的凭证:

web-ui-add-credentials.png

选择你的 LLM 服务商后,输入 API Key 和其他必要信息(根据不同的服务商,界面会显示相应的字段),点击确认即可。添加凭证后,在创建新模型时就可以从下拉列表中选择已有的凭证,避免重复输入敏感信息:

web-ui-add-model-use-credentials.png

凭证在数据库中是加密存储的。LiteLLM 使用以下方式进行加密:

  • 优先使用 LITELLM_SALT_KEY 进行加密
  • 如果未设置 LITELLM_SALT_KEY,则使用 LITELLM_MASTER_KEY 进行加密

这两个密钥都应该被妥善保管,不要泄露。

企业级凭据管理

对于企业级应用,对于凭据管理可能有着更高的安全要求,LiteLLM 支持与主流的 密钥管理服务(Secrets Manager) 集成,允许你将凭据存储在企业级的密钥管理服务中,而不是 LiteLLM 的数据库中。支持的 Secrets Manager 包括:

  • AWS Secrets Manager
  • AWS Key Management Service
  • Azure Key Vault
  • Google Secret Manager
  • Google Key Management Service
  • HashiCorp Vault

除了传统的 API Key,LiteLLM 还支持 OpenID Connect (OIDC) 身份认证,这是一种更现代、更安全的认证方式。支持的 OIDC 提供商包括:

  • Google Cloud Run
  • GitHub Actions
  • Azure AD
  • CircleCI
  • Azure Kubernetes Service 等

这两个功能特别适合大型企业环境,可以显著提高安全性和合规性。详细的企业特性配置,请参考 LiteLLM 官方文档。

小结

通过这篇文章,我们详细学习了 LiteLLM Proxy 的模型管理功能。主要内容包括:

  • 基础配置:对于相对稳定的模型配置,应该在 config.yaml 中定义,这样可以版本控制,便于回滚;充分利用 model_info 字段来添加模型描述、能力说明、使用建议等,这会让用户更容易选择合适的模型;
  • 动态管理:通过 /model/new 接口在运行时动态添加模型,支持 API、命令行、Web UI 三种方式对模型进行管理,无需重启服务;
  • 模型发现:通过通配符自动获取整个服务商的模型列表;
  • Model Hub:公开展示可用的模型信息,提升用户体验;
  • 模型价格同步:手动或自动从 GitHub 同步最新的模型成本数据,支持自定义模型成本表;
  • 凭据管理:集中管理 API Key 和凭据信息,降低凭据泄露的风险;对于高安全要求场景,考虑使用企业特性(Secret Manager 或 OIDC),实现零密钥存储或临时凭据;

LiteLLM 的模型管理系统设计得相当完善,既支持初期的简单配置,也支持后期的复杂运维场景。从 config.yaml 的声明式配置,到运行时的动态管理,再到企业级的高安全凭据存储,LiteLLM 为不同规模的应用提供了灵活的解决方案。


LiteLLM 快速入门

在 AI 应用的开发过程中,开发者们往往面临一个共同的难题:如何高效地集成多家 LLM 服务商的接口?不同的服务商提供的 API 设计各不相同,OpenAI 有自己的风格,Anthropic 有另一套标准,Azure OpenAI、Google Vertex AI 又有各自的特色。每次需要切换服务商或支持多家模型时,开发者都要费力去学习和适配新的 API 规范,这无疑增加了开发成本和维护难度。

LiteLLM 正是为了解决这个问题而诞生的。它是一个开源的 Python 库,提供了一个统一的接口来调用 100+ 个 LLM 服务商的模型,无论是 OpenAI、Anthropic、Google、Cohere,还是国内的 DeepSeek、Qwen 等,都可以通过相同的 API 来调用。更强大的是,LiteLLM 不仅可以作为客户端 SDK 集成到你的应用中,还提供了一个功能丰富的 Proxy Server,可以用作 LLM Gateway 来统一管理和路由所有的 LLM 请求。

icon.png

这篇文章是我们 LiteLLM 学习系列的第一篇,今天就让我们一起快速上手 LiteLLM,了解它的核心特性和基本用法。

LiteLLM 概览

LiteLLM 的核心价值主要体现在以下几个方面:

统一的 API 接口:LiteLLM 将所有 LLM 服务商的 API 都转换为 OpenAI 的 API 格式,这意味着你只需要学习一套 API,就可以调用任何支持的模型。无论服务商更换、模型迭代,你的代码基本不需要改动。
完善的重试和容错机制:通过 Router 和 Fallback 功能,LiteLLM 支持在多个模型部署之间进行负载均衡和自动容错,当某个服务商出现故障时,可以自动切换到备用方案,确保服务的可用性。
成本追踪和预算管理:LiteLLM 可以自动计算每次 API 调用的成本,并支持设定每个用户或团队的预算限额,帮助企业更好地控制成本。
Proxy Server 网关:LiteLLM 提供的代理服务器可以作为一个中心化的 LLM 网关,统一处理认证、速率限制、成本追踪等问题,特别适合大型组织内部部署。

目前有不少开源项目使用了 LiteLLM,比如 smolagentsOpen InterpreterQuivr 等:

projects.png

我们之前学习的 Surfsense、Mem0、Claude Code、Chat2Graph 等项目,都或多或少地有着 LiteLLM 的影子。

作为客户端 SDK 使用

LiteLLM 最简单的使用方式就是作为 Python 客户端库,直接在你的应用中调用。首先安装依赖:

$ pip install litellm

基础调用

下面是最基础的使用示例,调用 OpenAI 的 gpt-4o 模型:

from litellm import completion
import os

# 设置 API Key(也可以通过环境变量设置)
os.environ["OPENAI_API_KEY"] = "sk-xxx"

# 发送请求
response = completion(
  model="openai/gpt-4o",
  messages=[
    {"role": "user", "content": "你好,请自我介绍一下"}
  ]
)

# 打印响应
print(response.choices[0].message.content)

这里的 model 参数遵循 provider/model_name 的格式,LiteLLM 通过这个格式来识别应该用哪个服务商的 API。响应格式完全兼容 OpenAI 的 API,所以如果你之前用过 OpenAI SDK,会发现非常熟悉。

{
  "id": "chatcmpl-CWZUWaec9CC3vYyH5WlJN5LJ6tGxj",
  "created": 1761878960,
  "model": "gpt-4o-2024-08-06",
  "object": "chat.completion",
  "system_fingerprint": null,
  "choices": [
    {
      "finish_reason": "stop",
      "index": 0,
      "message": {
        "content": "你好!我是一个由人工智能驱动的助手 ...",
        "role": "assistant",
        "tool_calls": null,
        "function_call": null
      }
    }
  ],
  "usage": {
    "completion_tokens": 68,
    "prompt_tokens": 13,
    "total_tokens": 81,
    "completion_tokens_details": null,
    "prompt_tokens_details": {
      "audio_tokens": null,
      "cached_tokens": 0
    },
    "cache_creation_input_tokens": 0,
    "cache_read_input_tokens": 0
  }
}

丰富的模型支持

LiteLLM 支持 100+ 个模型,包括:

  • 商业模型:OpenAI、Anthropic、Google Gemini、Cohere、Mistral 等
  • 国内模型:DeepSeek、通义千问、智谱 GLM、百川、千帆 等
  • 本地模型:Ollama、Hugging Face、vLLM 等
  • 企业服务:Azure OpenAI、AWS Bedrock、Google Vertex AI 等

这里是完整的模型供应商列表:

例如,如果你想切换到 Claude,代码只需要改一行:

os.environ["ANTHROPIC_API_KEY"] = "sk-xxx"

response = completion(
  model="anthropic/claude-sonnet-4-20250514",
  messages=[
    {"role": "user", "content": "你好,请自我介绍一下"}
  ]
)

或者使用国内的 DeepSeek:

os.environ["DEEPSEEK_API_KEY"] = "sk-xxx"

response = completion(
  model="deepseek/deepseek-chat",
  messages=[
    {"role": "user", "content": "你好,请自我介绍一下"}
  ]
)

流式响应

对于需要实时流式输出的应用(比如对话应用),LiteLLM 通过传入 stream=True 参数来支持流式响应:

response = completion(
  model="openai/gpt-4o",
  messages=[
    {"role": "user", "content": "写一首关于春天的诗"}
  ],
  stream=True
)

# 逐块输出响应
for chunk in response:
  content = chunk.choices[0].delta.content
  if content:
    print(content, end="")

异步调用

LiteLLM 也提供了异步 API acompletion,方便在异步框架中使用:

import asyncio
from litellm import acompletion

# 异步请求
async def chat():
  response = await acompletion(
    model="openai/gpt-4o",
    messages=[
      {"role": "user", "content": "你好,请自我介绍一下"}
    ]
  )
  return response

# 运行异步函数
response = asyncio.run(chat())
print(response.choices[0].message.content)

异常处理

LiteLLM 会将所有服务商的异常都映射到 OpenAI 的异常类型,这样你就可以用统一的方式处理各种错误:

from openai.error import APIError, RateLimitError
from litellm import completion

try:
  response = completion(
    model="openai/gpt-4o",
    messages=[{"role": "user", "content": "你好"}]
  )
except RateLimitError:
  print("请求过于频繁,请稍后重试")
except APIError as e:
  print(f"API 错误: {e}")

关于异常映射的详细信息可参考下面的文档:

丰富的接口支持

除了 completion 文本补全接口,LiteLLM 还兼容大量供应商的接口,比如:

作为 Proxy Server 使用

除了作为 SDK 使用,LiteLLM 还提供了一个企业级的 代理服务器(Proxy Server),可以作为一个 大模型网关(LLM Gateway) 来使用。这对于需要统一管理多个服务商、对接多个应用的场景特别有价值。

核心功能

LiteLLM Proxy 主要有以下功能:

多模型管理和负载均衡:可以配置多个模型和多个部署,Proxy 会自动进行负载均衡,分散请求到不同的模型部署,提高整体吞吐量。
密钥管理和成本追踪:为每个团队或用户生成虚拟 API Key,追踪每个 Key 的成本消耗,支持设定使用预算和速率限制。
统一的认证和授权:Proxy 可以作为中心化的认证层,所有应用通过它来访问 LLM 服务,避免将各种 API Key 散布在各个应用中。
可观测性和日志:支持与 Langfuse、Helicone、LunaryAI 等可观测平台集成,记录所有 API 调用的详细信息,便于监控和调试。

快速启动

安装 Proxy 服务器需要额外的依赖:

$ pip install 'litellm[proxy]'

最简单的启动方式,只需一条命令:

$ litellm --model openai/gpt-4o

# INFO: Uvicorn running on http://0.0.0.0:4000

这样就启动了一个代理服务器,默认监听在 4000 端口上,直接浏览器打开可以看到它的 Swagger 文档页面,这里列出了 LiteLLM Proxy 的所有接口:

swagger.png

可以通过 --port 参数修改监听的端口。

使用 Config.yaml 配置

如果你想用其他模型或配置多个模型,可以使用配置文件。创建一个 config.yaml 文件来配置多个模型:

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-sonnet-4-20250514
      api_key: os.environ/ANTHROPIC_API_KEY

  - model_name: deepseek
    litellm_params:
      model: deepseek/deepseek-chat
      api_key: os.environ/DEEPSEEK_API_KEY

general_settings:
  master_key: sk-1234  # 管理员密钥

完整的配置文件参数参考官方文档:https://docs.litellm.ai/docs/proxy/configs

然后用配置文件启动:

$ litellm --config config.yaml

# INFO: Uvicorn running on http://0.0.0.0:4000

调用 Proxy

启动后,你可以通过 OpenAI SDK 或任何兼容 OpenAI API 的工具来调用 Proxy。Proxy 的 API 与 OpenAI 完全兼容,这意味着你可以无缝地将现有的 OpenAI 集成改为使用 LiteLLM Proxy。

使用 OpenAI Python SDK:

import openai

client = openai.OpenAI(
  api_key="sk-1234",
  base_url="http://127.0.0.1:4000"
)

response = client.chat.completions.create(
  model="gpt-4o",  # 使用配置中的模型名
  messages=[{"role": "user", "content": "你好"}]
)

print(response.choices[0].message.content)

使用 cURL:

$ curl -X POST 'http://127.0.0.1:4000/chat/completions' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "gpt-4o",
    "messages": [{"role": "user", "content": "你好"}]
  }'

Docker 部署

对于生产环境,LiteLLM 提供了完整的 Docker 支持。最简单的方式是使用 Docker Compose:

# 下载 Docker Compose 配置
$ curl -O https://raw.githubusercontent.com/BerriAI/litellm/main/docker-compose.yml

# 创建 .env 文件设置必要的环境变量
$ cat > .env <<EOF
LITELLM_MASTER_KEY="sk-1234"
OPENAI_API_KEY="your-api-key"
EOF

# 启动服务
$ docker compose up -d

或者直接使用 Docker 运行:

docker run \
  -v $(pwd)/config.yaml:/app/config.yaml \
  -e OPENAI_API_KEY="your-api-key" \
  -p 4000:4000 \
  ghcr.io/berriai/litellm:main-stable \
  --config /app/config.yaml

Web UI 和管理界面

此外,LiteLLM Proxy 还提供了一个管理后台,方便我们添加新的模型配置、查看调用日志、监控成本和使用情况等。启动 Proxy 之后,首次访问 http://127.0.0.1:4000/ui 进入登录页面:

login.png

默认用户名为 admin,密码为 config.yaml 文件中配置的 master_key,默认就是 sk-1234,登录成功后即可进入管理界面:

admin-ui.png

可以在 .env 文件中通过 UI_USERNAMEUI_PASSWORD 修改管理员的用户名和密码:

UI_USERNAME=aneasystone
UI_PASSWORD=12345678

另外,对于不希望有管理后台的用户,可以通过 DISABLE_ADMIN_UI 参数关闭 Web UI 功能:

DISABLE_ADMIN_UI=True

小结

这篇文章作为 LiteLLM 学习系列的开篇,我们快速了解了 LiteLLM 的核心特性和两种主要的使用方式:

  1. 作为 Python SDK:简单易用,适合快速集成和个人项目,只需几行代码就能调用任何模型;
  2. 作为 Proxy Server:功能完整,适合企业级部署,可以统一管理多个模型,实现成本追踪、速率限制、虚拟 Key 管理等功能;

LiteLLM 通过统一的 API 接口解决了多模型集成的复杂性问题,而 Proxy Server 则进一步提供了一个企业级的 LLM 网关解决方案。在后续的系列文章中,我们将深入探讨 LiteLLM 的高级功能,包括路由和负载均衡、成本追踪和预算管理的细节、与可观测性平台的集成等。

敬请期待!


重温 Java 21 之结构化并发

结构化并发(Structured Concurrency) 最初由 JEP 428 提出,并在 JDK 19 中作为孵化 API 发布,接着又在 JDK 20 中通过 JEP 437 再次孵化,现在该特性进入预览版本了。结构化并发是一种多线程编程方法,它将在不同线程中运行的相关任务组视为单个工作单元,从而简化错误处理和取消操作,提高程序的可靠性和可观察性。

结构化并发和虚拟线程、作用域值一样,都是由 Loom 项目发展而来。

那么到底什么是结构化并发呢?我们不妨从结构化编程的概念开始聊起。

结构化编程(Structured Programming)

计算机发展的早期,程序员必须使用很低级的编程语言去写程序,比如汇编语言,通过一条条的硬件指令去操作计算机,这种编程方式非常痛苦;于是一些计算机界大佬便开始着手重新设计编程语言,使用类似英语的语句来表达操作,这就诞生了一批比汇编语言稍微高级一点的编程语言,如 FORTRAN、FLOW-MATIC、COBOL 等。

这些语言和现在我们所使用的 Java 或者 C 等高级语言还是有一些差距的,没有函数代码块,没有条件或循环控制语句,这些现在看来稀松平常的特性当时还没有被发明出来。设想一下如果程序只能从上往下顺序执行,那么我们就不能复用之前已经编写过的逻辑,想要重新执行一遍之前的逻辑,就得把前面的代码重写一遍,很显然这是非常麻烦的,所以一些设计者在语言中加入了 GOTO 语句,可以让程序在执行时跳转到指定位置,从而实现代码复用。

GOTO 语句的发明使得编程语言变得更加强大,但是这种跳转执行的逻辑使得程序充满了不确定性,一旦程序中大量使用了 GOTO 语句,整个代码就会变得一团糟:

spaghetti.jpg

这种代码如同面条一般,所以被形象地戏称为 面条式代码(Spaghetti Code)

1968 年 3 月,荷兰计算机科学家 Edsger W. Dijkstra 发表了一篇文章 Goto Statement Considered Harmful,提出了著名的 GOTO 有害论;后来,他又编写了一部札记 Notes on Structured Programming,通过大量的篇幅详细阐述了他理想中的编程范式,首次提出了 结构化编程(Structured Programming) 的概念。

structured-programming.jpg

结构化编程的核心思想是 基于块语句,实现代码逻辑的抽象与封装,从而保证控制流拥有单一的入口与出口,现代编程语言中的条件语句、循环语句、方法调用都是结构化编程的体现,我们基于现代编程语言所编写的程序,基本上都是结构化的。

相比 GOTO 语句,结构化编程使代码逻辑变得更加清晰,思维模型变得更加简单;如今,大部分现代编程语言都已经禁用 GOTO 语句,尽管 breakcontinue 语句仍然可以实现跳转逻辑,但是他们还是遵循结构化的基本原则:控制流拥有单一的入口与出口。

少部分编程语言仍然支持 GOTO,但是它们大都遵循高德纳所提出的前进分支和后退分支不得交叉的原则。

结构化并发(Structured Concurrency)

了解了结构化编程的历史后,我们再来看看什么是结构化并发。假设我们有两个独立的任务 task1task2 需要执行,由于它们之间互不影响,我们可以使用 ExecutorService 来并发执行:

private static void testExecutorService() throws Exception {
  System.out.println("main thread start");
  ExecutorService executor = Executors.newCachedThreadPool();
  Future<Integer> f1 = executor.submit(() -> task1(0));
  Future<Integer> f2 = executor.submit(() -> task2(0));
  System.out.println(f1.get());
  System.out.println(f2.get());
  System.out.println("main thread end");
  executor.shutdown();
}

通过 submit 提交任务,并通过 get 等待任务执行结束,代码非常简单,整个流程也非常顺利。然而,真实情况却未必如此,由于子任务并发执行,每个子任务都可能成功或失败,当某个子任务失败时,我们要考虑的事情可能会变得出乎意料地复杂:

  • 如果 task1 运行失败,那么在调用 f1.get() 时会抛出异常,但 task2 将继续在其自己的线程中运行,这是一种线程泄漏,不仅浪费资源,而且可能会干扰其他任务;
  • 如果 task2 运行失败,由于先执行 f1.get(),会阻塞等待 task1 运行结束才会执行 f2.get() 抛出异常,task1 可能会执行很久,这是一种不必要的等待;
  • 如果主线程被中断,该中断不会传播到子任务中,task1task2 线程都会泄漏;
  • 另一种场景中,如果我们只需要 task1task2 中的任意一个结果,这又该如何实现?

其实以上这些场景都可以实现,但需要极其复杂、难以维护的代码,比如 这里 使用 CompletableFuture 演示了三个子任务之间互相取消的场景,其代码的复杂程度应该会吓坏不少人。

此外,这类代码也不好调试,通过线程转储,我们会得到一堆名为 “pool-X-thread-Y” 的线程,我们无法知道哪个子线程属于哪个主线程,每个子线程的运行就像非结构化编程中的 GOTO 一样,不知道会跳转到哪里。这种情况被称为 非结构化并发(Unstructured Concurrency)。我们的任务在一张错综复杂的线程网中运行,其开始与结束在代码中难以察觉,缺乏清晰的错误处理机制,当主线程结束时,常常会出现孤立线程的情况。

结构化并发(Structured Concurrency) 正是为解决这些问题而提出的,它的核心思想和结构化编程一样:在并发模型下,也要保证控制流拥有单一的入口与出口。程序可以产生多个子线程来实现并发,但是所有子线程最终都要在统一的出口处完成合并:

structured-concurrency-vs-unstructured-concurrency.png

使用结构化并发有着诸多好处:

  • 在出口处,所有子线程都应该处于完成或取消状态,所以子线程的开始和结束变得清晰可见,这使得代码更易于阅读和维护;
  • 子线程发生的错误能传播到父线程中,父线程的取消也能传播到子线程中,从而简化了线程之间的错误处理和状态控制;
  • 另外,线程转储还可以保持父线程与子线程之间的调用层次结构,增强了可观察性,有助于程序调试。

使用 StructuredTaskScope 实现结构化并发

在 Java 中,实现结构化并发的基本 API 是 StructuredTaskScope,它的基本用法如下:

private static void testStructuredTaskScope() throws Exception {
  System.out.println("main thread start");
  try (var scope = new StructuredTaskScope<Object>()) {
    Subtask<Integer> t1 = scope.fork(() -> task1(0));
    Subtask<Integer> t2 = scope.fork(() -> task2(0));
    scope.join();
    System.out.println(t1.get());
    System.out.println(t2.get());
  }
  System.out.println("main thread end");
}

这里实现了和之前代码同样的逻辑,只是写法上略有区分,我们将 ExecutorService 替换为 StructuredTaskScope,并将 executor.submit() 替换为 scope.fork(),然后使用 scope.join() 等待所有任务完成。之后,我们可以通过 Subtask.get() 读取子任务的结果,如果某个子任务发生异常,Subtask.get() 会抛出 IllegalStateException 异常。因此,在调用 get() 之前,最好先用 state() 查询子任务的状态:

if (t1.state() == Subtask.State.SUCCESS) {
  System.out.println(t1.get());
} else {
  System.out.println("task1 error: " + t1.exception().getMessage());
}

StructuredTaskScope 的关闭策略

scope.join() 可以保证所有子线程全部处于完成或取消状态,这样可以消除孤儿线程的风险。但是在有些场景下,如果某个子线程异常,等待其他子任务的结果就没有了意义,这时我们可以取消其他子任务,避免无谓的等待;还有些情况是,只要有一个子任务运行成功即可,无需等待所有任务都运行结束。这就引出了 StructuredTaskScope关闭策略(Shutdown policies)StructuredTaskScope 定义了两种关闭策略,分别处理这两种情况:

ShutdownOnFailure 策略

使用 ShutdownOnFailure 策略,当某个子任务中发生异常时,将导致所有其他子任务终止。它的使用方法如下所示:

private static void testStructuredTaskScopeShutdownOnFailure() throws Exception {
  System.out.println("main thread start");
  try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
    Subtask<Integer> t1 = scope.fork(() -> task1(1));
    Subtask<Integer> t2 = scope.fork(() -> task2(0));
    scope.join().throwIfFailed();
    System.out.println(t1.get());
    System.out.println(t2.get());
  }
  System.out.println("main thread end");
}

首先,我们使用 new StructuredTaskScope.ShutdownOnFailure() 创建一个 ShutdownOnFailure 策略的 StructuredTaskScope,然后在 scope.join() 的时候,通过 throwIfFailed() 让其在子任务失败时抛出异常。假设 task1 异常,运行结果如下:

main thread start
task1 start
task2 start
java.lang.InterruptedException
  at java.base/java.lang.VirtualThread.sleepNanos(VirtualThread.java:805)
  at java.base/java.lang.Thread.sleep(Thread.java:507)
  at StructuredConcurrencyDemo.task2(StructuredConcurrencyDemo.java:91)
  at StructuredConcurrencyDemo.lambda$9(StructuredConcurrencyDemo.java:130)
  at java.base/java.util.concurrent.StructuredTaskScope$SubtaskImpl.run(StructuredTaskScope.java:889)
  at java.base/java.lang.VirtualThread.run(VirtualThread.java:311)
task2 end
Exception in thread "main" java.util.concurrent.ExecutionException: java.lang.RuntimeException: code is illegal
  at java.base/java.util.concurrent.StructuredTaskScope$ShutdownOnFailure.throwIfFailed(StructuredTaskScope.java:1318)
  at java.base/java.util.concurrent.StructuredTaskScope$ShutdownOnFailure.throwIfFailed(StructuredTaskScope.java:1295)
  at StructuredConcurrencyDemo.testStructuredTaskScopeShutdownOnFailure(StructuredConcurrencyDemo.java:131)
  at StructuredConcurrencyDemo.main(StructuredConcurrencyDemo.java:14)
Caused by: java.lang.RuntimeException: code is illegal
  at StructuredConcurrencyDemo.task1(StructuredConcurrencyDemo.java:74)
  at StructuredConcurrencyDemo.lambda$8(StructuredConcurrencyDemo.java:129)
  at java.base/java.util.concurrent.StructuredTaskScope$SubtaskImpl.run(StructuredTaskScope.java:889)
  at java.base/java.lang.VirtualThread.run(VirtualThread.java:311)

可以看到当 task1 异常时,task2 出现了 InterruptedException,说明 task2 被中断了,从而避免了无谓的等待。

ShutdownOnSuccess 策略

使用 ShutdownOnSuccess 策略,只要某个子任务中成功,将导致所有其他子任务终止。它的使用方法如下所示:

private static void testStructuredTaskScopeShutdownOnSuccess() throws Exception {
  System.out.println("main thread start");
  try (var scope = new StructuredTaskScope.ShutdownOnSuccess<Object>()) {
    scope.fork(() -> task1(0));
    scope.fork(() -> task2(0));
    scope.join();
    System.out.println(scope.result());
  }
  System.out.println("main thread end");
}

首先,我们使用 new StructuredTaskScope.ShutdownOnSuccess<Object>() 创建一个 ShutdownOnSuccess 策略的 StructuredTaskScope,然后通过 scope.join() 等待子任务结束,任意一个子任务结束,整个 StructuredTaskScope 都会结束,并保证其他子任务被取消,最后通过 scope.result() 获取第一个运行成功的子任务结果。运行结果如下:

main thread start
task1 start
task2 start
task2 end
2
java.lang.InterruptedException
  at java.base/java.lang.VirtualThread.sleepNanos(VirtualThread.java:805)
  at java.base/java.lang.Thread.sleep(Thread.java:507)
  at StructuredConcurrencyDemo.task1(StructuredConcurrencyDemo.java:78)
  at StructuredConcurrencyDemo.lambda$10(StructuredConcurrencyDemo.java:142)
  at java.base/java.util.concurrent.StructuredTaskScope$SubtaskImpl.run(StructuredTaskScope.java:889)
  at java.base/java.lang.VirtualThread.run(VirtualThread.java:311)
task1 end
main thread end

可以看到当 task2 最先运行结束,所以输出了 task2 的结果,同时 task1 出现了 InterruptedException,说明 task1 被中断了,避免了线程泄露。

自定义关闭策略

如果这两个标准策略都不满足你的需求,我们还可以编写自定义的策略,通过继承 StructuredTaskScope 类,并重写其 handleComplete(...) 方法,从而实现不同于 ShutdownOnSuccessShutdownOnFailure 的策略。这里 有一个自定义关闭策略的示例可供参考。

可观察性

使用结构化并发的另一个好处是,线程是有层次结构的,我们可以从线程转储中看到某个主线程都派生了哪些子线程,也可以看出某个子线程来自于哪个主线程,从而方便问题排查。使用下面的命令以 JSON 格式进行线程转储:

$ jcmd <pid> Thread.dump_to_file -format=json threads.json

从转储结果中可以清晰的看到线程之间的层次结构:

{
  "container": "java.util.concurrent.StructuredTaskScope$ShutdownOnSuccess@58644d46",
  "parent": "<root>",
  "owner": "1",
  "threads": [
    {
      "tid": "19",
      "name": "",
      "stack": [
        "java.base\/java.lang.VirtualThread.parkNanos(VirtualThread.java:631)",
        "java.base\/java.lang.VirtualThread.sleepNanos(VirtualThread.java:803)",
        "java.base\/java.lang.Thread.sleep(Thread.java:507)",
        "StructuredConcurrencyDemo.task1(StructuredConcurrencyDemo.java:78)",
        "StructuredConcurrencyDemo.lambda$10(StructuredConcurrencyDemo.java:142)",
        "java.base\/java.util.concurrent.StructuredTaskScope$SubtaskImpl.run(StructuredTaskScope.java:889)",
        "java.base\/java.lang.VirtualThread.run(VirtualThread.java:311)"
      ]
    },
    {
      "tid": "21",
      "name": "",
      "stack": [
        "java.base\/java.lang.VirtualThread.parkNanos(VirtualThread.java:631)",
        "java.base\/java.lang.VirtualThread.sleepNanos(VirtualThread.java:803)",
        "java.base\/java.lang.Thread.sleep(Thread.java:507)",
        "StructuredConcurrencyDemo.task2(StructuredConcurrencyDemo.java:92)",
        "StructuredConcurrencyDemo.lambda$11(StructuredConcurrencyDemo.java:143)",
        "java.base\/java.util.concurrent.StructuredTaskScope$SubtaskImpl.run(StructuredTaskScope.java:889)",
        "java.base\/java.lang.VirtualThread.run(VirtualThread.java:311)"
      ]
    }
  ],
  "threadCount": "2"
}

小结

今天我们学习了 Java 21 中的 结构化并发(Structured Concurrency) 特性,这是 Loom 项目的重要成果,它借鉴了结构化编程的核心思想,将并发编程中的多个子任务视为单个工作单元进行统一管理。主要内容包括:

  1. 核心思想 - 结构化并发将结构化编程的原则引入并发编程,保证控制流拥有单一的入口与出口。所有子线程在统一的出口处完成合并,使得任务的开始与结束变得清晰可见,代码逻辑更易于理解和维护,这一设计有效解决了传统非结构化并发中的线程泄漏、错误处理复杂、可观察性差等问题;
  2. StructuredTaskScope API - Java 提供了 StructuredTaskScope 作为实现结构化并发的基础 API,它通过 fork() 提交任务,通过 join() 等待任务完成,为子任务的生命周期管理提供了清晰的语义。同时通过关闭策略(如 ShutdownOnFailureShutdownOnSuccess)来满足不同的并发场景需求,还支持自定义关闭策略以应对复杂的业务逻辑;
  3. 增强的可观察性 - 结构化并发带来的一个重要好处是线程之间拥有清晰的层次结构。通过 jcmd 工具生成的线程转储能够直观地展示父线程与子线程的关系,这对于问题排查和性能分析提供了极大的便利,使得高并发应用的调试与维护变得更加高效。

结构化并发与虚拟线程、作用域值等特性共同构成了 Java 高性能并发编程的新范式,有望为 Java 应用程序的构建方式带来深刻的变革。当这些特性结合使用时,开发者将能够编写更加清晰、可靠、易于维护的高吞吐量并发应用程序,这对 Java 在云计算、微服务和高并发场景中的应用具有重要意义。