---
title: "创建对话补全"
description: "创建对话补全（流式或非流式）。"
canonical: "https://pirouter.ai/zh/docs/api/chat-completions"
last-updated: "2026-10-13"
lang: "zh"
---

# 创建对话补全

创建对话补全（流式或非流式）。

`POST https://api.pirouter.ai/v1/chat/completions`

兼容 OpenAI 的对话补全接口。请求带 `"stream": true` 时，响应是 Server-Sent Events 流（`text/event-stream`）；否则是单个 JSON 响应体。未知的请求字段原样转发给上游 provider。

响应头由网关自己写，不是上游的：每个响应（包括错误）都带 `X-Pi-Trace-Id` 和 CORS 响应头；由上游 provider 实际应答的响应还带 `X-Pi-Provider`、`X-Pi-Model`、`X-Pi-Upstream-Model` 和 `X-Pi-Upstream-Request-Id`。网关自己给出的错误（鉴权、余额、限流、校验、没有可用 provider）没有上游可言，不带这四个响应头。上游发来的其他响应头不会转发，`Content-Type`、`Content-Length`、`Content-Encoding`、`Cache-Control` 和 `Retry-After` 除外。浏览器的预检请求（`OPTIONS`）不需要鉴权，返回 204。

## 鉴权

用下面任一请求头传 API key。

| 请求头 | 值 | 说明 |
| --- | --- | --- |
| `Authorization` | `Bearer sk-pi-…` | 平台签发的 API key，以 `sk-pi-` 开头，作为 Bearer token 发送。 |
| `X-Api-Key` | `sk-pi-…` | 同一个平台签发的 `sk-pi-` key，放在 `X-Api-Key` 请求头里发送。只有 `Authorization` 缺失或为空时才读取这个请求头；两个都带时，以 `Authorization` 为准。两个请求头都接受不带 `Bearer ` 前缀的裸 key。 |

## 请求体

`application/json`

兼容 OpenAI 的对话补全请求。未列出的字段原样转发给上游，但有两类例外：路由字段 `provider`、`models` 和 `route` 由路由使用，转发前会被移除；`preset` 标记为 x-pi-reserved，在预设功能上线前会以 validation_failed 被拒绝。

| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `model` | string | 是 | 模型 ID，格式为 "vendor/model"。 |
| `messages` | object[] | 是 |  |
| `messages[].role` | string | 是 | 可选值: `system`, `user`, `assistant`. |
| `messages[].content` | string | 是 |  |
| `provider` | object | 否 | 按请求设置的 provider 路由偏好，在所请求的模型有多个 provider 提供时生效。限制类字段（`only`、`ignore`、`data_collection`、`zdr`、`quantizations`）只能在工作区路由设置的基础上收紧。工作区的排序方式（`order` 和 `sort`）只是默认值，请求里给出时会整体替换它。provider 名称使用平台 ID，匹配时不区分大小写，另外接受别名 `google-vertex`（gcp）、`google-ai-studio`（gemini）和 `amazon-bedrock`（aws）。已知但尚未实现的字段会被拒绝，提示 `provider.<field> is not supported yet`；其他未知的键也会被拒绝，提示 `provider: unrecognized key "<key>"`。 |
| `provider.order` | string[] | 否 | 优先尝试的 provider，按此顺序；未列出的 provider 排在它们之后。 |
| `provider.only` | string[] | 否 | 只使用这些 provider（与工作区的允许列表取交集）。 |
| `provider.ignore` | string[] | 否 | 不使用这些 provider（追加到工作区的忽略列表）。优先级高于 `only`。 |
| `provider.allow_fallbacks` | boolean | 否 | 设为 `false` 且同时给出 `order` 时，只有 `order` 里的 provider 可以处理请求。工作区设为 `false` 时，请求无法放宽。 默认值: `true`. |
| `provider.sort` | string \| object | 否 | 在每个 `order` 层级内，按 `input_text + output_text` 的单价从低到高给 provider 排序。不设时，由部署权重决定。 |
| `provider.sort.by` | string | 是 | 可选值: `price`. |
| `provider.data_collection` | string | 否 | `deny` 会排除可能用提示词训练模型、或保留提示词超过有限期限的 provider（未声明的按「可能」处理）。 可选值: `allow`, `deny`. 默认值: `"allow"`. |
| `provider.zdr` | boolean | 否 | 只使用零数据保留的 provider。 默认值: `false`. |
| `provider.quantizations` | string[] | 否 | 只使用精度在此列表内的部署。 可选值: `fp4`, `int4`, `int8`, `fp8`, `fp16`, `bf16`, `fp32`, `unknown`. |
| `models` | string[] · max 3 | 否 | 回退模型列表。当前模型的所有部署都在返回首字节之前失败时，在 `model` 之后按数组顺序依次尝试这些模型（见「运行时回退」）。与 `model` 或前面条目重复的条目会被丢弃；未提供 `model` 时，第一个条目作为主模型。每个条目都必须存在（否则返回 404 model_not_found，并指出该条目）；超过 3 个时返回 validation_failed。不转发给上游。 |
| `preset` | string | 否 | (暂未开放) 保留字段。预设引用，也可以写成 model "@preset/{slug}"。目前会以 validation_failed 被拒绝（`preset is not supported yet`）。 |
| `route` | string | 否 | 路由变体。只接受 `fallback`，效果与省略该字段相同；其他任何值都返回 validation_failed。不转发给上游。 可选值: `fallback`. |
| `stream` | boolean | 否 | 为 true 时，以 Server-Sent Events 流的形式响应。 默认值: `false`. |
| `stream_options` | object | 否 | 仅用于流式的选项；stream 为 false 时忽略。 |
| `stream_options.include_usage` | boolean | 否 | 为 true 时，最后一个数据帧携带 usage 块。 |
| `max_tokens` | integer | 否 | 生成 token 数的上限。 |
| `temperature` | number | 否 | 采样温度；透传给上游 provider。 |
| `top_p` | number | 否 | 核采样参数；透传给上游 provider。 |

## 响应

`200` `application/json`, `text/event-stream`

补全结果。非流式请求得到单个 `ChatCompletion` JSON 响应体。流式请求得到 SSE 流：每个事件是一行 `data:`，内容是一个 JSON 格式的 `ChatCompletionChunk`；事件之间以空行分隔，流以 `data: [DONE]` 结束。`stream_options.include_usage` 为 true 时，`[DONE]` 之前的最后一个数据帧携带 `usage` 块。

| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `id` | string | 是 | 上游 provider 自己的响应 ID，原样传回。平台的请求 ID 在 `X-Pi-Trace-Id` 响应头里。 |
| `object` | string | 是 | 可选值: `chat.completion`. |
| `created` | integer | 是 | Unix 时间戳（秒）。 |
| `model` | string | 是 | 实际处理请求的模型的平台模型 ID（例如 `openai/gpt-6-sol`）。发生回退后，它是给出回答的那个模型，可能和请求里写的不同。上游自己报告的模型名在 `X-Pi-Upstream-Model` 响应头里。 |
| `choices` | object[] | 是 |  |
| `choices[].index` | integer | 是 |  |
| `choices[].message` | object | 是 |  |
| `choices[].message.role` | string | 是 | 可选值: `assistant`. |
| `choices[].message.content` | string \| null | 否 |  |
| `choices[].finish_reason` | string | 是 | 上游的结束原因，原样透传（如 stop、length）。 |
| `usage` | object | 否 | 一次补全的 token 用量（OpenAI 标准的三个字段；以后可能增加其他字段）。 |
| `usage.prompt_tokens` | integer | 是 |  |
| `usage.completion_tokens` | integer | 是 |  |
| `usage.total_tokens` | integer | 是 |  |

## 错误

| 状态码 | 错误码 | 说明 |
| --- | --- | --- |
| `400` | `invalid_request` | 请求缺少必填字段（`invalid_request`）：请求体既没有 `model` 也没有 `models` 时，返回 `model is required`。 |
| `401` | `invalid_api_key`, `api_key_not_found`, `api_key_revoked`, `api_key_expired` | API key 缺失或格式错误（`invalid_api_key`）、不存在（`api_key_not_found`）、已吊销（`api_key_revoked`）或已过期（`api_key_expired`）。 |
| `402` | `insufficient_balance` | 钱包余额不足以支付这次调用（`insufficient_balance`）。 |
| `404` | `model_not_found`, `no_eligible_provider` | 所请求的模型 ID 不存在或未启用（`model_not_found`）；或者请求的 `provider` 偏好与工作区路由设置合并后，没有 provider 能提供该模型（`no_eligible_provider`，`error.metadata` 里带有路由筛选漏斗）。 |
| `422` | `validation_failed` | 请求未通过校验（`validation_failed`），例如未知的键、尚不支持的字段、类型错误，或 `provider` 里出现未知的 provider 名称。错误信息会指出具体字段。 |
| `429` | `rate_limited` | 请求因限流被拒绝（`rate_limited`）。 |
| `500` | `internal_error` | 其他失败：没有健康的上游可以处理请求时返回 `provider_unavailable`（503）；平台侧的意外故障返回 `internal_error`（500）。由上游 provider 自己应答的错误会连同它的状态码一起传回，并带上四个上游响应头；网关自己给出的错误不带。 |
| `503` | `provider_unavailable` | 其他失败：没有健康的上游可以处理请求时返回 `provider_unavailable`（503）；平台侧的意外故障返回 `internal_error`（500）。由上游 provider 自己应答的错误会连同它的状态码一起传回，并带上四个上游响应头；网关自己给出的错误不带。 |

错误体

```json
{
  "error": {
    "message": "No such model. Model names are vendor-qualified (vendor/model), so a name copied from a provider's own docs needs its vendor prefix added. Call GET /v1/models for the slugs this gateway serves.",
    "type": "not_found_error",
    "code": "model_not_found"
  }
}
```

## 响应头

每个响应头后面列出它会出现在哪些状态码的响应里。

| 响应头 | 出现于 | 说明 |
| --- | --- | --- |
| `X-Pi-Trace-Id` | `200`, `400`, `401`, `402`, `404`, `422`, `429`, `default` | 平台请求 id，由网关生成。推理端点的每个响应都带；反馈问题时请附上它。 |
| `Access-Control-Allow-Origin` | `200`, `400`, `401`, `402`, `404`, `422`, `429`, `default` | 恒为 `*`。凭证是携带 API key 的请求头，从不是 cookie。 |
| `Access-Control-Expose-Headers` | `200`, `400`, `401`, `402`, `404`, `422`, `429`, `default` | 列出每一个 `X-Pi-*` 响应头，外加 `Retry-After` 与 `Content-Encoding`，让浏览器里的代码能读到它们。 |
| `X-Pi-Provider` | `200`, `default` | 处理这次响应的 provider，取值与 `provider.order`、`GET /v1/models/{vendor}/{model}/endpoints` 同一套词表。只有上游 provider 作出应答时才有（一次补全或一次上游错误）；发生 fallback 后是接手的那个 provider。 |
| `X-Pi-Model` | `200`, `default` | 处理这次响应的模型 slug，与响应体里的 `model` 是同一个值。由 fallback 模型接手时就是那个模型。只有上游 provider 作出应答时才有。 |
| `X-Pi-Upstream-Model` | `200`, `default` | 上游 provider 在它自己的响应里报告的完整模型 id，原样透传（流式时取自第一个数据事件）。上游响应没有给出模型时不带这个头；不会用平台自己的记录补上。 |
| `X-Pi-Upstream-Request-Id` | `200`, `default` | 上游 provider 自己的请求 id，原样透传，用于在 provider 一侧查这次调用。provider 没有返回时不带这个头。 |

## 请求示例

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)
```

## 响应示例

`200` `application/json`

```json
{
  "id": "chatcmpl-EY6GuWpg...",
  "object": "chat.completion",
  "created": 1791795968,
  "model": "openai/gpt-6-sol",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Hello! How can I help?"
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 8,
    "completion_tokens": 10,
    "total_tokens": 18
  }
}
```

`200` `text/event-stream`

```text
data: {"id":"chatcmpl-EY6GwdSM...","object":"chat.completion.chunk","created":1791795970,"model":"openai/gpt-6-sol","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}

data: {"id":"chatcmpl-EY6GwdSM...","object":"chat.completion.chunk","created":1791795970,"model":"openai/gpt-6-sol","choices":[{"index":0,"delta":{"content":"Hi"},"finish_reason":null}]}

data: {"id":"chatcmpl-EY6GwdSM...","object":"chat.completion.chunk","created":1791795970,"model":"openai/gpt-6-sol","choices":[{"index":0,"delta":{"content":"!"},"finish_reason":null}]}

data: {"id":"chatcmpl-EY6GwdSM...","object":"chat.completion.chunk","created":1791795970,"model":"openai/gpt-6-sol","choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"usage":{"prompt_tokens":8,"completion_tokens":5,"total_tokens":13}}

data: [DONE]
```
