> 原始 Markdown 孪生体（构建期从源 Markdown 生成）。渲染页：https://docs.gatellm.io/zh-CN/quickstart/anthropic-interop · 文档索引：https://docs.gatellm.io/zh-CN/llms.txt


# 用 OpenAI SDK 调 Anthropic Claude

本章教你用一个 OpenAI SDK 调 Anthropic 的 Claude 模型——客户端协议（OpenAI Chat Completions）和上游协议（Anthropic Messages）不同，网关做双向翻译。这是网关跨协议能力的典型示例。

## 你将完成什么

- 一个 `anthropic` 上游（指向 Anthropic API）
- 一个 `claude-sonnet` 模型（上游协议是 `anthropic`）
- 用 OpenAI Python SDK 调 `claude-sonnet`，看到模型回复

## 前置

- 网关已运行（`http://localhost:7890`），能登录控制台
- 已设 `ENCRYPTION_KEY`——下面要保存的上游 API key 与访问密钥都落库前加密，没设会在保存时报 `encryption_key not set in config`。见 [Docker 单机跑通 → 前置](/zh-CN/quickstart/docker-single-node.md#prereq)
- 一个 Anthropic API key

## 1. 建 anthropic 上游

控制台 → **上游服务** → **新建**：

| 字段 | 值 | 说明 |
|------|-----|------|
| 名称 | `anthropic` | 上游唯一标识 |
| 协议 | `anthropic` | 决定执行器与请求 schema |
| 基础 URL | `https://api.anthropic.com` | 上游真实地址，结尾不带 `/` |
| API Key | Anthropic 的 key | 点「添加」可加多把，按权重分布 |
| 启用 | ✓ | |

保存。

## 2. 建 claude 模型

在上游 `anthropic` 行点 **展开** → 模型子表 → **新建模型**：

| 字段 | 值 | 说明 |
|------|-----|------|
| 名称 | `claude-sonnet` | 对外暴露给客户端的模型名 |
| 上游 | `anthropic` | 选刚建的上游 |
| 上游模型 ID | `claude-sonnet-4-5` | Anthropic 真实模型名 |
| 启用 | ✓ | |

保存。客户端用 `claude-sonnet` 调用时，网关路由到上游 `anthropic` 的 `claude-sonnet-4-5`。

> 「上游模型 ID」要填 Anthropic 真实存在的模型名（本例 `claude-sonnet-4-5`），填错或填已下线模型会得到 404。完整可用模型清单见 [Anthropic 官方模型列表](https://docs.anthropic.com/en/docs/about-claude/models)。

## 3. 配密钥组放行

控制台 → **访问密钥** → **密钥组** 页签 → **新建**：

| 字段 | 值 | 说明 |
|------|-----|------|
| 名称 | `default` | 分组名 |
| 模型 | 选 `claude-sonnet`，或 `*`（全部） | 决定该组密钥能调哪些模型 |
| 启用 | ✓ | |

## 4. 签发访问密钥

控制台 → **访问密钥** → **新建**：

| 字段 | 值 | 说明 |
|------|-----|------|
| 名称 | `my-app-key` | 密钥的标识，用于管理与审计 |
| API 密钥 | 点「生成」 | 自动生成一串，客户端调用时带的凭证 |
| 分组 | `default` | 决定这把密钥能访问哪些模型 |
| 启用 | ✓ | |

## 5. 用 OpenAI SDK 调用

```python
from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:7890/v1",
    api_key="<你的访问密钥>",
)

resp = client.chat.completions.create(
    model="claude-sonnet",
    messages=[{"role": "user", "content": "你好"}],
)
print(resp.choices[0].message.content)
```

请求体是 OpenAI Chat Completions 格式。网关：

1. 接收 OpenAI 格式请求
2. 翻译成 Anthropic Messages 格式发给 `https://api.anthropic.com/v1/messages`
3. 收到 Anthropic 响应后翻译回 OpenAI 格式返回

客户端无感，看到的就是标准 OpenAI 响应。

## 6. 或用 curl

```bash
curl http://localhost:7890/v1/chat/completions \
  -H "Authorization: Bearer <你的访问密钥>" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet",
    "messages": [{"role":"user","content":"你好"}]
  }'
```

收到 Claude 的回复即跑通。

## 跨协议翻译细节

### 工具调用

跨协议工具调用（OpenAI tools → Anthropic tools）时，网关自动翻译 `tools` / `tool_choice` / `tool_calls` 等字段。关键约束：

- **`tool_call_id` 在跨协议往返中必须保留原值**——你在多轮工具对话里回传的 `tool_call_id` 要和网关给你的完全一致，否则上游无法匹配。
- **响应里的 `tool_use` id 由网关合成**——网关为每个 `tool_use` 块分配全局唯一的 `toolu_` id（不透传上游分配的原始 id）。你只需把它原样回显为下一轮的 `tool_use_id` / `tool_call_id`，无需关心上游最初给的 id。
- **请求历史里的 `tool_use` id 必须全局唯一**——网关对 `/v1/messages` 请求做与 Anthropic 官方 API 一致的校验，历史含重复 `tool_use` id 时回 `400 invalid_request_error`（消息形如 `tool_use ids must be unique`）。正常回显网关合成的 id 不会触发。

### 流式

流式请求也被翻译：网关把 Anthropic 的 SSE 事件流转换成 OpenAI 的 `data: {...}` 块流。如果上游推理时间长，网关会插入 `:keep-alive` SSE 注释保持连接活跃。SSE 客户端标准实现会自动忽略，无需特殊处理。

### 流异常中断

当上游流在传输中途异常中断时，网关不会直接报错打断对话，而是：

- 关闭尚未结束的内容块
- 在 SSE 流里插入一个 `_gateway_warning` 扩展字段，告诉你中断原因（含 `reason` / `detail` / `last_finish_reason` / `timestamp`）
- 发送正常的终止序列，让客户端能正常收尾

解析流时如果看到 `_gateway_warning`，说明这次响应中途出了问题，可据此记录或告警。

## 反向：用 Anthropic SDK 调 OpenAI

也可以反过来：上游是 OpenAI（`openai` 协议）、客户端用 Anthropic SDK 调 `/v1/messages`。网关把 Anthropic 请求翻译成 OpenAI 请求发给上游，响应再翻译回 Anthropic。具体接法见 [客户端接入与网关差异](/zh-CN/reference/clients-and-gateway-diffs.md)。

## 常见问题

**Q：跨协议调用时工具调用丢了 / 上游报 400 invalid tool_call_id？**
检查你在多轮工具对话里回传的 `tool_call_id` 是否和网关给你的完全一致。跨协议翻译中 `tool_call_id` 必须保留原值。

**Q：调 `/v1/messages` 报 400 `tool_use ids must be unique`？**
你发来的对话历史里有两个 `tool_use` 块用了同一个 `id`——Anthropic 契约要求 `tool_use` id 全局唯一，网关与官方 API 一样拒绝。检查你的历史构造逻辑是否在多轮里复用了 id；正常回显网关合成的 `toolu_` id 不会撞车。

**Q：响应里混进了 `_gateway_warning` 字段？**
不是上游返回的，是网关加的。说明上游流中途断了。看里面的 `reason`/`detail` 判断是否需重试。

**Q：客户端报 400 unsupported_feature？**
该「客户端协议 → 上游协议」组合没有翻译器。看 [协议互通矩阵](/zh-CN/reference/protocol-matrix.md) 查支持矩阵。

**Q：客户端报 401 / 403 / 404？**
- 401：访问密钥没带对
- 403 model_access_denied：密钥组「模型」列表没包含 `claude-sonnet`
- 404 model_not_found：模型名拼错，或 `claude-sonnet` 被设了 `hide_name`

**下一步**：[端点 · 认证 · 协议互通](/zh-CN/reference/endpoints.md) 看完整端点；[协议互通矩阵](/zh-CN/reference/protocol-matrix.md) 看所有协议对支持情况；[客户端接入与网关差异](/zh-CN/reference/clients-and-gateway-diffs.md) 看各 SDK 接法。
