# 5 分钟从 LiteLLM 迁移

换一个基础 URL 和密钥，把应用从 LiteLLM 代理迁到 Kaeso，再把 config.yaml 的其余部分逐项搬过来。

网页：https://kaeso.app/zh-CN/articles/migrate-from-litellm
其他语言：[English](https://kaeso.app/articles/migrate-from-litellm.md) · [Deutsch](https://kaeso.app/de/articles/migrate-from-litellm.md)

作者：Kaeso Team · 5 November 2026

如果您的应用现在调用的是 LiteLLM 代理，它们已经在说 OpenAI 或 Anthropic 的 API。Kaeso 两种都说。所以迁移一个应用，主要就是换个地址：新的基础 URL，新的密钥。代码、SDK 和流式接收回复的方式都不用变。

这 5 分钟指的就是这次切换：启动 Kaeso，连接一个服务商，把一个应用指向它。一份很长的 `config.yaml` 需要更久才能搬完，所以本指南的后半部分逐项讲解：模型、回退、密钥、预算、缓存和日志，也包括哪些地方做法不同，以及 Kaeso 不做的少数几件事。

迁移期间请让 LiteLLM 继续运行。这里的任何步骤都不会改动它，任何应用只要把基础 URL 改回去就能回退。

## 开始之前

- **一台服务器。** 装有 Docker Engine 和 Docker Compose 2.24 或更新版本的 Linux，2 个 vCPU、4 GB 内存和 20 GB 磁盘。想先在自己的电脑上试用，把域名设为 `localhost` 即可。
- **一个域名**，其 DNS 记录指向这台服务器，并开放 80 和 443 端口，以便自带的 Caddy 获取证书。
- **您的服务商密钥。** 也就是 LiteLLM 现在用的那些；`config.yaml` 里写作 `os.environ/OPENAI_API_KEY` 之类。
- **一台 SMTP 服务器**，用于发送登录链接和邀请。试用时可以先不配。

## 切换

### 启动 Kaeso

每个版本都会发布一份 `compose.yaml`，用来运行网关、控制台、PostgreSQL、存放请求日志的 ClickHouse、Valkey 和 Caddy。下载它，写好设置，然后全部启动：

```bash
mkdir -m 700 kaeso && cd kaeso
curl -fsSLO https://github.com/logicplanes/kaeso/releases/latest/download/compose.yaml

umask 077
cat > .env <<EOF
KAESO_DOMAIN=kaeso.example.com
POSTGRES_PASSWORD=$(openssl rand -hex 24)
POSTGRES_SUPERUSER_PASSWORD=$(openssl rand -hex 24)
CLICKHOUSE_PASSWORD=$(openssl rand -hex 24)
VALKEY_PASSWORD=$(openssl rand -hex 24)
KAESO_MAIL_TRANSPORT=log
EOF

docker run --rm ghcr.io/logicplanes/kaeso-gateway:latest master-key generate > master-keys
sudo chown 65532:65532 master-keys && sudo chmod 0400 master-keys

docker compose up -d --wait
docker compose exec gateway kaeso setup-link
```

首次启动需要一两分钟来下载镜像。在 Docker Desktop 或 Colima 上，只运行 `chmod 0400 master-keys`，不运行 `chown` 那一行。

`KAESO_MAIL_TRANSPORT=log` 会把邮件写进网关的日志，而不是发出去，一个人试用时足够了。邀请他人之前，请换成您的 SMTP 服务器（[邮件设置](https://docs.kaeso.app/zh-CN/self-hosting/email)）。

这里有个名字指的是两回事。Kaeso 的主密钥用来加密它存储的服务商密钥；它不是 LiteLLM 的 `master_key`，也不能用来调用模型。请把 `master-keys` 的副本妥善保存，并与数据库备份分开存放。

最后一条命令会打印一个设置链接。打开它，填写您的姓名、邮箱、密码和组织名称，然后选择**设置 Kaeso**。现在您就是实例管理员，也是该组织的所有者。

### 连接服务商

打开**服务商**，选择**添加服务商密钥**，选好服务商并粘贴它的密钥。一个服务商的第一个密钥会成为它的默认密钥，所有项目都会使用它。

Kaeso 加密存储这个密钥，之后不再显示。应用永远看不到它：它们用自己的密钥调用 Kaeso。

### 添加模型

请求只能指定项目目录中的模型，这和 LiteLLM 基本只服务 `model_list` 里列出的模型类似。在**项目**中选择**创建项目**，用应用的名字命名。然后打开**模型**，选择**添加模型**，搜索应用要调用的模型，例如 `claude-sonnet-5-5` 或 `gpt-6-sol`，把它们添加进来。

价格和上下文窗口不用自己填。它们来自 [KPMR](https://kpmr.kaeso.app)，即 Kaeso Provider & Model Registry，实例会自动保持更新。

### 创建密钥

在项目中选择 **API 密钥**，再选择**创建密钥**。用应用的名字命名，访问权限保持**模型调用**，并选择有效期。关闭对话框之前复制密钥 `sk-kso-…`：Kaeso 只保留它的哈希。

### 把应用指向 Kaeso

改基础 URL 和密钥，别的都不用动：

```diff
 import os
 from openai import OpenAI

 client = OpenAI(
-    base_url="http://litellm.internal:4000",
-    api_key=os.environ["LITELLM_API_KEY"],
+    base_url="https://kaeso.example.com/v1",
+    api_key=os.environ["KAESO_API_KEY"],
 )
```

如果应用从环境变量读取设置，就改这些变量：

```bash
OPENAI_BASE_URL=https://kaeso.example.com/v1
OPENAI_API_KEY=sk-kso-…

ANTHROPIC_BASE_URL=https://kaeso.example.com
ANTHROPIC_API_KEY=sk-kso-…
```

注意 `/v1`。LiteLLM 在 `/chat/completions` 和 `/v1/chat/completions` 上都会应答，所以很多应用让 OpenAI SDK 直接指向主机地址。Kaeso 只在 `/v1` 下提供模型 API，域名下的其余路径都是控制台。Anthropic SDK 正好相反：它会自己加上 `/v1`，所以它的基础 URL 就是域名本身。

| SDK | 基础 URL | 密钥的发送方式 |
| --- | --- | --- |
| OpenAI | `https://kaeso.example.com/v1` | `Authorization: Bearer` |
| Anthropic | `https://kaeso.example.com` | `x-api-key` 或 `Authorization: Bearer` |

发送一个请求。每个应答都带有 `kaeso-request-id` 请求头，几秒后，项目的**请求日志**就会显示这个请求的状态、Token、费用和耗时。切换就完成了。

和 LiteLLM 一样，任何 SDK 都能调用任何聊天模型，所以 OpenAI SDK 也能调用 Claude。如果应用发送了模型的服务商不接受的字段，Kaeso 不会悄悄丢掉它，而是拒绝请求，并在错误中指出这个字段，这样任何设置都不会在您不知情时丢失。

### Claude Code 和 Codex

编程工具和其他应用一样。对 Claude Code，在 `~/.claude/settings.json` 中改两个值：

```json
{
  "env": {
    "ANTHROPIC_BASE_URL": "https://kaeso.example.com",
    "ANTHROPIC_AUTH_TOKEN": "sk-kso-…"
  }
}
```

Claude Code 会调用一个 Opus、一个 Sonnet 和一个 Haiku 模型，最后一个用于后台任务，所以这三个都需要在项目目录中。`ANTHROPIC_DEFAULT_OPUS_MODEL`、`ANTHROPIC_DEFAULT_SONNET_MODEL` 和 `ANTHROPIC_DEFAULT_HAIKU_MODEL` 决定具体用哪几个，也可以填别名。对 Codex，把 Kaeso 添加为模型服务商，设置 `base_url = "https://kaeso.example.com/v1"` 和 `wire_api = "responses"`。[编程工具](https://docs.kaeso.app/zh-CN/get-started/coding-tools) 里有两份文件的完整内容。

## 逐行解读 config.yaml

下面是一份很多团队都在用的那类 LiteLLM 配置：三个模型，其中一个用了自定义名称，外加回退、重试、Redis 缓存，以及存放密钥和支出的数据库。

```yaml
model_list:
  - model_name: claude-sonnet-5-5
    litellm_params:
      model: anthropic/claude-sonnet-5-5
      api_key: os.environ/ANTHROPIC_API_KEY
  - model_name: gpt-6-sol
    litellm_params:
      model: openai/gpt-6-sol
      api_key: os.environ/OPENAI_API_KEY
  - model_name: fast
    litellm_params:
      model: openai/gpt-5.4-mini
      api_key: os.environ/OPENAI_API_KEY

litellm_settings:
  num_retries: 2
  fallbacks: [{"claude-sonnet-5-5": ["gpt-6-sol"]}]
  context_window_fallbacks: [{"fast": ["claude-sonnet-5-5"]}]
  cache: true
  cache_params: {type: redis}

general_settings:
  master_key: os.environ/LITELLM_MASTER_KEY
  database_url: os.environ/DATABASE_URL
```

在 Kaeso 中，这些都不放在文件里。您在控制台中设置，或者用脚本通过 Platform API 设置，审计日志会记录每一次更改。

| config.yaml 中 | Kaeso 中 |
| --- | --- |
| `api_key: os.environ/…` | **服务商**页面上的服务商密钥，加密存储 |
| `model_list` | **模型**页面上的项目目录 |
| `model_name: claude-sonnet-5-5` | 模型本身：应用继续发送同一个名称 |
| `model_name: fast` | 名为 `fast` 的别名 |
| `fallbacks`、`context_window_fallbacks` | 别名的路由，带回退 |
| `num_retries` | SDK 自带的重试 |
| `cache: true` | 项目的响应缓存 |
| `master_key` | 给人用的控制台账户，给脚本用的平台密钥 |
| `database_url`、Redis | `compose.yaml` 中的 PostgreSQL、ClickHouse 和 Valkey |
| 虚拟密钥 | API 密钥 `sk-kso-…`，每个应用一个 |
| 团队 | 项目 |
| `max_budget`、`tpm_limit`、`rpm_limit` | 项目、成员或密钥上的限额 |

下面各节逐一说明。

## 模型和服务商

### 应用已经在发送的名称

如果 `model_name` 就是服务商自己的模型 ID，例如 `claude-sonnet-5-5`，只需把这个模型加入目录。应用照常发送它。

自己起的名称，例如 `fast`，就成为一个别名。在**模型**中打开**别名**，选择**创建别名**，命名为 `fast` 并选择 `gpt-5.4-mini`。应用发送 `fast`，以后您可以把它换到另一个模型上，不用改动应用。

Kaeso 也认 `provider/model` 的写法，所以像 `anthropic/claude-sonnet-5-5` 这样的名称可以原样使用。不过别名不能包含 `/`，所以像 `prod/claude` 这样的 LiteLLM 名称需要在应用中修改。

### 服务商前缀

`litellm_params.model` 中的 LiteLLM 前缀告诉您要添加哪个服务商密钥。大多数在 Kaeso 中名称相同，少数拼写不同：

| LiteLLM | Kaeso |
| --- | --- |
| `openai/`、`anthropic/`、`groq/`、`mistral/`、`deepseek/`、`xai/`、`cerebras/`、`openrouter/` | 相同的 ID |
| `together_ai/` | `togetherai` |
| `cohere/`、`cohere_chat/` | `cohere` |
| `moonshot/` | `moonshotai` |
| `dashscope/` | `alibaba`，即 QwenCloud |
| `vercel_ai_gateway/` | `vercel` |

配置很大时，有两个捷径。**添加所有当前 OpenAI 模型**，以及其他每个服务商对应的同类按钮，可以代替 `openai/*` 这样的通配符；它添加服务商现有的模型，不会添加以后出现的模型。另外，当两个服务商提供相同的模型 ID 时，写明您要的那个，例如 `groq/openai/gpt-oss-120b`。

### 自己设定的价格

LiteLLM 的 `input_cost_per_token` 和 `output_cost_per_token` 以每 Token 美元计。Kaeso 的价格以每百万 Token 美元计，所以乘以一百万：`0.000003` 就是 `3`。打开模型的侧滑面板，选择**编辑覆盖值**并填入价格。它只对当前项目生效，**恢复为 KPMR 的值**可以撤销。

### 自托管的服务器

带有 `api_base` 的条目，例如 vLLM、Ollama 或 LM Studio 服务器，会成为自定义服务商。在**服务商**中打开**自定义服务商**，选择**添加自定义服务商**，填入基础 URL 和密钥，再选择**检测设置**。Kaeso 会询问服务器该如何调用它，并在您把模型添加到项目时列出它的模型。

Kaeso 无从知道您的服务器成本，所以每个模型的价格需要您来填；不按 Token 付费的硬件填 `0` 即可。如果服务器位于私有地址，请在 `compose.yaml` 旁边的 `compose.override.yaml` 中允许它所在的网络，再用 `docker compose up -d --wait` 应用：

```yaml
services:
  gateway:
    environment:
      KAESO_CUSTOM_PROVIDERS_ALLOWED_NETWORKS: 10.0.0.0/8
```

### Kaeso 没有的服务商

Kaeso 内置了 14 个服务商：Anthropic、Cerebras、Cohere、DeepSeek、Groq、Mistral、Moonshot、Ollama Cloud、OpenAI、OpenRouter、QwenCloud、SpaceX、Together AI 和 Vercel AI Gateway。Azure OpenAI、Amazon Bedrock、Google Vertex AI 和 Gemini API 不在其中。如果您的配置用到了 `azure/`、`bedrock/`、`vertex_ai/` 或 `gemini/`，有两条路。Gemini 模型也可以通过 OpenRouter 和 Vercel AI Gateway 调用，例如 `openrouter/google/gemini-2.5-pro`。其余的，可以把 LiteLLM 留在 Kaeso 后面，做法见本指南末尾。

## 回退、重试和负载均衡

### 回退

在 LiteLLM 中，回退是一个按模型名称组织的列表。在 Kaeso 中，回退属于别名：别名的路由先尝试一个模型，再尝试下一个。路由随 Kaeso 0.6.0 推出，撰写本文时它还处于候选版本阶段；在 0.5.6 中，一个别名只指向一个模型。

要让应用继续发送原来的名称，就给别名起这个名字。别名优先于同名模型，列表中会标记为**遮蔽同名模型**。对上面的配置：

1. 创建一个名为 `claude-sonnet-5-5` 的别名。
2. 在**从模板开始**中选择**回退链**。
3. 把 `claude-sonnet-5-5` 设为第一步，`gpt-6-sol` 设为它的回退，然后选择**保存**。

当一步的模型不可用、触发速率限制，或无法处理请求中的某些内容（例如图片）时，这一步就会回退。对应的原因是 `unavailable`、`limited` 和 `unsupported`，也就是默认值。第四个原因 `rejected` 覆盖了 `context_window_fallbacks` 和 `content_policy_fallbacks` 的作用：服务商因为上下文过长或内容本身而拒绝了请求。只有当回退模型能接受第一个模型拒绝的内容时，才加上它。

对于长提示词，有比等待报错更好的办法。**从模板开始**还提供**长提示词另走**：根据请求的输入 Token 数设置条件，让长提示词直接发往上下文更大的模型。

对别名的每个应答都带有 `kaeso-route` 请求头，列出请求尝试过的每一步及其状态。请求日志在**先尝试的模型**下记录同样的步骤，**测试**标签页则能在保存之前显示请求会去往哪里。

### 重试

Kaeso 每个请求只发送一次。OpenAI 和 Anthropic 的 SDK 在错误允许时会自行重试，默认两次。如果您过去依靠 `num_retries` 在代理上重试，请改为调高客户端的 `max_retries`（TypeScript 中为 `maxRetries`）。

### 负载均衡

同一个 `model_name` 下的多个条目，例如同一模型配两个密钥，没有直接对应的做法。一个项目对每个服务商只用一个密钥，Kaeso 不会合并多个密钥，也不会按延迟或用量挑选部署。要把负载分散到多个服务商账户，可以用**分配给项目**把某个服务商密钥分配给部分项目。要在模型之间分配流量，可以在路由中使用分流：它按权重把每个请求送往其中一个分支，可以按请求、按调用方或按某个请求头的值来分。

## 密钥、团队和预算

### 每个应用都换新密钥

LiteLLM 的虚拟密钥不会迁移过来：Kaeso 签发自己的密钥，并且只保留它们的哈希。每个应用都会拿到一个新密钥，反正这也是您要对它做的唯一改动。

团队对应项目。每个项目有自己的目录、密钥、限额和日志，成员以某个角色加入：管理员、开发者或查看者。给软件用服务账号，而不是某个人的密钥，这样那个人离开后，它的密钥仍然有效。

### 虚拟密钥的设置对应什么

| `/key/generate` | Kaeso |
| --- | --- |
| `key_alias` | 密钥的名称 |
| `models` | 密钥的**模型** |
| `duration` | 有效期：1、7、30 或 90 天，某个日期，或永不过期 |
| `max_budget` 加 `budget_duration` | 按天、按月或总计的支出预算 |
| `tpm_limit` | Token 速率 |
| `rpm_limit` | 请求速率 |
| `team_id` | 项目 |
| `user_id` | 拥有该密钥的成员或服务账号 |

Kaeso 的天和月指 UTC 的自然日和自然月，所以 `budget_duration` 为 `30d` 时对应月度预算，`1d` 对应每日预算。预算默认是硬性的，用完后会拒绝请求；关掉这一项，它就只发提醒，默认在 50%、80% 和 100% 时发送。Kaeso 没有并发请求数限额，所以 `max_parallel_requests` 没有对应项，密钥的 `metadata` 也没有：请求日志和用量中显示的是密钥的名称。

限额是逐层嵌套的。密钥的预算不能高于其所有者的预算，所有者的预算不能高于项目的预算，所以 LiteLLM 中的团队预算对应项目上的限额。

### 批量创建密钥

有几十个密钥时，请用 Platform API。在**组织设置** › **平台密钥**中创建一个平台密钥，然后为每个应用创建一个服务账号，以及一个带限额的密钥：

```bash
ORG_URL=https://kaeso.example.com/platform/v1/orgs/org_…
PROJECT=proj_…

ACCOUNT=$(curl -s "$ORG_URL/projects/$PROJECT/service-accounts" \
  -H "Authorization: Bearer $KAESO_PLATFORM_KEY" \
  -H "content-type: application/json" \
  -d '{"name": "support-bot", "role": "developer"}' | jq -r .id)

curl -s "$ORG_URL/projects/$PROJECT/service-accounts/$ACCOUNT/keys" \
  -H "Authorization: Bearer $KAESO_PLATFORM_KEY" \
  -H "content-type: application/json" \
  -d '{
    "name": "support-bot",
    "expires_in_days": 90,
    "limits": [
      {"kind": "spend_budget", "period": "month", "amount": "50"},
      {"kind": "request_rate", "period": "minute", "amount": 600}
    ]
  }' | jq -r .secret
```

最后一条命令会打印一次新密钥。把它存到应用读取的位置。[用 Platform API 自动化](https://docs.kaeso.app/zh-CN/api/automation) 涵盖其余内容，从添加模型到轮换密钥。

## 缓存

`cache: true` 变成每个项目的一个开关。打开项目的**设置**，在**响应缓存**下开启**缓存回复**，再选择回复保留多久，从 5 分钟到 7 天。

只有当请求与之前的某个请求完全相同时，缓存才会应答；比较发生在格式转换之后，所以 OpenAI 应用和 Anthropic 应用可以共用同一条缓存。它只存储非流式回复，并且只在项目内部共享。没有语义缓存。应用可以用标准的 `Cache-Control` 请求头逐个控制请求：`no-cache` 重新询问服务商，`no-store` 跳过缓存。每个应答都会在 `kaeso-cache` 中说明缓存做了什么，命中缓存不会消耗预算。

## 日志和支出

Kaeso 自己记录每个请求：模型、服务商、状态、Token、费用、耗时、密钥和发送者，默认还包括发送和返回的内容。保留多久由组织决定：如果不改，元数据保留 90 天，内容保留 30 天。要像 `turn_off_message_logging` 那样完全不保留提示词，请在**组织设置** › **日志记录**中关闭**记录请求内容**，也可以只对单个项目关闭。

用量可以按天、模型、密钥或成员查看，在控制台中或通过 Platform API 都行，请求日志可以导出为 CSV 或 JSON Lines。网关在单独的端口上提供 Prometheus 指标，供您的仪表盘使用。

Kaeso 不会把日志转发给外部工具，所以 Langfuse、Datadog 这类回调没有对应项；请改为读取 Platform API 的日志或导出文件。历史支出也不会迁移过来。Kaeso 从它处理的第一个请求开始计数，所以如果需要历史记录，请保留一份 LiteLLM 数据库的转储。

## Kaeso 不做的，交给 LiteLLM

Kaeso 的模型 API 涵盖 Chat Completions、Responses、Messages、Embeddings、Token 计数和模型列表。它没有图片、音频、重排序、内容审核、文件或批处理的端点，没有透传路由，也没有防护栏，而且不为您的应用代理 MCP 服务器。它还会拒绝要求服务商存储或续接回复的 Responses 请求，例如带 `previous_response_id` 的请求；请每次都发送完整的对话。

这些端点请继续直接调用 LiteLLM；一个应用同时使用两者完全没问题。对于 Kaeso 没有的服务商，您还可以更进一步，把 LiteLLM 作为自定义服务商放在 Kaeso 后面：

1. 在 LiteLLM 中创建一个虚拟密钥，只允许访问 Kaeso 需要用到的模型，例如您的 Bedrock 和 Azure 条目。
2. 如果 LiteLLM 位于私有地址，在 `compose.override.yaml` 中允许它所在的网络，做法与自托管服务器相同。
3. 在 Kaeso 中选择**添加自定义服务商**，填入 LiteLLM 的地址，例如 `http://10.0.0.12:4000/v1`，以及这个密钥。**检测设置**会识别出 Chat Completions。把 **ID** 设为 `litellm`。
4. 把它的模型添加到项目并填入价格。Kaeso 按这些价格计费，并据此执行预算。

之后，应用在 LiteLLM 的 `model_name` 前加上这个 ID 来调用，例如 `litellm/bedrock-claude`，也可以调用以它命名的别名，使用的密钥和基础 URL 与其他模型相同。Kaeso 的密钥、限额和日志对这些请求同样适用。

## 切回去，以及关掉 LiteLLM

在停掉 LiteLLM 之前，回退就是反向做同样的改动：旧的基础 URL 和旧的密钥。一次迁移一个应用，看着它的请求出现在 Kaeso 的请求日志中。

当每个应用的流量都出现在 Kaeso 中、LiteLLM 的日志也安静下来，就为它的数据库做最后一次转储，然后停掉它。如果您的配置里有哪部分在上面各节中都找不到对应，[请告诉我们](https://kaeso.app/zh-CN/contact)。这能帮助决定 Kaeso 下一步做什么。
