Skip to main content

介绍

实时对话通过 WebSocket(一种在客户端与服务端之间保持长连接、可双向推送数据的协议)建立持久连接,把你的音频或文本输入实时送入对话模型,模型再以增量方式推送文本与语音回复,适合语音助手、实时问答、口语陪练等需要来回交互的场景。 它与实时转录同样走 WebSocket,但用途不同: 可用模型:
  • gpt-realtime-2.1:语音对话模型,支持音频与文本输入,实时输出文本与语音回复。
本接口面向服务端集成,浏览器无法直连。 出于安全考虑,网关会校验并拒绝带 Origin 头的连接、拒绝 openai-insecure-api-key 子协议,密钥只接受标准 Authorization 头。浏览器发起的 WebSocket 会自动附带 Origin 头,因此会被拒绝。若需在前端做实时对话,请在你自己的服务端建立到网关的连接、再把音频与结果在前端与服务端之间转发。

快速开始

连接端点

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

鉴权

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

音频格式要求

当前音频输入与输出均只支持一种格式,发送前请将音频转换为:
  • 编码:PCM16(16 位有符号整数,小端序)
  • 采样率:24000 Hz
  • 声道:单声道(mono)
audio/pcm@24000。输入或输出声明为其它格式(如 G.711/µ-law)会被拒绝并关闭会话。
与转录不同,对话会话支持语音活动检测(turn_detection / VAD)。开启后模型会自动判断一段话何时结束并触发回复;关闭(设为 null)则由你手动控制何时提交音频、何时请求回复。二者按需选择即可。

会话配置(session.update)

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

配置参数

string
必填
会话类型,对话场景为 realtime
string
系统指令,用于设定模型的角色、语气与回答约束。
string[]
输出模态,取值为 ["audio"]["text"]:传 ["audio"](默认)时模型输出语音,回复文本随 response.output_audio_transcript.delta 事件返回;传 ["text"] 时只输出文本,文本随 response.output_text.delta 事件返回。其它组合(如 ["audio", "text"])会被拒绝并返回 error 事件。
object
必填
输入音频格式,固定为 { "type": "audio/pcm", "rate": 24000 }
object | null
语音活动检测。传入 { "type": "server_vad" } 开启自动断句;传入 null 关闭,由客户端手动提交与请求回复。
object
必填
输出音频格式,固定为 { "type": "audio/pcm", "rate": 24000 }
string
回复语音的音色。首次回复开始后不可再更改:会话进入生成状态后,再次发送的 voice 会被忽略(其余配置正常生效)。因此如需指定音色,请在首次请求回复前设置。
以下能力本期暂不支持,配置后会话将被关闭(关闭码 1008):在对话会话内开启内嵌转写(audio.input.transcription,原因 input_transcription_not_supported)、通过会话项注入音频(原因 item_audio_not_supported)或图像(原因 image_input_not_supported)、文本以外的其它内容项类型(原因 unsupported_content_part)。音频输入请统一走 input_audio_buffer.append 通道。

发送输入

发送音频

将 PCM16 音频切成小片(如每 100ms 一片),base64 编码后通过 input_audio_buffer.append 事件持续发送:
开启 VAD 时,模型会自动判断说话结束并触发回复;关闭 VAD 时,发完一段音频后需手动提交并请求回复:

发送文本

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

接收回复

服务端会持续推送事件,关键事件类型:
event
会话创建、配置更新的确认。收到 session.created 后即可开始发送音频与文本。
event
会话项写入完成:用户输入与模型回复各生成一条会话项。
event
开启 VAD 时,服务端检测到用户开始、结束说话。speech_started 通常意味着用户正在打断模型,处理方式见打断与截断
event
一轮回复开始生成。
event
本轮回复的输出项开始、结束。added 事件里的 item.id 是后续截断音频时要引用的会话项 ID。
event
回复语音的增量片段(base64 编码的 PCM16 音频)与结束标记,可边收边播。
event
与回复语音逐句对应的文字稿增量与结束标记,字段 delta 是本次新增的文字。开启语音输出时,回复文本从这个事件取,可用于边播语音边上屏字幕。
event
纯文本回复的增量与结束标记,仅在把输出模态设为纯文本(output_modalities: ["text"])时出现。
event
一轮回复完成。该事件携带本轮的 token 用量(usage),是计费的依据。
event
截断请求已生效的确认,见打断与截断
event
错误事件,包含错误码与说明。请求本身有问题(如 output_modalities 取值非法)时只回一帧 error,会话继续可用;涉及策略(如改模型、余额耗尽)时关闭会话。
取回复文本要认准事件。 默认(输出含语音)时模型只推 response.output_audio_transcript.delta不会response.output_text.delta;把输出模态设为纯文本后,文本才走 response.output_text.delta。两种模式都建议一并监听,避免漏字(见下方运行效果)。

打断与截断

用户在模型说话途中开口时,已经生成但还没播放的内容会与用户的下一句错位。WebSocket 连接由客户端负责播放,打断后的收尾需要客户端完成。 开启 VAD 时,服务端检测到用户开口后会推送 input_audio_buffer.speech_started。客户端收到该事件后:
  1. 立即停止本地播放,并记录这一轮回复已播放到的位置(毫秒)。
  2. 发送 conversation.item.truncate,把未播放的音频从会话中移除,避免下一轮对话里模型认为这些内容已经说过。
  • 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.appendinput_audio_buffer.commitresponse.create

完整示例

下面给出三种写法,任选其一:
  • OpenAI 官方 SDK(推荐):无需手写 WebSocket,把 websocket_base_url(SDK 的 WebSocket 基址参数)指到网关即可复用官方库。
  • OpenAI Agents SDK:官方 agent 框架的实时语音形态,把 model_config 里的 url 换成网关地址即可。
  • 原生 websockets:不装 SDK,直接按协议收发帧,依赖最少、便于排查。
为什么要在连接时传模型名? AiHubMix 网关在 WebSocket 握手那一刻就要用 model 选择模型推理商、鉴权、预留额度,而 session.update 是握手完成之后才到、来不及。所以用 SDK 时要给 connect() 显式传 model(SDK 会把它拼进 URL query);缺了它网关在握手期就会拒绝,连接根本建不起来。与转录不同,对话端点不需要 intent=transcription
把任意音频转成本接口要求的裸 PCM 格式,可用 ffmpeg:

复用官方示例

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

运行效果(线上实测)

以下为 OpenAI SDK 示例在 aihubmix.com 线上环境(模型 gpt-realtime-2.1)的真实运行结果。会话开启 server_vad,prompt 与语音均为英文。 文本输入
音频输入
两种配置的实测差异
实测确认:默认(输出含语音)时回复文本只从 response.output_audio_transcript.delta 逐字返回,response.output_text.delta 不出现;response.done 携带本轮 usage;握手耗时约 2 至 4 秒,为建会话时的额度预留开销。

计费说明

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

限制与约束

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

常见错误


更新时间:2026-09-21