浏览器麦克风 → 自家后端签发短期 client secret → WebRTC 建立媒体轨道与 data channel → Realtime Session → 工具调用回到受信任后端。服务端机器人可用 WebSocket,但要自己发送/接收 Base64 音频并处理播放、取消和截断。普通文本流优先 Responses SSE;低延迟语音、自然轮次和随时打断才是 Realtime 的核心价值。
官方资料(2026-10-31 核对):Realtime API guide · WebRTC · WebSocket · Realtime conversations · VAD · API Pricing
先判断:Realtime、SSE 还是 Responses WebSocket?
| 方案 | 连接/媒体 | 适合 | 不要误用 |
|---|---|---|---|
| Realtime + WebRTC | 双向媒体轨道 + data channel | 浏览器/移动端语音、低延迟、自然打断 | 不要把标准 API Key 放前端 |
| Realtime + WebSocket | 双向 JSON 事件,音频为 Base64 | 受信任服务端、电话/媒体管线、自控音频缓冲 | 客户端要自行处理播放与截断 |
| Responses + SSE | 单次 HTTP 请求的服务器事件流 | 文字逐步显示、普通问答、实现简单 | 不是双向音频会话 |
| Responses WebSocket | 持久双向文本/工具事件连接 | 长链路 Agent、多回合工具、同连接多 stream | 不等同 Realtime 语音传输 |
已有文字应用先看 OpenAI API Streaming;工具链路很多再评估 Responses WebSocket。如果核心需求是语音打断、低首音频延迟和轮次检测,才进入本页架构。
浏览器安全建连:API Key 留在服务器
方案 A:服务端签发 client secret
- 用户先登录你的应用,前端向自己的后端请求 Realtime 临时凭证。
- 后端用标准 OpenAI API Key 创建 client secret,并把短期值返回给该用户。
- 前端用 client secret 创建 WebRTC 连接;音频走 media track,控制事件走 data channel。
- 工具调用、业务数据和权限判断仍回到后端,不把数据库凭证或私有逻辑放浏览器。
当前官方说明 client secret 默认有效 600 秒,可设置 10–7200 秒;到期前可创建多个会话,已创建的会话可继续。它仍需绑定用户、业务会话、速率限制与审计,不应写入永久缓存或分析日志。
方案 B:统一 WebRTC 接口
浏览器生成 SDP offer 发给你的后端;后端携带标准 API Key 把 SDP 与 session 配置转发到 /v1/realtime/calls,再把 SDP answer 返回浏览器。它减少前端直接接触临时凭证,但服务器必须校验用户、会话配置和允许的工具。
// 伪代码:只在受信任服务器创建短期凭证
const secret = await openai.realtime.clientSecrets.create({
session: { type: "realtime", model: "gpt-realtime-2.1" }
});
return { value: secret.value }; // 不记录、不长期缓存
服务端 WebSocket:事件与音频都要自己管理
服务端可连接 wss://api.openai.com/v1/realtime?model=gpt-realtime-2.1,使用标准 API Key 鉴权。连接建立后先收到 session.created,客户端发送 session.update,再等 session.updated 确认。不要在收到确认前假设配置已生效。
{
"type": "session.update",
"session": {
"type": "realtime",
"instructions": "简洁回答;工具结果不确定时明确说明",
"audio": {
"input": { "format": { "type": "audio/pcm", "rate": 24000 } },
"output": { "format": { "type": "audio/pcm", "rate": 24000 } }
},
"turn_detection": { "type": "server_vad" }
}
}
PCM 配置当前为 24 kHz、单声道。WebSocket 输入通过 input_audio_buffer.append 发送 Base64 音频,每个事件的音频块上限为 15 MB;输出音频从 response.output_audio.delta 持续读取,done 事件不再携带音频字节。生产中应使用更小、稳定的帧并监控发送队列,避免大块数据造成抖动。
理解状态:Session、Conversation 与 Response
- Session:连接级模型、指令、音频格式、VAD、工具和输出配置;当前最长 60 分钟。
- Conversation:按顺序保存用户、助手与工具 Items;它不是你的永久业务数据库。
- Response:一次模型输出,可含音频、转写、文本或函数调用。以完成/取消/失败事件判断终态。
一旦会话已经输出过音频,当前 voice 不能在同一 session 中更换;需要换音色应创建新会话。output_modalities 可选择音频(含 transcript)或文字,不能同时请求两种独立输出。长会话要把业务状态、用户授权和可恢复摘要保存在后端,并在接近 60 分钟时平滑重连。
VAD、按键说话与语音打断
server_vad 与 semantic_vad
server_vad 根据音量与静音判断说话开始/结束,是语音会话默认起点;semantic_vad 根据话语是否像“说完了”决定等待,可通过 eagerness 调整抢答与等待的平衡。两者都应监听 input_audio_buffer.speech_started 与 speech_stopped,并用真实口音、噪声和网络延迟测试。
Push-to-talk
把 turn_detection 设为 null,按下时必要时发送 response.cancel 并清空旧缓冲,松开时提交 input_audio_buffer.commit,再发送 response.create。按键模式更可控,但界面必须明确录音状态、取消与错误。
WebSocket 打断必须对齐“实际听到的位置”
- 收到用户开始说话事件,立即停止本地播放并发送
response.cancel。 - 记录上一条助手音频实际播放到的毫秒位置,而不是已下载字节数。
- 发送
conversation.item.truncate,带上对应 item 和audio_end_ms。 - 等待终态,确认
response.done的状态为 cancelled,再继续新回合。
WebRTC/SIP 可由服务端自动截断未播放音频;WebSocket 客户端若只停播放器不 truncate,后续模型可能基于用户没有听到的内容继续回答,造成上下文错位。
工具调用:模型决定调用,后端决定是否执行
在 session 中声明函数名称、描述与 JSON Schema。模型返回函数调用参数后,后端必须验证参数、登录用户、资源权限、幂等键和超时;执行结果作为工具 item 写回,再触发后续 response。不要让浏览器直接执行退款、发信、下单或数据库修改。
工具参数完成前不执行;同一 call_id 只落一次业务副作用;超时返回结构化错误;敏感操作二次确认;日志记录调用链但遮蔽凭证与音频隐私。
完整的参数校验与回传模式见 OpenAI Function Calling 指南。
安全、隐私与可观测性
- 身份:服务端签发临时凭证前验证登录态;向 API 传稳定、不可逆的安全标识,例如内部用户 ID 的哈希。
- 最小暴露:标准 Key、工具密钥、数据库与管理接口全部留在后端;client secret 只短期使用。
- 同意:麦克风开启、录音/存储、人工复核和删除策略应对用户可见,并符合所在地区要求。
- 失败路径:记录 session/request/response/call_id、错误类型、重连、取消和工具耗时,但不把秘密或原始敏感音频写进普通日志。
- 指标:P50/P95 首音频时间、打断成功率、空响应率、重连率、工具成功率、每成功会话成本和人工转接率。
速率与故障排查可结合 429 限制指南和 5xx/超时指南。
模型与成本:用真实会话评测
当前官方价格页列出 gpt-realtime-2.1 与较低成本的 mini 版本,并分别计费音频、文本、缓存和图像 Token。价格和模型目录可能变化,所以页面不把报价写进架构常量:上线前在官方 Pricing 与模型目录复核,再用真实口音、环境噪声、打断、工具回合与业务成功率比较。
| 成本杠杆 | 做法 | 风险 |
|---|---|---|
| 会话时长 | 空闲超时、接近 60 分钟前收尾 | 过早断开会损伤体验 |
| 模型 | mini 建立基线,再对关键任务升档 | 口音、噪声或工具精度可能下降 |
| 输出 | 简短指令、限制最大输出与冗余确认 | 限制过严会截断必要信息 |
| 工具 | 减少重复调用、做幂等与缓存 | 缓存必须按用户和权限隔离 |
上线前检查清单
- 浏览器源码、Network、日志和错误上报中都没有标准 API Key。
- WebRTC/WebSocket 的建连、失败、重连、60 分钟收尾和撤销权限均测试。
- server_vad、semantic_vad、push-to-talk 与真实噪声场景分别评测。
- 用户打断后本地播放停止,WebSocket truncate 的毫秒位置与会话上下文一致。
- 所有工具参数、权限、幂等、超时和人工确认均由后端控制。
- 音频格式、采样率、队列背压、取消、错误与终态都有明确状态机。
- 安全标识、隐私告知、数据保留、监控告警与成本预算完成评审。
常见问题
OpenAI Realtime API 适合什么场景?
它适合需要低延迟语音对话、自然轮次、用户随时打断,以及会话中调用工具的应用。普通文字问答或只需逐字显示的界面,通常先用 Responses API 的 HTTP/SSE;长链路文本 Agent 可评估 Responses WebSocket,不必为了“实时”一词全部迁移到 Realtime。
浏览器应该用 WebRTC 还是 WebSocket?
浏览器和移动端语音优先用 WebRTC,它直接处理媒体轨道并更能适应实时音频网络;受信任的后端可用 WebSocket 读取和发送 JSON 事件与 Base64 音频。标准 OpenAI API Key 只能保存在服务器,浏览器应使用服务端创建的短期 client secret,或由服务器代理统一 WebRTC 建连。
Realtime client secret 能用多久?
官方当前说明默认有效期为 600 秒,可配置 10 到 7200 秒。它可在到期前创建多个会话,已建立的会话可在 secret 到期后继续;因此服务端仍要把签发与登录用户、业务会话、速率限制和审计绑定,不能把 secret 当成长期账号凭证。
Realtime 会话最长可以持续多久?
当前官方 Realtime conversations 指南说明单个 session 最长 60 分钟。应用应在接近上限前安排提示、状态摘要与重连,并把业务状态放在自己的后端;不要假设底层 Realtime 连接会永久保存会话。
用户打断语音时为什么要发送 conversation.item.truncate?
WebSocket 客户端可能已经收到但尚未播放一段音频。停止本地播放只会让用户听不到,模型会话仍可能认为整段已播放。客户端应记录实际播放到的毫秒数,取消未完成响应并发送 conversation.item.truncate,使服务端上下文与用户真正听到的内容一致;WebRTC/SIP 场景可由服务端自动截断未播放音频。
Realtime API 可以同时返回文字和音频吗?
当前配置中 output_modalities 可设为 audio(同时带音频转写)或 text,但不能同时请求 text 与 audio 两种独立输出模式。需要字幕时使用音频响应附带的 transcript 事件,不要把它误解为另一次独立文字回答。
Realtime API 的费用怎么控制?
先限定单会话时长、模型、最大输出、工具回合与并发,再记录每个会话的音频/文本输入输出 Token、缓存命中、错误和用户实际完成率。模型与价格会变化,上线前应重新核对官方模型目录和 Pricing;低成本试验可比较 mini,但要用真实口音、噪声、打断和工具任务评测质量。
下一步怎么接?
先用 WebRTC 做单用户、单工具、可打断的最小会话,再加入重连、幂等、指标和权限。文字 Agent 不必迁移时,保留 Responses 架构更简单。
如果不是会说话、可打断的对话助手,应先比较文件转录、实时字幕和语音生成工作流;限制与迁移日期见 OpenAI Audio API 指南。