콘텐츠로 이동

전송 방식

세션이 실행되는 위치와 원문 미디어 또는 이벤트를 얼마나 세밀하게 제어해야 하는지에 따라 전송 방식을 선택하세요.

시나리오권장 전송 방식이유
브라우저 음성 대 음성 앱OpenAIRealtimeWebRTC가장 간편한 경로입니다. SDK가 마이크 캡처, 재생, WebRTC 연결을 대신 관리합니다.
서버 측 음성 루프 또는 사용자 지정 오디오 파이프라인OpenAIRealtimeWebSocket오디오 캡처와 재생을 이미 제어하고 있으며 이벤트에 직접 액세스하려는 경우에 적합합니다.
SIP 또는 전화 통신 브리지OpenAIRealtimeSIPcallId를 사용하여 기존 SIP 기반 Realtime 통화에 RealtimeSession을 연결합니다.
Cloudflare Workers / workerdCloudflare 확장 전송 방식workerd는 전역 WebSocket 생성자로 아웃바운드 WebSocket을 열 수 없습니다.
Twilio의 제공업체별 전화 흐름Twilio 확장 전송 방식Twilio 오디오 전달과 인터럽션(중단 처리) 동작을 대신 처리합니다.

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

이 경로에서 session.connect()는 resolve되기 전에 초기 세션 설정이 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() {
// 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());
}

더 낮은 수준의 사용자 지정을 위해 OpenAIRealtimeWebRTCchangePeerConnection도 허용합니다. 이를 통해 offer가 생성되기 전에 새로 생성된 RTCPeerConnection을 검사하거나 교체할 수 있습니다.

WebRTC 대신 WebSocket 연결을 사용하려면 세션을 생성할 때 transport: 'websocket' 또는 OpenAIRealtimeWebSocket 인스턴스를 전달하세요. 서버 측 사용 사례, 전화 통신 브리지, 사용자 지정 오디오 파이프라인에 적합합니다.

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-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

섹션 제목: “통화 제공업체와 전화 통신 브리지용 SIP”

기존 SIP 기반 Realtime 통화에 RealtimeSession을 연결하려면 OpenAIRealtimeSIP를 사용하세요. 이는 SIP를 인식하는 경량 전송 방식입니다. 오디오는 SIP 통화 자체에서 처리되며 callId로 SDK 세션을 연결합니다.

  1. OpenAIRealtimeSIP.buildInitialConfig()로 초기 세션 설정을 생성하여 수신 통화를 수락합니다. 이렇게 하면 SIP 초대와 이후 SDK 세션이 동일한 기본값으로 시작됩니다.
  2. OpenAIRealtimeSIP 전송 방식을 사용하는 RealtimeSession을 연결하고 제공업체 웹훅에서 발급한 callId로 접속합니다.
  3. 제공업체별 미디어 전달이나 이벤트 브리징이 필요한 경우 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 런타임은 전역 WebSocket 생성자를 사용하여 아웃바운드 WebSocket을 열 수 없습니다. 내부적으로 fetch() 기반 업그레이드를 수행하는 확장 패키지의 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.1',
});
const session = new RealtimeSession(agent, {
// Set your own transport.
transport: cfTransport,
});

전체 설정은 Cloudflare용 Realtime 에이전트를 참조하세요.

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

전체 설정은 Twilio용 Realtime 에이전트를 참조하세요.

다른 음성 대 음성 API 또는 자체 사용자 지정 전송 메커니즘을 사용하려면 RealtimeTransportLayer 인터페이스를 구현하고 RealtimeTransportEventTypes 이벤트를 직접 내보낼 수 있습니다.

필요시 원문 Realtime 이벤트 액세스

섹션 제목: “필요시 원문 Realtime 이벤트 액세스”

기반 Realtime API에 더 직접 액세스하려면 두 가지 옵션이 있습니다.

RealtimeSession의 모든 기능을 계속 활용하면서 session.transport를 통해 전송 계층에 액세스할 수 있습니다.

전송 계층은 수신하는 모든 이벤트를 * 이벤트로 내보내며 sendEvent()를 사용하여 원문 이벤트를 전송할 수 있습니다. * 리스너는 현재 SDK 스키마가 인식하지 못하는 필드를 포함하여 파싱된 원본 JSON 페이로드의 구조화된 복제본을 수신합니다. 명명된 이벤트 리스너와 파생 이벤트 리스너는 계속해서 검증되고 정규화된 이벤트 객체를 수신합니다. 이는 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 response
session.transport.sendEvent({
type: 'response.create',
// ...
});

자동 도구 실행, 가드레일 또는 로컬 기록 관리가 필요하지 않다면 연결과 인터럽션(중단 처리)만 관리하는 “경량” 클라이언트로 전송 계층을 사용할 수도 있습니다.

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 yourself
client.on('audio', (newAudio) => {});
client.sendAudio(audioBuffer);