跳转到内容

传输机制

请根据会话运行位置,以及您对原始媒体或事件控制的需求程度来选择传输层。

场景推荐传输层原因
浏览器端语音到语音应用OpenAIRealtimeWebRTC阻力最低的路径。SDK 会为您管理麦克风采集、音频播放和 WebRTC 连接。
服务端语音循环或自定义音频管线OpenAIRealtimeWebSocket当您已自行控制音频采集/播放并希望直接访问事件时,这种方式非常适合。
SIP 或电话桥接OpenAIRealtimeSIP通过 callIdRealtimeSession 绑定到现有的 SIP 发起 Realtime 通话。
Cloudflare Workers / workerdCloudflare 扩展传输层workerd 无法通过全局 WebSocket 构造函数发起出站 WebSocket 连接。
Twilio 上的特定供应商电话流程Twilio 扩展传输层可为您处理 Twilio 音频转发与中断行为。

默认的浏览器传输层使用 WebRTC。音频会自动从麦克风采集并自动播放,这也是为什么快速开始只需临时 token 和 session.connect(...) 即可连接。

在此路径下,session.connect() 会尽量等待初始会话配置通过 session.updated 确认后再 resolve,因此您的 instructions 和 tools 会在音频开始流动前生效。如果该确认始终未到达,仍有超时回退机制。

若要使用您自己的媒体流或音频元素,请在创建会话时传入 OpenAIRealtimeWebRTC 实例。

import { RealtimeAgent, RealtimeSession, OpenAIRealtimeWebRTC } from '@openai/agents/realtime';
const agent = new RealtimeAgent({
name: 'Greeter',
instructions: 'Greet the user with cheer and answer questions.',
});
async function main() {
const transport = new OpenAIRealtimeWebRTC({
mediaStream: await navigator.mediaDevices.getUserMedia({ audio: true }),
audioElement: document.createElement('audio'),
});
const customSession = new RealtimeSession(agent, { transport });
}

对于更底层的自定义,OpenAIRealtimeWebRTC 还支持 changePeerConnection,让您可在生成 offer 前检查或替换新创建的 RTCPeerConnection

创建会话时传入 transport: 'websocket'OpenAIRealtimeWebSocket 实例,即可使用 WebSocket 连接而非 WebRTC。这非常适合服务端场景、电话桥接和自定义音频管线。

在 WebSocket 路径下,session.connect() 会在 socket 打开且初始配置已发送后 resolve。对应的 session.updated 事件可能稍后才到达,因此不要假设 connect() 返回就代表该更新已回显。

import { RealtimeAgent, RealtimeSession } from '@openai/agents/realtime';
const agent = new RealtimeAgent({
name: 'Greeter',
instructions: 'Greet the user with cheer and answer questions.',
});
const myRecordedArrayBuffer = new ArrayBuffer(0);
const wsSession = new RealtimeSession(agent, {
transport: 'websocket',
model: 'gpt-realtime',
});
await wsSession.connect({ apiKey: process.env.OPENAI_API_KEY! });
wsSession.on('audio', (event) => {
// event.data is a chunk of PCM16 audio
});
wsSession.sendAudio(myRecordedArrayBuffer);

可使用任意录音/播放库来处理原始 PCM16 音频字节。

对于高级集成,OpenAIRealtimeWebSocket 支持 createWebSocket(),便于您提供自定义 socket 实现;还支持 skipOpenEventListeners,用于自定义连接器负责将 socket 切换到已连接状态的场景。@openai/agents-extensions 中的 Cloudflare 传输层就是基于这些钩子构建的。

SIP 适用于呼叫服务商与电话桥接

Section titled “SIP 适用于呼叫服务商与电话桥接”

当您希望 RealtimeSession 绑定到现有 SIP 发起的 Realtime 通话时,请使用 OpenAIRealtimeSIP。它是一个轻量、SIP 感知的传输层:音频由 SIP 通话本身处理,您通过 callId 连接 SDK 会话。

  1. 通过 OpenAIRealtimeSIP.buildInitialConfig() 生成初始会话配置来接受来电。这可确保 SIP 邀请和后续 SDK 会话使用同一套默认值。
  2. 绑定使用 OpenAIRealtimeSIP 传输层的 RealtimeSession,并使用服务商 webhook 签发的 callId 进行连接。
  3. 如果您需要服务商特定的媒体转发或事件桥接,请使用集成传输层(如 Twilio 扩展)。
import OpenAI from 'openai';
import {
OpenAIRealtimeSIP,
RealtimeAgent,
RealtimeSession,
type RealtimeSessionOptions,
} from '@openai/agents/realtime';
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY!,
webhookSecret: process.env.OPENAI_WEBHOOK_SECRET!,
});
const agent = new RealtimeAgent({
name: 'Receptionist',
instructions:
'Welcome the caller, answer scheduling questions, and hand off if the caller requests a human.',
});
const sessionOptions: Partial<RealtimeSessionOptions> = {
model: 'gpt-realtime',
config: {
audio: {
input: {
turnDetection: { type: 'semantic_vad', interruptResponse: true },
},
},
},
};
export async function acceptIncomingCall(callId: string): Promise<void> {
const initialConfig = await OpenAIRealtimeSIP.buildInitialConfig(
agent,
sessionOptions,
);
await openai.realtime.calls.accept(callId, initialConfig);
}
export async function attachRealtimeSession(
callId: string,
): Promise<RealtimeSession> {
const session = new RealtimeSession(agent, {
transport: new OpenAIRealtimeSIP(),
...sessionOptions,
});
session.on('history_added', (item) => {
console.log('Realtime update:', item.type);
});
await session.connect({
apiKey: process.env.OPENAI_API_KEY!,
callId,
});
return session;
}

Cloudflare Workers 及其他 workerd 运行时无法使用全局 WebSocket 构造函数发起出站 WebSocket。请使用扩展包中的 Cloudflare 传输层,它在内部通过 fetch() 完成升级。

import { CloudflareRealtimeTransportLayer } from '@openai/agents-extensions';
import { RealtimeAgent, RealtimeSession } from '@openai/agents/realtime';
const agent = new RealtimeAgent({
name: 'My Agent',
});
// Create a transport that connects to OpenAI Realtime via Cloudflare/workerd's fetch-based upgrade.
const cfTransport = new CloudflareRealtimeTransportLayer({
url: 'wss://api.openai.com/v1/realtime?model=gpt-realtime',
});
const session = new RealtimeSession(agent, {
// Set your own transport.
transport: cfTransport,
});

完整配置请参阅 Cloudflare 上的实时智能体

您可以使用原始 WebSocket,或 @openai/agents-extensions 中专用的 Twilio 传输层,将 RealtimeSession 连接到 Twilio。若希望 SDK 为 Twilio Media Streams 处理打断时机与音频转发,专用传输层是更好的默认选择。

完整配置请参阅 Twilio 上的实时智能体

如果您想使用不同的语音到语音 API,或已有自定义传输机制,可以实现 RealtimeTransportLayer 接口,并自行发出 RealtimeTransportEventTypes 事件。

如果您希望更直接地访问底层 Realtime API,有两种方式。

如果您仍希望利用 RealtimeSession 的全部能力,可通过 session.transport 访问传输层。

传输层会将其收到的所有事件都通过 * 事件发出,您也可使用 sendEvent() 发送原始事件。这是进行底层操作(如 session.updateresponse.createresponse.cancel)的逃生口。

import { RealtimeAgent, RealtimeSession } from '@openai/agents/realtime';
const agent = new RealtimeAgent({
name: 'Greeter',
instructions: 'Greet the user with cheer and answer questions.',
});
const session = new RealtimeSession(agent, {
model: 'gpt-realtime',
});
session.transport.on('*', (event) => {
// JSON parsed version of the event received on the connection
});
// Send any valid event as JSON. For example triggering a new response
session.transport.sendEvent({
type: 'response.create',
// ...
});

如果您不需要自动工具执行、护栏或本地历史管理,也可以将传输层作为“轻量”客户端使用,仅管理连接与中断。

import { OpenAIRealtimeWebRTC } from '@openai/agents/realtime';
const client = new OpenAIRealtimeWebRTC();
const audioBuffer = new ArrayBuffer(0);
await client.connect({
apiKey: '<api key>',
model: 'gpt-realtime',
initialSessionConfig: {
instructions: 'Speak like a pirate',
outputModalities: ['audio'],
audio: {
input: {
format: 'pcm16',
},
output: {
format: 'pcm16',
voice: 'ash',
},
},
},
});
// optionally for WebSockets
client.on('audio', (newAudio) => {});
client.sendAudio(audioBuffer);