传输机制
请根据会话运行的位置,以及你需要多少原始媒体或事件控制能力来选择传输机制。
| 场景 | 推荐传输机制 | 原因 |
|---|---|---|
| 浏览器语音到语音应用 | OpenAIRealtimeWebRTC | 上手成本最低的路径。SDK 会为你管理麦克风采集、播放和 WebRTC 连接。 |
| 服务器端语音循环或自定义音频管线 | OpenAIRealtimeWebSocket | 当你已经控制音频采集/播放,并希望直接访问事件时很适合。 |
| SIP 或电话桥接 | OpenAIRealtimeSIP | 通过 callId 将 RealtimeSession 附加到现有的 SIP 发起的 Realtime 呼叫。 |
| Cloudflare Workers / workerd | Cloudflare 扩展传输机制 | workerd 无法使用全局 WebSocket 构造函数打开出站 WebSocket。 |
| Twilio 上特定于提供商的电话流程 | Twilio 扩展传输机制 | 为你处理 Twilio 音频转发和打断行为。 |
WebRTC:默认浏览器选择
Section titled “WebRTC:默认浏览器选择”默认浏览器传输机制使用 WebRTC。音频会从麦克风采集并自动播放,这也是为什么快速开始只需一个临时令牌和 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。
WebSocket:默认服务器选择
Section titled “WebSocket:默认服务器选择”在创建会话时传入 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-2',});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 实现;当该自定义连接器负责将 socket 转换为已连接状态时,也可以使用 skipOpenEventListeners。@openai/agents-extensions 中的 Cloudflare 传输机制就是基于这些 hook 构建的。
SIP:呼叫提供商和电话桥接场景
Section titled “SIP:呼叫提供商和电话桥接场景”当你希望 RealtimeSession 附加到现有的 SIP 发起的 Realtime 呼叫时,请使用 OpenAIRealtimeSIP。它是一个具备 SIP 感知能力的轻量传输机制:音频由 SIP 呼叫本身处理,你通过 callId 连接 SDK 会话。
- 通过
OpenAIRealtimeSIP.buildInitialConfig()生成初始会话配置来接收入站呼叫。这可确保 SIP 邀请和之后的 SDK 会话从相同的默认值开始。 - 附加一个使用
OpenAIRealtimeSIP传输机制的RealtimeSession,并使用提供商 webhook 签发的callId进行连接。 - 如果你需要特定于提供商的媒体转发或事件桥接,请使用集成传输机制,例如 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-2', 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
Section titled “Cloudflare Workers 和 workerd”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-2',});
const session = new RealtimeSession(agent, { // Set your own transport. transport: cfTransport,});完整设置请阅读 Cloudflare 上的实时智能体。
Twilio 电话呼叫
Section titled “Twilio 电话呼叫”你可以使用原始 WebSocket 或 @openai/agents-extensions 中专用的 Twilio 传输机制,将 RealtimeSession 连接到 Twilio。当你希望 SDK 为 Twilio Media Streams 处理打断时机和音频转发时,专用传输机制是更好的默认选择。
完整设置请阅读 Twilio 上的实时智能体。
自定义传输机制
Section titled “自定义传输机制”如果你想使用不同的语音到语音 API,或者有自己的自定义传输机制,可以实现 RealtimeTransportLayer 接口,并自行发出 RealtimeTransportEventTypes 事件。
原始 Realtime 事件访问
Section titled “原始 Realtime 事件访问”如果你想更直接地访问底层 Realtime API,有两个选项。
选项 1 - 传输层访问
Section titled “选项 1 - 传输层访问”如果你仍然希望受益于 RealtimeSession 的所有能力,可以通过 session.transport 访问你的传输层。
传输层会在 * 事件下发出它收到的每个事件,你也可以使用 sendEvent() 发送原始事件。这是执行底层操作的逃生通道,例如 session.update、response.create 或 response.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-2',});
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 responsesession.transport.sendEvent({ type: 'response.create', // ...});选项 2 - 仅使用传输层
Section titled “选项 2 - 仅使用传输层”如果你不需要自动工具执行、护栏或本地历史记录管理,也可以将传输层用作一个”轻量”客户端,仅用于管理连接和打断。
import { OpenAIRealtimeWebRTC } from '@openai/agents/realtime';
const client = new OpenAIRealtimeWebRTC();const audioBuffer = new ArrayBuffer(0);
await client.connect({ apiKey: '<api key>', model: 'gpt-realtime-2', initialSessionConfig: { instructions: 'Speak like a pirate', outputModalities: ['audio'], audio: { input: { format: 'pcm16', }, output: { format: 'pcm16', voice: 'ash', }, }, },});
// optionally for WebSocketsclient.on('audio', (newAudio) => {});
client.sendAudio(audioBuffer);