# Responses 格式

来源: https://platform.lyrouter.com/ai_gateway/docs/responses-api
更新日期: 2026-10-22

创建一个模型响应：用 `input` 传入文本或一组输入项，返回带 `id` 的响应对象，输出放在 `output` 数组里，按项区分消息、函数调用和推理内容，支持流式。兼容 OpenAI Responses API：OpenAI SDK 的 `client.responses` 和使用 Responses 协议的客户端（例如 [Codex](https://platform.lyrouter.com/ai_gateway/docs/codex) CLI）把 Base URL 设为 `https://api.lyrouter.com/v1` 即可使用，与 Chat Completions 相同。网关按 Responses 协议转发请求、不做协议转换，所选模型和服务它的通道都必须支持 Responses。

`POST /v1/responses`

## 鉴权

在请求头中携带 API Key：

```text
Authorization: Bearer <API Key>
```

`Bearer` 区分大小写。也可以改用 `x-api-key: <API Key>`，两者同时存在时只读 `Authorization`。API Key 在工作空间的 **API 密钥** 页面创建，只用于 LYRouter 鉴权，不会转发给上游服务商。完整说明见[接入地址与鉴权](https://platform.lyrouter.com/ai_gateway/docs/call-gateway)。

## 请求头

| 请求头 | 必填 | 说明 |
| --- | --- | --- |
| `Content-Type` | 否 | 建议携带 `application/json`。不带时网关按 JSON 解析请求体；写成其他值（如 `application/x-www-form-urlencoded`）时返回 400 |

## 请求体

| 参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `model` | string | 否 | 模型 ID，也可以写 `@vmodel/<名称>`（[虚拟模型](https://platform.lyrouter.com/ai_gateway/docs/presets)）或 `lyrouter/auto`（[Auto 智能路由](https://platform.lyrouter.com/ai_gateway/docs/auto)）。省略、为 `""` 或 `null` 时使用工作空间的默认模型，没有默认模型时返回 400 |
| `input` | string / array | 是 | 字符串等同于一条用户消息；数组按顺序放入消息项和其他输入项，见下文「input 数组中的项」 |
| `instructions` | string | 否 | 系统级指令。使用虚拟模型时，虚拟模型的系统提示词追加在这段指令之后 |
| `stream` | boolean | 否 | `true` 时以 SSE 事件流返回，见下文「流式响应」 |
| `tools` | array | 否 | 函数工具写作 `{"type": "function", "name", "description", "parameters", "strict"}`，字段平铺，不像 Chat 那样包在 `function` 里。内置工具（如 `web_search`）原样转发，是否可用取决于上游 |
| `tool_choice` | string / object | 否 | `auto`、`none`、`required`，或 `{"type": "function", "name": "..."}` |
| `parallel_tool_calls` | boolean | 否 | 是否允许一次返回多个函数调用 |
| `max_output_tokens` | integer | 否 | 输出上限，包含推理 Token。请使用这个字段；Chat 的 `max_tokens` 会原样转发，是否生效由上游决定 |
| `reasoning` | object | 否 | 例如 `{"effort": "low", "summary": "auto"}`。透传给上游，是否生效取决于模型 |
| `text.format` | object | 否 | 输出格式：`{"type": "text"}`、`{"type": "json_object"}`，或 `{"type": "json_schema", "name": "...", "schema": {...}, "strict": true}`。效果取决于上游：例如有的上游在 `json_object` 时仍把 JSON 包在 Markdown 的 json 代码块里返回，在 `json_schema` 时不按 schema 输出（响应回显的 `text.format` 中字段名为 `schema_`）。依赖结构化输出前请先用所选模型验证，解析前去掉代码块标记 |
| `temperature`、`top_p` | number | 否 | 透传给上游，推理模型通常不支持 |
| `store` | boolean | 否 | 是否让上游保存这次响应。网关原样转发，不填时按上游默认（OpenAI 默认为 `true`） |
| `previous_response_id` | string | 否 | 接续上一轮响应，由上游拼接上下文，见下文「多轮对话与函数调用」 |
| `include` | array | 否 | 附加返回内容，例如 `["reasoning.encrypted_content"]`。透传 |
| `metadata` | object | 否 | 透传 |

### input 数组中的项

| 项 | 写法 | 用途 |
| --- | --- | --- |
| 消息 | `{"role": "user", "content": "..."}`。`role` 可为 `user`、`assistant`、`system`、`developer`；`content` 可以是字符串，也可以是 `input_text`、`input_image` 等内容部分的数组 | 传入对话内容。图片输入需要模型支持，见[多模态能力](https://platform.lyrouter.com/ai_gateway/docs/multimodal) |
| 函数调用结果 | `{"type": "function_call_output", "call_id": "...", "output": "..."}` | 把工具执行结果交回模型 |
| 上一轮的输出项 | 上一次响应 `output` 中的 `message`、`function_call`、`reasoning` 项，原样放回 | 不使用 `previous_response_id` 时，由客户端自己携带历史 |

## 请求示例

**请求示例**

cURL:
```bash
curl https://api.lyrouter.com/v1/responses \
  -H "Authorization: Bearer $LYROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "MODEL_ID",
    "instructions": "你是一个简洁的助手。",
    "input": "用一句话解释什么是 API 网关。",
    "max_output_tokens": 1024
  }'
```

Python:
```python
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["LYROUTER_API_KEY"],
    base_url="https://api.lyrouter.com/v1",
)
response = client.responses.create(
    model="MODEL_ID",
    instructions="你是一个简洁的助手。",
    input="用一句话解释什么是 API 网关。",
    max_output_tokens=1024,
)
print(response.output_text)
print(response.usage)
```

Node.js:
```js
import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.LYROUTER_API_KEY,
  baseURL: "https://api.lyrouter.com/v1",
});
const response = await client.responses.create({
  model: "MODEL_ID",
  instructions: "你是一个简洁的助手。",
  input: "用一句话解释什么是 API 网关。",
  max_output_tokens: 1024,
});
console.log(response.output_text);
console.log(response.usage);
```

将 `MODEL_ID` 替换为工作空间中已开通、且支持 Responses 的模型 ID。`output_text` 是 SDK 提供的便捷属性，会把所有 `output_text` 内容拼接起来；原始 JSON 中没有这个字段，直接解析 HTTP 响应时请遍历 `output`。Python 示例需要 openai Python SDK 1.66 或更高版本，旧版本没有 `client.responses`，会报 `AttributeError: 'OpenAI' object has no attribute 'responses'`。

## 响应

非流式请求返回一个 `response` 对象；出错时返回 `error` 对象。下面的 200 是带推理摘要的典型响应，400 是所选模型不支持 Responses，403 是工作空间没有开通这个模型。

**响应示例**

200:
```json
{
  "id": "resp_68ee1b9a52c48190a71c3e7d6a0b2f5e",
  "object": "response",
  "created_at": 1760427600,
  "status": "completed",
  "error": null,
  "incomplete_details": null,
  "model": "gpt-5.5",
  "instructions": "你是一个简洁的助手。",
  "output": [
    {
      "id": "rs_68ee1b9ab1d08190b3a2c5e7f9013d4a",
      "type": "reasoning",
      "summary": [
        { "type": "summary_text", "text": "用户要一句话定义，直接给出结论。" }
      ]
    },
    {
      "id": "msg_68ee1b9b0e7c8190b9f2d4a6c8e01a37",
      "type": "message",
      "status": "completed",
      "role": "assistant",
      "content": [
        {
          "type": "output_text",
          "text": "API 网关是位于客户端与后端服务之间的统一入口，负责鉴权、路由、限流和监控。",
          "annotations": []
        }
      ]
    }
  ],
  "max_output_tokens": 1024,
  "previous_response_id": null,
  "reasoning": { "effort": "low", "summary": "auto" },
  "store": true,
  "text": { "format": { "type": "text" } },
  "tool_choice": "auto",
  "tools": [],
  "usage": {
    "input_tokens": 1830,
    "input_tokens_details": { "cached_tokens": 1536 },
    "output_tokens": 196,
    "output_tokens_details": { "reasoning_tokens": 128 },
    "total_tokens": 2026
  },
  "metadata": {}
}
```

400:
```json
{
  "error": {
    "message": "This model does not support the responses API",
    "type": "invalid_request_error",
    "code": "unsupported_model_api"
  }
}
```

403:
```json
{
  "error": {
    "message": "Model is not available in the model plaza",
    "type": "access_denied",
    "code": "model_not_available"
  }
}
```

| 字段 | 说明 |
| --- | --- |
| `id` | 响应 ID，由上游生成，常见为 `resp_` 开头（也有上游返回 `resp-` 开头的 ID），不是 LYRouter 的 Request ID。用于 `previous_response_id` |
| `status` | `completed`；输出达到 `max_output_tokens` 时为 `incomplete`，原因在 `incomplete_details.reason`；还可能是 `failed`、`cancelled`，后台执行时有 `queued`、`in_progress` |
| `model` | 上游返回的实际模型名，可能与请求中的模型 ID 不同。对应日志的「模型（实际）」 |
| `output` | 输出项数组，按 `type` 分别处理：`message` 的 `content` 里是 `output_text`；`function_call` 是函数调用；`reasoning` 是推理摘要或加密的推理内容。不能按 Chat 的 `choices[0].message` 解析 |
| `usage` | 本次 Token 用量，网关原样返回上游的值，见下表 |

### usage 与日志中的四项 Token

`usage` 与[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)「Token 消耗」四项的对应关系：

| `usage` 字段 | 含义 | 日志中的对应项 |
| --- | --- | --- |
| `input_tokens` | 全部输入，**包含**缓存命中的部分 | 「输入（缓存未命中）」+「输入（缓存命中）」 |
| `input_tokens_details.cached_tokens` | 命中上游提示词缓存的输入 | 「输入（缓存命中）」 |
| `output_tokens` | 全部输出，**包含**推理 Token | 「输出」 |
| `output_tokens_details.reasoning_tokens` | 输出中用于推理的部分 | 包含在「输出」中 |

上例中「输入（缓存未命中）」为 1830 − 1536 = 294，「输入（缓存命中）」为 1536，「输出」为 196；Responses 上游不产生「显式缓存创建」。计费方法见[调用费用与缓存计费](https://platform.lyrouter.com/ai_gateway/docs/estimate)。

## 流式响应

设置 `"stream": true` 后，响应是 `text/event-stream`。每个事件由 `event:` 行和 `data:` 行组成，`data` 中的 `type` 与事件名相同，`sequence_number` 递增。实际的流中每个事件前还有一行 `id:`，`event:`、`data:` 的冒号后也可能没有空格（如 `data:{...}`），按 SSE 规范两种写法都合法，自己写解析器时要兼容。以下片段省略了 `id:` 行和 `response` 对象中的部分字段：

```text
event: response.created
data: {"type":"response.created","sequence_number":0,"response":{"id":"resp_68ee1b9a52c48190a71c3e7d6a0b2f5e","object":"response","status":"queued","output":[],"usage":null}}

event: response.output_item.added
data: {"type":"response.output_item.added","sequence_number":2,"output_index":0,"item":{"id":"msg_68ee1b9b0e7c8190b9f2d4a6c8e01a37","type":"message","status":"in_progress","role":"assistant","content":[]}}

event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":4,"item_id":"msg_68ee1b9b0e7c8190b9f2d4a6c8e01a37","output_index":0,"content_index":0,"delta":"API 网关是"}

event: response.output_text.done
data: {"type":"response.output_text.done","sequence_number":9,"item_id":"msg_68ee1b9b0e7c8190b9f2d4a6c8e01a37","output_index":0,"content_index":0,"text":"API 网关是位于客户端与后端服务之间的统一入口，负责鉴权、路由、限流和监控。"}

event: response.completed
data: {"type":"response.completed","sequence_number":12,"response":{"id":"resp_68ee1b9a52c48190a71c3e7d6a0b2f5e","object":"response","status":"completed","usage":{"input_tokens":1830,"input_tokens_details":{"cached_tokens":1536},"output_tokens":196,"output_tokens_details":{"reasoning_tokens":128},"total_tokens":2026}}}
```

| 事件 | 含义 |
| --- | --- |
| `response.created`、`response.in_progress` | 响应已创建、正在生成。`response.created` 中的 `status` 可能是 `queued` |
| `response.output_item.added` / `.done` | 一个输出项（消息、函数调用、推理）开始 / 结束 |
| `response.content_part.added` / `.done` | 消息中的一个内容块开始 / 结束 |
| `response.output_text.delta` / `.done` | 文本增量 / 完整文本 |
| `response.reasoning_text.delta` / `.done` | 推理文本增量 / 完整推理文本，推理模型会返回 |
| `response.function_call_arguments.delta` / `.done` | 函数调用参数增量 / 完整参数 |
| `response.completed` | 正常结束，`response.usage` 是本次用量 |
| `response.incomplete`、`response.failed` | 输出被截断或生成失败，同样携带完整的 `response` 对象 |

- Responses 流**没有** `data: [DONE]`，以 `response.completed`（或 `response.incomplete`、`response.failed`）作为结束。网关不会给 Responses 请求加 `stream_options`，用量只在结束事件里。
- 输出开始后上游中断时，网关在流末尾补一个 `response.failed` 事件后结束：`response.status` 为 `failed`，`response.error.code` 为 `server_error`，`response.id` 是这条流的响应 ID，不再有 `response.completed`。没有收到结束事件就按失败处理，见[超时与流式中断](https://platform.lyrouter.com/ai_gateway/docs/stream-errors)。

**流式示例**

cURL:
```bash
curl -N https://api.lyrouter.com/v1/responses \
  -H "Authorization: Bearer $LYROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"MODEL_ID","input":"写一首两行的小诗","stream":true}'
```

Python:
```python
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["LYROUTER_API_KEY"],
    base_url="https://api.lyrouter.com/v1",
)
stream = client.responses.create(
    model="MODEL_ID",
    input="写一首两行的小诗",
    stream=True,
)
for event in stream:
    if event.type == "response.output_text.delta":
        print(event.delta, end="", flush=True)
    elif event.type == "response.completed":
        print("\n", event.response.usage)
```

Node.js:
```js
import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.LYROUTER_API_KEY,
  baseURL: "https://api.lyrouter.com/v1",
});
const stream = await client.responses.create({
  model: "MODEL_ID",
  input: "写一首两行的小诗",
  stream: true,
});
for await (const event of stream) {
  if (event.type === "response.output_text.delta") {
    process.stdout.write(event.delta);
  } else if (event.type === "response.completed") {
    console.log("\n", event.response.usage);
  }
}
```

各协议流式格式的对比见[流式响应](https://platform.lyrouter.com/ai_gateway/docs/streaming)。

## 多轮对话与函数调用

多轮对话有两种写法：

- **`previous_response_id`**：把上一轮响应的 `id` 填进下一次请求，只发送新的输入，由上游保存并拼接上下文。需要上游支持，且上一轮没有设置 `store: false`。
- **自带历史**：每次在 `input` 中带上完整历史，把上一轮 `output` 中的项原样追加进去，再加新的输入。这种写法不依赖上游保存的状态，模型有多个通道或凭证时更稳妥。不需要上游保存时可以设置 `store: false`；此时要回传推理项，请同时设置 `"include": ["reasoning.encrypted_content"]`。

网关用 `previous_response_id` 把同一条接续链的请求归为一个会话，可以在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)的「会话」列中查看。网关**不会**把接续请求固定到创建上一轮响应的那个上游：模型有多个通道或凭证时，接续请求可能落到没有保存这条响应的上游，由上游返回找不到响应的错误。

函数调用的完整流程如下。第一次请求声明工具：

```json
{
  "model": "MODEL_ID",
  "input": "上海现在天气怎么样？",
  "tools": [
    {
      "type": "function",
      "name": "get_weather",
      "description": "查询城市的实时天气",
      "parameters": {
        "type": "object",
        "properties": { "city": { "type": "string" } },
        "required": ["city"],
        "additionalProperties": false
      },
      "strict": true
    }
  ]
}
```

模型决定调用工具时，`output` 中出现 `function_call` 项，`arguments` 是 JSON 字符串：

```json
{
  "id": "fc_68ee1c20a3f88190c2d4e6f8a0b1c3d5",
  "type": "function_call",
  "status": "completed",
  "call_id": "call_k3Jw9Xq2mZ7tVb1R",
  "name": "get_weather",
  "arguments": "{\"city\":\"上海\"}"
}
```

在客户端执行工具，再把结果以 `function_call_output` 交回，`call_id` 必须与调用一致。下面用自带历史的写法，同时带上原来的 `tools`：

```json
{
  "model": "MODEL_ID",
  "input": [
    { "role": "user", "content": "上海现在天气怎么样？" },
    {
      "type": "function_call",
      "call_id": "call_k3Jw9Xq2mZ7tVb1R",
      "name": "get_weather",
      "arguments": "{\"city\":\"上海\"}"
    },
    {
      "type": "function_call_output",
      "call_id": "call_k3Jw9Xq2mZ7tVb1R",
      "output": "{\"temp_c\":22,\"condition\":\"多云\"}"
    }
  ],
  "tools": ["……与第一次请求相同……"]
}
```

示例中 `tools` 的值为省略写法，实际请求要放入完整的工具定义。与 Chat Completions 的写法对比见[工具调用](https://platform.lyrouter.com/ai_gateway/docs/tool-call)。

## 网关行为

- **不做协议转换**：网关按 Responses 协议把请求转发到上游的 `/responses`，不会把它转换成 Chat Completions 或 Anthropic Messages，所以模型和服务它的通道都必须原生支持 Responses。模型声明了支持的接口、且其中没有 Responses 时，网关直接返回 400 `This model does not support the responses API`（`unsupported_model_api`）；没有声明的模型会照常转发，由上游返回错误。
- **请求基本原样转发**：网关只做以下改动：把 `model` 换成所选通道的实际模型名；使用虚拟模型时合并参数和系统提示词；把 `input` 中以 `at_` 开头的项 ID 改为以 `msg_` 开头，以兼容要求 `msg_` 前缀的上游；重新排列请求 JSON 中对象的键顺序（数组顺序不变），让相同前缀稳定命中上游缓存。`store`、`previous_response_id`、`background`、`include` 和内置工具都原样转发。
- **虚拟模型**：虚拟模型的系统提示词在 `instructions` 为空时直接填入，已有内容时空一行后追加；参数按 Chat Completions 的字段名合并，`max_tokens` 不会换成 `max_output_tokens`，见[虚拟模型](https://platform.lyrouter.com/ai_gateway/docs/presets#系统提示词何时注入)。
- **用量**：`usage` 原样返回上游的值，网关不补全、不改写。
- **失败回退**：开始输出之前上游返回错误或连接失败时，网关按[失败重试与备用模型](https://platform.lyrouter.com/ai_gateway/docs/fallback)换通道，必要时改用备用模型和工作空间默认模型。接手的模型同样要支持 Responses，否则返回上面的 `unsupported_model_api`。流式输出开始后不再换通道。
- **Codex CLI**：在 Codex 中配置 `wire_api = "responses"` 就是调用本接口，模型和通道还需要支持函数工具。配置方法见 [Codex](https://platform.lyrouter.com/ai_gateway/docs/codex)。
- 配置了配额时，响应带 `x-aigw-quota-*` 响应头，见[网关扩展请求头与响应头](https://platform.lyrouter.com/ai_gateway/docs/gateway-headers)。

## 常见错误

网关返回的错误为 `{"error":{"message":"...","type":"...","code":"..."}}`，`code` 只有部分错误才有。上游原样透传的错误可能是其他形状，例如 `previous_response_id` 指向的响应不存在时，返回的是 400 `{"request_id":"...","code":"InvalidParameter","message":"..."}`，外层没有 `error`，解析时请兼容。

| 状态码 | `error.message` | `error.code` | 原因与处理 |
| --- | --- | --- | --- |
| 400 | `This model does not support the responses API` | `unsupported_model_api` | 模型不支持 Responses。改用支持的模型，或改用 [Chat Completions](https://platform.lyrouter.com/ai_gateway/docs/chat-completions)；Codex 中出现时同样换模型 |
| 400 | `you must provide a model parameter` | `missing_model` | 请求没写 `model`，工作空间也没有默认模型。写上模型 ID |
| 403 | `Model is not available in the model plaza` | `model_not_available` | 工作空间没有开通该模型，见[模型不可用](https://platform.lyrouter.com/ai_gateway/docs/unavailable) |
| 503 | `all routed candidates exhausted` | `no_route_candidate` | 找不到可服务这次请求的通道，例如 `@vmodel/<名称>` 写错、这个虚拟模型不存在。核对名称，见[模型不可用](https://platform.lyrouter.com/ai_gateway/docs/unavailable) |
| 上游状态码 | 上游原文 | 上游原样 | 例如 `previous_response_id` 指向的响应在当前上游不存在。在日志「状态说明」中来源显示为「上游」 |

- 401、403 鉴权问题见[401 / 403：鉴权与权限](https://platform.lyrouter.com/ai_gateway/docs/auth-errors)，429 见[429：限流与配额](https://platform.lyrouter.com/ai_gateway/docs/rate-errors)。
- 500 / 504 是连接上游失败或等待上游超时，响应体是 HTML 页面而不是 JSON，见[超时与流式中断](https://platform.lyrouter.com/ai_gateway/docs/stream-errors)。
- 完整列表见[错误码与请求标识](https://platform.lyrouter.com/ai_gateway/docs/errors)。网关的响应中不包含请求 ID，排查时请在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)中按 API Key 和时间找到这次请求，从日志详情顶部复制 Request ID。
