---
title: "OpenAI 协议"
description: "pirouter 接受 OpenAI 协议的模型可以直接用官方 OpenAI SDK 调用，只改 base URL、API key 和模型 ID 三项；Chat Completions 与 Responses 的参数原样转发，差异集中在响应里的模型名、流式用量和错误体。"
canonical: "https://pirouter.ai/zh/docs/api/openai"
last-updated: "2026-10-17"
lang: "zh"
source: "content/docs/zh/api/openai.mdx"
---

# OpenAI 协议

pirouter 接受 OpenAI 协议的模型可以直接用官方 OpenAI SDK 调用，只改 base URL、API key 和模型 ID 三项；Chat Completions 与 Responses 的参数原样转发，差异集中在响应里的模型名、流式用量和错误体。

用官方 OpenAI SDK 调用 pirouter，改三项就够：base URL 填 `https://api.pirouter.ai/v1`，key 换成 pirouter 的 API key，模型 ID 写成 `vendor/model`。其余请求参数原样转发，写法与 OpenAI 官方文档相同。

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

## 用官方 SDK 发请求

SDK 会把 key 放进 `Authorization: Bearer` 请求头。

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.1-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.1-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.1-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.1-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.1-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.1-sol',
  input: 'Hello!',
})
console.log(response.output_text)
```

成功时返回一段模型回复，控制台的 **日志** 里能找到这两次请求。

请求体里 pirouter 不认识的字段原样转发给 provider。只有四个顶层字段由 pirouter 自己使用、不转发：`provider`、`models`、`route`、`fallbacks`，见 [Provider 路由](https://pirouter.ai/zh/docs/guides/routing.md)和[模型回退](https://pirouter.ai/zh/docs/guides/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.1-sol",
    "stream": true,
    "messages": [{ "role": "user", "content": "Hello!" }]
  }'
```

返回的是一行行 `data: ` 事件，最后一行是 `data: [DONE]`。

Chat Completions 的流式请求，pirouter 总会打开 `stream_options.include_usage`，即使你传了 `false`。所以 `[DONE]` 之前总有一个 `choices` 为空、带 `usage` 的事件。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`       |

## 控制推理

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

判断模型支不支持推理，看 `supported_parameters` 里有没有 `reasoning`。那里不列 `reasoning_effort`。

推理用掉的 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/api/openai.md#流式返回)                                      |
| 错误体          | pirouter 自己的错误是 `{"error": {"message", "type", "code"}}`，`code` 是字符串错误码，见[错误码](https://pirouter.ai/zh/docs/api/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 换到下一个 provider，最多尝试 5 次，见[故障切换](https://pirouter.ai/zh/docs/guides/routing.md#故障切换)       |

## 出错时

按 `error.code` 处理，每个错误码的含义与要不要重试见[错误码](https://pirouter.ai/zh/docs/api/errors.md)。这个协议上最常遇到的是 `422` `validation_failed`：模型不在你调用的端点上提供，例如用图像模型调 Chat Completions。`message` 会列出它在哪些端点上提供，见[协议不匹配](https://pirouter.ai/zh/docs/models.md#协议不匹配)。

## 目前没有的能力

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

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

调用这两个路径返回 `400` `invalid_request`，`message` 是 `model is required`，意思是 pirouter 不提供这个端点，不是你的请求缺字段，见 [`invalid_request`](https://pirouter.ai/zh/docs/api/errors.md#invalid_request)。

## 下一步

- [创建对话补全](https://pirouter.ai/zh/docs/api/chat-completions.md): Chat Completions 端点的全部参数与响应。
- [Anthropic 协议](https://pirouter.ai/zh/docs/api/anthropic.md): 用官方 Anthropic SDK 调用 Claude 等模型。
