选择您的应用使用的 API。每个 API 都有各自的身份验证方式、会话创建流程和事件约定。
从您的服务器控制 GPT-Live 会话
当服务器需要接收对话事件、执行私有工具或更新对话时,将您的应用服务器连接到现有的 GPT-Live WebRTC 或 SIP 会话。这条额外的连接称为 旁路 WebSocket。两条连接共享同一个会话,主要音频仍由 WebRTC 或 SIP 传输。
旁路连接传输事件和命令。您的应用负责执行工具、检查授权并实施业务规则。请将 API 密钥和工具凭据保留在您的服务器上。
确定是否需要旁路连接
对于浏览器应用,请使用 WebRTC 数据通道传输字幕和更新本地 UI。当转录文本处理在您的服务器上运行时,例如进行护栏检查、情感分析或推测性工具调用,请使用旁路连接。您的服务器可以接收事件并直接引导同一个会话,而浏览器音频仍通过 WebRTC 传输。有关示例,请参阅响应转录文本片段。
如果您的后端已经管理主 WebSocket 连接,它就已经能够接收会话事件并发送命令。
Responses 委派也可以在没有旁路连接的情况下工作。浏览器可以将数据通道中的函数调用事件转发到经过身份验证的后端执行。OpenAI 托管的工具通过受委派的后端运行,无需应用提供工具执行器。
连接到现有会话
-
保存您的后端将控制的会话的 ID。对于 WebRTC,请使用
POST /v1/live/sessions的 JSON 响应中的session.id。对于 SIP,请先接受来电,然后使用其 webhook 中的data.session_id。将此 ID 与应用的用户和对话记录一同保存。 -
从您的服务器向以下 URL 建立 WebSocket 连接,并将保存的 ID 原样代入。使用创建或接受该会话时所用的项目身份验证凭据,通过
Authorization: Bearer $OPENAI_API_KEY进行身份验证。同时提供创建会话时所需的相同连接标头。wss://api.openai.com/v1/live/sessions/{session_id}/attach -
通过连接到会话的套接字接收事件和发送命令。会话已经在运行,请勿再次发送
session.start。
将会话 ID 视为不透明值。保留其前缀,并仅将其用于您的应用已获授权访问的对应会话。从 Live JSON 响应中读取 ID,而不是从 Realtime 的 Location 标头或 call_id URL 参数中读取。
观察事件并发送命令
| 任务 | 事件或命令 |
|---|---|
| 跟踪对话 | 接收用户和助手的转录文本增量、委派事件以及嵌套的 Responses 事件。 |
| 更新后端配置 | 使用 session.update 在现有委派模式下更改受支持的设置。前端模型和音频配置等启动设置保持不变。 |
| 提供上下文 | 使用 session.instructions.append 提供指令,使用 session.thinking.append 提供无需说出的上下文,使用 session.commentary.append 提供可说出的更新内容。 |
| 返回工具结果 | 使用 Responses 委派时,先发送 response.item.create,再发送 response.create,以继续后端工作。 |
| 控制麦克风输入 | 使用 session.input_audio.mute 和 session.input_audio.unmute。将输入静音不会停止助手的输出。 |
| 结束会话 | 发送 session.close 并收到 session.closed 后,再断开连接。 |
命令遵循与主连接相同的验证和委派规则。追加上下文时,对通用会话上下文使用 delegation_id: null;非 null 的 ID 必须标识一个现有的客户端委派。有关配置、函数执行和上下文追加的示例,请参阅委派与工具。
对于浏览器会话,请继续通过协商好的 WebRTC 媒体轨道传输麦克风输入和扬声器输出。使用旁路连接处理对话事件和控制操作。转录文本事件或命令确认并不能证明音频已经播放或用户已经听到音频。
接收镜像音频
主连接传输实时媒体的同时,旁路连接也会接收后续输入和输出音频的副本:
| 事件 | 音频字段 | 时间信息 |
|---|---|---|
session.input_audio.append | audio | 无时间戳。 |
session.output_audio.delta | delta | start_ms 和 end_ms 描述输出在会话时间线上的范围。 |
无论主传输通道使用何种音频格式,这两种载荷都是经过 base64 编码的原始单声道 PCM16LE 音频,采样率为 24 kHz。这两个事件都没有 event_id。镜像输入包含在输入静音处理之前接收到的音频,并不能确认模型已处理这些采样。镜像输出的时间范围可能因丢帧而出现间隙,也不能表明通话方何时听到了音频。
这些是服务器事件,并不意味着可以通过旁路连接发送音频。请通过主传输通道发送麦克风音频;不要在连接到会话的套接字上发送 session.input_audio.append。
为每项操作指定唯一负责方
确定每项操作由浏览器还是后端处理。如果两条连接都收到了函数调用事件,也只执行一次该函数。对于上下文更新和继续后端工作的请求,也应采用相同的职责分配规则。
在您的应用中保存转录文本和工具状态。如果后端需要从一开始就观察对话,请尽早建立连接,并保留连接前收集的所有历史记录。不要依赖建立连接来重建先前的转录文本或工具结果。
旁路连接本身并不会对浏览器隐藏会话事件。请将敏感的工具凭据和授权决策保留在您的后端,仅返回对话所需的上下文。
应用对话护栏
使用您的服务器连接监控对话,根据应用的策略检查请求,并在检查触发时进行干预。旁路连接让您的服务器能够访问会话事件和发送命令;您的应用负责运行检查并执行检查结果所要求的操作。当您的服务器已经管理主 WebSocket 连接时,同样适用这一工作流程。
在对话进行的同时运行检查
护栏是在转录文本片段到达时即时处理的一种用途。在运行这些检查的同时,同一数据流也可以触发推测性查询或更新 UI。
- 监控转录文本。 累积
session.input_transcript.delta片段,检查用户请求中是否存在越狱尝试、敏感信息或违反策略的内容。使用session.output_transcript.delta检查助手的语音内容中是否存在缺乏依据的断言或超出应用范围的回答。确保每次检查都与其评估的转录文本和应用请求保持关联。 - 并发运行检查。 快速的轻量模型可以在对话继续进行时评估请求。返回一个简短的结构化结果,例如
{"triggered": true},以便您的应用据此采取操作。对于需要审批的操作,在其通过检查之前应始终阻止执行;超时或检查失败并不代表获得审批。 - 阻止受影响的操作。 当检查触发时,在应用状态中将请求标记为已阻止。在执行工具或提交更改之前检查该状态,已排队的工作也不例外。口头拒绝并不能阻止工具运行。
- 停止相关工作。 如果您的后端支持取消,请取消由应用管理的作业,并丢弃来自已阻止或已被取代请求的迟到结果。使用 Responses 委派时,停止执行受影响的自定义函数,并且不要发送
response.create来继续已阻止的工作。这不会取消已经在运行的托管响应,也不会停止前端语音。 - 记录并重新引导。 将决策与受影响的请求 ID 和委派 ID 一同记录到日志中,然后发送纠正指令。
guardrail.triggered这样的事件名称属于您的应用遥测,并非 GPT-Live API 事件。
有关收集片段的方法,请参阅转录文本增量;有关如何让后端结果与当前任务保持一致,请参阅委派与工具。
重新引导对话
使用 session.instructions.append 根据护栏要求引导对话。它可以中断正在进行的语音并应用新指令。例如,在您的应用阻止某个请求后,发送:
export function sendUpdate(connection) {
connection.send({
type: "session.instructions.append",
event_id: "guardrail_block_17",
delegation_id: null,
content:
"Stop speaking immediately. Do not continue or act on the last request. Refuse briefly, then wait.",
});
}确保指令由应用编写。不要将不受信任的用户文本复制到其中作为指令。对于这种作用于整个会话的纠正,请使用 delegation_id: null,并将 content 限制在 500 个 Token 以内。
通过 client_event_id 将 session.instructions.appended 与您的命令对应起来。确认消息会在预计上下文注入完成后到达;它并不能证明助手已停止说话,也不能证明队列中的音频已停止播放。纠正指令无法收回用户已经听到的音频。
对于要求使用特定措辞播报的告知内容,也应使用指令。有关示例和播放注意事项,请参阅播报告知内容。
按需控制播放
先测试纠正指令和操作阻止机制。如果您的应用还需要阻止模型音频播放,请在客户端或媒体中继端控制输出:暂时静音或丢弃输出,丢弃本地队列中的音频,发送纠正指令,然后根据应用的恢复策略恢复播放。恢复前,请清除过时的音频。仅靠边带连接无法控制媒体传输路径,指令确认消息也不是恢复播放的信号。
session.input_audio.mute 控制通话方的麦克风输入。它不会将模型输出静音,也不会取消委派的工作。
GPT-Live 在说话的同时流式传输转录文本片段。如果某项检查必须在用户听到音频前完成,您的应用就需要先缓冲音频,并在批准后再播放。这会增加延迟。阻止音频播放还可能导致模型的对话上下文超前于用户实际听到的内容,因此请测试对话恢复时的表现。
测试干预效果
测试以下情况:允许和阻止的请求、误报、检查缓慢或失败、说话期间触发检查、工具运行期间触发检查,以及已取消工作延迟返回结果。分别验证操作阻止机制、应用状态、纠正后的语音和实际播放效果。如果您控制输出,还应在测试中涵盖队列中的音频和恢复过程。使用语音智能体评估 Cookbook 比较任务成功情况和语音响应时间。
正常结束会话
当后端负责执行工具或收集最终用量时,请持续接收事件。在发送 session.close 之前注册 session.closed 处理程序,并在等待待处理工作完成期间保持 WebRTC 连接、数据通道和边带连接开启。清理之前,保存最终会话用量以及通过 Responses 事件收到的所有后端用量。如果连接在最终事件到达前失败,请将收尾状态记录为未完成。有关关闭顺序,请参阅管理会话。
Realtime API 允许客户端通过 WebRTC 或 SIP 直接连接到 API 服务器。不过,您通常会希望将工具使用和其他业务逻辑放在应用服务器上,以使这些逻辑保持私密且不依赖特定客户端。
通过“边带”控制通道建立连接,可将工具使用、业务逻辑和其他细节安全地保留在服务器端。目前,SIP 和 WebRTC 连接都支持边带连接。
使用边带连接意味着同一个 Realtime 会话有两个活动连接:一个来自用户的客户端,另一个来自您的应用服务器。服务器连接可用于监控会话、更新指令和响应工具调用。
使用 WebRTC
- 建立对等连接时,您会从 Realtime API 获取 SDP 响应,用于配置连接。如果您使用了 WebRTC 指南中的示例代码,其形式大致如下:
const baseUrl = "https://api.openai.com/v1/realtime/calls";
const sdpResponse = await fetch(baseUrl, {
method: "POST",
body: offer.sdp,
headers: {
Authorization: `Bearer ${EPHEMERAL_KEY}`,
"Content-Type": "application/sdp",
},
});- 获取到的响应会包含一个
Location标头,其中有唯一的通话 ID。服务器可以使用此 ID 建立连接到同一个 Realtime 会话的 WebSocket 连接。
// Location: /v1/realtime/calls/rtc_123456
const location = sdpResponse.headers.get("Location");
const callId = location?.split("/").pop();
console.log(callId);- 随后,您可以在服务器上将该通话 ID 用于 URL
wss://api.openai.com/v1/realtime?call_id=rtc_xxxxx,像使用常规 Realtime API WebSocket 连接一样监听事件并配置会话,如下所示:
import WebSocket from "ws";
const callId = "rtc_u1_9c6574da8b8a41a18da9308f4ad974ce";
// Connect to a WebSocket for the in-progress call
const url = "wss://api.openai.com/v1/realtime?call_id=" + callId;
const ws = new WebSocket(url, {
headers: {
Authorization: "Bearer " + process.env.OPENAI_API_KEY,
},
});
ws.on("open", function open() {
console.log("Connected to server.");
// Send client events over the WebSocket once connected
ws.send(
JSON.stringify({
type: "session.update",
session: {
type: "realtime",
instructions: "Be extra nice today!",
},
})
);
});
// Listen for and parse server events
ws.on("message", function incoming(message) {
console.log(JSON.parse(message.toString()));
});这样,您就可以在服务器上添加工具、监控会话和执行业务逻辑,而无需在客户端配置这些操作。
使用 SIP
- 用户通过电话使用 SIP 连接到 OpenAI。
- OpenAI 会向您的应用服务器的 webhook URL 发送 webhook 通知,告知应用当前的会话状态。webhook 内容大致如下:
POST https://my_website.com/webhook_endpoint
user-agent: OpenAI/1.0 (+https://platform.openai.com/docs/webhooks)
content-type: application/json
webhook-id: wh_685342e6c53c8190a1be43f081506c52 # unique id for idempotency
webhook-timestamp: 1750287078 # timestamp of delivery attempt
webhook-signature: v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4= # signature to verify authenticity from OpenAI
{
"object": "event",
"id": "evt_685343a1381c819085d44c354e1b330e",
"type": "realtime.call.incoming",
"created_at": 1750287018, // Unix timestamp
"data": {
"call_id": "some_unique_id",
"sip_headers": [
{ "name": "From", "value": "sip:+142555512112@sip.example.com" },
{ "name": "To", "value": "sip:+18005551212@sip.example.com" },
{ "name": "Call-ID", "value": "03782086-4ce9-44bf-8b0d-4e303d2cc590"}
]
}
}
- 应用服务器使用 webhook 中提供的
call_id值,通过类似wss://api.openai.com/v1/realtime?call_id={callId}的 URL 建立连接到 Realtime API 的 WebSocket 连接。此 WebSocket 连接将在整个 SIP 通话期间保持连接。
随后,您就可以通过此 WebSocket 连接发送和接收事件来控制通话,方式与通过 WebSocket 连接发起的会话相同。这包括监控通话、动态更新指令和响应工具调用。