# Responses（OpenAI Responses 格式）

> POST /v1/responses 的接入、无状态约束、请求转发方式、流式事件与错误格式。

来源：https://www.scirouter.cn/docs/responses · 更新于 2026-10-24

```http
POST https://api.scirouter.cn/v1/responses
```

请求与响应格式与 OpenAI Responses API 一致。新版 OpenAI SDK 的 `client.responses.*` 与 Codex CLI（`wire_api = "responses"`）等按 Responses 格式发送请求的客户端，替换 base URL 与 Key 即可调用。平台上的所有对话模型均可通过此接口调用；线路不原生支持 Responses 时，网关转换请求，见[请求的转发方式](#请求的转发方式)。

## 接入

OpenAI SDK 在 base URL 后拼接 `/responses`，base URL 为 `https://api.scirouter.cn/v1`（带 `/v1`），与对话补全相同。Key 为 SciRouter 控制台创建的 API Key（以 `sk-sr-` 开头，见[认证与 API Key](https://www.scirouter.cn/docs/authentication)），使用 OpenAI 官方的 Key 返回 401。

Python：

```python
import os
from openai import OpenAI

client = OpenAI(api_key=os.environ["SCIROUTER_API_KEY"], base_url="https://api.scirouter.cn/v1")

r = client.responses.create(
    model="YOUR_MODEL_ID",
    instructions="你是一个严谨的科研助手。",
    input="这段序列的二级结构倾向？",
    max_output_tokens=1024,
)
print(r.output_text)
```

TypeScript：

```typescript
import OpenAI from 'openai'

const client = new OpenAI({ apiKey: process.env.SCIROUTER_API_KEY, baseURL: 'https://api.scirouter.cn/v1' })

const r = await client.responses.create({
  model: 'YOUR_MODEL_ID',
  input: '这段序列的二级结构倾向？',
  max_output_tokens: 1024,
})
console.log(r.output_text)
```

curl：

```bash
curl https://api.scirouter.cn/v1/responses \
  -H "Authorization: Bearer $SCIROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "YOUR_MODEL_ID",
    "input": "这段序列的二级结构倾向？",
    "max_output_tokens": 1024
  }'
```

## Codex CLI

Codex 的 `config.toml` 写法与平台对 Codex 请求的处理见 [Codex](https://www.scirouter.cn/docs/codex)。

## 请求

| 字段 | 必填 | 说明 |
|---|---|---|
| `model` | 是 | 平台的模型 id，也可填写平台为该模型配置的别名。响应中的 `model` 为解析后的平台模型 id |
| `input` | 是 | 字符串或输入项数组，不能为空。输入项：`message`（`input_text` / `input_image` / `output_text` / `refusal`）、`function_call`、`function_call_output`、`reasoning`（客户端带回的推理项，见[转换](#转换)） |
| `instructions` | 否 | 系统提示 |
| `max_output_tokens` | 否 | 正整数。超过模型或套餐的单次输出上限时按上限发出，并在响应头 `X-SciRouter-Max-Tokens-Clamped` 与 `scirouter.max_tokens_clamped` 中写明，不静默截短。预扣按输入估算加输出上限冻结配额，充值余额大于 0 的账户输出只按输出上限与平台设定值中的较小者估算，见[认证与 API Key](https://www.scirouter.cn/docs/authentication)「预扣」 |
| `stream` | 否 | `true` 时为流式，见[流式响应](#流式响应) |
| `tools` / `tool_choice` / `parallel_tool_calls` | 否 | 函数工具（`{"type": "function", "name", "parameters", "strict"}`）照常使用；`namespace` 工具展开为 `{namespace}__{name}` 的函数工具。厂商的服务端工具（`web_search`、`file_search`、`code_interpreter`、`computer_use`、`image_generation`、`mcp` 等）不支持，返回 400 `validation_failed`，`details.reason` 为 `server_tool_unsupported` |
| `store` | 否 | 平台不保存响应，一律按 `false` 处理：不传（SDK 默认不传，厂商默认为 true）或传 `true` 均按 `false` 处理，响应中写 `"store": false`，透传给上游时也强制写为 `false` |
| `reasoning` / `text` / `temperature` / `top_p` | 否 | 按线路处理，见[请求的转发方式](#请求的转发方式)；各参数无法带到线路上时的处理见[参数如何被处理](https://www.scirouter.cn/docs/params) |
| `metadata` / `user` / `safety_identifier` | 否 | 用作平台的归因标签与终端用户标识（见[可观测性](https://www.scirouter.cn/docs/observability)），不转给上游 |

请求体上限为 32 MB（与 `/messages` 相同），超过时返回 413 `payload_too_large`。

### 不支持的字段

平台无状态。以下字段返回 400 `validation_failed`，`details.reason` 为固定值：

| 字段 | `details.reason` | 处理方式 |
|---|---|---|
| `previous_response_id`、`conversation`、`prompt`、`input` 中的 `item_reference` | `stateful_unsupported` | 将完整的对话历史放入 `input` |
| `background` | `background_unsupported` | 改为同步调用 |

按 id 操作已保存响应的接口（`GET` / `DELETE` / `cancel`）不存在，返回 404。

## 请求的转发方式

| 方式 | 条件 |
|---|---|
| [原样转发](#原样转发) | 模型的线路标为「原生 Responses」 |
| [转换](#转换) | 其他线路，不论入口协议 |

请求包含只能原样转发的内容时，另见[只能原样转发的内容](#只能原样转发的内容)。

### 原样转发

线路标为「原生 Responses」时，请求原样转发到上游的 `/responses`。该标记由平台在线路的接口能力中设置，线路可用的入口中须有 OpenAI 兼容的 `openai` / `custom`（见[多厂商差异](https://www.scirouter.cn/docs/vendors)「字段生效规则」）。

平台只修改以下几处：

- `model` 换成上游的模型名；
- 去掉 `metadata` / `user` / `safety_identifier`；
- `store` 写为 `false`；
- `max_output_tokens` 写入生效值。

`include`、`prompt_cache_key`、`text.verbosity`、`reasoning.summary`、客户端带回的带 `encrypted_content` 的推理项与厂商自定义字段均到达上游。响应事件原样返回，只将 `model` 换回平台的模型 id；`id` 保留厂商的值，Codex 续接推理依赖该值。

「原样」指请求的格式与字段：鉴权、计费、限额与线路选择仍由平台完成，发给厂商的凭据是平台在该厂商的凭据，调用方的 SciRouter Key 不会到达厂商。

### 转换

线路未标「原生 Responses」时，网关将请求转为对话补全格式后调用，再将结果转回 Responses 格式：

| 请求内容 | 转换为 |
|---|---|
| `instructions` | system 消息 |
| `input` 中的消息、`function_call`、`function_call_output` | 逐项转换；输出中的图片移入紧随其后的用户消息 |
| 函数工具的 `strict` | 保留 |
| `max_output_tokens` | `max_tokens` |
| `reasoning.effort` | 按模型的思考控制翻译；强度不在模型的档位中时降档，模型没有思考能力时去掉并留痕 |
| `text.format`（`text` / `json_object` / `json_schema`） | `response_format`；模型没有原生结构化输出时由平台模拟 |

各参数的规则见[参数如何被处理](https://www.scirouter.cn/docs/params)。

客户端带回的推理项按来源处理：

| 推理项 | 处理 |
|---|---|
| 平台生成的（id 格式为 `rs_<请求 id>_0`，带 `encrypted_content`） | 解回为带签名的思考块，按入口支持的写法发给上游：Anthropic 入口原样写回思考块；OpenAI 兼容入口按线路配置，以上游支持的扩展写法带上签名。平台优先将请求发回签发该签名的线路 |
| 其他厂商签发的 `encrypted_content`，以及 `include: ["reasoning.encrypted_content"]` | 丢弃，不报错。平台在请求日志的 `scirouter.converted_dropped` 中记录丢弃的内容 |

转回的响应与原生响应的差异：

| 项 | 转换方式下的值 |
|---|---|
| `id` | `resp_<请求 id>`，与 `X-Request-Id` 对应 |
| 输出项的 id | `msg_<请求 id>_0`、`rs_<请求 id>_0`、`fc_<call_id>` |
| 思考过程 | `reasoning` 项的 `reasoning_text`。思考块带签名或加密数据时，`rs_` 项另带 `encrypted_content`（可验证思考块的序列化），下一轮原样放入 `input` 即可续接，内容不做修改 |
| 工具调用 | 在流的末尾整块发出，参数完整 |

### 签名被拒时的重试

推理项落到其他线路时，签名可能无效并被厂商拒绝。线路走 Anthropic Messages 入口时，平台在同一条线路上重试一次：

| 情况 | 重试方式 | `param_actions` 的 `reshaped` |
|---|---|---|
| 厂商判定这些思考块属于其他对话（此前的历史有改动），且该线路支持 | 请厂商只丢掉对不上的块及其后的思考块。此后发往该线路的请求均如此发送 | 厂商给出的原因，如 `thinking(prefix_binding_mismatch)` |
| 其他情况 | 去掉请求历史中的思考块后重试 | `thinking(signature_rejected)` |

- 第一种方式重试后仍被拒，或线路不支持该选项时，去掉思考块再重试一次。
- 第二种方式下，平台记录该线路拒绝过的思考块。此后发往该线路的请求，去掉历史中最后一条带有被拒块的消息及其之前的思考块。
- 重试仍失败时按普通失败处理。

线路走其他入口时，厂商的 400 照旧原样交回。Anthropic 格式的 `/v1/messages` 不做上述重试，签名被拒的 400 照旧原样交回。

### 只能原样转发的内容

以下内容只走标为「原生 Responses」的线路：

- `input_file`；
- 按 `file_id` 引用的图片；
- `include` 中厂商工具的输出；
- 厂商定义的客户端工具，如 `local_shell` / `apply_patch` / `custom`；
- `text.format` 为 `grammar` 等非标准格式；
- `context_management`。

模型没有此类线路时，返回 400 `unsupported_param`，`details.reason` 为 `unsupported_content`，`details.unsupported_content` 列出相应内容（如 `["include:code_interpreter_call.outputs"]`）。平台不会丢弃这些内容后作答。该错误由请求内容引起，重试无效。

## 响应

非流式：

```json
{
  "id": "resp_req_…",
  "object": "response",
  "status": "completed",
  "model": "YOUR_MODEL_ID",
  "store": false,
  "output": [
    { "id": "msg_req_…_0", "type": "message", "role": "assistant", "status": "completed",
      "content": [{ "type": "output_text", "text": "…", "annotations": [] }] }
  ],
  "usage": { "input_tokens": 42, "input_tokens_details": { "cached_tokens": 0 }, "output_tokens": 318, "output_tokens_details": { "reasoning_tokens": 0 }, "total_tokens": 360 },
  "scirouter": { "request_id": "req_…", "attempts": 1, "cost_quota": 18240, "…": "…" }
}
```

数值为示例。

顶层的 `scirouter` 是平台的扩展块，内容与[对话补全](https://www.scirouter.cn/docs/chat-completions)相同，SDK 忽略该字段。单次调用扣除的配额见 `scirouter.cost_quota`。

| 字段 | 说明 |
|---|---|
| `status` | 回答达到 `max_output_tokens` 时为 `incomplete`，`incomplete_details.reason` 为 `max_output_tokens`，与厂商一致 |
| `usage.input_tokens` | 包含命中缓存的部分，`cached_tokens` 单列 |
| `usage.output_tokens` | 包含推理，`reasoning_tokens` 单列 |

`usage` 的维度与账单一一对应。

## 流式响应

请求带 `"stream": true` 时按 Responses 的事件格式发送，每条事件带 `event:` 行与连续的 `sequence_number`。事件顺序：

1. `response.created`
2. `response.in_progress`
3. 每个输出项：`response.output_item.added` → `response.content_part.added` → `response.output_text.delta`… → `response.output_text.done` → `response.content_part.done` → `response.output_item.done`。推理项为 `response.reasoning_text.delta` / `done`，`function_call` 项为 `response.function_call_arguments.delta` / `done`
4. `response.completed` 或 `response.incomplete`

与对话补全的流式响应的差异：

- 终态事件（`response.completed` / `response.incomplete`）中的 `response` 为完整结果，与非流式响应逐字段相同。平台在结算后才发送终态事件，事件顶层多一个 `scirouter` 字段（含本次的 `cost_quota`）。
- 终态事件之后还有一行 `data: [DONE]`。OpenAI 官方不发送该行，Open Responses 规范要求发送；官方 SDK 与 Codex 在终态事件处结束读取，不受影响。
- 开始输出后出错时，发送 `event: response.failed` 事件，随后发送 `[DONE]`。`response.status` 为 `failed`，`response.error` 带 `code` / `message` / `request_id`；`code` 只使用原厂支持的值，平台错误码在 `scirouter_code` 中。上下文超长时无论在开流前后都按此发送，`code` 为 `context_length_exceeded`。
- **未收到终态事件即结束的流按失败处理。**
- 流中有以 `:` 开头的心跳注释行，SDK 自动忽略。

非流式请求最长等待约 270 秒，超时返回 504 `upstream_timeout`（`details.timeout` 为 `response`），不计费；回答可能很长时使用流式，见 [SDK 与框架](https://www.scirouter.cn/docs/sdks)「重试与超时」。

## 错误

- 错误体为 OpenAI 格式，与对话补全相同，鉴权失败与路径错误也是如此。按小写的 `error.code` 分支处理，对照见[错误码](https://www.scirouter.cn/docs/errors)。
- 上下文超长、参数不支持与内容审核三类上游语义错误的 `error.code` 为原厂兼容值（如 `context_length_exceeded`），平台错误码在 `error.scirouter_code` 中。
- 流式请求的上下文超长返回 HTTP 200 加 `response.failed` 事件，不返回 400，见 [Codex](https://www.scirouter.cn/docs/codex) 与[流式响应](#流式响应)。
- 本接口特有的 400 见[不支持的字段](#不支持的字段)与[只能原样转发的内容](#只能原样转发的内容)。

## 计价参数与模型变体

透传到「原生 Responses」线路时，`service_tier` 取 `auto`、`default` 以外的值会使厂商按另一档单价计费：

| 情况 | 结果 |
|---|---|
| 平台已上架覆盖该参数的模型变体（id 格式为 `厂商/模型名:priority`） | 自动改用变体，按变体的价格结算，响应头 `X-SciRouter-Variant-Switch` 列出触发的参数 |
| 没有对应的变体 | 400 `validation_failed`，`details.reason` 为 `price_param_unsupported` |

转换方式不带 `service_tier`，不做检查。规则与 [Messages](https://www.scirouter.cn/docs/messages) 相同。

## 请求头与响应头

### 请求头

| 请求头 | 取值 | 说明 |
|---|---|---|
| `X-SciRouter-Unsupported-Params` | `strict` / `lenient` | 参数无法带到线路上时的默认处置，见[参数如何被处理](https://www.scirouter.cn/docs/params) |
| `X-SciRouter-Validate-Schema` | `1` | `text.format` 由平台模拟时按 schema 校验结果，写入 `scirouter.schema_valid` |

### 响应头

| 响应头 | 取值 | 说明 |
|---|---|---|
| `X-SciRouter-Variant-Switch` | 触发的参数 | 请求被自动改用模型变体时出现，见[计价参数与模型变体](#计价参数与模型变体) |
| `X-SciRouter-Max-Tokens-Clamped` | 如 `requested=32000; effective=8192; limit=model` | `max_output_tokens` 超过模型或套餐的单次上限、按上限发出时出现 |
| `X-SciRouter-Param-Actions` | — | 有参数被去掉、翻译、模拟、整形或自愈时出现，见[参数如何被处理](https://www.scirouter.cn/docs/params) |
| `x-should-retry` | `false` | 本次错误重试无效（不带 `Retry-After` 的 503，见[错误码](https://www.scirouter.cn/docs/errors)） |

其余 `X-SciRouter-*`、`x-ratelimit-*` 响应头与对话补全相同，见[可观测性](https://www.scirouter.cn/docs/observability)。

## 缓存、幂等与重试

- `Idempotency-Key` 与平台响应缓存的规则与对话补全相同，见[缓存与幂等](https://www.scirouter.cn/docs/caching)。同一问题以三种格式调用时分别缓存，互不命中。
- OpenAI SDK 默认自动重试 429 与 5xx，并先检查 `x-should-retry`。
- 控制台的请求日志按调用格式筛选时，本接口的调用格式为 `responses`。
