媒体处理 WebSocket 音频端到端接入

这篇档面向客户端接入方,描述如何通过 WebSocket 协议接入本服务的端到端实时语音对话能力(Speech-to-Speech, S2S),包含 URL 规范、鉴权流程、全量事件协议、交互时序、错误码与常。

相关产品
媒体处理 产品页,含版本规格、价格与购买入口。

测试工具:单击打开测试工具 Demo

注意:说明:

一、1. 服务概述

·通信协议:WebSocket (RFC 6455) over TLS,wss:// 生产强制、ws:// 仅内网调试。

·消息格式:Text 帧承载 JSON 事件,Binary 帧不接受(会被服务端忽略并打 warn); 原厂协议透传模式(isProxy=1)下使用原厂协议。

·音频承载:所有音频均以 base64 字符串放在 JSON 事件的 audio / delta 字段。

·支持的能力系列:

model 参数 定位
audio-og-realtime-2.1 端到端语音对话 · 基础能力。
audio-og-realtime-2.1mini 端到端语音对话 · 轻量型。
audio-og-live-1 端到端语音对话 · Live 能力
audio-s-realtime-3.0 端到端语音对话 · 增强能力。
audio-gg-3.8-live 端到端语音对话 · Live 能力(支持图片输入)

注意:说明:

·单会话最大空闲超时:默认30秒,可通过 timeoutSec 查询参数覆盖,上限120秒。

·未指定 model 时的兜底:服务端根据账号维度的默认路由做兜底,仍未命中时使用 audio-og-realtime-2.1。

三、2.1 URL 模板

wss://{host}/ete/v1/{appid} ?model=<audio-og-realtime-2.1|audio-og-realtime-2.1mini|audio-og-live-1|audio-s-realtime-3.0|audio-gg-3.8-live> &secretId=<TC3 SecretId> &signature=<TC3-HMAC-SHA256 hex> &timeStamp=<unix 秒> &expired=<unix 秒> &nonce=<随机整数> &timeoutSec=<会话空闲超时秒> &isProxy=<0|1>

注意:说明:

注意:

四、2.2 路径参数

参数 必填 说明
appid 是 腾讯云 AppID,十进制无符号整数,随路径 /ete/v1/{appid} 传入。非数字时握手返回 400;必须与 secretId 所属主账号 AppID 一致,否则返回 401 authentication_failed: code=4111。

五、2.3 查询参数(Query)

参数 必填 类型 说明
secretId 是 string CAM SecretId。
signature 是 string TC3-HMAC-SHA256 签名(hex,小写),见 第 3 节。
timeStamp 是 int64 签名时的当前 UNIX 时间戳(秒)。
expired 是 int64 签名过期时间的 UNIX 时间戳(秒),必须 >= timeStamp 且 >= now,否则返回401 invalid_timestamp。
nonce 是 string 随机串(推荐随机整数),参与签名,防重放由 CAM 校验。
model 否 string 能力系列别名,见 服务概述。未指定时按账号默认路由兜底。默认模式下握手阶段不校验取值,非法值会在首次 session.update 时返回 error(code=pipeline_init_failed) 并断开连接;isProxy=1 时在握手阶段校验,非法值返回400 invalid_request: unsupported model。
timeoutSec 否 int 会话空闲超时(秒),默认30;> 120 时截断为120;<= 0 或非数字时忽略并使用默认值30。
resId 否 string 业务侧资源 ID,透传用于对账。
isProxy 否 string 协议模式,仅接受 0 / 1,其它值握手返回400 invalid_request: invalid param。0 或不传(默认):这篇档描述的统一 Realtime GA 协议。1:原厂协议透传,服务端只做鉴权 / 限流并原样转发消息,见 2.4.1。

注意:说明:

注意:除上表参数外,服务端不读取其他 query 参数;但任何出现在 URL 上的参数(signature 除外)都会参与签名校验。

六、2.4 URL 示例

wss://mps.cloud.tencent.com/ete/v1/1301234567 ?model=audio-s-realtime-3.0 &secretId=AKIDzxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx &signature=8f2c…4b3a &timeStamp=1735012345 &expired=1735015945 &nonce=8391023472 &timeoutSec=60 &resId=order_20260826_0001

七、2.4.1 原厂协议透传模式(isProxy=1)

URL 参数 isProxy=1 时,服务端不再提供统一的 Realtime GA 协议,客户端直接使用各能力系列对应模型的原厂协议收发消息,服务端原样转发。握手阶段的鉴权、账户状态检查、并发连接数限流与默认模式一致(见 第 3 章 / 11.1)。

适用于已按模型原厂协议完成开发、希望直接复用原厂能力的接入方。

2.4.1.1 开启方式

在 URL 上追加 isProxy=1,该参数必须参与签名(见 3.1):

wss://mps.cloud.tencent.com/ete/v1/1301234567 ?model=audio-s-realtime-3.0 &isProxy=1 &secretId=AKIDzxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx &signature=8f2c…4b3a &timeStamp=1735012345 &expired=1735015945 &nonce=8391023472 &timeoutSec=60

isProxy 取值 行为
不传 / 0 默认模式,统一 Realtime GA 协议(这篇档除本节外的全部内容),行为不变。
1 原厂协议透传模式(本节)。
其它 握手返回 400 invalid_request: invalid param。

model 的取值与默认模式相同(不传时按账号默认路由兜底),无法识别时握手返回400 invalid_request: unsupported model。

九、2.5.1 概述

本节集中罗列5个对外能力系列(audio-og-realtime-2.1、audio-og-realtime-2.1mini、audio-og-live-1、audio-s-realtime-3.0、audio-gg-3.8-live)对上行事件 / 下行事件 / 可变字段 / 多模态输入的支持情况。矩阵列为 model 取值,行为能力点。

注意:说明:

十、2.5.2 上行事件(Client → Server)

事件 / 能力点 audio-og-realtime-2.1(mini) audio-og-live-1 audio-s-realtime-3.0 audio-gg-3.8-live
session.update(首次) ✅ 建立会话 ✅ 建立会话 ✅ 建立会话 ✅ 建立会话
session.update(后续再次发送) ⚠️ 见下方注 ⚠️ 同左 ⚠️ 同左 ⚠️ 同左
input_audio_buffer.append ✅ ✅ ✅ ✅
input_audio_buffer.commit ✅ ❌ 无回执(内置 VAD 自动切分)。 ✅ ⚠️ 通知尽快结束当前用户输入,无回执。
input_audio_buffer.clear ✅ 清除已送入音频 + 回 cleared。 ⚠️ 仅回 cleared,已送入的音频不会被清除。 ⚠️ 同左 ⚠️ 同左
response.create(带 instructions) ✅ 作为本轮生成指令。 ⚠️ 见 9.1 ✅ 让服务端说出该文本。 ⚠️ 作为一条用户文本输入并回复,见 10.3。
response.create(不带 instructions) ✅ 触发一轮生成。 ⚠️ 见 9.1 ⚠️ 静默 no-op(无回执)。 ⚠️ 仅在之前追加过 message 时触发回复,否则 no-op。
response.cancel ✅ ❌ 无回执(no-op,依赖内置 barge-in)。 ✅ ⚠️ 立即回 response.done(cancelled),见 10.4。
conversation.item.create – message / function_call_output ✅ ⚠️ 见 9.3 ✅ ✅(不回 conversation.item.created)。
conversation.item.create – 含 input_image ✅ Data URL / HTTP URL / detail ❌ not_supported ❌ not_supported ⚠️ 仅 Data URL,见 10.5。
conversation.item.retrieve / delete ✅ ❌ 无回执 ✅ ❌ 无回执
conversation.item.truncate ✅ ❌ not_supported ❌ not_supported ❌ not_supported
output_audio_buffer.clear ✅ 取消当前 response + 回 cleared。 ⚠️ 仅回 cleared(不会打断当前回复)。 ✅ 同第一列 ✅ 同 response.cancel + 回 cleared。
session.close ✅ ✅ ✅ ✅
transcription_session.update ❌ not_supported ❌ not_supported ❌ not_supported ❌ not_supported
其它未知 type 静默忽略 静默忽略 静默忽略 静默忽略

注意:说明:

注意:后续 session.update 的实际行为(所有能力一致):会话参数在首次 session.update 时一次性生效,此后再发送的 session.update 不会生效,voice / instructions / tools / delegation 等均不会变更;服务端仍会回一条 session.updated,其内容是客户端历次提交字段的浅合并回显,不代表已生效。唯一的例外是下行音频格式:每次 session.update 都会重新校验 audio.output.format,非法时回 unsupported_output_format 并断开连接。如需变更会话参数,请重新建立连接。

十一、2.5.3 下行事件(Server → Client)

事件 audio-og-realtime-2.1(mini) audio-og-live-1 audio-s-realtime-3.0 audio-gg-3.8-live
session.updated ✅ ✅ ✅ ✅
input_audio_buffer.speech_started / speech_stopped ✅ ❌ 不下发 ❌ 不下发 ⚠️ 不保证下发,见 10.2
input_audio_buffer.committed ✅ ❌ 不下发 ✅ ⚠️ 不保证下发,同上。
input_audio_buffer.cleared ✅ ✅ ✅ ✅
conversation.item.input_audio_transcription.delta ✅ ⚠️ 携带 start_ms / end_ms,不带 item_id。 ✅ ✅
conversation.item.input_audio_transcription.completed ✅(可能带 usage) ❌ 不下发(客户端自行断句,见 9.5)。 ✅ ✅(不带 usage;在助手开始回复时下发)。
conversation.item.input_audio_transcription.failed ❌ 不下发 ❌ 不下发 ✅ ❌ 不下发
conversation.item.created ✅ ❌ 不下发 ✅ ❌ 不下发
conversation.item.retrieved / deleted ✅ ❌ 不下发 ✅ ❌ 不下发
response.created ✅ ⚠️ 见 9.1 ❌ 不下发 ✅
response.output_item.added / content_part.added ✅ ⚠️ 仅 function call 时下发。 ✅ ✅
response.output_audio.delta ✅ ⚠️ 不带 item_id / response_id。 ✅ ✅
response.output_audio_transcript.delta ✅ ⚠️ 携带 start_ms / end_ms,不带 item_id / response_id。 ✅ ✅
response.output_audio.done / response.output_audio_transcript.done ✅ ❌ 不下发 ✅ ✅(被打断 / 取消的轮次同样下发)。
response.content_part.done / response.output_item.done ✅ ⚠️ 仅 function call 时下发。 ✅ ✅
response.done(含 usage) ✅ ⚠️ 仅 responses delegation 下发;client delegation 不下发。 ✅ ✅
response.function_call_arguments.done ✅ ⚠️ 仅 responses delegation。 ✅ ✅
response.function_call_arguments.delta ❌ 不下发 ❌ 不下发 ❌ 不下发 ❌ 不下发
output_audio_buffer.started ❌ 不下发 ❌ 不下发 ✅ ❌ 不下发
output_audio_buffer.stopped ✅ ❌ 不下发 ✅ ✅
output_audio_buffer.cleared ✅ ✅ ✅ ✅
session.delegation.created ❌ 不下发 ✅ 专属(见 9.2) ❌ 不下发 ❌ 不下发
session.closed ✅ 客户端 session.close 后下发。 ✅ 同左 ✅ 同左 ✅ 同左
rate_limits.updated / response.output_text.* ❌ 不下发 ❌ 不下发 ❌ 不下发 ❌ 不下发
error ✅ ✅ ✅ ✅

十二、2.5.4 session.update 字段支持(仅首次 session.update 生效)

字段 audio-og-realtime-2.1(mini) audio-og-live-1 audio-s-realtime-3.0 audio-gg-3.8-live
instructions ✅ ✅ ✅ ✅
audio.output.voice ⚠️ 需在服务端音色白名单内,否则使用默认音色。 ✅ 不校验,直接使用。 ⚠️ 仅支持加密音色 ID,见 Q9。 ⚠️ 需在内置音色列表内(大小写不敏感),否则使用默认音色。
audio.input.format / audio.output.format ✅ 见 第 7 节 ✅ 同左 ✅ 同左 ✅ 同左
audio.input.transcription.language ✅ ❌ 静默忽略(自动识别语言)。 ❌ 静默忽略(自动识别语言)。 ✅ 推荐 BCP-47(如 zh-CN / en-US)。
audio.input.turn_detection(VAD) ❌ 静默忽略(由服务端配置决定)。 ❌ 静默忽略(强制启用 VAD)。 ❌ 静默忽略。 ❌ 静默忽略(强制启用 VAD)。
tools ✅ ✅ 非空时自动切换为 responses delegation(见 9.2)。 ✅ ✅ 仅 type=function
tool_choice ❌ 静默忽略 ❌ 静默忽略(固定 auto) ❌ 静默忽略 ❌ 静默忽略
audio.output.speed / audio.output.loudness ❌ 静默忽略 ❌ 静默忽略 ✅ ❌ 静默忽略
delegation(client / responses) ❌ 静默忽略 ✅ 专属 ❌ 静默忽略 ❌ 静默忽略
extension(私有扩展 asr / tts / dialog) ❌ 静默忽略 ❌ 静默忽略 ✅ ❌ 静默忽略

十三、2.5.5 多模态输入与用量字段

能力点 audio-og-realtime-2.1(mini) audio-og-live-1 audio-s-realtime-3.0 audio-gg-3.8-live
音频输入 ✅ ✅ ✅ ✅
文本输入 ✅ ✅(client delegation 下仅 system / assistant 角色生效)。 ✅ ✅
图片输入(input_image) ✅ ❌ ❌ ⚠️ 仅 Data URL(png / jpeg / webp / heic / heif)。
response.done.usage ⚠️ 有用量数据时携带。 ⚠️ 仅 responses delegation。 ⚠️ 有用量数据时携带。 ⚠️ 有用量数据时携带。
reasoning_tokens / cache_write_tokens ⚠️ 适用时存在。 ⚠️ 仅 responses delegation 且适用时存在。 ⚠️ 适用时存在。 ⚠️ 仅 reasoning_tokens,适用时存在。

十四、3. 签名

签名沿用腾讯云 CAM 签名标准。

流程参考:签名生成。

十五、3.1 参与签名的查询参数

除 signature 本身外的所有 query 参数都参与签名(按字母升序排列)。这意味着:

·必填参数 secretId / timeStamp / expired / nonce 一定参与签名。

·可选参数(如 model / timeoutSec / resId)只要你在 URL 里带上了就必须参与签名;未带则不参与。

·signature 参数本身不参与签名(作为签名结果放在 URL 上)。

其他业务参数(如音频格式、voice、instructions、tools 等)通过握手成功后的 session.update 事件传递,与 URL 无关。

十六、3.2 签名算法

Step 1: 排序并 URL-encode,构造规范化查询串 keys = sort(参与签名的 params keys) // 除 signature 之外的所有 query canonicalQueryString = keys.map(k => k + '=' + urlEncode(params[k])).join('&')Step 2: 构造规范化请求 canonicalRequest = "post" + "\\n" + "/ete/v1/{appid}" + "\\n" + canonicalQueryString + "\\n" + "content-type:application/json; charset=utf-8" + "\\n" + "host:" + host + "\\n" + "" + "\\n" + "content-type;host" + "\\n"Step 3: 构造待签字符串 date = UTC(timeStamp) 的 YYYY-MM-DD credentialScope = date + "/mps/tc3_request" hashedRequest = hex( SHA-256( canonicalRequest ) ) stringToSign = "TC3-HMAC-SHA256" + "\\n" + timeStamp + "\\n" + credentialScope + "\\n" + hashedRequestStep 4: 计算派生签名密钥 kDate = HMAC-SHA256( date, "TC3" + secretKey ) kService = HMAC-SHA256( "mps", kDate ) kSigning = HMAC-SHA256( "tc3_request", kService )Step 5: 计算最终签名 signature = hex( HMAC-SHA256( stringToSign, kSigning ) ) // 小写 hex

十七、3.3 JavaScript 参考实现

浏览器环境下的完整实现见 测试 Demo。

generateSignature() 方法,使用浏览器原生 crypto.subtle API 完成。以下节选核心片段:

async function sign(cfg) { const now = Math.floor(Date.now() / 1000); const expired = now + 3600; const params = { // 除 signature 外的所有 query 参数, 均需参与签名 model: cfg.model, // 可选; 未传则不放入 params timeStamp: String(now), expired: String(expired), nonce: String(Math.floor(Math.random() * 1e10)), secretId: cfg.secretId, timeoutSec: String(cfg.timeoutSec || 30), // 若使用 resId, 也一并放入并参与签名: // resId: cfg.resId, }; const path = `/ete/v1/${cfg.appid}`; const keys = Object.keys(params).sort(); const canonicalQueryString = keys .map((k) => `${k}=${encodeURIComponent(params[k])}`).join('&'); const canonicalRequest = [ 'post', path, canonicalQueryString, 'content-type:application/json; charset=utf-8', `host:${cfg.host}`, '', 'content-type;host', '', ].join('\\n'); const hashed = await sha256Hex(canonicalRequest); const date = new Date(now * 1000).toISOString().split('T')[0]; const scope = `${date}/mps/tc3_request`; const stringToSign = ['TC3-HMAC-SHA256', String(now), scope, hashed].join('\\n'); const kDate = await hmacSha256(date, 'TC3' + cfg.secretKey); const kService = await hmacSha256('mps', kDate); const kSigning = await hmacSha256('tc3_request', kService); const signature = bufToHex(await hmacSha256(stringToSign, kSigning)); const q = new URLSearchParams(); keys.forEach((k) => q.append(k, params[k])); q.append('signature', signature); return `wss://${cfg.host}${path}?${q.toString()}`;}

十八、3.4 Go 参考实现

func sign(host, appID, secretID, secretKey, model string, timeoutSec int) string { now := time.Now().Unix() expired := now + 3600 params := map[string]string{ "timeStamp": strconv.FormatInt(now, 10), "expired": strconv.FormatInt(expired, 10), "nonce": strconv.Itoa(rand.Intn(1e9)), "secretId": secretID, "timeoutSec": strconv.Itoa(timeoutSec), } if model != "" { params["model"] = model } keys := make([]string, 0, len(params)) for k := range params { keys = append(keys, k) } sort.Strings(keys) parts := make([]string, 0, len(keys)) for _, k := range keys { parts = append(parts, k+"="+url.QueryEscape(params[k])) } cqs := strings.Join(parts, "&") path := "/ete/v1/" + appID canonical := strings.Join([]string{ "post", path, cqs, "content-type:application/json; charset=utf-8", "host:" + host, "", "content-type;host", "", }, "\\n") hashed := sha256Hex([]byte(canonical)) date := time.Unix(now, 0).UTC().Format("2006-01-02") scope := date + "/mps/tc3_request" stringToSign := strings.Join([]string{ "TC3-HMAC-SHA256", strconv.FormatInt(now, 10), scope, hashed, }, "\\n") kDate := hmac256([]byte(date), []byte("TC3"+secretKey)) kService := hmac256([]byte("mps"), kDate) kSigning := hmac256([]byte("tc3_request"), kService) signature := hex.EncodeToString(hmac256([]byte(stringToSign), kSigning)) q := url.Values{} for k, v := range params { q.Set(k, v) } q.Set("signature", signature) return "wss://" + host + path + "?" + q.Encode()}func sha256Hex(b []byte) string { h := sha256.Sum256(b); return hex.EncodeToString(h[:]) }func hmac256(msg, key []byte) []byte { m := hmac.New(sha256.New, key); m.Write(msg); return m.Sum(nil) }

十九、3.5 鉴权失败的握手响应

服务端在 WebSocket 握手升级前就完成鉴权与并发检查,任一步失败会以 HTTP 响应拒绝,不会进入 WebSocket 通道,因此客户端不会收到 error 事件,而是拿到一个标准的 HTTP 状态码。见 第 11.1 节。

21、4.1 关键约定

握手成功后服务端不主动下发任何事件。首条消息必须由客户端发起:

·客户端发 session.update 完成会话初始化,服务端才回一条 session.updated。

·收到 session.updated 才代表“可以开始送音频”。

23、4.3 打断当前 response

客户端可以随时发送 {"type": "response.cancel"} 打断当前正在生成的 response。

服务端会立即停止 TTS 下发,并回一条 response.done(status 可能为 cancelled)。

25、5.1 事件类型速览

下表仅列事件用途;各 model 对每个事件的支持与差异情况集中见 2.5 模型能力矩阵。

事件 type 用途
session.update 更新会话参数(首次调用等价于“完成握手初始化”)。
input_audio_buffer.append 追加一段用户音频(base64 编码)。
input_audio_buffer.commit 手动提交音频缓冲(关闭 server_vad 时使用)。
input_audio_buffer.clear 清空未 commit 的上行音频缓冲。
response.create 主动请求服务端生成一次 response(可携带 instructions 用作打招呼 / 干预回复)。
response.cancel 打断当前正在生成的 response。
conversation.item.create 向会话上下文新增一条 item(含 function_call_output 回传)。
conversation.item.retrieve 请求获取指定 item 详情。
conversation.item.delete 删除指定 item。
conversation.item.truncate 截断已生成的 assistant 音频(部分场景不支持,会回 error(not_supported))。
output_audio_buffer.clear 清空当前 assistant 音频播放缓冲(服务端会同步映射为 response.cancel)。
transcription_session.update 独立 transcription 会话更新(当前不支持,会回 error(not_supported))。
session.close 主动优雅关闭会话,服务端会回 session.closed 携带会话总用量后断开(所有能力均支持,详见 9.4)

注意:说明:

注意:首次 session.update 之前收到的控制事件:response.create / conversation.item.create / retrieve / delete / truncate 回 error(code=session_not_ready);input_audio_buffer.append / commit / response.cancel 静默丢弃;input_audio_buffer.clear / output_audio_buffer.clear 仍回 cleared;session.close 正常执行关闭流程。未知 type 一律静默忽略。

26、5.2 session.update

{ "type": "session.update", "session": { "instructions": "你是一个专业的智能助手, 说话简洁友好。", "audio": { "input": { "format": { "type": "audio/pcm", "rate": 16000 }, "transcription": { "language": "zh" } }, "output": { "format": { "type": "audio/pcm", "rate": 24000 }, "voice": "xxxxxx", "speed": 100, "loudness": 100 } }, "tools": [ { "type": "function", "name": "get_current_time", "description": "获取当前系统时间", "parameters": { "type": "object", "properties": {}, "required": [] } } ] }}

字段说明:

字段 类型 说明
session.instructions string System instructions,覆盖服务端默认。
session.audio.input.format.type string 上行音频格式,见 第 7 节。
session.audio.input.format.rate int 上行采样率(Hz)。
session.audio.input.transcription.language string ASR 转写语言(ISO 639-1,如 zh / en / ja)。留空则由服务端自动检测;部分能力基于内建语言自适应,客户端指定值可能会被忽略。
session.audio.output.format.type string 下行音频格式。
session.audio.output.format.rate int 下行采样率(Hz)。
session.audio.output.voice string 发音人 ID。支持明文音色 ID 与加密音色 ID(由音色加密服务生成),服务端自动识别。若音色不适用于当前会话能力,服务端会静默 fallback 到默认音色(详见 Q9)。
session.audio.output.speed int 语速(部分能力支持,不支持时静默忽略)。
session.audio.output.loudness int 响度(部分能力支持,不支持时静默忽略)。
session.tools array Function tool 定义,遵循标准 GA Function Tool schema(audio-gg-3.8-live 仅支持 type=function,其它类型被忽略)。
session.delegation string/object/null 仅 audio-og-live-1,见 9.2。
session.extension object 私有扩展字段 {asr, tts, dialog}(仅 audio-s-realtime-3.0 生效,其它能力忽略)。

VAD / turn_detection:服务端默认启用 server_vad。客户端在 session.audio.input.turn_detection 里的自定义参数,服务端会尽力适配;具体生效情况以 session.updated.session.audio.input.turn_detection 回执为准。

27、5.3 input_audio_buffer.append

{ "type": "input_audio_buffer.append", "audio": "<base64-encoded audio chunk>"}

·audio 是一段完整的音频负载,服务端按 session.audio.input.format 声明的格式解码。

·推荐分片大小:20ms-40ms(PCM 16k 单声道下约 640~1280 字节 base64 前)。

·首次 session.update 之前送入的 append 会被静默丢弃。

28、5.4 input_audio_buffer.commit / clear

{ "type": "input_audio_buffer.commit" }{ "type": "input_audio_buffer.clear" }

·commit 仅在关闭 server_vad 时需要显式调用。

·clear 用于取消当前未提交的用户音频,无论能力后端是否原生支持,服务端都会回一条 input_audio_buffer.cleared 事件给客户端。

29、5.5 response.create / cancel

{ "type": "response.create", "response": { "instructions": "你好, 我是你的智能助手。" // 可选 }}{ "type": "response.cancel" }

各能力语义:

能力 带 response.instructions 不带 instructions
audio-og-realtime-2.1(mini) instructions 作为本轮生成指令(不是逐字朗读)。 触发一轮生成。
audio-s-realtime-3.0 服务端逐字合成该文本(打招呼 / 播报)。 静默 no-op,无回执(function call 回传后会自动续接,无需发送)。
audio-og-live-1(client delegation) 服务端让模型说出该文本。 回 error(code=not_supported)。
audio-og-live-1(responses delegation) 触发继续生成,instructions 被丢弃。 继续生成(function call 回传后必须发送)。
audio-gg-3.8-live instructions 作为一条用户文本输入,模型据此回复(不是逐字朗读)。 之前通过 conversation.item.create 追加过 message 时触发回复,否则静默 no-op。

response.create 支持的字段(仅 audio-og-realtime-2.1(mini) 支持 instructions 以外的字段):

字段 类型 说明
response.instructions string 见上表。
response.voice string 本轮临时覆盖的音色(可选)。
response.modalities []string 本轮输出模态(可选,标准 GA 语义)。
response.metadata object 元数据(可选)。

30、5.6 conversation.item.create

用途 1:追加 user / assistant message

{ "type": "conversation.item.create", "item": { "type": "message", "role": "user", "content": [{ "type": "input_text", "text": "帮我查一下深圳今天的天气" }] }}

用途 2:回传 function call 结果(详见 第 8 节)

{ "type": "conversation.item.create", "item": { "type": "function_call_output", "call_id": "call_abc123", "output": "2026-08-26 09:30:00" }}

用途 3:图片输入(多模态)

在同一条 user message 里混合 input_text 与 input_image 内容块,可以让模型基于图片回答问题。当前仅 audio-og-realtime-2.1 / audio-og-realtime-2.1mini /audio-gg-3.8-live 支持图片输入,其它 model 收到含 input_image 的 item 会返回 error(code=not_supported)。

注意:说明:

注意:audio-gg-3.8-live 仅支持写法 A(Data URL),格式与大小限制不同,且不回执。conversation.item.created,见 10.5。

写法 A:Data URL(推荐,无需暴露外部 URL)

{ "type": "conversation.item.create", "item": { "type": "message", "role": "user", "content": [ { "type": "input_text", "text": "请描述这张图里的关键信息" }, { "type": "input_image", "image_url": "data:image/jpeg;base64,/9j/4AAQSkZJRg…", "detail": "auto" } ] }}

写法 B:HTTP(S) URL

{ "type": "conversation.item.create", "item": { "type": "message", "role": "user", "content": [ { "type": "input_text", "text": "帮我识别这张截图里的错误码" }, { "type": "input_image", "image_url": "https://example.com/foo.png", "detail": "high" } ] }}

字段说明:

字段 类型 必填 说明
type string 是 固定 "input_image"。
image_url string 是 Data URL(data:image/{jpeg,png,gif,webp};base64,…)或 HTTP/HTTPS URL。
detail string 否 "auto"(默认)/ "low" / "high"。low 定量小 token 快回复;high 分辨率高,识别细节更好,消耗更多 tokens。

发送后的时序:

1. 服务端确认:conversation.item.created。

2. 客户端需主动触发一次响应:{"type": "response.create"}(因为图片消息不像语音会自动触发 VAD)。

3. 服务端下发常规的 response.output_audio.delta / response.output_audio_transcript.delta / response.done。

图片 tokens 计入 response.done.response.usage.input_tokens 总量;detail=high 的图片 tokens 显著高于 detail=low。

限制与建议:

·单条 message 建议图片数量 ≤ 4 张,避免 message 过大导致响应变慢。

·Data URL 单张建议 ≤ 2 MB(base64 后 ≤ 2.7 MB),过大可能被拒绝。

·HTTP URL 必须公网可访问,不支持带鉴权头的私有资源。

·动态图(gif) 可能只取首帧,不做逐帧理解。

·图片输入不会占用语音会话的音频通道,与麦克风持续送入的 input_audio_buffer.append 可并行使用。

31、5.7 conversation.item.retrieve / delete / truncate

{ "type": "conversation.item.retrieve", "item_id": "item_xxx" }{ "type": "conversation.item.delete", "item_id": "item_xxx" }{ "type": "conversation.item.truncate", "item_id": "item_xxx", "content_index": 0, "audio_end_ms": 1500 }

32、5.8 output_audio_buffer.clear

{ "type": "output_audio_buffer.clear" }

服务端会:

1. 内部触发一次 response.cancel 打断当前 TTS。

2. 回一条 output_audio_buffer.cleared,客户端据此清空本地音频播放缓冲。

34、6.1 完整事件清单

下表仅列事件触发时机;各 model 对每个事件的支持情况集中见 2.5 模型能力矩阵。

事件 type 触发时机
session.updated 每次收到 session.update 后回显;首次即为握手后的第一条下行事件。
error 参数错误 / 服务后端异常 / 不支持的能力。
conversation.item.created 一条 item 加入会话上下文(服务端确认回执)。
conversation.item.retrieved 响应 conversation.item.retrieve。
conversation.item.deleted 响应 conversation.item.delete。
conversation.item.input_audio_transcription.delta 用户 ASR 增量转写(非稳态)。
conversation.item.input_audio_transcription.completed 用户 ASR 稳态转写(可能携带 usage)。
conversation.item.input_audio_transcription.failed 用户 ASR 转写失败。
input_audio_buffer.committed 用户一句话音频入缓冲(VAD 触发或客户端 commit)。
input_audio_buffer.cleared 响应 input_audio_buffer.clear。
input_audio_buffer.speech_started 服务端 VAD 检测到用户开始说话。
input_audio_buffer.speech_stopped 服务端 VAD 检测到用户停止说话。
response.created 一次 response 开始生成。
response.output_item.added response 内新增一个 output_item(message / function_call)。
response.content_part.added output_item 内新增一个 content part(audio / text)。
response.output_audio.delta 助手音频增量(base64)。
response.output_audio.done 助手音频结束。
response.output_audio_transcript.delta 助手音频伴随文本增量。
response.output_audio_transcript.done 助手音频伴随文本稳态。
response.function_call_arguments.done Function call 参数完整下发(不下发 .delta 增量)。
response.content_part.done content part 结束。
response.output_item.done output_item 结束。
response.done 一次 response 全部结束(可能携带 usage;被打断时 status=cancelled)。
output_audio_buffer.started 服务端开始下发助手音频。
output_audio_buffer.stopped 服务端一段助手音频结束。
output_audio_buffer.cleared 响应客户端 output_audio_buffer.clear。
session.delegation.created audio-og-live-1 专属:模型发起 delegation(见 9.2)。
session.closed 客户端主动 session.close 后下发一次,携带 reason / usage / session_duration_seconds(详见 9.4)。

注意:说明:

35、6.2 session.updated

{ "type": "session.updated", "event_id": "evt_xxxxxxxx", "session": { "id": "sess_xxxxxxxx", "type": "realtime", "model": "audio-s-realtime-3.0", "audio": { "input": {…}, "output": {…} }, "instructions": "…" }}

客户端应在收到此事件之后才开始送 input_audio_buffer.append。

session 对象是客户端历次 session.update 中 session 字段的浅合并回显,服务端仅补充 id(会话 ID)、type(固定 realtime)、model 三个字段,不代表实际生效的配置。其中 model 取值规则:客户端在 session.model 中自行传入时原样回显;否则为 URL 参数 modelURL 未指定时 model 则显 audio-og-realtime-2.1——注意此时实际生效的能力可能是账号默认路由选中的其它能力,客户端不要依赖该字段判断实际能力,建议始终在 URL 中显式传 model。

36、6.3 用户 ASR 事件

{ "type": "conversation.item.input_audio_transcription.delta", "event_id": "evt_xxx", "item_id": "item_xxx", "content_index": 0, "delta": "深圳", "start_ms": 1240, "end_ms": 1560}{ "type": "conversation.item.input_audio_transcription.completed", "event_id": "evt_xxx", "item_id": "item_xxx", "content_index": 0, "transcript": "深圳今天天气怎么样", "usage": { "type": "duration", "seconds": 2 }}

usage 字段承载本次 ASR 转写的用量(type="duration" + seconds),可用于客户端本地成本观测。目前仅 audio-og-realtime-2.1(mini) 可能携带,其余情况缺省(omitempty);客户端应做字段可选兼容。

start_ms / end_ms 是 delta 对应音频在会话时间线上的起止毫秒偏移(以会话开始为零点),仅 audio-og-live-1 携带,且取值为 0 时字段会被省略。该能力下 delta 不带 item_id,服务端也不下发 transcription.completed,客户端需按 start_ms / end_ms 的 gap 自合并完整问话,具体见 9.5。其它能力正常下发 completed,不携带这两个字段。

audio-s-realtime-3.0 的 ASR delta 为追加式增量;识别过程中若修正了已识别文字,增量可能为空并被跳过,最终以 completed.transcript 为准。

transcription.completed.usage 与 response.done.response.usage(token 用量)是两个独立并列的用量字段:前者按 ASR 音频转写秒数记录,后者按 response 的 token 用量记录,量纲不同不可互相换算。

37、6.4 助手音频 / 文本事件

{ "type": "response.output_audio.delta", "event_id": "evt_xxx", "response_id": "resp_xxx", "item_id": "item_xxx", "output_index": 0, "content_index": 0, "delta": "<base64 pcm16 / opus chunk>"}{ "type": "response.output_audio_transcript.delta", "event_id": "evt_xxx", "response_id": "resp_xxx", "item_id": "item_xxx", "delta": "深圳"}

注意:说明:

注意:audio-og-live-1 下这两个事件不带 response_id / item_id,transcript delta 额外带 start_ms / end_ms,见 9.5。客户端解析时请把 item_id 作可选

38、6.5 response.done

{ "type": "response.done", "event_id": "evt_xxx", "response": { "id": "resp_xxx", "status": "completed", "usage": { "total_tokens": 123, "input_tokens": 45, "output_tokens": 78, "input_token_details": { "text_tokens": 20, "audio_tokens": 15, "cached_tokens": 10, "cached_tokens_details": { "text_tokens": 6, "audio_tokens": 4 } }, "output_token_details": { "text_tokens": 30, "audio_tokens": 48, "reasoning_tokens": 25 } } }}

注意:说明:

注意:reasoning_tokens(仅具备推理能力的模型会下发)表示本轮回答的推理 tokens,为 output_token_details.text_tokens 的内含子集(不与 text / audio 并列);仅在适用时存在,其它能力下为 0 或缺省。input_token_details.cache_write_tokens 表示提示词缓存首次写入的 tokens(与 cached_tokens 命中互斥)。

status 取值:audio-og-realtime-2.1(mini) 为 completed / cancelled / failed /incomplete;audio-s-realtime-3.0 / audio-gg-3.8-live 仅有 completed / cancelled;audio-og-live-1 缺省为 completed。

response.usage 承载本轮 response 的 token 用量明细,字段结构对齐标准 Realtime GA;无用量数据时该字段缺省(omitempty)。客户端可用于本地用量观测。

39、6.6 error

{ "type": "error", "event_id": "evt_xxx", "error": { "type": "invalid_request_error", "code": "unsupported_output_format", "message": "unsupported opus output rate 44100, allowed: 8000/12000/16000/24000/48000", "event_id": "客户端触发本 error 的原事件 event_id" }}

以下错误发生后服务端会主动关闭连接:unsupported_output_format /pipeline_init_failed / upstream_send_error / upstream_error / upstream_closed。空闲超时(idle_timeout)时服务端直接关闭连接,客户端通常收不到该 error 事件,应以 WebSocket close 作为判断依据。完整错误码见 11.1。

41、7.1 上行音频(Input)

格式(format.type) 说明 允许的采样率
pcm / audio/pcm / pcm16 / pcm_s16le / s16le 16-bit signed LE mono PCM 任意(推荐 16000)
opus / audio/opus 裸 Opus packet(每个 append 携带一个完整 packet) 8k / 12k / 16k / 24k / 48k

42、7.2 下行音频(Output)

格式 允许的采样率 备注
pcm 任意 服务端会按需做重采样至客户端声明的采样率。
opus 8k / 12k / 16k / 24k / 48k 服务端负责编码为裸 Opus packet;每个 response.output_audio.delta.delta 通常对应一个 20 ms Opus 帧。

兼容 MIME 别名:客户端可以用 audio/pcm / pcm / pcm16 / pcm_s16le 任一形式声明 PCM;用 audio/opus / opus 声明 Opus。服务端会自动归一化。

43、7.3 服务端下行链路策略

服务端在会话建立时会根据客户端声明的 session.audio.output.format 自动选择最优下行链路(直接透传或服务端重采样 / 格式转换),客户端无感知。

客户端只需保证 format / rate 落在 7.1 / 7.2 表格声明的合法范围内;实际生效的格式会在 session.updated.session.audio 里给出。

45、8.1 时序

回传工具结果后是否需要 response.create:

能力 是否需要 说明
audio-og-realtime-2.1(mini) 需要 标准 GA 语义,回传后发 {"type":"response.create"}。
audio-s-realtime-3.0 不需要 收到工具结果后自动续接;发送空 response.create 无副作用(no-op)。
audio-og-live-1(responses delegation) 需要 不会自动续接;多个并行 call 需全部回传后再发一次。
audio-og-live-1(client delegation) — 不会触发 function call,见 9.2。
audio-gg-3.8-live 不需要 收到工具结果后自动续接(新的一轮 response);发送空 response.create 无副作用(no-op)。

注意:说明:

注意:统一建议:所有 function_call_output 回传后都发送一次不带 instructions 的 response.create,可同时兼容以上能力。

46、8.2 关键字段

下行 response.function_call_arguments.done:

{ "type": "response.function_call_arguments.done", "event_id": "evt_xxx", "response_id": "resp_xxx", "item_id": "item_xxx", "call_id": "call_abc123", "name": "get_current_time", "arguments": "{}"}

上行 conversation.item.create 回传:

{ "type": "conversation.item.create", "item": { "type": "function_call_output", "call_id": "call_abc123", "output": "2026-08-26 09:30:00" }}

注意:说明:

注意:客户端按标准 Realtime GA 语义发送即可;按上表"统一建议"处理续接即可兼容各能力。audio-s-realtime-3.0 一轮触发多个 call 时,服务端会拆成多条 function_call_arguments.done(该能力下事件不带 item_id),每个 call 需分别回传。audio-gg-3.8-live 一轮可能触发多个 call,每个 call 需分别回传;触发 function call 的那一轮会先下发 response.done,续接回复是新一轮 response_id

47、8.3 完整可运行示例

参见 测试工具 中:

·勾选左侧 “启用 Demo Tool” 复选框。

·提问 “现在几点了?”。

·观察运行日志中完整的 function call 时序。

48、9. audio-og-live-1 专属交互协议

本章集中说明 audio-og-live-1 相比其它能力系列的行为差异与专属协议扩展。事件名与字段结构仍沿用 Realtime GA,但该能力缺少多类边界事件、部分控制事件语义不同,客户端需要按本章做单独适配(主要是按时间戳自行断句、按 delegation 模式处理工具调用与上下文注入)。

49、9.1 协议兼容性总览

·会话参数一次性生效:voice / instructions / tools / delegation 均在首次 session.update 时生效,后续 session.update 不生效(所有能力一致,见2.5.1)。如需变更,请重开会话。

·上行控制事件的实际行为:

事件 行为
input_audio_buffer.commit 不支持,无回执(内置 VAD 自动切分轮次)。
input_audio_buffer.clear 仅回 input_audio_buffer.cleared,已送入的音频不会被清除。
response.cancel no-op,无回执(内置 barge-in,用户说话即自动打断)。
output_audio_buffer.clear 仅回 output_audio_buffer.cleared,当前回复不会被打断。
response.create client delegation:带 instructions 时让模型说出该文本,不带时回 not_supported;responses delegation:触发继续生成(instructions 被丢弃)。
conversation.item.create 见 9.3;含 input_image 时回 not_supported。
conversation.item.retrieve / delete 不支持,无回执。
conversation.item.truncate 回 error(code=not_supported)。

·VAD 强制启用:内置语音端点检测且不可关闭,turn_detection 会被忽略。

·不下发 ASR / 助手文本的边界事件:不下发 conversation.item.input_audio_transcription.completed、response.output_audio.done、

response.output_audio_transcript.done、speech_started / speech_stopped、input_audio_buffer.committed。用户 ASR delta 与助手 transcript delta 额外携带 start_ms / end_ms(以会话开始为零点的毫秒偏移),客户端按 gap 自行断句,见 9.5。

·delta 事件不带 item_id / response_id:该能力为连续流模型,没有 item 维度:

·conversation.item.input_audio_transcription.delta 不带 item_id。

·response.output_audio_transcript.delta / response.output_audio.delta 不带 item_id / response_id。

客户端展示层应基于 start_ms / end_ms 自行分组(例如本地生成 client-asr-${serial} / client-llm-${serial})。function_call 相关事件仍携带 item_id / call_id。

·response.created / response.done:

·responses delegation:只在整个会话首个助手 delta 到达时下发一次;不下发 response.done。

·client delegation:response.created,此后不再下发;不下发 response.done。客户端应根据 transcript 时间戳判定每轮回复结束。不下发 response.done。

50、9.2 Delegation 模式 (responses 模式需要联系我们单独开启,默认不支持)

audio-og-live-1 有两种 delegation 模式,客户端可在首次 session.update 中通过 session.delegation 字段声明。两者的核心区别是是否支持 function call:

模式 function call 上下文注入 适用场景
responses ✅ 模型将工具推理委托给服务端工具推理服务,下发 function_call_arguments.done,客户端执行后回传。 ❌ 需要调用外部工具(天气、查询、本地数据)。
client ❌ 不会触发 function call,tools 被忽略。 ✅ 通过 conversation.item.create(role=system/assistant) 纯语音对话,背景信息由客户端主动注入。

注意:说明:

注意:使用 responses 模式需要为账号开通工具推理能力;未配置时首次 session.update 回 error(code=pipeline_init_failed) 并断开连接。

两种模式的交互时序对比:

responses 模式(需回传工具结果并再发 response.create):

client 模式(无 function call,背景信息由客户端注入):

51、9.2.1 显式声明

支持以下写法(取值大小写不敏感):

// 简写{ "type": "session.update", "session": { "delegation": "responses" } }// 原生对象(仅读取 type 字段){ "type": "session.update", "session": { "delegation": { "type": "responses" } } }// 显式 null:强制 client 模式(覆盖账号默认配置){ "type": "session.update", "session": { "delegation": null } }

非法值(既不是 client 也不是 responses)视为未声明,进入下一级自动决策,不会导致会话拒绝。

52、9.2.2 自动决策优先级

服务端按以下优先级选择模式(高 → 低):

1. 客户端显式声明的 session.delegation(含显式 null → client)。

2. session.tools 非空 → responses。

3. 账号维度默认配置。

4. 兜底 client。

决策流程可视化:

53、9.2.3 边界行为

·客户端声明 client 但同时携带了 session.tools:尊重客户端选择走 client,tools 被忽略(仅服务端日志 warn),不阻断会话。

·最终选中 responses 但账号未开通工具推理能力:首次 session.update 回 error(code=pipeline_init_failed) 并断开连接;此时建议改用 client 模式或联系管理员开通。

·responses 模式下 tool_choice 固定为 auto,客户端传入的 tool_choice 被忽略。

54、9.3 client 模式下的上下文注入

client 模式下,客户端可以在任意时刻(无需等待服务端请求)通过 conversation.item.create 向模型注入上下文。模型在需要外部信息时会下发

session.delegation.created(target=client),客户端可据此补充上下文,但这不是必需的。

服务端会自动为注入内容附带最近一次 target=client 的 delegation ID(尚未收到时按会话级上下文注入),客户端无需也无法自行指定 delegation_id(item 中携带该字段会被忽略)。

注意:说明:

注意:responses 模式下 conversation.item.create 的 item 按标准语义处理(用于 function_call_output 回传等),不做下表的 role 映射。

55、9.3.1 支持的 role 语义

item.role 语义 适用场景
system 静默上下文,模型会用作思考依据但不会主动读出来。 注入用户画像、时间地点、外部查询结果等。
assistant 让模型主动说出的一段话。 定制开场白、播报事件通知。
user / 其他 / 缺省(如 function_call_output) 忽略,无回执(仅服务端日志)。 —

注意:说明:

注意:本模式下服务端不会回 conversation.item.created;文本为空的 item 同样被忽略且无回执。

上下文注入的完整闭环时序:

注意:system 与 assistant 两种 role 的区别:system 是静默注入(模型会思考但不发声),assistant 是主动说出(模型立即用 TTS 合成语音)。

56、9.3.2 item.content 写法

支持两种 GA 兼容写法(等价):

// 写法 A: input_text (推荐)"content": [{ "type": "input_text", "text": "…" }]// 写法 B: text"content": [{ "type": "text", "text": "…" }]

多个 content 块的 text 会被服务端直接拼接为单个字符串(不加分隔符);拼接后超过1800 个字符的部分会被截断(单次注入上限约 500 tokens)。content 中包含 input_image 时整条 item 回 error(code=not_supported)。

57、9.3.3 完整示例

示例 A:注入用户画像作为静默背景

{ "type": "conversation.item.create", "item": { "type": "message", "role": "system", "content": [{ "type": "input_text", "text": "用户身份: VIP; 语言偏好: 中文; 回复要简短" }] }}

效果:模型后续回答会考虑这些信息,但不会主动读出来。

示例 B:让模型主动开场白

{ "type": "conversation.item.create", "item": { "type": "message", "role": "assistant", "content": [{ "type": "input_text", "text": "你好,我是你的 AI 助手,请问有什么可以帮你?" }] }}

效果:模型立即用 TTS 说出这段文本。

示例 C:注入外部查询结果

{ "type": "conversation.item.create", "item": { "type": "message", "role": "system", "content": [{ "type": "input_text", "text": "北京当前晴, 25°C, 湿度 40%" }] }}

效果:模型基于新信息继续对话,比如回答"今天穿什么合适"。

58、9.4 优雅关闭与最终用量

注意:说明:

注意:适用范围:本节协议(session.close / session.closed)是本服务的私有扩展,四种能力均支持,放在本章仅为历史原因。

客户端可在断开 WebSocket 之前发送 session.close,让服务端返回本会话的总用量。

标准 Realtime GA 协议下客户端直接 ws.close() 无法感知服务端会话级总消耗。

59、9.4.1 上行 session.close

客户端主动关闭会话时发送:

{ "type": "session.close" }

无其他字段。服务端收到后会:

1. 停止后续上行处理;

2. 收尾当前会话:

·audio-og-realtime-2.1(mini) / audio-s-realtime-3.0 / audio-gg-3.8-live:若有进行中的 response,先执行一次 response.cancel(当前回复会被打断),再最多等待 10 秒收到该轮 response.done 以加最后一轮 usage。

·audio-og-live-1:等待模型侧结束会话,最多 10 秒(不打断当前回复)。

3. 下发一次 session.closed 事件携带本会话总用量。

4. 关闭 WebSocket 连接。

因此从发送 session.close 到收到 session.closed 最长可能约 10 秒。首次 session.update 之前发送 session.close 也会正常收到 session.closed(用量为 0)。

60、9.4.2 下行 session.closed

{ "type": "session.closed", "event_id": "evt_xxx", "reason": "client_request", "session_duration_seconds": 87.3, "usage": { "total_tokens": 1488, "input_tokens": 1442, "output_tokens": 46, "input_token_details": { "cached_tokens": 0, "cache_write_tokens": 0 }, "output_token_details": { "reasoning_tokens": 11 } }}

字段语义:

·reason:当前固定为 client_request。空闲超时、服务内部异常等服务端主动断开的场景下,session.closed 不会送达客户端,客户端只能观察到 WebSocket close。

·session_duration_seconds:会话时长(秒)。audio-og-live-1 优先使用模型侧统计的会话时长;其它能力或无该统计时,按上行音频累计时长计算(Opus 上行按解码后的时长)。

·usage:会话内各轮 response.done.response.usage 的累计值,字段结构与之一致(含 reasoning_tokens / cache_write_tokens 明细)。该字段总是存在;audio-og-live-1的 client delegation 下或从未产生 token 用量时各字段为 0。

61、9.4.3 推荐流程

兜底建议:服务端收尾最长约 10 秒,客户端发 session.close 后建议启动一个略大于10秒的定时器(如12秒),超时未收到 session.closed(例如网络异常)则主动 ws.close(),避免 UI 卡住。若业务更在意断开速度而非拿到总用量,可缩短该定时器,代价是可能收不到 session.closed。测试页里的 disconnect() 是这套流程的参考实现(定时器为5秒)。

注意:如果客户端直接 ws.close() 而不发 session.close,服务端无法下发 session.closed,但会话总用量仍会在服务端完整统计;如需获取可携带会话 ID 联系管理员。

62、9.5 ASR / 助手文本的客户端自行断句

audio-og-live-1 是"连续流"模型,用户 ASR 与助手 transcript 的 delta 边界只反映音频节奏,不是语义 turn 边界。服务端把每个 delta 携带的 start_ms / end_ms(以会话开始为零点的毫秒偏移)原样下发给客户端,不在服务端合成 .completed / .done 边界事件。

63、9.5.1 影响范围

受此策略影响、audio-og-live-1 下 不下发的事件:

·conversation.item.input_audio_transcription.completed

·conversation.item.input_audio_transcription.failed

·input_audio_buffer.speech_started / .speech_stopped

·input_audio_buffer.committed

·response.output_audio.done

·response.output_audio_transcript.done

对应会额外携带 start_ms / end_ms 、且不带 item_id / response_id 的下行事件:

·conversation.item.input_audio_transcription.delta(用户 ASR)

·response.output_audio_transcript.delta(助手文本)

·response.output_audio.delta(助手音频;不带 start_ms / end_ms,仅不带 ID)

注意:说明:

注意:start_ms / end_ms 为0时字段会被省略,客户端应按缺省为0处理。

64、9.5.2 推荐的客户端断句算法

·维护 { curItemID, lastEndMs }:

·curItemID 为当前合成中的 utterance 本地 ID。

·lastEndMs 为当前 utterance 最后一条 delta 的 end_ms。

·收到新的 delta { start_ms, end_ms, delta }:

·若 curItemID 为空 或 start_ms – lastEndMs > GAP_MS(经验值 600~1000ms):

·认为上一句已结束,把 curItemID 对应的 UI 条目标为稳态。

·分配新的 curItemID(例如 client-asr-${serial},client-llm-${serial})。

·把 delta 追加到 curItemID 的缓冲,刷新 UI 为非稳态;

·更新 lastEndMs = end_ms。

ASR 与助手 transcript 两条通道互相独立,各自维护一套状态。

注意:说明:

注意:其它能力系列不受影响:audio-og-realtime-2.1(mini) 与 audio-s-realtime-3.0 仍按标准 Realtime GA 下发完整的 .completed / .done 事件,start_ms / end_ms 不保证存在,客户端应按能力系列分支处理:收到 delta 带 start_ms 则走时间戳断句;否则沿用 .completed / .done 稳态事件驱动。

65、9.5.3 参考实现

浏览器测试页中有两个对称的最小参考实现(均 gapMs = 800):

·handleClientSynthAsrDelta():用户 ASR 断句,生成 client-asr-${serial} 本地 ID。

·handleClientSynthAssistantDelta():助手文本断句,生成 client-llm-${serial} 本地 ID。

两个函数共享相同的模板:按 start_ms – lastEndMs > gapMs 切换条目,将上一条标为稳态后开启新条目。

66、9.6 完整交互时序(client / responses 两种模式)

audio-og-live-1 的下行时序与 4.2 典型时序 相比有若干关键差异:不下发 transcription.completed / speech_started / speech_stopped / input_audio_buffer.committed / response.output_audio.done / response.output_audio_transcript.done;所有 ASR 与助手 transcript delta

额外携带 start_ms / end_ms;response.done 行为随 delegation.type 而不同。本节分别给出两种模式的完整时序。

注意:约定:

67、9.6.1 client delegation 模式

模型自己完成推理与 TTS;需要外部信息时下发 session.delegation.created(target=client),客户端可通过 conversation.item.create(role=system/assistant)回灌。本模式不下发 response.done,response.created 仅在会话首轮下发一次,客户端通过 ASR / assistant transcript 的 start_ms / end_ms 时间戳 gap 自行判定 turn 边界。

68、9.6.2 responses delegation 模式

模型把工具推理委托给服务端工具推理服务;每轮推理完成时服务端立即下发一次 response.done(含 token usage)。多轮 function_call 场景下每轮独立下发一次 response.done 传 function_call_output 后 function_call_output 必须再发 response.create 才会续接。

69、9.6.3 两种模式快速对照

维度 client delegation responses delegation
工具推理 ❌ 无 ✅ 服务端工具推理服务
工具能力 ❌ 不支持(tools 被忽略) ✅ 支持 tools + function_call
上下文注入 ✅ conversation.item.create(role=system/assistant) ❌ item 按标准语义处理(用于回传 function_call_output)
session.delegation.created target: "client" target: "responses"
response.created 仅会话首轮一次 每轮一次
response.done 下发 ❌ 不下发(客户端自行断句) ✅ 每轮推理完成立即下发
Token usage ❌ 无(session.closed.usage 各字段为 0) ✅ response.done.response.usage 携带每轮 token
典型适用场景 快速接入、依赖客户端状态的对话 需外部工具查询(天气、股价、本地数据)

70、9.7 与其它能力系列的对照速查

完整的模型×事件支持矩阵集中在 2.5 模型能力矩阵 一节提供,此处仅给出 audio-og-live-1 最需关注的行为差异:

·VAD 强制启用:turn_detection 被忽略;input_audio_buffer.commit 与 response.cancel 无回执(no-op),由内置 VAD 自动切分轮次与内置 barge-in 处理;output_audio_buffer.clear 只回 cleared,无法打断当前回复。

·response.create 语义随 delegation 而异:见 9.1。

·response.done 语义不同:仅 responses delegation 下在每轮推理完成时立即下发,含 token usage;client delegation 下不下发。

·不下发 ASR / 助手文本的边界事件:transcription.completed / speech_started /speech_stopped / input_audio_buffer.committed / response.output_audio.done /response.output_audio_transcript.done 均不下发;ASR / assistant transcript delta 额外携带 start_ms / end_ms,客户端自行断句,见 9.5。

·专属协议扩展:

·session.delegation:client / responses 双模式(见 9.2)。

·conversation.item.create 在 client 模式下用于上下文注入(见 9.3)。

·session.delegation.created 下行事件。

·不支持图片输入:input_image content 块会直接回 not_supported,不会静默丢弃图片部分后只用文本;需图片能力时请切换到 audio-og-realtime-2.1(mini) 或 audio-gg-3.8-live。

·非致命错误不下发:模型侧的非致命错误(如工具推理服务异常)仅记录在服务端,会话继续(工具调用可能失效);只有连接级异常时客户端才会收到 upstream_error /upstream_closed 并断开。

71、10. audio-gg-3.8-live 接入说明

audio-gg-3.8-live 沿用标准 Realtime GA 事件名、字段结构与 response 生命周期事件(response.created → output_item.added → output_audio.delta → *.done → response.done),按 第 4 章 编写的客户端可以直接接入。本章列出需要关注的行为差异,完整 支持矩阵见 2.5。

建连示例:

wss://{host}/ete/v1/{appid}?model=audio-gg-3.8-live&secretId=…&signature=…&timeStamp=…&expired=…&nonce=…

注意:兼容说明:

注意:历史别名 audio-gem-3.8-live(任意大小写)仍可继续使用,服务端会自动归一为audio-gg-3.8-live,行为与计费完全一致。新接入请使用 audio-gg-3.8-live。

72、10.1 会话参数

·一次性生效:instructions / voice / tools / language 均在首次 session.update 时生效,后续 session.update 不生效(所有能力一致)。如需变更请重新建立连接。

·音色(session.audio.output.voice):仅支持以下内置音色,大小写不敏感;不在列表内(如 alloy)时静默回退到默认音色,不中断建连:

Zephyr / Puck / Charon / Kore / Fenrir / Leda / Orus / Aoede / Callirrhoe /

Autonoe / Enceladus / Iapetus / Umbriel / Algieba / Despina / Erinome / Algenib /

Rasalgethi / Laomedeia / Achernar / Alnilam / Schedar / Gacrux / Pulcherrima /

Achird / Zubenelgenubi / Vindemiatrix / Sadachbia / Sadaltager / Sulafat

·转写语言(session.audio.input.transcription.language):可选,作为 ASR 语言提示,推荐 BCP-47 形式(如 zh-CN / en-US);不传时自动识别。

·工具(session.tools):遵循标准 GA Function Tool schema(name / description /parameters),仅支持 type=function,其它类型被忽略。

·VAD:服务端强制启用,turn_detection 被忽略。

·音频格式:上下行格式与采样率同 第 7 节,由服务端统一转换。

·会话时长:本服务不限制会话总时长,但模型服务对单会话时长可能有上限;达到上限时连接以 error(code=upstream_closed) 断开,客户端需重新建连(上下文不会保留)。

73、10.2 下行事件差异

事件 行为
input_audio_buffer.speech_started / speech_stopped / committed 不保证下发(依赖模型服务是否提供语音活动信号)。客户端请勿以此作为必需的状态驱动,推荐以 response.created / transcription.delta 作为"用户已说话 / 模型已开始回复"的信号。
conversation.item.input_audio_transcription.delta ✅ 追加式增量
conversation.item.input_audio_transcription.completed ✅ 由服务端合成,transcript 为本段用户话语各 delta 的拼接;在助手开始回复时下发(模型未回复时,在用户开始下一段话或本轮结束时下发)。不带 usage。
conversation.item.created ❌ 不下发(含 conversation.item.create 的回执)。
response.created / response.done ✅ 每轮回复各一次;response_id 由服务端生成。
response.output_audio_transcript.delta / .done ✅ .done 的 transcript 为本轮各 delta 的拼接。
output_audio_buffer.started ❌ 不下发。
output_audio_buffer.stopped ✅ 在本轮音频结束时下发。

74、10.3 response.create 语义

场景 行为
带 response.instructions instructions 作为一条用户文本输入发给模型,模型据此回复(不是逐字朗读)。用于"主动打招呼"时请写成指令形式,如 "请用一句话向用户打招呼"。
不带 instructions,且之前通过 conversation.item.create 追加过 message 触发模型基于已追加内容回复。
不带 instructions,其它情况 静默 no-op,无回执(function call 回传后模型会自动续接,无需发送)。

conversation.item.create(type=message)只追加上下文、不会自动触发回复,与标准 GA 一致;role=assistant 作为模型历史发言,user / system 均作为用户输入。

注意:触发回复(带 instructions 或追加 message 后的 response.create)时,若当前有回复正在进行,该回复可能被打断并以 response.done(status=cancelled) 结束。

75、10.4 打断与取消

·用户说话打断(barge-in):模型正在回复时用户开始说话,当前回复会被自动打断,服务端立即下发 response.output_audio.done / response.output_audio_transcript.done(如有)与 response.done.status=cancelled)。客户端收到后应清空本地播放缓冲。

·response.cancel / output_audio_buffer.clear:服务端立即以 status=cancelled 结束当前 response,并丢弃该轮后续的音频 / 文本 / function call;output_audio_buffer.clear 额外回 output_audio_buffer.cleared。无进行中的 response 时 response.cancel 为 no-op,无回执。

·被取消轮次的 usage 可能不完整,未结算部分会计入下一轮 response.done.usage。

76、10.5 图片输入

请求写法同 5.6 用途 3 · 写法 A,差异如下:

项目 audio-gg-3.8-live
image_url 仅支持 Data URL:data:image/{png,jpeg,webp,heic,heif};base64,…(image/jpg 视同 image/jpeg)。也兼容 {"url": "data:…"} 对象写法。
HTTP(S) URL ❌ 不支持,回 error(code=invalid_image)。
gif 等其它格式 ❌ 不支持,回 error(code=invalid_image)。
单张大小 解码后 ≤ 7 MB,超过回 error(code=invalid_image);建议 ≤ 2 MB 以降低延迟。
detail 忽略。
回执 不下发 conversation.item.created;成功时无回执,失败时回 error(code=invalid_image)。
校验失败 整条 item 不生效(文本也不会发送),不会静默丢弃图片只发文本。

发送后需主动发 {"type": "response.create"} 触发回复。图片 tokens 计入 response.done.response.usage.input_token_details.image_tokens。

77、10.6 Function Call

流程同 第 8 节,差异:

·模型发起调用时下发 response.function_call_arguments.done(带 response_id / item_id /call_id / name / arguments),随后立即下发本轮 response.done。

·客户端通过 conversation.item.create(type=function_call_output) 回传结果,call_id 须与下行一致;output 推荐使用 JSON 字符串(如 "{\\"time\\":\\"09:30\\"}"),非 JSON 字符串按纯文本处理。

·模型收到结果后自动续接,以新的一轮 response(新 response_id)播报结果,无需发送 response.create。

·一轮可能同时触发多个 call,每个 call 需分别回传。

·模型可能在等待工具结果时继续与用户对话,客户端请勿假设"function call 之后的下一轮 response 一定是工具结果的播报"。

78、10.7 用量

response.done.response.usage 与 session.closed.usage 结构同 Q11:

·input_token_details:text_tokens / audio_tokens / image_tokens / cached_tokens(适用时)。

·output_token_details:text_tokens / audio_tokens / reasoning_tokens(适用时,为 text_tokens 的内含子集)。

·不下发 cache_write_tokens。

81、11.1 握手阶段的 HTTP 拒绝码

在 WebSocket 升级完成前的鉴权与并发检查阶段,任一失败会以 HTTP 状态码拒绝:

HTTP 状态 Reason Phrase 触发原因
400 invalid_request: … URL 参数缺失 / appid 非法 / model 值非法。
401 invalid_timestamp timeStamp 或 expired 已过期或格式错误。
401 authentication_failed: code=<n> CAM 签名校验失败。
403 account_invalid 账户欠费 / 冻结。
429 connection_limit_exceeded: uin=… num=… max=… 并发连接数超上限。
500 authentication_failed: <err> CAM 后端调用异常。
500 check_user_status_error: <err> 账户状态查询异常。
500 limit_check_error: <err> 并发限流查询异常。

客户端应根据这些状态码提示用户重试 / 联系管理员。

82、11.2 会话阶段的 error 事件

握手成功后,业务错误通过 JSON error 事件下发:

error.type error.code 说明
invalid_request_error invalid_json 消息不是合法 JSON。
invalid_request_error invalid_audio 上行音频 base64 解码或解码器解析失败。
invalid_request_error unsupported_output_format 下行 format 非 pcm / opus,或 opus 采样率不在白名单。
invalid_request_error not_supported 使用了当前会话能力下不支持的控制事件(如 conversation.item.truncate / transcription_session.update / 不带 instructions 的空 response.create)。
invalid_request_error session_not_ready 未先发 session.update 就送控制事件(response.create / conversation.item.* 等)。
invalid_request_error missing_item conversation.item.create 缺 item 字段。
invalid_request_error missing_item_id conversation.item.retrieve / delete 缺 item_id 字段。
server_error pipeline_init_failed 服务端会话初始化失败。
server_error upstream_send_error 服务端向能力后端发送数据失败。
server_error upstream_error 能力后端返回异常。
server_error upstream_closed 能力后端主动关闭。
session_expired idle_timeout 会话空闲超时(默认 30 s,可通过 timeoutSec 覆盖)。

84、Q1: 为什么建连成功后什么事件都没有收到?

本服务采用“客户端主导”模式,握手成功后服务端不主动下发任何事件。

客户端必须先发一条 session.update 完成会话初始化,服务端才回 session.updated(作为“首次可见响应”),此后才能开始送音频。这与标准 GA 规范中 session.created 先行的行为有意不同,为的是更符合“客户端主动”的语义。

85、Q2: 客户端签名总是 401,如何排查?

优先检查:

1. 本机时钟偏差:TC3 允许 timeStamp 与服务器差异不超过 15 分钟,先用 date -u 校准机器时间。

2. 参与签名的参数集:除 signature 外的所有 query 参数都要参与签名。

timeoutSec / model / resId 只要出现在 URL 上就必须一并进入 canonicalQueryString。

3. 参数排序:keys 必须按字母升序,然后逐个 k=urlEncode(v) 用 & 拼接。

4. canonicalRequest 空行:content-type;host 之前必须有一个空行(\\n\\n)。

5. date 使用 UTC:不要用本地时区。

86、Q3: 上行只能发 JSON 吗?为什么发 Binary 帧被忽略?

是的,本服务与标准 Realtime GA 规范保持一致,只接受 WebSocket Text 帧承载的 JSON 事件。音频通过 input_audio_buffer.append 事件里的 audio 字段以 base64 承载。

87、Q4: 如何让服务端主动打招呼?

在 session.updated 之后立即发:

{ "type": "response.create", "response": { "instructions": "你好, 我是智能助手, 请问需要什么帮助?" } }

所有 model 都支持这种“客户端指定文本,让服务端主动说出”的用法。

88、Q5: 客户端下行想要 opus 而不是 pcm,怎么做?

在 session.update.audio.output.format 中声明:

{ "format": { "type": "opus", "rate": 48000 } }

采样率必须是 Opus 白名单:8000 / 12000 / 16000 / 24000 / 48000。返回的 response.output_audio.delta.delta 字段是裸 Opus packet 的 base64(一次 delta 通常对应一个20ms Opus 帧),客户端需用 Opus 解码器还原为 PCM。

89、Q6: conversation.item.truncate 报 not_supported,如何截断已生成的助手音频?

当前会话若回复了 not_supported,说明实际生效的 model 未提供原生的 truncate 能力。推荐替代方案:

·打断当前 TTS:发 response.cancel。

·清空已下发但未播完的音频:发 output_audio_buffer.clear,服务端会一并下发 output_audio_buffer.cleared,客户端本地清空播放调度即可。

90、Q7: 单次会话最长多久?

本服务不限制会话总时长,只做空闲超时:默认30秒无收发消息即断开。

可通过 URL 参数 timeoutSec 覆盖,上限120秒。心跳发法建议:客户端在语音间歇期偶发送20ms的静音 PCM input_audio_buffer.append 即可保活。

91、Q8: 有 Python / Java / iOS / Android 的 SDK 吗?

本服务对外协议 100% 兼容 标准 Realtime GA WebSocket API,因此任何按标准 GA 规范编写的客户端 SDK 都可以直接接入,只需改动:

·WebSocket URL 换成本服务的 URL。

·增加 TC3-HMAC-SHA256 签名逻辑。

·session.audio.output.format 使用本服务支持的格式。

92、Q9: 如何使用加密音色 ID?和明文音色可以混用吗?

session.audio.output.voice 字段同时支持明文音色 ID 与加密音色 ID,服务端会自动识别并处理:

·明文音色 ID:直接使用。

·加密音色 ID(由音色加密服务生成):服务端通过内部解密接口换回真实音色 ID 后再使用。

Fallback 策略:以下情况都会静默降级到服务端配置的默认音色,不会中断会话建立:

1. 服务端解析异常 / 超时(内部会重试一定次数,仍失败则 fallback)。

2. 明文音色 ID(服务端无需解密,直接使用)。

3. 音色 ID 不适用于当前 model(例如把一个 model 下的专用音色传给了另一个 model)。

4. 音色 ID 不在当前 model 可用音色集内。

因此客户端可以放心把任何合法音色 ID 直接填进去,服务端会尽力解析并给出最好的结果;只有当所有路径都失败时才用服务端默认音色。

93、Q10: response.done.response.usage 与 transcription.completed.usage 分别怎么计费?

两个字段承载两个独立并列的计费维度:

·conversation.item.input_audio_transcription.completed.usage

= 本次 ASR 转写的按秒用量(type="duration" + seconds);部分能力会携带此字段,其余情况缺省。

·response.done.response.usage

= 本轮 response 的按 token 用量明细(total_tokens / input_tokens / output_tokens / *_token_details);能力后端未返回 usage 时该字段缺省。

客户端可用于本地成本观测;实际计费以账单为准。

94、Q11: 客户端可观测的 usage 字段有哪些?

response.done.response.usage(每轮)与 session.closed.usage(会话累计,所有能力)字段结构对齐 Realtime GA response.usage,客户端可据此展示完整明细:

input_token_details: text, audio, image, cached, cache_write └── cached_tokens_details: text, audio, imageoutput_token_details: text, audio, reasoning

各字段语义与标准 Realtime GA 一致;无用量数据时字段缺省(omitempty)。

关于 reasoning_tokens 的加总关系:

output_token_details.reasoning_tokens 是 output_token_details.text_tokens 的内含子集(不是与 text / audio 并列的第三项),代表本轮回答里被消耗在推理阶段的 tokens 数量。加总关系:

output_tokens = output_token_details.text_tokens + output_token_details.audio_tokensreasoning_tokens ≤ output_token_details.text_tokens // 内含关系

例如某轮 output_tokens=1260、text_tokens=314、audio_tokens=946、reasoning_tokens=87,可验证 314 + 946 = 1260;reasoning=87 已计入 text=314。客户端做本地用量展示时,按 text / audio 两项拆分即完整覆盖output_tokens reasoning_tokens 作观测字段展示、不重复计入总量。

95、附录:完整可运行 Demo

浏览器 Demo:测试 Demo (单文件,零依赖,单击打开即可)。

赞 (0)
上一篇 4天前
下一篇 4天前