Courses
我第一次打开 GPT-Live-1 浏览会话时,本以为会是常见的语音循环:说话、等待,然后听答案。结果却是,助手在回复时麦克风一直保持开启。对话不再拘谨,但应用仍需管理背后的工作。
OpenAI 先是在 7 月于 ChatGPT 中推出 GPT-Live,随后在本周早些时候将 GPT-Live-1 引入 API,恰好赶在我开始这个项目之前。我们的 GPT-Realtime-2.1 教程介绍了单模型方案,而 GPT Live 转写指南侧重于实时字幕。在本文中,您将构建一个语音学习助手,它会搜索真实的 DataCamp 资源,并且只在确认后才保存计划。
我称之为 DataCamp 语音学习助手。这是一个教程原型,而非正式的 DataCamp AI 助手。项目将跟随一位学习者,从口述目标到保存计划的全过程。
核心收获
GPT-Live-1 将口语交互与后端工作分离。以下四点塑造了这个学习助手:
- WebRTC 与后端工作走不同路径:媒体轨道承载语音,而 Responses 委托处理搜索与工具调用。
- 口头打断不会取消后端工作:任务版本保护应用动作,但 Responses 委托无法保证将所有旧结果排除在下一次回复之外。
- 转写增量不等于最终对话轮次:网络时序可变,用户与助手区间会重叠,且没有任何转写事件标记权威的“轮次完成”。
- 一次 函数调用并非保存许可:应用会在写入计划前等待第二次确认。
这些结论适用于此学习计划流程。不同的提示或网络环境可能改变行为,使用客户端委托也会改变控制边界。
什么是 GPT-Live-1?
GPT-Live-1 是 OpenAI 的全双工语音模型。它处理口语轮次与打断(包括其中的停顿),并将搜索或工具调用等更长的工作发送到后端。

对学习者而言,最直观的不同首先体现在这些停顿上。
全双工对话如何运作
全双工改变了轮流发言的方式。您可以停顿思考或打断助手,助手也能停下来听取更正。OpenAI 的提示指南展示了用于简短致意与打断的提示片段。
这对学习助手很重要。描述职业目标的人可能会停顿、重来,或在中途添加限制。一个愿意等待“嗯,我想,每周大概五小时吧”的模型能让学习者把想法说出来。
拆分语音与后端工作
委托会把任务移到后端,但不会交出应用控制权。应用仍决定谁能执行操作,以及是否允许保存。它也拥有已存储的任务状态。
GPT-Live-1 与 GPT-Realtime-2.1
如果您用过 GPT-Realtime-2.1,或许会想 GPT-Live-1 是否取代了它。并没有。
GPT-Realtime-2.1 在 v1/realtime 路径上,用一个模型处理聆听、推理与工具选择,按音频与文本 Token 计费。GPT-Live-1 使用 v1/live/sessions,语音层按秒计费,并将推理发送到独立后端。
Realtime-2.1 不是更旧或更弱的选项。它只是采用了不同的设计。
构建一个 GPT-Live-1 语音学习助手
应用接收口述目标并将其转化为有顺序的真实 DataCamp 资源列表。后端工作期间语音会话保持开启。当请求发生变化,应用会在执行后端动作前更新其任务版本。
在学习者于应用内再次确认之前,不会写入任何内容。
GPT-Live-1 应用架构
浏览器页面负责 WebRTC 连接与麦克风,服务器创建 GPT-Live-1 会话并保管 API 密钥。Responses 后端(gpt-5.6-sol)使用网页搜索与 save_learning_plan 函数。当前任务版本与已确认计划保存在应用状态中。
当搜索过程中请求发生变化时,任务版本决定应用接受哪个后端动作。完整可运行应用请查看 GitHub 仓库;接下来的章节将聚焦其 GPT-Live 路径。

浏览器、GPT-Live-1 与后端模型相连。作者供图。
如何在 Python 中设置 GPT-Live-1
您需要一个具备 GPT-Live-1 访问权限的 OpenAI 项目(免费层不支持)、Python,以及运行在 HTTPS 或 localhost 上的浏览器以便弹出麦克风授权。我使用的是 Python 3.11 与 openai 3.13.0。Live API 需要至少 openai 3.12.0;更早版本的客户端没有 .live 属性。
并发会话上限取决于您的用量等级。在打开多个浏览器标签页前,请检查项目限制。
python -m venv .venv
.venv\Scripts\Activate.ps1
pip install openai fastapi uvicorn python-dotenv streamlit requests
在 macOS 或 Linux 上,请使用 source .venv/bin/activate 激活环境。于项目根目录创建 .env 文件并添加如下值。
OPENAI_API_KEY=sk-...
python-dotenv 会在服务器导入后自动加载该文件,因此密钥无需出现在代码中。
OpenAI() 客户端在未显式传入密钥时,也会读取同名环境变量。
将 API 密钥保存在服务器端
浏览器永远不会看到您的项目密钥。它会将 WebRTC offer 发给您的服务器,服务器再使用该密钥创建会话。完成 SDP 交换后,浏览器通过 WebRTC 将音频发送至 OpenAI,而无需接收该密钥。
位于 /api/session 之内的 GPT-Live 调用,会根据 SDP offer 创建会话。它在同一请求中传递语音指令、后端模型、网页搜索与保存函数。
result = client.live.create(
session={
"model": "gpt-live-1",
"instructions": LIVE_INSTRUCTIONS,
"delegation": {
"type": "responses",
"responses": {
"model": "gpt-5.6-sol",
"instructions": BACKEND_INSTRUCTIONS,
"tools": [
{
"type": "web_search",
"filters": {
"allowed_domains": ["datacamp.com", "www.datacamp.com"]
},
},
SAVE_LEARNING_PLAN_TOOL,
],
"tool_choice": "auto",
},
},
},
transport={"type": "webrtc", "sdp": sdp},
)
该调用会向 POST /v1/live/sessions 发送请求,并返回会话 ID 与 SDP answer。HTTP 请求即开启会话,因此不要在之后再发送 session.start 事件。
示例服务器仅接受来自 localhost:8501 与 127.0.0.1:8501 的浏览器请求。该规则仅供本地使用。
如果部署应用,请替换这些来源,并对 /api/session 与 /api/save-plan 进行认证。限制会话创建频率,因为每个请求都会花费费用并占用并发。客户端可以自行发送 confirmed: true,因此公共服务器不能将该字段视为请求者身份的证明。
如何通过 WebRTC 创建 GPT-Live-1 会话
遵循 OpenAI 的 WebRTC 指南,浏览器会请求麦克风访问并打开一个 RTCPeerConnection。使用文档中的 oai-events 数据通道标签,并在生成 SDP offer 之前创建它。会话开始后,该通道双向承载 JSON 事件。

WebRTC 启动、流式传输音频,然后关闭。作者供图。
连接麦克风与音频输出
媒体设置本身属于常规 WebRTC。GPT-Live 事件使用上一行创建的数据通道。
const connection = new RTCPeerConnection();
connection.addEventListener("track", (event) => {
audio.srcObject = new MediaStream([event.track]);
audio.play();
});
const microphone = await navigator.mediaDevices.getUserMedia({ audio: true });
for (const track of microphone.getAudioTracks()) {
connection.addTrack(track, microphone);
}
const events = connection.createDataChannel("oai-events");
创建 offer 后,浏览器调用 setLocalDescription() 并等待 ICE 收集完成。它将本地 SDP 发送至 /api/session,然后使用 setRemoteDescription() 应用 OpenAI 的 answer。麦克风音频与助手语音都在媒体轨道上传输,因此无需额外的 语音转文本与文本转语音 请求。
请勿在 oai-events 上承载音频。不要在 WebRTC 数据通道上发送 session.input_audio.append 或等待 session.output_audio.delta。
数据通道遵循不同的时序规则。请等待 session.started 后再通过 oai-events 发送事件。我的第一次尝试过早发送,连接直接忽略了它。
没有得到有用的错误信息,这让一个小小的顺序问题排查起来颇为恼人。
流式传输 GPT-Live 转写事件
如果您不需要可见字幕,可以跳过本小节;音频连接已经就绪。
session.input_transcript.delta 与 session.output_transcript.delta 返回带有毫秒偏移的文本片段,用于实时字幕。OpenAI 文档提醒,转写片段不是已完成的轮次。传递可能不均匀,用户与助手的转写区间可能重叠。
将转写片段抵达即附加到屏幕,但不要据此发起后端工作。由模型决定何时进行委托。
如何为 GPT-Live-1 设计自然对话提示
Live 模型的说明应尽量简短。OpenAI 指南建议将详细的任务步骤放在后端提示中。我将任务流程放在后端提示里,使 Live 提示专注于语音。
这段摘录将语音行为与学习计划任务分离。语音规则置于触发委托的条件之上。
You are Sage, a warm, encouraging voice learning coach for DataCamp learners.
Speak naturally at an unhurried pace. Be clear and direct, not overly cheerful.
Backchannel policy: Use moderate backchannels without competing with the response.
Interruption policy: Stop speaking when the learner interrupts, and listen.
Delegation policy:
Backend tools:
- learning_plan_research: search DataCamp resources and assemble a personalized learning plan.
- save_learning_plan: propose the current plan for app confirmation when the learner asks to save.
Delegate to the backend when:
- The learner states or changes a goal, skill level, or weekly time.
- A correction changes the plan already requested.
- The learner asks to save the plan.
Do not delegate for greetings, small clarifications, or a result already given.
Saving: a proposed save only asks the app to confirm. Do not say the plan is saved until the app reports a saved result.
After a save, keep the conversation open and ask what the learner wants next.
这些规则让问候语停留在 Live 层面,而把研究或保存请求发往后端。确认权仍属于应用。
处理停顿、回应与打断
“backchannel” 与“打断”两行指示助手如何围绕停顿作出反应。“适度 backchannel”表示偶尔以“嗯哼”等方式确认,但不要填满每一段沉默。我选择这一程度是为了给学习者留出思考空间;若课程停顿更长,可能需要更少的回应。
若您的应用需要不同行为,可修改该行;例如添加“当用户说话时绝不发声”也会去除 backchannel。
将语音指令与任务指令分离
两类提示各司其职。Live 提示控制语音与交接,而后端提示控制检索与答案格式。OpenAI 指南不建议将详细搜索步骤置于语音指令中。
如何添加 GPT-Live 后端委托
前述的拆分体现在会话的 delegation 字段中。当学习者陈述目标时,GPT-Live 会将任务发送给能够搜索课程目录并制定计划的模型。
GPT-Live-1 提供 Responses 委托与客户端委托。Responses 委托由 OpenAI 管理后端调用;客户端委托则交由您的代码处理。本应用使用 Responses 委托,以避免再套一层后端循环。
配置后端模型
我使用 gpt-5.6-sol。OpenAI 委托指南以 gpt-5.6-terra 为示例,并列出 gpt-5.6-luna 以应对低成本任务。使用 Sol,后端返回了所需的计划结构。
将 tool_choice 保持为 auto ,便于后端在网页搜索与保存函数之间做出选择。委托模式在启动时固定;如需切换到客户端委托,请关闭当前会话并创建新会话。
决定助手何时应进行委托
Live 提示中的规则很简单:问候与简短问题留给 Live 模型,学习计划或对该计划的更改交给后端。API 不会强制这一边界。请用您的应用将会收到的请求类型进行测试,因为最终由模型自行做出选择。
如何为 DataCamp 资源添加网页搜索
一旦委托,后端只有一个任务:将学习者的目标转化为带链接的 DataCamp 资源简短清单。我为其提供了 web_search 工具,并将 filters.allowed_domains 设置为 datacamp.com 与 www.datacamp.com。请将该过滤器视为搜索指令,而非每个链接都正确的证明。
示例目标是每周 5 小时,具备部分 Python 基础、但无 SQL 经验的数据工程路径。回复以 How to Learn Data Engineering From Scratch in 2026 与 Associate Data Engineer in SQL 方向开篇。
其余条目包含一个项目、一个 Python 数据库课程、另一个路径,以及最后的流水线项目。所有列出的 URL 都能打开现有的 DataCamp 页面。
将搜索结果转化为学习计划
后端提示要求输出 4 到 7 个有序条目。每个条目包含标题、URL、简短理由,以及类型 course、project、track 或 article。组合会遵循学习者所述的格式偏好与每周时长。
当页面未标注课程时长时,我没有要求模型去猜测。此类情况下给出精确数字会超出来源可支持的范围。
如何在后端工作时继续对话
GPT-Live 可在 Responses 后端工作期间保持语音会话活跃。如果学习者在第一个计划返回前添加了“动手实践”的限制,原先的后端工作不会被自动取消。
在运行过程中更新请求
口头更正不会自动取消或重写后端已开始的工作。打断助手发声与更改任务是两件事。由应用决定如何处理较早的结果。
服务器跟踪一个 task_version 计数器,并在每次新委托开始时自增。当结果到达时,应用会在执行前检查其版本;处理器会记录旧版本结果但不执行。
Responses 委托在这里有个限制:Live 模型会直接接收后端结果,因此版本检查无法完全控制其下一句口头回复。客户端委托允许您的代码在结果到达模型前丢弃旧结果。因此,任务版本保护的是应用动作,而非助手可能说出的每个字。

任务版本保持新约束生效。作者供图。
第一轮后端响应完成后,我又补充要求“动手项目,且不要初级 Python”。修订后的 7 项计划以 Introduction to SQL 开头,随后混合了 1 个路径、2 门课程与 4 个项目,包括 Exploring London's Travel Network 与 Building a Retail Data Pipeline。这展示了跨已完成轮次的修订;并不涉及如何停止一条正在进行的响应。
将后端更新发送给语音模型
后端工作期间,有三种追加事件可更新 Live 模型: session.thinking.append 添加不应口述的上下文,session.commentary.append 添加应由模型用自己的话说出的文本,session.instructions.append 则可改变其指令。
每次追加传递一段不超过 500 个 token 的纯字符串。这些事件会更新 Live 模型的上下文或行为;并不会修改或取消已在运行中的后端 Responses 任务。指令可以重定向当前的 Live 行为,而评论内容为模型提供应当口述的信息。
仪表板会记录后端进度,但不会发送这些追加事件。使用 Responses 委托时,您的应用仍可通过 oai-events 发送更新,但需要使用 delegation_id: null。非空 delegation ID 用于客户端委托任务。
请将 task_id 与 task_version 保存在应用状态中,而不要将 delegation_id 用于任一者。
如何添加函数调用以实现“确认后保存”
在本应用中,模型回复本身不会保存任何内容。后端使用 save_learning_plan 来提出待执行的操作,而 /api/save-plan 负责实际写入。
后端函数调用出现在 response.event 内部。处理器会等待嵌套的 response.output_item.done 项,然后读取其 call_id、name 与 arguments。
等待完成项至关重要,因为更早的事件可能只包含调用的一部分。应用会解析参数,但暂不运行该函数。
SAVE_LEARNING_PLAN_TOOL = {
"type": "function",
"name": "save_learning_plan",
"description": "Propose the current learning plan for confirmation when the learner asks to save.",
"parameters": {
"type": "object",
"properties": {
"goal": {"type": "string"},
"weekly_hours": {"type": "number"},
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"title": {"type": "string"},
"url": {"type": "string"},
"reason": {"type": "string"},
"type": {
"type": "string",
"enum": ["course", "project", "track", "article"],
},
},
"required": ["title", "url", "reason", "type"],
"additionalProperties": False,
},
},
},
"required": ["goal", "weekly_hours", "items"],
"additionalProperties": False,
},
"strict": True,
}
该模式为应用在询问学习者确认前提供了一组固定字段。type 字段使课程、项目、路径与文章在保存数据中保持明确。

终端显示带类型的保存函数参数。作者供图。
在执行前强制确认
当学习者提出保存请求时,后端会以完整计划调用 save_learning_plan。组件会暂存这些参数并显示确认框,但该调用仍只是一个提议。
若不对该函数调用作出响应,会阻塞当前的委托回复以及后续后端轮次。组件会立即以“等待用户确认”的结果进行答复,然后发送 response.create,以便对话继续进行。
events.send(JSON.stringify({
type: "response.item.create",
item: {
type: "function_call_output",
call_id: callId,
output: JSON.stringify({
status: "awaiting_user_confirmation",
saved: false,
}),
},
}));
events.send(JSON.stringify({ type: "response.create" }));
此时尚未写入任何文件。助手可以引导学习者点击“确认并保存”按钮,同时不阻塞后续委托工作。
/api/save-plan 端点在 confirmed 为 true 之前拒绝写入。由于转写可能有误或不完整,仅凭口头请求不会保存计划。

确认将请求与已保存动作区分开来。作者供图。
将已确认保存返回到对话中
点击“确认”会向 /api/save-plan 发送待处理计划与 confirmed: true。服务器返回计划 ID 后,组件发送 session.commentary.append 并使用 delegation_id: null ,因为原函数调用已被答复。
const saveResponse = await fetch(${SERVER}/api/save-plan, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
confirmed: true,
plan: pendingFunctionCall.args,
}),
});
const saveResult = await saveResponse.json();
events.send(JSON.stringify({
type: "session.commentary.append",
delegation_id: null,
content: The plan was saved as ${saveResult.plan_id}.,
}));
该评论更新会告知 Live 模型写入已完成,并让其口头确认保存。早先的函数调用保持关闭状态,语音会话仍可用于学习者的下一条请求。
如何运行 GPT-Live-1 语音助手
前文的 GitHub 仓库包含 FastAPI 服务器、Streamlit 界面与置于 app/ 中的 WebRTC 组件。克隆后,在该文件夹中打开两个终端。在一端运行 uvicorn server:app --host 127.0.0.1 --port 8000,在另一端运行 streamlit run streamlit_app.py 。
Streamlit 界面封装了贯穿整个构建过程所用的同一服务器与组件。它将实时对话与学习计划、后端活动并列展示,同时仪表板在不重置通话的情况下更新。
下方视频演示了口述目标、后端搜索、修订计划与确认保存的流程。保存后通话仍保持开启,学习者可以继续交流。
单次录制的会话并不能展示应用在各种口音、网络条件或含混语句下的表现。
GPT-Live-1 成本与生产注意事项
OpenAI 将语音层定价为 每分钟 $0.05,按秒计费且不进位。后端模型 Token、网页搜索与其他工具使用另行计费。总成本为语音会话费用加上 gpt-5.6-sol、web_search 及会话期间其他工具的费用。
会话成本与空闲连接
只要会话处于开启状态,计费就会持续,包括静音与后端工作阶段。静音麦克风不会停止计时。请使用 session.close 关闭空闲连接,等待 session.closed,然后停止本地麦克风轨道与对等连接。
创建会话会在开始时计入 15 秒语音时间,随后会在运行时长中抵扣。这不是在会话费用之外的额外收费。
session.usage.updated 报告的是截至目前的总秒数,而非自上一次事件以来新增的秒数。通话结束时,session.closed.usage.seconds 为最终值。若将多次快照相加,会将同一时间重复计数。
将任务状态保存在 GPT-Live-1 之外
GPT-Live-1 具有 128,000 Token 的上下文窗口,其中包括未出现在转写中的音频 Token。一旦使用量超过 90%,较早的细节可能被摘要或忽略。因此,已保存的计划、确认标志与任务版本应保存在服务器状态中。
仓库会按会话持久化应用拥有的状态,而非将 Live 记忆视为唯一事实来源。
多用户应用需要以用户与会话为键的记录,并在读取或更改计划前进行访问检查。请将这些检查放在应用代码中,而非提示中。将确认与计划版本绑定,并为每次保存分配唯一 ID,以防重试导致重复写入。
对于电话场景,OpenAI 还提供了 SIP 与合作伙伴集成文档。本文的浏览器构建则保持在 WebRTC 上。
结语
开启的麦克风只是此设计的一半。正如任务版本一节所示,Responses 委托让后端调用留在 Live 会话之内,但在应用拒绝其动作后,旧结果仍可能抵达语音层。
将 Responses 委托用于可在下一轮修正的草案。若旧结果绝不能传至语音模型,则选择客户端委托。无论哪种方式,请将权限、任务版本与已保存数据保留在服务器端。
常见问题
我可以在会话中更换 GPT-Live-1 的语音吗?
不能。参见 会话指南,语音在会话开始时即固定。如需更改,必须开启新会话。
GPT-Live-1 支持图像或视频输入吗?
不能直接。 GPT-Live-1 模型页面列出的输入与输出类型为文本与音频,不包含图像或视频。具备视觉能力的被委托后端可以分析图像,并将文本返回给 Live 对话。
我可以存储并分叉一个 GPT-Live-1 会话吗?
可以。在创建源会话时设置 store: true;已存录音在 30 天后过期,而零数据留存会强制关闭存储。分叉会创建一个独立的 Live 会话与 ID,而非重开源连接。
OpenAI 会用 GPT-Live-1 会话数据进行训练吗?
默认不会。OpenAI 的 数据控制指南列出了 /v1/live/sessions 不用于训练,且在限定条件下支持零数据留存。
GPT-Live-1 是否支持结构化输出?
语音模型中不支持。当应用需要结构化数据时,请使用后端模型或函数模式。