开发低延迟语音助手时,语音识别、模型推理和语音合成往往需要分别接入,还要额外处理上下文、音频缓冲与中断控制。OpenAI Realtime API 提供持续的双向通信能力,使这些环节能够在同一会话中协同运行。接下来将从连接方式和事件模型入手,逐步完成实时语音对话的基本链路。
传统的语音助手开发需要拼接 ASR(语音识别)、LLM(大语言模型)、TTS(语音合成)三套系统,中间还要自己搭状态机、做音频缓冲、处理延迟抖动。OpenAI Realtime API 把这整条流水线压进一个 WebSocket 连接里,连采样率、编解码、流式 chunk 分发这些底层细节都替你兜底了。
这篇文章带你从零开始,用 Realtime API 搭建一个实时语音对话应用。
Realtime API 不是 HTTP 那种"你问一句我答一句"的请求-响应模型,而是像打开一扇门,你和模型之间建立起一条双向的、持续的、带状态的对话通道。
| 概念 | 说明 |
|---|---|
| WebSocket | 全双工通信协议,客户端和服务器可以同时发送和接收数据 |
| 事件驱动 | 所有交互都通过事件(Event)进行,包括音频输入、文本输出、工具调用等 |
| 会话状态 | 服务器维护对话上下文,支持多轮对话和打断处理 |
| 流式音频 | 音频数据以 chunk 形式实时传输,不需要等完整响应 |
| 模型 | 特点 | 适用场景 |
|---|---|---|
| gpt-4o-realtime-preview | 低延迟语音对话 | 实时客服、语音助手 |
| gpt-realtime-2 | GPT-5 级推理能力 | 复杂任务、多步骤推理 |
| gpt-realtime-translate | 实时翻译 | 多语言对话场景 |
| gpt-realtime-whisper | 语音转录 | 语音转文本 |
Realtime API 支持两种连接方式:
适合后端服务,需要长期保持连接的场景:
import websocket
import json
import base64
import pyaudio
# WebSocket 连接地址
ws_url = "wss://api.openai.com/v1/realtime?model=gpt-4o-realtime-preview"
# 创建 WebSocket 连接
ws = websocket.WebSocketApp(
ws_url,
header={
"Authorization": f"Bearer YOUR_API_KEY",
"OpenAI-Beta": "realtime=v1"
},
on_message=on_message,
on_error=on_error,
on_close=on_close,
on_open=on_open
)
ws.run_forever()
适合前端应用,直接在浏览器里处理音频:
// 获取临时会话密钥
const response = await fetch('https://api.openai.com/v1/realtime/client_secrets', {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'gpt-4o-realtime-preview',
expires_after: { anchor: 'created_at', seconds: 600 }
})
});
const { value: ephemeralKey } = await response.json();
// 创建 WebRTC 连接
const pc = new RTCPeerConnection();
const dc = pc.createDataChannel('oai-events');
dc.onmessage = (event) => {
const msg = JSON.parse(event.data);
console.log('收到事件:', msg);
};
// 获取麦克风音频
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
stream.getTracks().forEach(track => pc.addTrack(track));
// 建立连接
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
const connectResponse = await fetch('https://api.openai.com/v1/realtime', {
method: 'POST',
headers: {
'Authorization': `Bearer ${ephemeralKey}`,
'Content-Type': 'application/sdp'
},
body: offer.sdp
});
const answer = await connectResponse.text();
await pc.setRemoteDescription({ type: 'answer', sdp: answer });
Realtime API 的所有交互都通过事件进行。常见事件类型:
| 事件类型 | 方向 | 说明 |
|---|---|---|
session.created | 服务器 → 客户端 | 会话创建成功 |
session.update | 客户端 → 服务器 | 更新会话配置(模型、指令等) |
input_audio_buffer.append | 客户端 → 服务器 | 发送音频数据 |
input_audio_buffer.commit | 客户端 → 服务器 | 提交音频,触发模型处理 |
response.audio.delta | 服务器 → 客户端 | 接收音频响应片段 |
response.text.delta | 服务器 → 客户端 | 接收文本响应片段 |
response.done | 服务器 → 客户端 | 响应完成 |
import websocket
import json
import base64
import pyaudio
# 音频配置
SAMPLE_RATE = 24000
CHANNELS = 1
CHUNK_SIZE = 1024
# 初始化音频
audio = pyaudio.PyAudio()
input_stream = audio.open(
format=pyaudio.paInt16,
channels=CHANNELS,
rate=SAMPLE_RATE,
input=True,
frames_per_buffer=CHUNK_SIZE
)
output_stream = audio.open(
format=pyaudio.paInt16,
channels=CHANNELS,
rate=SAMPLE_RATE,
output=True
)
def on_message(ws, message):
"""处理服务器消息"""
data = json.loads(message)
event_type = data.get('type')
if event_type == 'session.created':
print('会话已创建')
# 更新会话配置
ws.send(json.dumps({
'type': 'session.update',
'session': {
'instructions': '你是一个友好的语音助手。',
'voice': 'alloy'
}
}))
elif event_type == 'response.audio.delta':
# 播放音频响应
audio_data = base64.b64decode(data['delta'])
output_stream.write(audio_data)
elif event_type == 'response.text.delta':
# 显示文本响应
print(data['delta'], end='', flush=True)
elif event_type == 'response.done':
print('n[响应完成]')
def on_error(ws, error):
print(f'错误: {error}')
def on_close(ws, close_status_code, close_msg):
print('连接已关闭')
input_stream.stop_stream()
input_stream.close()
output_stream.stop_stream()
output_stream.close()
audio.terminate()
def on_open(ws):
"""连接建立后开始录音"""
print('开始录音...')
def send_audio():
while True:
audio_data = input_stream.read(CHUNK_SIZE)
# 编码为 base64 并发送
ws.send(json.dumps({
'type': 'input_audio_buffer.append',
'audio': base64.b64encode(audio_data).decode('utf-8')
}))
import threading
threading.Thread(target=send_audio, daemon=True).start()
# 创建 WebSocket 连接
ws_url = "wss://api.openai.com/v1/realtime?model=gpt-4o-realtime-preview"
ws = websocket.WebSocketApp(
ws_url,
header={
"Authorization": f"Bearer YOUR_API_KEY",
"OpenAI-Beta": "realtime=v1"
},
on_message=on_message,
on_error=on_error,
on_close=on_close,
on_open=on_open
)
ws.run_forever()
Realtime API 支持用户打断模型响应。当用户开始说话时,模型会自动停止生成:
# 发送打断事件
ws.send(json.dumps({
'type': 'input_audio_buffer.clear'
}))
Realtime API 支持函数调用,可以让语音助手执行操作:
# 定义工具
tools = [
{
'type': 'function',
'name': 'get_weather',
'description': '获取指定城市的天气',
'parameters': {
'type': 'object',
'properties': {
'city': {
'type': 'string',
'description': '城市名称'
}
},
'required': ['city']
}
}
]
# 在会话配置中添加工具
ws.send(json.dumps({
'type': 'session.update',
'session': {
'tools': tools
}
}))
当模型调用工具时,会收到 response.function_call_arguments.done 事件,你需要执行函数并返回结果。
Realtime API 按分钟计费:
| 项目 | 价格 |
|---|---|
| 音频输入 | $0.06/分钟 |
| 音频输出 | $0.24/分钟 |
| 文本输入 | 按 Token 计费 |
| 文本输出 | 按 Token 计费 |
| 问题 | 可能原因 | 解决方法 |
|---|---|---|
| 连接失败 | API Key 无效或网络问题 | 检查 Key 和网络连接 |
| 音频无声 | 音频格式错误或设备问题 | 确认采样率 24kHz、单声道、PCM16 |
| 延迟高 | 网络不稳定或音频缓冲过大 | 优化网络,减小 chunk size |
| 响应中断 | 用户打断或超时 | 检查打断逻辑和超时设置 |
| 检查项 | 怎么确认 |
|---|---|
| API Key 有效 | 能正常调用其他 API |
| 音频设备正常 | 麦克风和扬声器工作正常 |
| 采样率正确 | 输入输出都是 24kHz |
| 音频格式正确 | PCM16、单声道 |
| WebSocket 库安装 | pip install websocket-client |
| PyAudio 安装 | pip install pyaudio |
Realtime API 把复杂的语音交互流程简化为一个 WebSocket 连接。只要理解了事件驱动的模式,就能快速搭建出低延迟的语音对话应用。