介绍
实时对话通过 WebSocket(一种在客户端与服务端之间保持长连接、可双向推送数据的协议)建立持久连接,把你的音频或文本输入实时送入对话模型,模型再以增量方式推送文本与语音回复,适合语音助手、实时问答、口语陪练等需要来回交互的场景。 它与实时转录同样走 WebSocket,但用途不同:
可用模型:
- gpt-realtime-2.1:语音对话模型,支持音频与文本输入,实时输出文本与语音回复。
快速开始
连接端点
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 事件持续发送:
发送文本
也可以直接注入一条文本消息,再请求回复:接收回复
服务端会持续推送事件,关键事件类型:event
会话创建、配置更新的确认。收到
session.created 后即可开始发送音频与文本。event
会话项写入完成:用户输入与模型回复各生成一条会话项。
event
一轮回复开始生成。
event
本轮回复的输出项开始、结束。
added 事件里的 item.id 是后续截断音频时要引用的会话项 ID。event
回复语音的增量片段(base64 编码的 PCM16 音频)与结束标记,可边收边播。
event
与回复语音逐句对应的文字稿增量与结束标记,字段
delta 是本次新增的文字。开启语音输出时,回复文本从这个事件取,可用于边播语音边上屏字幕。event
纯文本回复的增量与结束标记,仅在把输出模态设为纯文本(
output_modalities: ["text"])时出现。event
一轮回复完成。该事件携带本轮的 token 用量(
usage),是计费的依据。event
错误事件,包含错误码与说明。请求本身有问题(如
output_modalities 取值非法)时只回一帧 error,会话继续可用;涉及策略(如改模型、余额耗尽)时关闭会话。取回复文本要认准事件。 默认(输出含语音)时模型只推
response.output_audio_transcript.delta,不会推 response.output_text.delta;把输出模态设为纯文本后,文本才走 response.output_text.delta。两种模式都建议一并监听,避免漏字(见下方运行效果)。打断与截断
用户在模型说话途中开口时,已经生成但还没播放的内容会与用户的下一句错位。WebSocket 连接由客户端负责播放,打断后的收尾需要客户端完成。 开启 VAD 时,服务端检测到用户开口后会推送input_audio_buffer.speech_started。客户端收到该事件后:
- 立即停止本地播放,并记录这一轮回复已播放到的位置(毫秒)。
- 发送
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.append、input_audio_buffer.commit 与 response.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。复用官方示例
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 分钟的用量,会话才能建立。
- 在用量与账单的消费明细里可以逐条查看每次实时对话的计费记录。
限制与约束
- 单会话时长:一条 WebSocket 连接最长 62 分钟,到时服务端主动关闭(关闭码
1000,原因session_duration_limit);需要更长请分段重连。 - 空闲断连:客户端与模型双方都没有活动持续 5 分钟时,服务端关闭会话(关闭码
1008,原因idle_timeout)。任意一方有活动都会重置计时,模型持续输出的长回复不会因此中断。 - 余额不足:建立会话时可用余额不足以覆盖约 1 分钟的预留额度,握手直接被拒(HTTP 403),会话不会建立;会话进行中若余额耗尽,已建立的连接会被立即关闭。
- 仅服务端:不支持浏览器直连(校验
Origin头),请在服务端集成。 - 模型锁定:模型在连接 URL 定死,会话中通过
session.update改模型会被拒绝并关闭会话。 - 格式锁定:音频输入与输出均仅支持
audio/pcm@24000单声道,其它格式会被拒绝。 - 音色锁定:
voice在首次回复开始后不可更改,请在首次请求回复前设定。 - 暂不支持:对话会话内的内嵌转写、通过会话项注入音频或图像内容、以及文本以外的其它内容项类型。
- 单轮回复:同一会话同一时刻只允许一轮进行中的回复,上一轮未完成时再次发送
response.create会被拒绝并关闭会话(关闭码1008,原因response_already_active)。
常见错误
更新时间:2026-09-21