跳转到内容

传输机制

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

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

默认的浏览器传输机制使用 WebRTC。音频会自动从麦克风采集并自动播放,这就是为什么快速开始只需一个临时令牌和 session.connect(...) 就能完成连接。

在这一路径上,session.connect() 会尝试等待初始会话配置通过 session.updated 得到确认后再解析,因此您的 instructions 和工具会在音频开始流动之前生效。如果该确认始终未到达,仍然会有超时回退机制。

如果要使用您自己的媒体流或音频元素,请在创建会话时提供一个 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 打开且初始配置已发送后解析。对应的 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-1.5',
});
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 传输机制就是基于这些钩子构建的。

当您希望 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-1.5',
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 上的实时智能体

您可以使用原始 WebSockets,或使用 @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-1.5',
});
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-1.5',
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);