전송 방식
세션이 실행되는 위치와 원문 미디어 또는 이벤트 제어가 얼마나 필요한지에 따라 전송 방식을 선택하세요.
| 시나리오 | 권장 전송 방식 | 이유 |
|---|---|---|
| 브라우저 음성-음성 앱 | OpenAIRealtimeWebRTC | 가장 간편한 경로입니다. SDK가 마이크 캡처, 재생, WebRTC 연결을 대신 관리합니다. |
| 서버 측 음성 루프 또는 사용자 지정 오디오 파이프라인 | OpenAIRealtimeWebSocket | 이미 오디오 캡처/재생을 제어하고 있고 직접 이벤트 접근을 원할 때 적합합니다. |
| SIP 또는 전화 통신 브리지 | OpenAIRealtimeSIP | callId로 기존 SIP 시작 Realtime 통화에 RealtimeSession을 연결합니다. |
| Cloudflare Workers / workerd | Cloudflare 확장 전송 방식 | workerd는 전역 WebSocket 생성자로 아웃바운드 WebSocket을 열 수 없습니다. |
| Twilio의 공급자별 전화 플로우 | Twilio 확장 전송 방식 | Twilio 오디오 포워딩과 인터럽션(중단 처리) 동작을 대신 처리합니다. |
기본 전송 계층
섹션 제목: “기본 전송 계층”WebRTC는 기본 브라우저 선택지
섹션 제목: “WebRTC는 기본 브라우저 선택지”기본 브라우저 전송 방식은 WebRTC를 사용합니다. 오디오는 마이크에서 캡처되고 자동으로 재생되므로 빠른 시작에서는 임시 토큰과 session.connect(...)만으로 연결할 수 있습니다.
이 경로에서 session.connect()는 반환되기 전에 초기 세션 구성이 session.updated로 확인될 때까지 기다리려고 시도하므로, 오디오가 흐르기 시작하기 전에 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도 허용합니다. 이를 통해 오퍼가 생성되기 전에 새로 생성된 RTCPeerConnection을 검사하거나 교체할 수 있습니다.
WebSocket은 기본 서버 선택지
섹션 제목: “WebSocket은 기본 서버 선택지”WebRTC 대신 WebSocket 연결을 사용하려면 세션을 만들 때 transport: 'websocket' 또는 OpenAIRealtimeWebSocket 인스턴스를 전달하세요. 이는 서버 측 사용 사례, 전화 통신 브리지, 사용자 지정 오디오 파이프라인에 적합합니다.
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',});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는 통화 공급자와 전화 통신 브리지용
섹션 제목: “SIP는 통화 공급자와 전화 통신 브리지용”기존 SIP 시작 Realtime 통화에 RealtimeSession을 연결하려면 OpenAIRealtimeSIP를 사용하세요. 이는 SIP를 인식하는 얇은 전송 방식입니다. 오디오는 SIP 통화 자체에서 처리되며, SDK 세션은 callId로 연결합니다.
OpenAIRealtimeSIP.buildInitialConfig()로 초기 세션 구성을 생성하여 들어오는 통화를 수락합니다. 이렇게 하면 SIP 초대와 이후 SDK 세션이 동일한 기본값에서 시작됩니다.OpenAIRealtimeSIP전송 방식을 사용하는RealtimeSession을 연결하고 공급자 웹훅에서 발급한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
섹션 제목: “Cloudflare Workers와 workerd”Cloudflare Workers 및 기타 workerd 런타임은 전역 WebSocket 생성자를 사용해 아웃바운드 WebSocket을 열 수 없습니다. 내부적으로 fetch() 기반 업그레이드를 수행하는 extensions 패키지의 Cloudflare 전송 방식을 사용하세요.
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용 Realtime 에이전트를 참고하세요.
Twilio 전화 통화
섹션 제목: “Twilio 전화 통화”원문 WebSocket 또는 @openai/agents-extensions의 전용 Twilio 전송 방식을 사용하여 RealtimeSession을 Twilio에 연결할 수 있습니다. SDK가 Twilio Media Streams의 인터럽션(중단 처리) 타이밍과 오디오 포워딩을 처리하기를 원한다면 전용 전송 방식이 더 나은 기본값입니다.
전체 설정은 Twilio용 Realtime 에이전트를 참고하세요.
자체 전송 방식
섹션 제목: “자체 전송 방식”다른 음성-음성 API를 사용하거나 자체 사용자 지정 전송 메커니즘이 있다면 RealtimeTransportLayer 인터페이스를 구현하고 RealtimeTransportEventTypes 이벤트를 직접 내보낼 수 있습니다.
필요 시 원문 Realtime 이벤트 접근
섹션 제목: “필요 시 원문 Realtime 이벤트 접근”기반 Realtime API에 더 직접적으로 접근하려면 두 가지 옵션이 있습니다.
옵션 1 - 전송 계층 접근
섹션 제목: “옵션 1 - 전송 계층 접근”RealtimeSession의 모든 기능을 계속 활용하고 싶다면 session.transport를 통해 전송 계층에 접근할 수 있습니다.
전송 계층은 수신하는 모든 이벤트를 * 이벤트 아래에서 내보내며, sendEvent()를 사용해 원문 이벤트를 보낼 수 있습니다. 이는 session.update, response.create, response.cancel 같은 낮은 수준의 작업을 위한 escape hatch입니다.
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 - 전송 계층만 사용
섹션 제목: “옵션 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);