> ## Documentation Index
> Fetch the complete documentation index at: https://docs.aihubmix.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 实时对话

> 通过 WebSocket 建立持久连接，与语音对话模型进行低延迟的双向语音／文本交互

## 介绍

实时对话通过 WebSocket（一种在客户端与服务端之间保持长连接、可双向推送数据的协议）建立持久连接，把你的音频或文本输入实时送入对话模型，模型再以增量方式推送文本与语音回复，适合语音助手、实时问答、口语陪练等需要来回交互的场景。

它与[实时转录](/cn/api/realtime-transcription)同样走 WebSocket，但用途不同：

| 维度          | 实时转录                              | 实时对话（本页）                    |
| ----------- | --------------------------------- | --------------------------- |
| 目标          | 把语音转成文字                           | 与模型进行多轮对话，模型会生成回复           |
| 方向          | 单向：音频进、文本出                        | 双向：音频／文本进，文本＋语音出            |
| 连接参数        | `?intent=transcription&model=...` | 仅 `?model=...`（不带 `intent`） |
| 语音活动检测（VAD） | 不支持，必须 `null`                     | 支持，可开启自动断句                  |
| 典型场景        | 会议字幕、直播听写                         | 语音助手、实时口语交互                 |

**可用模型：**

* **gpt-realtime-2.1**：语音对话模型，支持音频与文本输入，实时输出文本与语音回复。

<Warning>
  **本接口面向服务端集成，浏览器无法直连。** 出于安全考虑，网关会校验并拒绝带 `Origin` 头的连接、拒绝 `openai-insecure-api-key` 子协议，密钥只接受标准 `Authorization` 头。浏览器发起的 WebSocket 会自动附带 `Origin` 头，因此会被拒绝。若需在前端做实时对话，请在你自己的服务端建立到网关的连接、再把音频与结果在前端与服务端之间转发。
</Warning>

## 快速开始

### 连接端点

```text theme={null}
wss://aihubmix.com/v1/realtime?model=gpt-realtime-2.1
```

* `model=gpt-realtime-2.1`：**必填**，模型在连接时由 URL 参数定死，会话中不可再更改（见下方约束）。
* **注意与转录的区别**：对话端点**不带** `intent=transcription`。

### 鉴权

握手时通过标准 HTTP 头传入密钥：

```text theme={null}
Authorization: Bearer $AIHUBMIX_API_KEY
```

### 音频格式要求

当前音频输入与输出均只支持一种格式，发送前请将音频转换为：

* **编码**：PCM16（16 位有符号整数，小端序）
* **采样率**：24000 Hz
* **声道**：单声道（mono）

即 `audio/pcm@24000`。输入或输出声明为其它格式（如 G.711/µ-law）会被拒绝并关闭会话。

<Note>
  与转录不同，对话会话**支持**语音活动检测（turn\_detection / VAD）。开启后模型会自动判断一段话何时结束并触发回复；关闭（设为 `null`）则由你手动控制何时提交音频、何时请求回复。二者按需选择即可。
</Note>

## 会话配置（session.update）

连接建立后，客户端可发送一帧 `session.update` 配置对话参数（如语音音色、系统指令、是否开启 VAD）。对话会话的模型已由连接 URL 锚定，因此**不发送 `session.update` 也能直接对话**；需要自定义音色或指令时再发送。

```json theme={null}
{
  "type": "session.update",
  "session": {
    "type": "realtime",
    "instructions": "You are a helpful voice assistant. Keep answers concise.",
    "audio": {
      "input": {
        "format": { "type": "audio/pcm", "rate": 24000 },
        "turn_detection": { "type": "server_vad" }
      },
      "output": {
        "format": { "type": "audio/pcm", "rate": 24000 },
        "voice": "alloy"
      }
    }
  }
}
```

### 配置参数

<ParamField body="session.type" type="string" required>
  会话类型，对话场景为 `realtime`。
</ParamField>

<ParamField body="session.instructions" type="string">
  系统指令，用于设定模型的角色、语气与回答约束。
</ParamField>

<ParamField body="session.output_modalities" type="string[]">
  输出模态，取值为 `["audio"]` 或 `["text"]`：传 `["audio"]`（默认）时模型输出语音，回复文本随 `response.output_audio_transcript.delta` 事件返回；传 `["text"]` 时只输出文本，文本随 `response.output_text.delta` 事件返回。其它组合（如 `["audio", "text"]`）会被拒绝并返回 `error` 事件。
</ParamField>

<ParamField body="session.audio.input.format" type="object" required>
  输入音频格式，固定为 `{ "type": "audio/pcm", "rate": 24000 }`。
</ParamField>

<ParamField body="session.audio.input.turn_detection" type="object | null">
  语音活动检测。传入 `{ "type": "server_vad" }` 开启自动断句；传入 `null` 关闭，由客户端手动提交与请求回复。
</ParamField>

<ParamField body="session.audio.output.format" type="object" required>
  输出音频格式，固定为 `{ "type": "audio/pcm", "rate": 24000 }`。
</ParamField>

<ParamField body="session.audio.output.voice" type="string">
  回复语音的音色。**首次回复开始后不可再更改**：会话进入生成状态后，再次发送的 `voice` 会被忽略（其余配置正常生效）。因此如需指定音色，请在首次请求回复前设置。
</ParamField>

<Note>
  以下能力**本期暂不支持**，配置后会话将被关闭（关闭码 `1008`）：在对话会话内开启内嵌转写（`audio.input.transcription`，原因 `input_transcription_not_supported`）、通过会话项注入音频（原因 `item_audio_not_supported`）或图像（原因 `image_input_not_supported`）、文本以外的其它内容项类型（原因 `unsupported_content_part`）。音频输入请统一走 `input_audio_buffer.append` 通道。
</Note>

## 发送输入

### 发送音频

将 PCM16 音频切成小片（如每 100ms 一片），base64 编码后通过 `input_audio_buffer.append` 事件持续发送：

```json theme={null}
{
  "type": "input_audio_buffer.append",
  "audio": "<base64 编码的 PCM16 音频片段>"
}
```

开启 VAD 时，模型会自动判断说话结束并触发回复；关闭 VAD 时，发完一段音频后需手动提交并请求回复：

```json theme={null}
{ "type": "input_audio_buffer.commit" }
{ "type": "response.create" }
```

### 发送文本

也可以直接注入一条文本消息，再请求回复：

```json theme={null}
{
  "type": "conversation.item.create",
  "item": {
    "type": "message",
    "role": "user",
    "content": [{ "type": "input_text", "text": "Introduce yourself in one sentence." }]
  }
}
{ "type": "response.create" }
```

## 接收回复

服务端会持续推送事件，关键事件类型：

<ParamField body="session.created / session.updated" type="event">
  会话创建、配置更新的确认。收到 `session.created` 后即可开始发送音频与文本。
</ParamField>

<ParamField body="conversation.item.added / conversation.item.done" type="event">
  会话项写入完成：用户输入与模型回复各生成一条会话项。
</ParamField>

<ParamField body="input_audio_buffer.speech_started / input_audio_buffer.speech_stopped" type="event">
  开启 VAD 时，服务端检测到用户开始、结束说话。`speech_started` 通常意味着用户正在打断模型，处理方式见[打断与截断](#interruption)。
</ParamField>

<ParamField body="response.created" type="event">
  一轮回复开始生成。
</ParamField>

<ParamField body="response.output_item.added / response.output_item.done" type="event">
  本轮回复的输出项开始、结束。`added` 事件里的 `item.id` 是后续截断音频时要引用的会话项 ID。
</ParamField>

<ParamField body="response.output_audio.delta / response.output_audio.done" type="event">
  回复语音的**增量**片段（base64 编码的 PCM16 音频）与结束标记，可边收边播。
</ParamField>

<ParamField body="response.output_audio_transcript.delta / response.output_audio_transcript.done" type="event">
  与回复语音逐句对应的文字稿**增量**与结束标记，字段 `delta` 是本次新增的文字。**开启语音输出时，回复文本从这个事件取**，可用于边播语音边上屏字幕。
</ParamField>

<ParamField body="response.output_text.delta / response.output_text.done" type="event">
  纯文本回复的**增量**与结束标记，仅在把输出模态设为纯文本（`output_modalities: ["text"]`）时出现。
</ParamField>

<ParamField body="response.done" type="event">
  一轮回复完成。该事件携带本轮的 token 用量（`usage`），是计费的依据。
</ParamField>

<ParamField body="conversation.item.truncated" type="event">
  截断请求已生效的确认，见[打断与截断](#interruption)。
</ParamField>

<ParamField body="error" type="event">
  错误事件，包含错误码与说明。请求本身有问题（如 `output_modalities` 取值非法）时只回一帧 `error`，会话继续可用；涉及策略（如改模型、余额耗尽）时关闭会话。
</ParamField>

<Note>
  **取回复文本要认准事件。** 默认（输出含语音）时模型只推 `response.output_audio_transcript.delta`，**不会**推 `response.output_text.delta`；把输出模态设为纯文本后，文本才走 `response.output_text.delta`。两种模式都建议一并监听，避免漏字（见下方[运行效果](#run-output)）。
</Note>

<h2 id="interruption">
  打断与截断
</h2>

用户在模型说话途中开口时，已经生成但还没播放的内容会与用户的下一句错位。WebSocket 连接由客户端负责播放，打断后的收尾需要客户端完成。

开启 VAD 时，服务端检测到用户开口后会推送 `input_audio_buffer.speech_started`。客户端收到该事件后：

1. **立即停止本地播放**，并记录这一轮回复已播放到的位置（毫秒）。
2. 发送 `conversation.item.truncate`，把未播放的音频从会话中移除，避免下一轮对话里模型认为这些内容已经说过。

```json theme={null}
{
  "type": "conversation.item.truncate",
  "item_id": "item_ABC123",
  "content_index": 0,
  "audio_end_ms": 1500
}
```

* `item_id`：本轮回复的会话项 ID，取自 `response.output_item.added` 事件的 `item.id`。
* `content_index`：音频内容项的下标，固定为 `0`。
* `audio_end_ms`：保留的音频长度，单位毫秒，按客户端实际播放到的位置填写。

服务端处理完成后返回 `conversation.item.truncated`。截断只影响这一轮回复的音频与对应文字稿，会话本身不受影响，之后可以继续下一轮对话。用 OpenAI SDK 时对应 `conn.conversation.item.truncate(item_id=..., content_index=0, audio_end_ms=...)`。

关闭 VAD（如按键说话）时，按下按键即表示打断：客户端在按下时发送 `response.cancel` 取消进行中的回复，再按上面的步骤截断；松开按键后依次发送 `input_audio_buffer.append`、`input_audio_buffer.commit` 与 `response.create`。

## 完整示例

下面给出三种写法，任选其一：

* **OpenAI 官方 SDK（推荐）**：无需手写 WebSocket，把 `websocket_base_url`（SDK 的 WebSocket 基址参数）指到网关即可复用官方库。
* **OpenAI Agents SDK**：官方 agent 框架的实时语音形态，把 `model_config` 里的 `url` 换成网关地址即可。
* **原生 websockets**：不装 SDK，直接按协议收发帧，依赖最少、便于排查。

<Note>
  **为什么要在连接时传模型名？** AiHubMix 网关在 WebSocket 握手那一刻就要用 `model` 选择模型推理商、鉴权、预留额度，而 `session.update` 是握手完成之后才到、来不及。所以用 SDK 时要给 `connect()` 显式传 `model`（SDK 会把它拼进 URL query）；缺了它网关在**握手期就会拒绝**，连接根本建不起来。与转录不同，对话端点**不需要** `intent=transcription`。
</Note>

<CodeGroup>
  ```python Python (OpenAI SDK) theme={null}
  # 依赖: pip install "openai[realtime]"
  import asyncio
  import base64
  from openai import AsyncOpenAI

  # 复用官方 SDK 只需两处适配:
  #   1) websocket_base_url 指向 AiHubMix 网关(而非 OpenAI 默认地址)
  #   2) connect() 显式传 model,网关握手必需(对话端点不需要 intent)
  client = AsyncOpenAI(
      api_key="sk-***",  # 替换为你的 AiHubMix API 密钥
      websocket_base_url="wss://aihubmix.com/v1",
  )

  async def main():
      async with client.realtime.connect(model="gpt-realtime-2.1") as conn:
          # 1) 配置会话: 系统指令 + 音色 + 开启 VAD(自动断句)
          await conn.session.update(session={
              "type": "realtime",
              "instructions": "You are a helpful voice assistant. Keep answers concise.",
              "audio": {
                  "input": {
                      "format": {"type": "audio/pcm", "rate": 24000},
                      "turn_detection": {"type": "server_vad"},
                  },
                  "output": {
                      "format": {"type": "audio/pcm", "rate": 24000},
                      "voice": "alloy",
                  },
              },
          })

          # 2) 发送一条文本消息并请求回复(音频输入见原生示例的 append/commit)
          await conn.conversation.item.create(item={
              "type": "message",
              "role": "user",
              "content": [{"type": "input_text", "text": "What is the capital of France?"}],
          })
          await conn.response.create()

          # 3) 接收本轮回复: 文本走转写增量, 语音走音频增量
          async for event in conn:
              if event.type == "response.output_audio_transcript.delta":
                  print(event.delta, end="", flush=True)  # 回复文本(输出含语音时)
              elif event.type == "response.output_audio_transcript.done":
                  print()  # 本轮文字稿结束
              elif event.type == "response.output_text.delta":
                  print(event.delta, end="", flush=True)  # 纯文本输出时
              elif event.type == "response.output_text.done":
                  print()
              elif event.type == "response.output_audio.delta":
                  pass  # base64 PCM16 音频片段, 可解码后播放
              elif event.type == "input_audio_buffer.speech_started":
                  pass  # 用户打断: 停播后调用 conn.conversation.item.truncate(...) 截断
              elif event.type == "response.done":
                  print("\n[本轮完成]", event.response.usage)
                  break
              elif event.type == "error":
                  print("\n[错误]", event.to_dict())
                  break

  asyncio.run(main())
  ```

  ```python Python (websockets) theme={null}
  import asyncio
  import base64
  import json
  import websockets

  API_KEY = "sk-***"  # 替换为你的 AiHubMix API 密钥
  URL = "wss://aihubmix.com/v1/realtime?model=gpt-realtime-2.1"

  async def main():
      # websockets >= 13 用 additional_headers；旧版本用 extra_headers
      async with websockets.connect(
          URL, additional_headers={"Authorization": f"Bearer {API_KEY}"}
      ) as ws:
          # 1) 配置会话(关闭 VAD, 手动控制回复时机)
          await ws.send(json.dumps({
              "type": "session.update",
              "session": {
                  "type": "realtime",
                  "instructions": "You are a helpful voice assistant.",
                  "audio": {
                      "input": {
                          "format": {"type": "audio/pcm", "rate": 24000},
                          "turn_detection": None,
                      },
                      "output": {
                          "format": {"type": "audio/pcm", "rate": 24000},
                          "voice": "alloy",
                      },
                  },
              },
          }))

          # 2) 读取本地 PCM16 / 24kHz / 单声道 裸音频,分块发送,再 commit + 请求回复
          async def send_audio():
              with open("audio_pcm16_24k.raw", "rb") as f:
                  pcm = f.read()
              chunk = 24000 * 2 // 10  # 100ms = 采样率 × 2字节 ÷ 10
              for i in range(0, len(pcm), chunk):
                  await ws.send(json.dumps({
                      "type": "input_audio_buffer.append",
                      "audio": base64.b64encode(pcm[i:i + chunk]).decode(),
                  }))
                  await asyncio.sleep(0.1)  # 模拟实时节奏
              # 关闭 VAD 时手动提交并请求回复
              await ws.send(json.dumps({"type": "input_audio_buffer.commit"}))
              await ws.send(json.dumps({"type": "response.create"}))

          asyncio.create_task(send_audio())

          # 3) 接收回复
          async for msg in ws:
              evt = json.loads(msg)
              etype = evt.get("type", "")
              if etype == "response.output_audio_transcript.delta":
                  print(evt.get("delta", ""), end="", flush=True)  # 回复文本(输出含语音时)
              elif etype == "response.output_audio_transcript.done":
                  print()  # 本轮文字稿结束
              elif etype == "response.output_text.delta":
                  print(evt.get("delta", ""), end="", flush=True)  # 纯文本输出时
              elif etype == "input_audio_buffer.speech_started":
                  pass  # 用户打断: 停播后发送 conversation.item.truncate 截断
              elif etype == "response.output_audio.delta":
                  pass  # base64 PCM16 音频片段, 可解码后播放
              elif etype == "response.done":
                  print("\n[本轮完成]", evt.get("response", {}).get("usage"))
                  break
              elif etype == "error":
                  print("\n[错误]", evt.get("error"))
                  break

  asyncio.run(main())
  ```

  ```python Python (Agents SDK) theme={null}
  # 依赖: pip install openai-agents
  import asyncio
  from agents.realtime import (
      OpenAIRealtimeWebSocketModel,
      RealtimeAgent,
      RealtimeSession,
  )

  agent = RealtimeAgent(
      name="Assistant",
      instructions="You are a helpful voice assistant. Keep answers concise.",
  )

  async def main():
      session = RealtimeSession(
          OpenAIRealtimeWebSocketModel(),
          agent,
          None,
          model_config={
              "api_key": "sk-***",  # 替换为你的 AiHubMix API 密钥
              "url": "wss://aihubmix.com/v1/realtime?model=gpt-realtime-2.1",
          },
          run_config={
              "model_settings": {
                  "modalities": ["audio"],
                  "output_audio_format": "pcm16",
                  # 必关: 默认开启的输入音频转写本接口暂不支持, 不关闭会话会被 1008 关闭
                  "input_audio_transcription": None,
              },
          },
      )
      async with session:
          await session.send_message("What is the capital of France?")
          async for event in session:
              if getattr(event, "type", "") == "raw_model_event":
                  data = getattr(event, "data", None)
                  if getattr(data, "type", "") == "transcript_delta":
                      print(getattr(data, "delta", ""), end="", flush=True)
                  elif getattr(data, "type", "") == "turn_ended":
                      print("\n[本轮完成]")
                      return

  asyncio.run(main())
  ```

  ```bash 连接测试 (wscat) theme={null}
  # 用 wscat 快速验证连通性与鉴权（需先 npm i -g wscat）
  wscat -c "wss://aihubmix.com/v1/realtime?model=gpt-realtime-2.1" \
    -H "Authorization: Bearer $AIHUBMIX_API_KEY"

  # 连接成功后，粘贴一帧 session.update 配置，再发文本消息 + response.create 即可开始
  ```
</CodeGroup>

<Tip>
  把任意音频转成本接口要求的裸 PCM 格式，可用 ffmpeg：

  ```bash theme={null}
  ffmpeg -i input.mp3 -f s16le -acodec pcm_s16le -ac 1 -ar 24000 audio_pcm16_24k.raw
  ```
</Tip>

### 复用官方示例

OpenAI 官方发布的实时对话示例多数只依赖 SDK 的基址参数，把地址换成 AiHubMix 端点即可复用：

| 官方示例                             | 只改地址能否复用 | 需要改动的地方                                                                                      |
| -------------------------------- | -------- | -------------------------------------------------------------------------------------------- |
| 官方 Python SDK 实时对话示例             | 可以       | `websocket_base_url` 设为 `wss://aihubmix.com/v1`，`connect()` 传入 `model`                       |
| 官方 Node / JS SDK 实时对话示例          | 可以       | `baseURL` 设为 `https://aihubmix.com/v1`（SDK 会自动换成 `wss` 并拼出 `/realtime?model=...`）            |
| 官方 Agents SDK 实时语音示例             | 可以       | `model_config.url` 设为 `wss://aihubmix.com/v1/realtime?model=gpt-realtime-2.1`，并关闭默认开启的输入音频转写 |
| 官方浏览器端 Demo（如实时控制台、多 Agent 语音示例） | 不可以      | 这类 Demo 由浏览器直连，会被网关的 `Origin` 校验拒绝；且依赖服务端签发临时密钥，本接口只开放服务端 WebSocket                          |

<h2 id="run-output">
  运行效果（线上实测）
</h2>

以下为 OpenAI SDK 示例在 `aihubmix.com` 线上环境（模型 `gpt-realtime-2.1`）的真实运行结果。会话开启 `server_vad`，prompt 与语音均为英文。

**文本输入**

```text theme={null}
# 发送文本 "What is the capital of France?"
[轮次1·文本] 完成 2.33s | 语音输出 2.70s PCM16
  回复：The capital of France is Paris.
  usage：input_tokens 29（text 29）/ output_tokens 81（audio 54 + text 27，含 reasoning 8）
```

**音频输入**

```text theme={null}
# 分块发送 6.3s 英文语音后，模型自动断句并回复
[轮次2·音频] 完成 9.59s | 语音输出 4.35s PCM16
  回复：Everything sounds good on my side, and I'm ready to keep this conversation going.
  usage：input_tokens 117（audio 67 + text 50）/ output_tokens 129（audio 87 + text 42，含 reasoning 11）
VAD 事件：input_audio_buffer.speech_started / input_audio_buffer.speech_stopped
```

**两种配置的实测差异**

| 配置                                       | 实测结果                                                                                                         |
| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| `turn_detection: {"type": "server_vad"}` | 送完音频后收到 `input_audio_buffer.speech_started` 与 `speech_stopped`，模型自动断句并开始回复，无需手动 `commit` 与 `response.create` |
| `output_modalities: ["text"]`            | 回复文本改从 `response.output_text.delta` 返回，本轮无语音输出事件，usage 中 `audio_tokens` 为 0                                  |

<Note>
  实测确认：默认（输出含语音）时回复文本只从 `response.output_audio_transcript.delta` 逐字返回，`response.output_text.delta` 不出现；`response.done` 携带本轮 `usage`；握手耗时约 2 至 4 秒，为建会话时的额度预留开销。
</Note>

## 计费说明

* **按 token 计费**：对话会话在每轮回复完成时随 `response.done` 事件返回本轮 token 用量（`usage`），据此计费。用量按**音频输入 / 音频输出 / 文本输入 / 文本输出**等组件分别计量，各组件单价以[模型详情页](https://aihubmix.com/model/gpt-realtime-2.1)实时挂牌价为准。
* **边用边结算**：这是一条长连接，费用在会话过程中随每轮回复实时扣除，无需等会话结束再一次性结算。建立会话时会先做一次约 1 分钟用量的**额度预留**（仅作准入校验，不是真实扣费），会话结束后释放剩余预留。**因此账户可用余额至少要够约 1 分钟的用量，会话才能建立。**
* 在[用量与账单](https://aihubmix.com)的消费明细里可以逐条查看每次实时对话的计费记录。

## 限制与约束

1. **单会话时长**：一条 WebSocket 连接最长 **62 分钟**，到时服务端主动关闭（关闭码 `1000`，原因 `session_duration_limit`）；需要更长请分段重连。
2. **空闲断连**：客户端与模型双方都没有活动持续 **5 分钟**时，服务端关闭会话（关闭码 `1008`，原因 `idle_timeout`）。任意一方有活动都会重置计时，模型持续输出的长回复不会因此中断。
3. **余额不足**：**建立会话时**可用余额不足以覆盖约 1 分钟的预留额度，握手直接被拒（HTTP 403），会话不会建立；**会话进行中**若余额耗尽，已建立的连接会被立即关闭。
4. **仅服务端**：不支持浏览器直连（校验 `Origin` 头），请在服务端集成。
5. **模型锁定**：模型在连接 URL 定死，会话中通过 `session.update` 改模型会被拒绝并关闭会话。
6. **格式锁定**：音频输入与输出均仅支持 `audio/pcm@24000` 单声道，其它格式会被拒绝。
7. **音色锁定**：`voice` 在首次回复开始后不可更改，请在首次请求回复前设定。
8. **暂不支持**：对话会话内的内嵌转写、通过会话项注入音频或图像内容、以及文本以外的其它内容项类型。
9. **单轮回复**：同一会话同一时刻只允许一轮进行中的回复，上一轮未完成时再次发送 `response.create` 会被拒绝并关闭会话（关闭码 `1008`，原因 `response_already_active`）。

## 常见错误

| 场景                             | 关闭码 / 状态                                   | 说明                                                             |
| ------------------------------ | ------------------------------------------ | -------------------------------------------------------------- |
| 服务未开启                          | HTTP 403 `realtime_disabled`               | 实时对话未对该环境开放                                                    |
| 携带 `Origin` 头 / 浏览器直连          | 握手被拒                                       | 改用服务端连接                                                        |
| 建连时余额不足                        | HTTP 403 `insufficient_user_quota`         | 余额不足以预留约 1 分钟用量，充值后重试                                          |
| 会话中改模型                         | `1008` `model_override_forbidden`          | 模型只能在连接 URL 指定                                                 |
| 音频格式非 PCM                      | `1008` `audio_format_unsupported`          | 转成 `audio/pcm@24000`                                           |
| 首次回复后改音色                       | `voice` 字段被忽略                              | 在首次请求回复前设定 `voice`                                             |
| 开启内嵌转写                         | `1008` `input_transcription_not_supported` | 对话会话本期暂不支持                                                     |
| 会话项注入音频                        | `1008` `item_audio_not_supported`          | 音频请走 `input_audio_buffer.append`                               |
| 会话项注入图像                        | `1008` `image_input_not_supported`         | 本期暂不支持                                                         |
| 会话项使用文本以外的内容类型                 | `1008` `unsupported_content_part`          | 会话项内容仅支持文本                                                     |
| `output_modalities` 取值非法       | `error` 事件 `invalid_value`                 | 仅支持 `["audio"]` 与 `["text"]`，会话不关闭                             |
| 会话达到最长时长                       | `1000` `session_duration_limit`            | 已达 62 分钟上限，重连后继续                                               |
| 双方空闲 5 分钟                      | `1008` `idle_timeout`                      | 任意一方有活动即重置计时                                                   |
| 上一轮回复未结束时再次请求                  | `1008` `response_already_active`           | 等 `response.done` 后再发 `response.create`                        |
| 重复的 `event_id`                 | `1008` `duplicate_event_id`                | 客户端事件的 `event_id` 需在会话内唯一                                      |
| `response.conversation` 设为非默认值 | `1008` `conversation_mode_not_supported`   | 仅支持默认会话模式                                                      |
| 客户端发送服务端专属事件                   | `1008` `client_forged_lifecycle_event`     | `response.*` 命名空间下客户端只能发 `response.create` 与 `response.cancel` |
| 会话中余额耗尽                        | 连接被关闭                                      | 充值后重连                                                          |

***

更新时间：2026-09-21
