---
title: "OpenAI 兼容接口"
description: "用官方 OpenAI SDK 调用 pirouter 上接受 OpenAI 协议的模型，只改 base URL 和 key。本页说明 Chat Completions 与 Responses 怎么调、流式与工具等参数怎么透传，以及和 OpenAI 官方行为的差异。"
canonical: "https://pirouter.ai/zh/docs/protocols/openai"
last-updated: "2026-10-17"
lang: "zh"
source: "content/docs/zh/(start)/protocols/openai.mdx"
---

# OpenAI 兼容接口

用官方 OpenAI SDK 调用 pirouter 上接受 OpenAI 协议的模型，只改 base URL 和 key。本页说明 Chat Completions 与 Responses 怎么调、流式与工具等参数怎么透传，以及和 OpenAI 官方行为的差异。

用官方 OpenAI SDK 调用 pirouter，只需要改 base URL 和 key。本页说明怎么发请求、流式返回、工具与结构化输出等参数怎么传、怎么控制推理，以及和 OpenAI 官方行为的差异。

OpenAI 协议有四个端点：`POST /v1/chat/completions`、`POST /v1/responses`、`POST /v1/images/generations`、`POST /v1/images/edits`。本页讲前两个，图像端点见[生成与编辑图片](https://pirouter.ai/zh/docs/images.md)。

## 用官方 SDK 发请求

SDK 的 base URL 填 `https://api.pirouter.ai/v1`，key 填 pirouter 的 API key，SDK 会把它放进 `Authorization: Bearer`。模型 ID 写 `vendor/model`。

Chat Completions：

cURL:

```bash
curl https://api.pirouter.ai/v1/chat/completions \
  -H "Authorization: Bearer $PIROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-6-sol",
    "messages": [{ "role": "user", "content": "Hello!" }]
  }'
```

Python:

```python
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.pirouter.ai/v1",
    api_key=os.environ["PIROUTER_API_KEY"],
)

completion = client.chat.completions.create(
    model="openai/gpt-6-sol",
    messages=[{"role": "user", "content": "Hello!"}],
)
print(completion.choices[0].message.content)
```

TypeScript:

```ts
import OpenAI from 'openai'

const client = new OpenAI({
  baseURL: 'https://api.pirouter.ai/v1',
  apiKey: process.env.PIROUTER_API_KEY,
})

const completion = await client.chat.completions.create({
  model: 'openai/gpt-6-sol',
  messages: [{ role: 'user', content: 'Hello!' }],
})
console.log(completion.choices[0].message.content)
```

Responses：

cURL:

```bash
curl https://api.pirouter.ai/v1/responses \
  -H "Authorization: Bearer $PIROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-6-sol",
    "input": "Hello!"
  }'
```

Python:

```python
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.pirouter.ai/v1",
    api_key=os.environ["PIROUTER_API_KEY"],
)

response = client.responses.create(
    model="openai/gpt-6-sol",
    input="Hello!",
)
print(response.output_text)
```

TypeScript:

```ts
import OpenAI from 'openai'

const client = new OpenAI({
  baseURL: 'https://api.pirouter.ai/v1',
  apiKey: process.env.PIROUTER_API_KEY,
})

const response = await client.responses.create({
  model: 'openai/gpt-6-sol',
  input: 'Hello!',
})
console.log(response.output_text)
```

你应该看到一段回答。在控制台的 **日志** 里能找到这两次请求。

请求体里 pirouter 不认识的字段原样转发给 provider。只有四个顶层字段 pirouter 自己用、不转发：`provider`、`models`、`route`、`fallbacks`，见 [Provider 路由](https://pirouter.ai/zh/docs/routing.md)和[模型回退](https://pirouter.ai/zh/docs/fallbacks.md)。

## 流式返回

在请求体里加 `"stream": true`，响应变成 SSE 事件流：

```bash
curl -N https://api.pirouter.ai/v1/chat/completions \
  -H "Authorization: Bearer $PIROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-6-sol",
    "stream": true,
    "messages": [{ "role": "user", "content": "Hello!" }]
  }'
```

你应该看到一行行 `data: ` 事件，最后一行是 `data: [DONE]`。

Chat Completions 的流式请求，pirouter 总是打开 `stream_options.include_usage`，所以 `[DONE]` 之前总有一个 `choices` 为空、带 `usage` 的事件，你传了 `false` 也一样。Responses 的流式请求不做这项处理。

## 使用工具、结构化输出和图片输入

这些参数 pirouter 一律原样转发，不检查模型支不支持。带了模型不支持的参数，请求照常转发，由 provider 决定接受、忽略还是报错。

调用前先查 `GET /v1/models` 里这个模型的字段：

| 你要用的             | 请求里写                                                          | 模型支持时                                          |
| ---------------- | ------------------------------------------------------------- | ---------------------------------------------- |
| 工具调用             | `tools`、`tool_choice`                                         | `supported_parameters` 含 `tools`、`tool_choice` |
| 一轮调用多个工具         | `parallel_tool_calls`                                         | `supported_parameters` 含 `parallel_tool_calls` |
| JSON 输出          | `response_format: {"type": "json_object"}`                    | `supported_parameters` 含 `response_format`     |
| 按 JSON schema 输出 | `response_format: {"type": "json_schema", …}`                 | `supported_parameters` 含 `structured_outputs`  |
| 图片输入             | 消息内容里的 `image_url` 块，可以是 `data:` URL                          | `architecture.input_modalities` 含 `image`      |
| PDF 输入           | 消息内容里的 `file` 块，`file_data` 是 base64 的 `data:application/pdf` | `architecture.input_modalities` 含 `file`       |

请求体的写法和 OpenAI 官方文档相同。

## 控制推理

用 `reasoning_effort`（Chat Completions）或 `reasoning.effort`（Responses）设推理档位，原样转发。一个模型接受哪些档位，看 `GET /v1/models` 里的 `reasoning.supported_efforts`；不写时用哪一档，看 `reasoning.default_effort`。档位的全集是 `none`、`minimal`、`low`、`medium`、`high`、`xhigh`、`max`。

`supported_parameters` 里列的是 `reasoning`，不列 `reasoning_effort`。看推理支持与否以 `reasoning` 为准。

推理用掉的 token 在 `usage.completion_tokens_details.reasoning_tokens` 里，按模型的 `internal_reasoning` 价格计费。

Chat Completions 上写 `thinking: {"type": "disabled"}` 时，pirouter 把它换成 `reasoning_effort: "none"` 再转发；你同时写了 `reasoning_effort` 或 `reasoning` 时，保留你写的值。

## 与 OpenAI 官方行为的差异

| 方面           | pirouter 的行为                                                                                                          |
| ------------ | --------------------------------------------------------------------------------------------------------------------- |
| 响应里的 `model` | 改写为 pirouter 的模型 ID（`vendor/model`），流式的每个事件都改。provider 自己报的名字在响应头 `X-Pi-Upstream-Model` 里                             |
| 流式用量         | Chat Completions 的流式总带用量事件，见[流式返回](https://pirouter.ai/zh/docs/protocols/openai.md#流式返回)                              |
| 错误体          | pirouter 自己的错误是 `{"error": {"message", "type", "code"}}`，`code` 是字符串错误码，见[错误码](https://pirouter.ai/zh/docs/errors.md) |
| 路由字段         | `provider`、`models`、`route`、`fallbacks` 不转发                                                                           |
| 不写推理参数时      | 部分 provider 登记了默认推理档：请求里没有 `reasoning_effort`、`reasoning`、`thinking` 时，pirouter 写入这一档                                 |
| 采样参数         | 部分 provider 只接受一部分采样参数（如 `temperature`、`top_p`、`seed`、`stop`）：清单外的参数被去掉后转发，不报错                                        |
| 推理预算         | 部分 provider 只按 token 预算限制推理：pirouter 按档位换算预算，并把你的输出上限分给推理和回答，两者之和不超过上限                                                |
| 强制调用工具       | `tool_choice` 为 `"required"` 或指定某个函数时，部分模型不保证调用工具：请求照常返回 `200`，回答可能是普通文本                                              |
| 失败重试         | provider 在返回第一个字节之前失败时，pirouter 自动换下一家，最多尝试 5 次，见[失败时自动换一家](https://pirouter.ai/zh/docs/routing.md#失败时自动换一家)          |

## 出错时的返回

| 状态码与 `error.code`            | 原因                                    | 处理                                                                         |
| ---------------------------- | ------------------------------------- | -------------------------------------------------------------------------- |
| `401` `invalid_api_key` 等    | key 缺失、写错或已失效                         | 检查 key，见[鉴权失败时的返回](https://pirouter.ai/zh/docs/authentication.md#鉴权失败时的返回) |
| `402` `insufficient_balance` | 余额不够                                  | [充值](https://pirouter.ai/zh/docs/billing.md#充值)后重发                         |
| `404` `model_not_found`      | 模型 ID 不存在                             | 核对 `vendor/model` 的写法                                                      |
| `422` `validation_failed`    | 模型不在这个端点上提供，例如用图像模型调 Chat Completions | 换到 `message` 列出的端点，见[协议不匹配](https://pirouter.ai/zh/docs/models.md#协议不匹配)   |
| `429` `rate_limited`         | 上游部署的分钟配额用满                           | 等 `Retry-After` 秒，见[限流](https://pirouter.ai/zh/docs/rate-limits.md)        |

全部错误码见[错误码](https://pirouter.ai/zh/docs/errors.md)。

## 目前没有的能力

下面这些 OpenAI 端点 pirouter 目前没有：

- `POST /v1/embeddings`
- `GET /v1/responses/{id}`

调用这两个路径返回 `400`，错误码 `invalid_request`，`message` 是 `model is required`。这个错误说的不是你的请求缺字段，而是 pirouter 不提供这个端点。

## 下一步

- [Anthropic Messages](https://pirouter.ai/zh/docs/protocols/anthropic.md): 用官方 Anthropic SDK 调用 Claude 等模型。
- [模型与协议](https://pirouter.ai/zh/docs/models.md): 每个模型接受哪些协议。
