OpenAI Realtime 2 简测

OpenAI Realtime API 将语音识别、模型理解和语音合成整合为实时语音到语音能力,降低了传统 ASR + LLM + TTS 拼接架构的接入复杂度。实际接入中,后端 WebSocket 代理、session 初始化、音频采样格式、服务端 VAD 和打断时的播放队列清理,是影响交互稳定性和流畅感的关键。对于中文呼叫中心场景,Realtime 已具备一定可用性,但在短输入语言检测、数字串识别、语调控制、音色自然度和长对话可靠性上仍存在明显限制。整体来看,Realtime 更适合内部工具、演示和低风险语音交互场景,距离高可靠生产级客服系统仍需进一步验证。

OpenAI  Realtime 2 简测

📖 目录导航

最近在一个面向呼叫中心的语音 Agent 项目里接入了 OpenAI Realtime,跑了一圈之后觉得有必要写点东西,主要讲三件事:接入过程里真正值得注意的地方、这个 API 的来龙去脉,以及它在非英语场景下的实际表现。

01. Realtime API 的发展脉络

先说背景,免得有人对这个 API 还不熟悉。2024 年 10 月,OpenAI 正式发布 Realtime API,走 WebSocket 协议,支持语音到语音的单轮 API 调用,不再需要 ASR + LLM + TTS 三段拼接。同月底追加了 5 个新音色,并引入了缓存计费。2025 年初加入了 WebRTC 支持,给纯前端接入提供了另一条路。2025 年 8 月 28 日,Realtime 正式 GA,退出 Beta 状态,推出了 gpt-realtime 正式模型。12 月 15 日又发了新的音频模型快照,官方说指令遵循提升了 22%。整体走了不到一年从 Beta 到 GA,迭代节奏不算慢,但也没快到让人放心的程度。

专注大模型的电话智能体

了解更多

02. 接入的核心流程

这里用的架构是前端连后端 WebSocket 代理,后端再连 OpenAI,API Key 不出服务端。

1. 后端代理有两个必须注意的地方

握手 Header 里必须带 OpenAI-Beta: realtime=v1,漏了直接 400,报错信息不明显,容易浪费时间。TLS 正常,不需要跳过证书验证,直接连即可。

cfg = providerConfig{
    apiKey:  os.Getenv("OPENAI_API_KEY"),
    baseURL: "wss://api.openai.com/v1/realtime",
    extraHeader: http.Header{
        "OpenAI-Beta": []string{"realtime=v1"}, // 必须带,否则 400
    },
}

代理本身就是双向透传,不解析内容,不做任何业务逻辑:

pipe := func(dst, src *websocket.Conn) {
    for {
        mt, msg, _ := src.ReadMessage()
        dst.WriteMessage(mt, msg) // 省略错误处理
    }
}
go pipe(upstream, client)
go pipe(client, upstream)
<-errc

2. 连接初始化

连上之后第一件事是发 session.update,把音频格式、VAD 配置、音色一次性定好。这个时机要在 onopen 里立即发,不要等用户操作:

ws.onopen = () => {
  ws.send(JSON.stringify({
    type: 'session.update',
    session: {
      modalities: ['text', 'audio'],
      voice: 'alloy',
      input_audio_format: 'pcm16',
      output_audio_format: 'pcm16',
      turn_detection: {
        type: 'server_vad',
        silence_duration_ms: 500, // 按场景调,客服类可以稍长
      },
    },
  }))
}

3. 音频采集

采集侧固定 24000Hz 单声道,输出 PCM16,base64 编码后发 input_audio_buffer.append。ScriptProcessor 已经是过时接口,但目前兼容性最广,AudioWorklet 的跨浏览器一致性还不够稳,暂时没换:

// sampleRate 必须和 API 的 input_audio_format 对齐,否则服务端 VAD 识别会漂移
const ctx = new AudioContext({ sampleRate: 24000 })

processor.onaudioprocess = (e) => {
  const f32 = e.inputBuffer.getChannelData(0)
  const pcm16 = new Int16Array(f32.length)
  for (let i = 0; i < f32.length; i++) {
    const s = Math.max(-1, Math.min(1, f32[i]))
    pcm16[i] = s < 0 ? s * 0x8000 : s * 0x7fff
  }
  ws.send(JSON.stringify({
    type: 'input_audio_buffer.append',
    audio: btoa(String.fromCharCode(...new Uint8Array(pcm16.buffer))),
  }))
}

4. 一个容易忽略的细节:VAD 打断时必须清队列

收到 input_audio_buffer.speech_started 时,意味着用户开始说话打断了 AI,这时候要立即清空本地的音频播放队列,否则旧的 AI 音频还会继续播出来:

case 'input_audio_buffer.speech_started':
  audioQueue = []
  nextPlayTime = 0 // 重置播放时间指针
  break

这个事件是整个交互流畅感的关键,漏了之后 debug 起来也比较困惑,放在这里单独提一下。

03. 非英语场景的真实处理

OpenAI 官方说 Realtime 支持 57 种以上的语言,但支持程度差异很大。官方文档有一个 WER(词错率)<50% 的语言列表,低于这个线的语言是能用但没有保证。中文整体可用,普通话识别准确率在呼叫中心场景(有口音、有背景噪声)表现还行,但有几个具体问题确实存在:

  • 短输入或背景噪声下语言检测容易误判,把中文识别成其他语言
  • 数字串(手机号、身份证号)的识别准确率比长句低,官方在 2025 年 12 月的更新里专门提到了对这类场景的改进
  • 语调控制几乎没有,模型不能针对疑问句自动上扬语调,这在电话客服场景里是个体验缺口

音色方面的遗憾是实打实的。 外网开发者社区里对这一点的吐槽很集中:

  • Realtime 的音色和 ChatGPT App 里的语音模式用的不是同一套,App 里更自然,API 里的版本明显差一截
  • 据 OpenAI 社区的讨论,有开发者反映 gpt-realtime-1.5 之后几个音色的口音特征基本消失了,变得更"标准化"但也更平
  • 说话语速无法控制,这个需求在社区里提了很久没有下文
  • ElevenLabs 等专门做 TTS 的服务在辅音清晰度、长句稳定性上仍然有优势,Realtime 的音色换取的是低延迟,不是最高音质

04. 外网开发者的整体评价

整理了一下社区里比较有代表性的反馈:正面的评价集中在架构简洁上。语音到语音一个 API 搞定,省掉 ASR + TTS 的编排开销,延迟确实低,在 demo 和内部工具场景里体验很好。负面评价主要集中在生产可靠性上。OpenAI 社区里有开发者明确说"too unpredictable to put in production",长对话容易出现奇怪的行为,静默段处理不稳定,工具调用流程缺乏精确控制。这个评价出现在 GA 之前,GA 之后是否有改善还需要时间验证。我自己的判断:Realtime 适合做内部工具、演示、语言学习类产品,暂时不适合做对可靠性要求很高的生产级客服系统。 如果你的业务能接受偶发的异常行为,可以上;如果不能,观望到 2026 年中再说。

05. 代理架构的一点额外价值

做成后端代理而不是前端直连,除了隐藏 Key,还有一个实际价值:后续再接其他家(Minimax、Google 等),改动在后端,前端零感知。这个设计选择目前来看是对的。