콘텐츠로 이동

전송 방식

세션이 어디에서 실행되는지, 그리고 얼마나 많은 원문 미디어 또는 이벤트 제어가 필요한지에 따라 전송 방식을 선택하세요.

시나리오권장 전송 방식이유
브라우저 음성-대-음성 앱OpenAIRealtimeWebRTC가장 간편한 경로입니다. SDK 가 마이크 캡처, 재생, WebRTC 연결을 대신 관리합니다
서버 측 음성 루프 또는 커스텀 오디오 파이프라인OpenAIRealtimeWebSocket이미 오디오 캡처/재생을 제어하고 있고 이벤트에 직접 접근하려는 경우 잘 맞습니다
SIP 또는 전화 브리지OpenAIRealtimeSIPcallId 로 기존 SIP 시작 Realtime 통화에 RealtimeSession 을 연결합니다
Cloudflare Workers / workerdCloudflare extension transportworkerd 는 전역 WebSocket 생성자로 외부 WebSocket 을 열 수 없습니다
Twilio 의 provider-specific 전화 흐름Twilio extension transportTwilio 오디오 전달과 인터럽션(중단 처리) 동작을 SDK 가 대신 처리합니다

기본 브라우저 전송 방식은 WebRTC 를 사용합니다. 오디오는 마이크에서 캡처되고 자동으로 재생되므로, 빠른 시작에서는 임시 토큰과 session.connect(...) 만으로 연결할 수 있습니다.

이 경로에서 session.connect() 는 resolve 되기 전에 초기 세션 구성이 session.updated 로 승인될 때까지 기다리려고 시도하므로, 오디오가 흐르기 전에 instructions 와 tools 가 적용됩니다. 다만 해당 승인이 끝내 도착하지 않으면 timeout fallback 이 있습니다.

자체 미디어 스트림이나 오디오 엘리먼트를 사용하려면, 세션 생성 시 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 });
}

더 낮은 수준의 커스터마이징을 위해 OpenAIRealtimeWebRTCchangePeerConnection 도 받습니다. 이를 통해 offer 생성 전에 새로 생성된 RTCPeerConnection 을 검사하거나 교체할 수 있습니다.

세션 생성 시 transport: 'websocket' 또는 OpenAIRealtimeWebSocket 인스턴스를 전달하면 WebRTC 대신 WebSocket 연결을 사용합니다. 서버 측 사용 사례, 전화 브리지, 커스텀 오디오 파이프라인에 잘 맞습니다.

WebSocket 경로에서 session.connect() 는 소켓이 열리고 초기 구성이 전송되면 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',
});
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 오디오 바이트 처리는 원하는 녹음/재생 라이브러리를 사용하세요.

고급 연동을 위해 OpenAIRealtimeWebSocketcreateWebSocket() 을 받아 자체 소켓 구현을 제공할 수 있고, 커스텀 커넥터가 소켓을 connected 상태로 전환하는 책임을 가질 때 skipOpenEventListeners 를 사용할 수 있습니다. @openai/agents-extensions 의 Cloudflare 전송 방식은 이 훅을 기반으로 구현되어 있습니다.

SIP 호출 provider 및 전화 브리지용

섹션 제목: “SIP 호출 provider 및 전화 브리지용”

기존 SIP 시작 Realtime 통화에 RealtimeSession 을 연결하려면 OpenAIRealtimeSIP 를 사용하세요. 이는 얇은 SIP 인지 전송 계층입니다. 오디오는 SIP 통화 자체에서 처리되고, SDK 세션은 callId 로 연결합니다.

  1. OpenAIRealtimeSIP.buildInitialConfig() 로 초기 세션 구성을 생성해 수신 통화를 수락하세요. 이렇게 하면 SIP 초대와 이후 SDK 세션이 같은 기본값에서 시작됩니다
  2. OpenAIRealtimeSIP 전송 방식을 사용하는 RealtimeSession 을 연결하고 provider webhook 이 발급한 callId 로 connect 하세요
  3. provider-specific 미디어 전달이나 이벤트 브리지가 필요하면 Twilio extension 같은 통합 전송 방식을 사용하세요
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',
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 을 열 수 없습니다. extensions 패키지의 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용 Realtime 에이전트에서 확인하세요.

원문 WebSocket 이나 @openai/agents-extensions 의 전용 Twilio 전송 방식 중 하나로 RealtimeSession 을 Twilio 에 연결할 수 있습니다. Twilio Media Streams 에 대해 SDK 가 인터럽션(중단 처리) 타이밍과 오디오 전달을 처리하게 하려면 전용 전송 방식이 더 좋은 기본 선택입니다.

전체 설정은 Twilio용 Realtime 에이전트에서 확인하세요.

다른 음성-대-음성 API 를 사용하거나 자체 커스텀 전송 메커니즘이 있다면 RealtimeTransportLayer 인터페이스를 구현하고 RealtimeTransportEventTypes 이벤트를 직접 emit 할 수 있습니다.

필요 시 원문 Realtime 이벤트 접근

섹션 제목: “필요 시 원문 Realtime 이벤트 접근”

기반 Realtime API 에 더 직접적으로 접근하려면 두 가지 옵션이 있습니다.

RealtimeSession 의 모든 기능을 계속 활용하고 싶다면 session.transport 를 통해 전송 계층에 접근할 수 있습니다.

전송 계층은 수신하는 모든 이벤트를 * 이벤트로 emit 하며, 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',
});
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',
// ...
});

자동 도구 실행, 가드레일, 로컬 히스토리 관리가 필요 없다면 연결 및 인터럽션(중단 처리)만 관리하는 “thin” 클라이언트로 전송 계층만 사용할 수도 있습니다.

import { OpenAIRealtimeWebRTC } from '@openai/agents/realtime';
const client = new OpenAIRealtimeWebRTC();
const audioBuffer = new ArrayBuffer(0);
await client.connect({
apiKey: '<api key>',
model: 'gpt-realtime',
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);