我们的 GPT-Realtime-2 概览文章 已覆盖发布信息、基准测试结论,以及 OpenAI 为何将实时语音拆分为一个小型模型家族。本教程从该文的终点开始:连接 API、发送音频,并观察代码中的变化。
这种拆分在实践中很重要。测试 1 使用 gpt-realtime-whisper 进行转写,测试 2 使用 gpt-realtime-translate 进行同声传译,测试 3 使用 gpt-realtime-2 构建语音助手。主模型也能胜任翻译或转写等更简单的任务,但您会为并不必要的推理能力和多种响应模式付费,显得大材小用。
在 Python 中设置 GPT-Realtime-2 API
在开始测试前,先将传输方式、认证方式和音频格式分开考虑。这些细节在各示例中大多保持一致。随着文章从文本输出到翻译语音,再到完整的语音循环,变化的是模型端点和事件名称。
在 WebRTC 与 WebSocket 之间选择
OpenAI 文档给出了一个简单规则 :在浏览器和移动端使用 WebRTC ,在 WebSockets 上构建服务端应用。WebRTC 负责抖动缓冲和音频传输。当后端已从电话系统或媒体流水线接收原始音频时,WebSocket 更合适。
Realtime API 的两条传输路径。图片由作者提供。
基于上述原因,三项 Python 测试均使用 WebSocket。这一路径能直接看到事件名称,从而在代码中清楚地对比不同模型。若是浏览器构建,请使用临时的客户端密钥,避免将 API Key 暴露到前端。
Python 环境与依赖包
使用 Python 3.9 或更高版本。四个脚本的完整代码可在 github.com/KhalidAbdelaty/gpt-realtime-api 获取。先克隆仓库,再安装依赖:
git clone https://github.com/KhalidAbdelaty/gpt-realtime-api.git
cd gpt-realtime-api
pip install websocket-client sounddevice numpy python-dotenv技术支持
websocket-client 用于处理套接字; sounddevice 用于捕获麦克风音频; numpy 用于缓冲区转换; python-dotenv 用于加载 API Key。在 macOS 上,可能需要先运行 brew install portaudio 才能使用 sounddevice;在 Linux 上,请安装 portaudio19-dev。
在项目根目录创建 .env 文件:
OPENAI_API_KEY = sk-.. .技术支持
然后在每个脚本中加载:
import os
from dotenv import load_dotenv
load_dotenv( )
OPENAI_API_KEY = os. environ. get( "OPENAI_API_KEY" ) 技术支持
认证与 WebSocket URL
服务端连接在 WebSocket 握手中使用 Authorization: Bearer 头。若应用跟踪单个用户,则添加 OpenAI-Safety-Identifier。以下是后续测试使用的路径:
wss: // api. openai. com/ v1/ realtime?model= gpt- realtime- 2
wss: // api. openai. com/ v1/ realtime/ translations?model= gpt- realtime- translate
wss: // api. openai. com/ v1/ realtime?intent= transcription技术支持
该翻译路径在测试 2 中很关键,因为它是唯一不直接使用 /v1/realtime 的端点。
测试 1:使用 GPT-Realtime-Whisper 的实时音频转写
转写是最容易过度设计的场景之一。若输出只是文本,转写模型已足够。
测试目标
gpt-realtime-whisper 接收音频并输出逐步的转写增量。它不会进行推理、调用工具或回话。这一更小的工作范围也是其按音频时长计费、而非按 gpt-realtime-2 所用的同一令牌模型计费的原因。成本章节会再谈价格。
代码讲解
关键字段是 session.type: "transcription"。它告诉 API 跳过助手响应,只发出转写事件。完整脚本还处理麦克风采集与线程。这部分改变了 Realtime 会话的行为:
session_config = {
"type" : "session.update" ,
"session" : {
"type" : "transcription" ,
"audio" : {
"input" : {
"format" : { "type" : "audio/pcm" , "rate" : 24000 } ,
"transcription" : {
"model" : "gpt-realtime-whisper" ,
"language" : "en"
} ,
"turn_detection" : None
}
}
}
}
ws. send( json. dumps( session_config) )
ws. send( json. dumps( {
"type" : "input_audio_buffer.append" ,
"audio" : audio_b64
} ) )
ws. send( json. dumps( { "type" : "input_audio_buffer.commit" } ) ) 技术支持
使用 24 kHz PCM16 单声道音频,base64 编码。与语音助手会话不同,该脚本按计时器手动提交输入缓冲,而不是使用 server_vad 进行轮次检测。空提交会触发 input_audio_buffer_commit_empty,因此完整脚本只会在发送了真实音频后才提交。
转写增量会逐词实时到达。图片由作者提供。
观察到的行为
在本地测试中,转写结果会在提交窗口内出现,大约在讲话开始后 3 至 4 秒。由于此设置依赖手动提交而非 VAD,时延与提交间隔相关。
另外要注意顺序:重叠轮次的完成事件可能乱序到达,如果要在 UI 中呈现流式结果,请按 item_id 对齐。
转写由周期性的手动提交触发,而非由静音检测触发。图片由作者提供。
结论:通过。 对于服务端实时转写,gpt-realtime-whisper 满足了本测试需求。但在设定时延目标前,仍建议用真实麦克风、口音和房间噪声进行测试。
测试 2:使用 GPT-Realtime-Translate 的实时翻译
实时语音翻译乍看与转写相似,但会话生命周期不同。翻译端点移除了助手响应循环,使示例更简洁。
测试目标
翻译会话没有助手轮次循环,也不使用 response.create。该模型充当同声传译,而非对话代理。若需要问答、工具或对话状态,测试 3 将切换至 gpt-realtime-2。
翻译会话使用专用且独立的端点。图片由作者提供。
该模型支持 70 多种输入语言和 13 种输出语言。您通过 session.audio.output.language 设置目标语言;源语言自动检测。限制也很明确:不支持自定义提示、不可选配音、也不支持领域词汇表。
代码讲解
前文已提到,翻译使用 /translations WebSocket URL。还有两处变化:session.audio.output.language 目标字段,以及 session.input_audio_buffer.append 事件名称。请注意 session. 前缀。翻译会话在此处使用它。
url = "wss://api.openai.com/v1/realtime/translations?model=gpt-realtime-translate"
session_config = {
"type" : "session.update" ,
"session" : {
"audio" : {
"output" : { "language" : "es" } ,
"input" : {
"transcription" : { "model" : "gpt-realtime-whisper" } ,
"noise_reduction" : { "type" : "near_field" }
}
}
}
}
ws. send( json. dumps( session_config) )
ws. send( json. dumps( {
"type" : "session.input_audio_buffer.append" ,
"audio" : audio_b64
} ) ) 技术支持
译后音频通过 session.output_audio.delta 到达,其音频字节位于 event["delta"],而非 event["audio"]。源转写与译文转写分别到达:
if event_type == "session.output_audio.delta" :
audio_out_queue. put( base64. b64decode( event[ "delta" ] ) )
elif event_type == "session.input_transcript.delta" :
print ( "[EN]" , event. get( "delta" , "" ) , end= "" )
elif event_type == "session.output_transcript.delta" :
print ( "[ES]" , event. get( "delta" , "" ) , end= "" ) 技术支持
一个边缘情况:如果源音频本就是目标语言,模型可能会输出静音而不是原样透传。
观察到的行为
对于简短的英译西短语,译后音频会在源语句结束前开始播放。终端会随着流式增量交织显示 [EN] 与 [ES] 行。语言差异更大的组合可能会为上下文等待更久。我能顺畅地跟随译后语音,但不支持自定义声音。
结论:通过,但有注意事项。 gpt-realtime-translate 适合直接的实时翻译。当需要术语管控或品牌化语音时,实用性会降低。
测试 3:构建支持轮流发言与插话的语音助手
这是一项 gpt-realtime-2 测试:构建一个能聆听、发声、保持上下文并可调用工具的语音代理。此处客户端代码的重要性也提升,因为播放与轮次状态可能不同步。
测试目标
gpt-realtime-2 是一个语音到语音的推理模型。它避免了单独的 STT-LLM-TTS 流水线,其 128K 上下文窗口也为长会话提供了空间。通过 reasoning.effort 控制推理强度;除非任务需要更强推理,否则从 low 开始,因为更高设置会增加时延。
代码讲解
下面的设置使用 semantic_vad,它基于语音线索而不只是静音。eagerness 控制模型多快判定用户已说完。需要关注的部分包括模型名称、音频输出设置、手动 response.create,以及助手音频事件名称:
session_config = {
"type" : "session.update" ,
"session" : {
"type" : "realtime" ,
"model" : "gpt-realtime-2" ,
"output_modalities" : [ "audio" ] ,
"audio" : {
"input" : {
"format" : { "type" : "audio/pcm" , "rate" : 24000 } ,
"transcription" : { "model" : "gpt-realtime-whisper" , "language" : "en" } ,
"turn_detection" : {
"type" : "semantic_vad" ,
"eagerness" : "medium" ,
"create_response" : False ,
"interrupt_response" : True
}
} ,
"output" : {
"format" : { "type" : "audio/pcm" , "rate" : 24000 } ,
"voice" : "marin"
}
} ,
"instructions" : "You are a helpful voice assistant. Keep answers short." ,
"reasoning" : { "effort" : "low" }
}
} 技术支持
当用户转写完成后,客户端创建助手响应。随后助手音频以 response.output_audio.delta 到达,而不是 response.audio.delta。
if event_type == "conversation.item.input_audio_transcription.completed" :
ws. send( json. dumps( { "type" : "response.create" } ) )
elif event_type == "response.output_audio.delta" :
audio_out_queue. put( base64. b64decode( event[ "delta" ] ) ) 技术支持
处理插话(Barge-In)
中断序列很容易出错。当用户打断助手说话时,服务器会发送 input_audio_buffer.speech_started。客户端应停止播放,记录已播放的时长,并发送带有 audio_end_ms 的 conversation.item.truncate,以标记被截断的位置。否则,服务器会继续转写用户未曾听到的文本,下一轮会感觉不对劲。
if current_response_item_id and playback_position_ms > 0 :
ws. send( json. dumps( {
"type" : "conversation.item.truncate" ,
"item_id" : current_response_item_id,
"content_index" : 0 ,
"audio_end_ms" : playback_position_ms
} ) ) 技术支持
使用笔记本扬声器的一个实际问题是:麦克风可能会拾取助手的音频输出并回传给模型。示例脚本使用 MUTE_MIC_DURING_ASSISTANT = True 在助手说话期间以及短暂冷却期内静音输入流。仅当使用耳机且需要中断支持时,才将其设为 False。
截断操作让服务器与客户端保持同步。图片由作者提供。
WebRTC 与 SIP 会处理更多缓冲。在本教程使用的 WebSocket 路径下,责任在客户端。示例脚本中的计数器足够支撑演示;生产代码应基于音频输出流的时间戳进行跟踪。
为推理时延配置开场语
当 reasoning.effort 高于 low 时,静默会更明显。可以在系统提示中加入简短的开场口播:
# Preambles
Use a short spoken update before longer tasks.
Keep preambles under five seconds.
Skip preambles for short factual questions.技术支持
此行为在 gpt-realtime-2 文档中有所说明。
观察到的行为
在安静环境中,默认设置下的轮流发言表现良好。使用笔记本扬声器时,我需要开启麦克风静音;否则模型会听到自己的输出并形成回声循环。
在更嘈杂的房间里,VAD 设置与麦克风摆放更为关键。十分钟测试中对话记忆保持一致,但若要发布更长时长的应用,我不会忽略重连方案。
结论:核心语音循环通过。 在测试中,gpt-realtime-2 能胜任低推理强度的助手。额外工作主要在客户端:播放、插话处理、重连,以及需要时的工具调用。
Streamlit 演示:一个界面集成三种模型
该 Streamlit 应用将测试置于选项卡选择器后。您可以录制音频、选择目标语言,并在不修改脚本的情况下对比不同模型路径。我将其保留为演示应用而非主要教学路径,因为终端脚本能更直观地展示事件。
三种模型,一套分栏界面。图片由作者提供。
下方演示视频展示了在有效 API Key 下的各个标签页。每个标签都使用真实的 Realtime WebSocket 调用。
我们的 GPT-Realtime-2 概览文章已覆盖发布信息、基准测试结论,以及 OpenAI 为何将实时语音拆分为一个小型模型家族。本教程从该文的终点开始:连接 API、发送音频,并观察代码中的变化。
这种拆分在实践中很重要。测试 1 使用
gpt-realtime-whisper进行转写,测试 2 使用gpt-realtime-translate进行同声传译,测试 3 使用gpt-realtime-2构建语音助手。主模型也能胜任翻译或转写等更简单的任务,但您会为并不必要的推理能力和多种响应模式付费,显得大材小用。在 Python 中设置 GPT-Realtime-2 API
在开始测试前,先将传输方式、认证方式和音频格式分开考虑。这些细节在各示例中大多保持一致。随着文章从文本输出到翻译语音,再到完整的语音循环,变化的是模型端点和事件名称。
在 WebRTC 与 WebSocket 之间选择
OpenAI 文档给出了一个简单规则:在浏览器和移动端使用 WebRTC,在 WebSockets 上构建服务端应用。WebRTC 负责抖动缓冲和音频传输。当后端已从电话系统或媒体流水线接收原始音频时,WebSocket 更合适。
Realtime API 的两条传输路径。图片由作者提供。
基于上述原因,三项 Python 测试均使用 WebSocket。这一路径能直接看到事件名称,从而在代码中清楚地对比不同模型。若是浏览器构建,请使用临时的客户端密钥,避免将 API Key 暴露到前端。
Python 环境与依赖包
使用 Python 3.9 或更高版本。四个脚本的完整代码可在 github.com/KhalidAbdelaty/gpt-realtime-api 获取。先克隆仓库,再安装依赖:
websocket-client用于处理套接字;sounddevice用于捕获麦克风音频;numpy用于缓冲区转换;python-dotenv用于加载 API Key。在 macOS 上,可能需要先运行brew install portaudio才能使用sounddevice;在 Linux 上,请安装portaudio19-dev。在项目根目录创建
.env文件:然后在每个脚本中加载:
认证与 WebSocket URL
服务端连接在 WebSocket 握手中使用
Authorization: Bearer头。若应用跟踪单个用户,则添加OpenAI-Safety-Identifier。以下是后续测试使用的路径:该翻译路径在测试 2 中很关键,因为它是唯一不直接使用
/v1/realtime的端点。测试 1:使用 GPT-Realtime-Whisper 的实时音频转写
转写是最容易过度设计的场景之一。若输出只是文本,转写模型已足够。
测试目标
gpt-realtime-whisper接收音频并输出逐步的转写增量。它不会进行推理、调用工具或回话。这一更小的工作范围也是其按音频时长计费、而非按gpt-realtime-2所用的同一令牌模型计费的原因。成本章节会再谈价格。代码讲解
关键字段是
session.type: "transcription"。它告诉 API 跳过助手响应,只发出转写事件。完整脚本还处理麦克风采集与线程。这部分改变了 Realtime 会话的行为:使用 24 kHz PCM16 单声道音频,base64 编码。与语音助手会话不同,该脚本按计时器手动提交输入缓冲,而不是使用
server_vad进行轮次检测。空提交会触发input_audio_buffer_commit_empty,因此完整脚本只会在发送了真实音频后才提交。转写增量会逐词实时到达。图片由作者提供。
观察到的行为
在本地测试中,转写结果会在提交窗口内出现,大约在讲话开始后 3 至 4 秒。由于此设置依赖手动提交而非 VAD,时延与提交间隔相关。
另外要注意顺序:重叠轮次的完成事件可能乱序到达,如果要在 UI 中呈现流式结果,请按
item_id对齐。转写由周期性的手动提交触发,而非由静音检测触发。图片由作者提供。
结论:通过。 对于服务端实时转写,
gpt-realtime-whisper满足了本测试需求。但在设定时延目标前,仍建议用真实麦克风、口音和房间噪声进行测试。测试 2:使用 GPT-Realtime-Translate 的实时翻译
实时语音翻译乍看与转写相似,但会话生命周期不同。翻译端点移除了助手响应循环,使示例更简洁。
测试目标
翻译会话没有助手轮次循环,也不使用
response.create。该模型充当同声传译,而非对话代理。若需要问答、工具或对话状态,测试 3 将切换至gpt-realtime-2。翻译会话使用专用且独立的端点。图片由作者提供。
该模型支持 70 多种输入语言和 13 种输出语言。您通过
session.audio.output.language设置目标语言;源语言自动检测。限制也很明确:不支持自定义提示、不可选配音、也不支持领域词汇表。代码讲解
前文已提到,翻译使用
/translationsWebSocket URL。还有两处变化:session.audio.output.language目标字段,以及session.input_audio_buffer.append事件名称。请注意session.前缀。翻译会话在此处使用它。译后音频通过
session.output_audio.delta到达,其音频字节位于event["delta"],而非event["audio"]。源转写与译文转写分别到达:一个边缘情况:如果源音频本就是目标语言,模型可能会输出静音而不是原样透传。
观察到的行为
对于简短的英译西短语,译后音频会在源语句结束前开始播放。终端会随着流式增量交织显示
[EN]与[ES]行。语言差异更大的组合可能会为上下文等待更久。我能顺畅地跟随译后语音,但不支持自定义声音。结论:通过,但有注意事项。
gpt-realtime-translate适合直接的实时翻译。当需要术语管控或品牌化语音时,实用性会降低。测试 3:构建支持轮流发言与插话的语音助手
这是一项
gpt-realtime-2测试:构建一个能聆听、发声、保持上下文并可调用工具的语音代理。此处客户端代码的重要性也提升,因为播放与轮次状态可能不同步。测试目标
gpt-realtime-2是一个语音到语音的推理模型。它避免了单独的 STT-LLM-TTS 流水线,其 128K 上下文窗口也为长会话提供了空间。通过reasoning.effort控制推理强度;除非任务需要更强推理,否则从low开始,因为更高设置会增加时延。代码讲解
下面的设置使用
semantic_vad,它基于语音线索而不只是静音。eagerness控制模型多快判定用户已说完。需要关注的部分包括模型名称、音频输出设置、手动response.create,以及助手音频事件名称:当用户转写完成后,客户端创建助手响应。随后助手音频以
response.output_audio.delta到达,而不是response.audio.delta。处理插话(Barge-In)
中断序列很容易出错。当用户打断助手说话时,服务器会发送
input_audio_buffer.speech_started。客户端应停止播放,记录已播放的时长,并发送带有audio_end_ms的conversation.item.truncate,以标记被截断的位置。否则,服务器会继续转写用户未曾听到的文本,下一轮会感觉不对劲。使用笔记本扬声器的一个实际问题是:麦克风可能会拾取助手的音频输出并回传给模型。示例脚本使用
MUTE_MIC_DURING_ASSISTANT = True在助手说话期间以及短暂冷却期内静音输入流。仅当使用耳机且需要中断支持时,才将其设为False。截断操作让服务器与客户端保持同步。图片由作者提供。
WebRTC 与 SIP 会处理更多缓冲。在本教程使用的 WebSocket 路径下,责任在客户端。示例脚本中的计数器足够支撑演示;生产代码应基于音频输出流的时间戳进行跟踪。
为推理时延配置开场语
当
reasoning.effort高于low时,静默会更明显。可以在系统提示中加入简短的开场口播:此行为在
gpt-realtime-2文档中有所说明。观察到的行为
在安静环境中,默认设置下的轮流发言表现良好。使用笔记本扬声器时,我需要开启麦克风静音;否则模型会听到自己的输出并形成回声循环。
在更嘈杂的房间里,VAD 设置与麦克风摆放更为关键。十分钟测试中对话记忆保持一致,但若要发布更长时长的应用,我不会忽略重连方案。
结论:核心语音循环通过。 在测试中,
gpt-realtime-2能胜任低推理强度的助手。额外工作主要在客户端:播放、插话处理、重连,以及需要时的工具调用。Streamlit 演示:一个界面集成三种模型
该 Streamlit 应用将测试置于选项卡选择器后。您可以录制音频、选择目标语言,并在不修改脚本的情况下对比不同模型路径。我将其保留为演示应用而非主要教学路径,因为终端脚本能更直观地展示事件。
三种模型,一套分栏界面。图片由作者提供。
下方演示视频展示了在有效 API Key 下的各个标签页。每个标签都使用真实的 Realtime WebSocket 调用。