传输机制
请根据会话的运行位置,以及您对原始媒体或事件控制的需求程度选择传输机制。
| 场景 | 推荐的传输机制 | 原因 |
|---|---|---|
| 浏览器语音到语音应用 | 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 得到确认后再完成,以确保您的指令和工具在音频开始传输之前生效。如果始终未收到确认,仍有超时回退机制。
如需使用您自己的媒体流或音频元素,请在创建会话时提供一个 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() { // Keep a handle on the stream you pass in. The transport does not stop a caller-supplied // stream on close(), so your application owns it and is responsible for ending it. const mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true, });
const transport = new OpenAIRealtimeWebRTC({ mediaStream, audioElement: document.createElement('audio'), });
const customSession = new RealtimeSession(agent, { transport });
// Later, once the application is actually done with the microphone, release it. Leaving this // out keeps the microphone indicator on even after the session closes. // mediaStream.getTracks().forEach((track) => track.stop());}对于更底层的自定义,OpenAIRealtimeWebRTC 还接受 changePeerConnection,以便您在生成 offer 之前检查或替换新创建的 RTCPeerConnection。
服务器的默认选择:WebSocket
Section titled “服务器的默认选择:WebSocket”创建会话时传入 transport: 'websocket' 或 OpenAIRealtimeWebSocket 实例,即可使用 WebSocket 连接代替 WebRTC。这种方式非常适合服务器端用例、电话桥接和自定义音频管道。
在 WebSocket 路径中,套接字打开并发送初始配置后,session.connect() 就会完成。对应的 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.1',});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(),以便您提供自己的套接字实现;当自定义连接器负责将套接字转换为已连接状态时,还可以使用 skipOpenEventListeners。@openai/agents-extensions 中的 Cloudflare 传输就是基于这些钩子构建的。
通话提供商和电话桥接使用的 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.1', 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.1',});
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 上的实时智能体。
如果您想使用不同的语音到语音 API,或拥有自定义传输机制,可以实现 RealtimeTransportLayer 接口并自行发出 RealtimeTransportEventTypes 事件。
原始 Realtime 事件的访问
Section titled “原始 Realtime 事件的访问”如果您希望更直接地访问底层 Realtime API,有以下两种选择。
选项 1——传输层访问
Section titled “选项 1——传输层访问”如果您仍希望使用 RealtimeSession 的全部功能,可以通过 session.transport 访问传输层。
传输层会在 * 事件下发出它收到的每个事件,您也可以使用 sendEvent() 发送原始事件。* 监听器接收原始已解析 JSON 载荷的结构化克隆,其中包括当前 SDK 架构尚不了解的字段。具名和派生事件监听器则会继续接收经过验证和规范化的事件对象。这为 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.1',});
session.transport.on('*', (event) => { // Event received from the underlying Realtime transport});
// Send any valid client event, for example, to trigger 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.1', initialSessionConfig: { instructions: 'Speak like a pirate', outputModalities: ['audio'], audio: { input: { format: 'pcm16', }, output: { format: 'pcm16', voice: 'ash', }, }, },});
// Listen for audio when you manage playback yourselfclient.on('audio', (newAudio) => {});
client.sendAudio(audioBuffer);