# 从其他服务迁移

URL: https://docs.router.ezat.io/zh/tools/migrate

> 把调用 Anthropic API 或 OpenRouter 等 OpenAI 兼容路由服务的代码迁移到 EZAT Router，以及迁移后要检查什么。

## 何时阅读本页

你的代码或工具已经在调用 Anthropic 的 API，或 OpenRouter 这样的 OpenAI 兼容路由服务，你想让它改为调用 EZAT Router。大多数情况下，只需修改 base URL 和 key，再检查一下模型名称。

## 从 Anthropic API 迁移

EZAT 支持 Anthropic 的 Messages 格式，而且 Anthropic 的模型名称是 EZAT id 的别名，所以为 Anthropic API 编写的代码无需修改即可使用。

| | Anthropic API | EZAT Router |
| --- | --- | --- |
| Base URL | `https://api.anthropic.com` | `https://api.router.ezat.io` |
| Key | Anthropic Console key | 你的 EZAT key（`ezat_sk_…`），放在 `x-api-key` 或 `Authorization: Bearer` 中 |
| 模型名称 | `claude-sonnet-5-5` 及其他 Anthropic 名称 | 同样的名称都可以使用。EZAT 自己的 id 格式为 `author/model`，例如 `anthropic/claude-sonnet-5-5`。 |
| 响应中的 `model` | 你发送的名称 | 你发送的名称 |
| 错误 | Anthropic 的格式 | Anthropic 的格式，另外余额用完时返回 `402` `billing_error` |

最快的切换方式不需要改代码。Anthropic SDK 会读取 `ANTHROPIC_BASE_URL` 和 `ANTHROPIC_API_KEY`：

```bash
export ANTHROPIC_BASE_URL="https://api.router.ezat.io"
export ANTHROPIC_API_KEY="$EZAT_API_KEY"
```

也可以把两者都传给客户端。修改前：

```python
client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
```

修改后：

```python tab="Python" test
import os

import anthropic

client = anthropic.Anthropic(
    base_url="https://api.router.ezat.io",
    api_key=os.environ["EZAT_API_KEY"],
)

message = client.messages.create(
    model="anthropic/claude-sonnet-5-5",
    max_tokens=64,
    messages=[{"role": "user", "content": "Say hello in five words."}],
)
print("".join(block.text for block in message.content if block.type == "text"))
```

```ts tab="TypeScript" test
import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic({
  baseURL: "https://api.router.ezat.io",
  apiKey: process.env.EZAT_API_KEY,
});

const message = await client.messages.create({
  model: "anthropic/claude-sonnet-5-5",
  max_tokens: 64,
  messages: [{ role: "user", content: "Say hello in five words." }],
});
console.log(message.content.filter((block) => block.type === "text").map((block) => block.text).join(""));
```

Claude Code 见 [Claude Code](https://docs.router.ezat.io/zh/tools/claude-code.md)：它使用 `ANTHROPIC_AUTH_TOKEN`，而不是 `ANTHROPIC_API_KEY`。

与 Anthropic 自己的 API 不同的地方：

- **不可用**：Message Batches API、Files API、服务端工具（网页搜索、代码执行）和 MCP connector。图片必须以 base64 发送，不能通过 URL。
- **`anthropic-beta`** 会传给模型提供方，而提供方不一定接受 Anthropic API 支持的所有 beta。
- **非流式请求在 590 秒后结束**，返回 `504` `timeout_error`。长请求请使用流式输出。
- **限额**按 EZAT key 计算（[速率限制](https://docs.router.ezat.io/zh/reference/rate-limits.md)）。EZAT 不发送 `anthropic-ratelimit-*` 响应头。
- **提示缓存（prompt caching）从空开始**。你最初的几个请求会重新写入缓存。

完整列表见 [Anthropic Messages API](https://docs.router.ezat.io/zh/anthropic/messages.md)。

## 从 OpenRouter 和其他 OpenAI 兼容路由服务迁移

使用 EZAT 的 [OpenAI 兼容 API](https://docs.router.ezat.io/zh/openai/base-url.md)。修改 base URL 和 key，并逐个检查模型 id。

| | OpenRouter | EZAT Router |
| --- | --- | --- |
| Base URL | `https://openrouter.ai/api/v1` | `https://api.router.ezat.io/openai/v1` |
| Key | OpenRouter key | 你的 EZAT key，以 `Authorization: Bearer` 发送 |
| 模型 id | `author/model`，版本号中用点号：`anthropic/claude-sonnet-5.5` | `author/model`，用连字符：`anthropic/claude-sonnet-5-5`。不带作者、带点号的名称 `claude-sonnet-5.5` 是别名。 |
| 提供的模型 | 来自很多厂商 | [模型](https://docs.router.ezat.io/zh/models.md)页面上列出的模型 |
| 内容部分上的 `cache_control` | 支持 | 支持，用法相同。你没有设置时，EZAT 还会自动缓存。 |
| `reasoning` 等路由服务特有的字段 | 生效 | 忽略。请使用 `reasoning_effort`。 |
| `web_search_options` | 生效 | 以 `400` 拒绝 |

<Callout type="warn" title="改写带点号的模型 id">
`anthropic/claude-sonnet-5.5` 不是 EZAT 的 id，会返回 `404` `model_not_found`。把点号换成连字符（`anthropic/claude-sonnet-5-5`），或者去掉 `anthropic/` 前缀（`claude-sonnet-5.5`）。`GET https://api.router.ezat.io/openai/v1/models` 会列出所有 id。
</Callout>

修改前：

```python
client = OpenAI(
    base_url="https://openrouter.ai/api/v1",
    api_key=os.environ["OPENROUTER_API_KEY"],
)
```

修改后：

```python tab="Python" test
import os

from openai import OpenAI

client = OpenAI(
    base_url="https://api.router.ezat.io/openai/v1",
    api_key=os.environ["EZAT_API_KEY"],
)

completion = client.chat.completions.create(
    model="anthropic/claude-sonnet-5-5",
    max_tokens=64,
    messages=[{"role": "user", "content": "Say hello in five words."}],
)
print(completion.choices[0].message.content)
```

```ts tab="Node.js" test
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.router.ezat.io/openai/v1",
  apiKey: process.env.EZAT_API_KEY,
});

const completion = await client.chat.completions.create({
  model: "anthropic/claude-sonnet-5-5",
  max_tokens: 64,
  messages: [{ role: "user", content: "Say hello in five words." }],
});
console.log(completion.choices[0].message.content);
```

读取 `OPENAI_BASE_URL` 和 `OPENAI_API_KEY` 的工具只需修改这两个变量。编辑器和框架见 [OpenAI 格式的工具](https://docs.router.ezat.io/zh/tools/openai-tools.md)。

不同的地方：

- **只有 Chat Completions 和模型端点**。没有 Responses API、embeddings、图片生成或音频。
- **会被拒绝的字段**：大于 1 的 `n`、`logprobs`、`logit_bias`、音频、`web_search_options`、旧版 `functions` API 和 `response_format` `json_object` 会返回 `400`。完整列表见 [Chat Completions](https://docs.router.ezat.io/zh/openai/chat-completions.md)。
- **`temperature` 和 `top_p`** 只会传给接受它们的模型；其他模型会丢弃它们。
- **模型过载时返回 `503`，余额用完时返回 `402` `insufficient_quota`**。

## 迁移后要检查什么

首先，列出你的 key 可以使用的模型，确认代码中的每个模型 id 都在列表中，或是[模型](https://docs.router.ezat.io/zh/models.md)页面上的别名：

```bash tab="Anthropic format" test
curl --fail-with-body https://api.router.ezat.io/v1/models -H "x-api-key: $EZAT_API_KEY"
```

```bash tab="OpenAI format" test
curl --fail-with-body https://api.router.ezat.io/openai/v1/models -H "Authorization: Bearer $EZAT_API_KEY"
```

然后：

1. **在代码中搜索 EZAT 没有的功能**：batches、文件上传、服务端工具、MCP connector、Responses API、embeddings。
2. **从你的应用发送一个真实请求**，在控制台的「用量」页面上找到它，查看它的 token 和费用。
3. **检查余额**。EZAT 是预付费的：余额用完后，请求会以 `402` 失败，直到你充值（[计费](https://docs.router.ezat.io/zh/billing.md)）。每个 key 的消费上限见 [API key](https://docs.router.ezat.io/zh/api-keys.md)。
4. **关注缓存读取**：前几个请求之后，查看长提示词的缓存读取情况（[提示缓存与会话](https://docs.router.ezat.io/zh/guides/prompt-caching.md)）。

## 给 AI agent 的说明

1. 从 Anthropic API 迁移：把 base URL 设为 `https://api.router.ezat.io`，使用来自 `EZAT_API_KEY` 的 EZAT key。保留 Anthropic 模型名称；它们是别名。
2. 从 OpenRouter 或其他 OpenAI 兼容路由服务迁移：把 base URL 设为 `https://api.router.ezat.io/openai/v1`，使用 EZAT key。改写带点号的模型 id（`anthropic/claude-sonnet-5.5` 改为 `anthropic/claude-sonnet-5-5`），并用 `GET https://api.router.ezat.io/openai/v1/models` 逐个核对 id。
3. 删除或替换对 EZAT 没有的功能的调用（batches、files、服务端工具、MCP connector、Responses API、embeddings、音频、图片生成）。
4. 不要在新配置中保留旧提供方的 key，也不要打印 EZAT key。
5. 发送一个请求，并在控制台的「用量」页面上确认。