传输机制
根据会话运行的位置,以及您对原始媒体或事件控制的需求程度来选择传输机制。
| 场景 | 推荐的传输机制 | 原因 |
|---|---|---|
| 浏览器语音到语音应用 | 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 得到确认后再解析,因此您的 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。
WebSocket 是默认的服务器选择
Section titled “WebSocket 是默认的服务器选择”在创建会话时传入 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 传输机制就是基于这些钩子构建的。
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-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
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',});
const session = new RealtimeSession(agent, { // Set your own transport. transport: cfTransport,});有关完整设置,请阅读Cloudflare 上的实时智能体。
Twilio 电话呼叫
Section titled “Twilio 电话呼叫”您可以使用原始 WebSockets,或使用 @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-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 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-1.5', 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);