음성 에이전트는 이전에 세 가지 이동 부분(음성-텍스트 변환, 언어 모델, 텍스트-음성 변환)이 필요했습니다. 각 단계마다 지연 시간이 추가되고 어조가 손실되었습니다. OpenAI의 Realtime API는 이를 하나의 음성-음성 모델로 통합했으며, gpt-realtime-2.1-mini는 해당 제품군의 더 저렴하고 빠른 계층입니다. 이 모델은 단일 스트리밍 연결을 통해 오디오를 듣고, 생각하고, 다시 말합니다.
이 가이드는 앱에 연결하기 전에 모델 ID, WebSocket 및 WebRTC를 통한 연결 방법, 세션 구성 방법, 그리고 Apidog를 사용하여 전체를 테스트하는 방법을 엔드 투 엔드로 보여줍니다. 여기 있는 모든 내용은 공식 OpenAI Realtime 가이드와 일치합니다.
먼저, 모델 이름을 올바르게 지정하세요
이름 때문에 혼동하는 경우가 많으니, 코드를 작성하기 전에 명확히 해둡시다. 동일한 미니 모델에는 두 가지 식별자가 있습니다.
gpt-realtime-2.1-mini: 버전이 지정된 ID입니다. 이 ID는 OpenAI 가격 페이지에 표시되며 2.1 세대에 고정됩니다.gpt-realtime-mini: 제품군 별칭입니다. 항상 최신 스냅샷(현재gpt-realtime-mini-2025-12-15)을 가리킵니다.
스냅샷을 사용하면 프로덕션 환경에서 동작을 고정할 수 있습니다.
| 식별자 | 가리키는 대상 |
|---|---|
gpt-realtime-mini |
최신 미니 스냅샷 (자동 업데이트) |
gpt-realtime-2.1-mini |
2.1세대 미니 |
gpt-realtime-mini-2025-12-15 |
고정된 스냅샷 (현재) |
gpt-realtime-mini-2025-10-06 |
고정된 스냅샷 (이전) |
개발 중에는 별칭을 사용하고, 배포 전에 날짜가 지정된 스냅샷을 고정하여 모델 업데이트가 에이전트의 동작을 갑자기 변경하지 않도록 하십시오.

gpt-realtime-2.1-mini의 기능
이 모델은 음성-음성 모델입니다. 오디오를 스트리밍하면 별도의 전사(transcription)나 TTS(텍스트-음성 변환) 단계 없이 자연스러운 억양으로 오디오를 다시 스트리밍합니다. 텍스트도 처리하므로, 동일한 세션에서 텍스트 입력과 음성 출력을 혼합할 수 있습니다.
다음은 모델 페이지의 사양 시트입니다.
| 속성 | 값 |
|---|---|
| 입력 모달리티 | 텍스트, 이미지, 오디오 |
| 출력 모달리티 | 텍스트, 오디오 |
| 컨텍스트 창 | 32,000 토큰 |
| 최대 출력 | 4,096 토큰 |
| 연결 | WebRTC, WebSocket, SIP |
| 음성 | alloy, ash, ballad, coral, echo, sage, shimmer, verse, marin, cedar |
marin과 cedar는 최신 음성이며 Realtime API 전용입니다. OpenAI는 가장 자연스러운 출력을 위해 이 음성들을 추천합니다. 특정 음색을 원한다면 이전 음성들도 여전히 작동합니다.
"미니" 계층은 추론 깊이를 약간 희생하는 대신 더 낮은 지연 시간과 훨씬 저렴한 비용을 제공합니다. 대부분의 지원 봇, 주문 접수 흐름 및 음성 프론트엔드에 적합한 기본값입니다. 대화에 더 심도 있는 추론이 필요할 때만 전체 gpt-realtime-2.1을 사용하십시오.
비용
미니는 전체 모델 가격의 대략 3분의 1입니다. 가격 페이지의 토큰 요금:
| 모델 | 텍스트 입력 | 캐시된 입력 | 오디오 입력 | 오디오 출력 |
|---|---|---|---|---|
gpt-realtime-2.1-mini |
$0.60 / 1M | $0.30 / 1M | $10 / 1M | $20 / 1M |
gpt-realtime-2.1 (전체) |
$4.00 / 1M | $0.40 / 1M | $32 / 1M | $64 / 1M |
오디오가 비용의 대부분을 차지하며, 가장 큰 비용 레버는 에이전트가 얼마나 많이 말하는가입니다. 분당 35초를 말하는 에이전트는 분당 15초를 말하는 에이전트보다 대략 두 배의 비용이 듭니다. 미니 모델의 실제 분당 비용은 장황함에 따라 $0.06~$0.15 정도이므로, 지침에서 모델에게 간결하게 말하도록 지시하면 비용을 직접 절감할 수 있습니다. 요금은 변동될 수 있으므로 예측하기 전에 실시간 가격 페이지에서 확인하십시오.
전제 조건
다음 세 가지가 필요합니다.
- Realtime 접근 권한이 있는 OpenAI API 키 (
OPENAI_API_KEY로 설정). - 서버 예제를 위한 Node.js 18+ (원시 WebSocket용
ws패키지 또는 공식openaiSDK). - 브라우저 오디오의 경우,
getUserMedia가 작동하도록 HTTPS 또는localhost를 통해 제공되는 페이지.
브라우저를 다루기 전에 한 가지 규칙: 실제 API 키를 클라이언트에 절대 노출하지 마세요. 브라우저 및 모바일 앱은 대신 단기 임시 토큰을 사용합니다. 이에 대한 자세한 내용은 아래에서 설명합니다.
연결 방법 선택
미니 모델은 세 가지 전송 방식을 지원합니다. 오디오가 어디에 있는지에 따라 선택하십시오.
| 전송 방식 | 사용 시기 | 인증 |
|---|---|---|
| WebRTC | 브라우저 또는 모바일 앱에서 오디오를 캡처하거나 재생할 때 | 임시 클라이언트 시크릿 |
| WebSocket | 서버가 미디어 파이프라인에서 원시 오디오를 이미 처리하는 경우 | API 키 (서버 측) |
| SIP | 전화 또는 전화 시스템을 연결하는 경우 | API 키 |
대부분의 사람들은 서버 측 프로토타입을 위해 WebSocket으로 시작한 다음, 실제 클라이언트를 위해 WebRTC로 전환합니다. 두 가지 모두 해봅시다.
빠른 시작 1: 서버에서 WebSocket 사용하기
WebSocket은 모델이 응답하는 것을 가장 빠르게 볼 수 있는 방법입니다. 엔드포인트는 쿼리 문자열에 모델이 포함된 단일 URL입니다.
wss://api.openai.com/v1/realtime?model=gpt-realtime-2.1-mini
이것은 GA(General Availability) 인터페이스이므로, 일반 Authorization: Bearer 헤더로 인증하며 더 이상 이전 OpenAI-Beta 헤더가 필요하지 않습니다. 다음은 마이크 없이 테스트할 수 있는 텍스트 입력-텍스트 출력 "헬로 월드" 예제입니다.
import WebSocket from "ws";
const url = "wss://api.openai.com/v1/realtime?model=gpt-realtime-2.1-mini";
const ws = new WebSocket(url, {
headers: { Authorization: `Bearer ${process.env.OPENAI_API_KEY}` },
});
ws.on("open", () => {
// 1. Configure the session
ws.send(JSON.stringify({
type: "session.update",
session: {
type: "realtime",
model: "gpt-realtime-2.1-mini",
output_modalities: ["text"],
instructions: "You are a concise API support agent. Keep answers short.",
},
}));
// 2. Add a user message
ws.send(JSON.stringify({
type: "conversation.item.create",
item: {
type: "message",
role: "user",
content: [{ type: "input_text", text: "What is an idempotent request?" }],
},
}));
// 3. Ask for a response
ws.send(JSON.stringify({ type: "response.create" }));
});
ws.on("message", (raw) => {
const event = JSON.parse(raw.toString());
if (event.type === "response.output_text.delta") process.stdout.write(event.delta);
if (event.type === "response.done") ws.close();
});
흐름은 항상 동일합니다. 구성하고, 입력을 추가하고, 응답을 요청하고, 델타를 수신합니다. 서버 이벤트는 JSON으로 스트리밍됩니다. 가장 중요한 이벤트는 다음과 같습니다.
session.created/session.updated: 구성이 수락되었습니다response.output_text.delta: 텍스트 조각response.output_audio.delta: base64 오디오 조각response.output_audio_transcript.delta: 모델이 말하는 내용의 전사본response.done: 턴이 완료되었습니다
텍스트에서 음성으로 전환하려면 output_modalities를 ["audio"]로 변경하고 오디오 구성을 추가하세요 (다음 섹션). 오디오는 response.output_audio.delta 이벤트로 base64 PCM 청크 형태로 도착하며, 이를 디코딩하여 재생합니다.
빠른 시작 2: 브라우저에서 WebRTC 사용하기
실제 음성 앱의 경우, 브라우저가 마이크를 캡처하고 응답을 직접 재생하여 지연 시간을 낮게 유지합니다. 문제는 인증입니다. API 키를 노출할 수 없으므로, 서버에서 먼저 단기 토큰을 생성해야 합니다.
1단계: 서버에서 임시 토큰 생성. 실제 키로 클라이언트 시크릿 엔드포인트를 호출합니다.
// 서버 측
const r = await fetch("https://api.openai.com/v1/realtime/client_secrets", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
session: { type: "realtime", model: "gpt-realtime-2.1-mini" },
}),
});
const { value } = await r.json(); // 임시 키, "ek_"로 시작
value를 브라우저로 보냅니다. 이 값은 빠르게 만료되므로 유출 위험이 낮습니다.
2단계: WebRTC를 사용하여 브라우저에서 연결. 마이크를 캡처하고, 이벤트용 데이터 채널을 열고, /v1/realtime/calls 엔드포인트와 SDP를 교환합니다.
// 브라우저 측: EPHEMERAL_KEY는 서버에서 가져옴
const pc = new RTCPeerConnection();
// 모델의 오디오 재생
pc.ontrack = (e) => (document.getElementById("audio").srcObject = e.streams[0]);
// 마이크 전송
const mic = await navigator.mediaDevices.getUserMedia({ audio: true });
pc.addTrack(mic.getTracks()[0]);
// 이벤트는 데이터 채널을 통해 흐름
const channel = pc.createDataChannel("oai-events");
channel.onmessage = (e) => console.log(JSON.parse(e.data));
// SDP 핸드셰이크
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
const sdpResp = await fetch(
"https://api.openai.com/v1/realtime/calls?model=gpt-realtime-2.1-mini",
{
method: "POST",
body: offer.sdp,
headers: {
Authorization: `Bearer ${EPHEMERAL_KEY}`,
"Content-Type": "application/sdp",
},
}
);
await pc.setRemoteDescription({ type: "answer", sdp: await sdpResp.text() });
연결이 활성화되면 모델은 마이크 트랙을 듣고 pc.ontrack을 통해 말합니다. WebSocket 예제와 동일한 JSON 이벤트를 사용하여 동일한 oai-events 데이터 채널을 통해 구성 및 텍스트를 전송합니다.
세션 구성
session 객체는 동작을 제어하는 곳입니다. 위에서 본 내용의 전체 오디오 버전은 다음과 같습니다.
{
type: "session.update",
session: {
type: "realtime",
model: "gpt-realtime-2.1-mini",
output_modalities: ["audio"],
instructions: "You are a friendly booking assistant. Confirm details before acting.",
audio: {
input: {
format: { type: "audio/pcm", rate: 24000 },
turn_detection: { type: "semantic_vad" },
},
output: {
format: { type: "audio/pcm", rate: 24000 },
voice: "marin",
},
},
},
}
중요한 필드:
instructions: 시스템 프롬프트입니다. 페르소나, 가이드라인을 설정하고, 비용이 중요하다면 "간결하게" 지시하십시오.output_modalities: 대화형 에이전트의 경우["audio"], 전사본 전용 봇의 경우["text"].audio.output.voice: 열 가지 음성 중 선택하십시오.marin또는cedar가 가장 자연스럽습니다.audio.input.turn_detection: 모델이 사용자가 말을 멈췄다고 판단하는 방법입니다.semantic_vad는 의미상 자연스러운 일시 정지를 기다리고,server_vad는 침묵에 반응합니다. 의미론적 감지는 방해가 덜하고 대화에서 더 부드럽게 느껴집니다.
통화 중 언제든지 다른 session.update를 전송하여 필드를 변경할 수 있습니다. 다시 연결할 필요는 없습니다.
에이전트가 동작하도록 도구 추가
채팅만 할 수 있는 음성 에이전트는 데모에 불과합니다. 테이블을 예약하거나 주문을 확인하려면 모델에 도구가 필요합니다. Realtime은 플랫폼의 다른 부분과 동일한 함수 호출 계약을 사용합니다. 세션에서 함수를 선언하면 모델이 호출을 내보내고, 이를 실행한 다음 결과를 다시 전달합니다. 이전에 채팅 API에 도구를 연결해 본 적이 있다면, 이것은 동일한 개념 모델입니다. OpenAI 함수 호출에 대한 저희의 안내는 스키마를 심층적으로 다루며, 구조화된 출력은 인수가 엄격한 형식과 일치해야 할 때 도움이 됩니다.
세션 내에서 도구를 선언하고, response.function_call_arguments.done 이벤트를 처리한 다음 코드를 실행하고, 다음 response.create 전에 결과와 함께 conversation.item.create를 게시하십시오. 몇 가지 함수보다 더 복잡한 경우에는 OpenAI의 AgentKit이 다단계 음성 에이전트를 조정하는 더 높은 수준의 방법을 제공합니다.
구축하기 전에 Apidog로 엔드포인트 테스트하기
반쯤 만들어진 앱에서 콘솔 로그를 읽으며 REST 호출과 WebSocket 핸드셰이크를 디버그하고 싶지는 않을 것입니다. 먼저 각 부분을 개별적으로 테스트하십시오. 바로 이 점에서 Apidog가 실시간 워크플로우에서 제 역할을 합니다.
클라이언트 코드를 작성하기 전에 두 가지를 검증할 가치가 있습니다.
- 토큰 엔드포인트.
POST https://api.openai.com/v1/realtime/client_secrets는 일반적인 REST 호출입니다. Apidog에서 요청을 생성하고,Authorization: Bearer헤더를 추가하고, 모델 ID가 포함된 JSON 본문을 넣고 전송하십시오.ek_토큰과 만료일을 즉시 볼 수 있으므로, WebRTC를 사용하기 전에도 키와 계정 접근이 양호한지 알 수 있습니다. 이는 응답 API와 같은 OpenAI의 REST 인터페이스를 스모크 테스트하는 데 사용하는 것과 동일한 접근 방식입니다. - WebSocket 메시지 흐름. Apidog에는 WebSocket 클라이언트가 있으므로,
wss://api.openai.com/v1/realtime?model=gpt-realtime-2.1-mini에 연결을 열고, 인증 헤더를 추가한 다음,session.update,conversation.item.create,response.create메시지를 하나씩 수동으로 전송할 수 있습니다. 읽기 쉬운 패널에서 서버 이벤트가 돌아오는 것을 보면 이벤트 시퀀스가 명확해지며, 메시지를 팀을 위한 예제로 저장할 수 있습니다. 이미 견고한 API 테스트 전략을 사용하고 있다면, 이것은 완벽하게 들어맞습니다.
전송 계층을 단독으로 테스트한다는 것은 앱에서 무언가 문제가 발생했을 때, 그것이 API 계약 때문이 아니라는 것을 이미 알고 있다는 의미입니다. 따라하고 싶다면 Apidog를 다운로드하십시오.
비용 관리
오디오 출력이 비용이 많이 드는 부분이므로, 몇 가지 습관이 도움이 됩니다.
- 모델에게 간결하게 말하도록 지시하십시오. 지침에 "답변을 한두 문장으로 유지"라고 하면 오디오 출력 토큰을 직접적으로 절감합니다.
- 프로덕션 환경에서 스냅샷을 고정하십시오.
gpt-realtime-mini-2025-12-15는 변경되지 않지만,gpt-realtime-mini별칭은 변경될 수 있습니다. semantic_vad를 사용하십시오. 오탐이 적다는 것은 비용을 지불해야 하는 낭비되는 절반 응답이 적다는 것을 의미합니다.- 시스템 프롬프트를 캐시하십시오. 캐시된 입력은 100만 개당 $0.30인 반면, 새로운 텍스트 입력은 $0.60이므로, 안정적인 지침 블록은 모든 턴에서 더 저렴합니다.
- 유휴 세션을 닫으십시오. 비활성 사용자와의 열린 연결도 비용이 청구될 수 있는 세션입니다.
일반적인 오류 및 해결 방법
- 401 Unauthorized (권한 없음): 키가 잘못되었거나 만료된 임시 토큰을 보냈습니다. 임시 키는 본래 수명이 짧으므로, 세션당 새로운 키를 생성하십시오.
- Model not found (모델을 찾을 수 없음): 정확한 ID를 확인하십시오.
gpt-realtime-mini-2.1이 아니라gpt-realtime-2.1-mini입니다. - No audio in the browser (브라우저에 오디오 없음):
pc.ontrack에서 원격 스트림을 연결하지 않았거나, 페이지가 HTTPS/localhost에 없어서 마이크가 열리지 않았을 수 있습니다. - The model won’t stop talking over the user (모델이 사용자 말에 계속 끼어듦):
turn_detection을semantic_vad로 전환하고 마이크 트랙이 연결에 도달하고 있는지 확인하십시오. - Sending the beta header (베타 헤더 전송): GA 엔드포인트는
OpenAI-Beta: realtime=v1을 원하지 않습니다. 제거하십시오.
자주 묻는 질문
- gpt-realtime-2.1-mini와 gpt-realtime-mini는 동일한가요? 실질적으로 그렇습니다.
gpt-realtime-2.1-mini는 버전이 지정된 ID이며,gpt-realtime-mini는 최신 스냅샷(gpt-realtime-mini-2025-12-15)을 가리키는 별칭입니다. 개발 시에는 별칭을 사용하고, 배포 시에는 스냅샷을 고정하십시오. - 음성 에이전트 대신 일반 전사(transcription)에 사용할 수 있나요? Realtime API는 상호 작용하는 음성-음성 변환을 위해 만들어졌습니다. 일회성 전사의 경우, OpenAI의 전용 전사 모델이 더 적합합니다. 낮은 지연 시간으로 양방향 대화가 필요할 때 미니 실시간 모델을 사용하십시오.
- WebRTC가 필요한가요, 아니면 WebSocket으로 충분한가요? WebSocket은 서버 측 파이프라인 및 빠른 프로토타입에 충분합니다. 브라우저나 모바일 앱이 오디오를 직접 캡처하고 재생할 때는 WebRTC를 사용하십시오. WebRTC가 미디어 스트림과 지터(jitter)를 처리해 주기 때문입니다.
- 어떤 음성을 선택해야 하나요?
marin과cedar는 가장 최신이며 자연스럽고, Realtime API 전용입니다. 특정 사운드를 원한다면 다른 8가지(alloy, ash, ballad, coral, echo, sage, shimmer, verse)도 여전히 작동합니다. - 비용은 어떻게 청구되나요? 모달리티별로 나뉘어 토큰당 청구됩니다. 미니 모델의 경우: 텍스트 입력 100만 개당 $0.60, 오디오 입력 100만 개당 $10, 오디오 출력 100만 개당 $20입니다. 오디오 출력이 주요 비용이므로, 장황함이 주요 비용 조절 수단입니다.
- 채팅 모델처럼 함수를 호출할 수 있나요? 예. Realtime은 동일한 함수 호출 계약을 사용하므로, 음성 에이전트는 대화 중에 주문을 조회하거나, 재고를 확인하거나, 작업을 트리거할 수 있습니다.
다음 단계
이제 전체 루프를 갖추었습니다: 올바른 모델 ID, WebSocket 프로토타입, WebRTC 브라우저 클라이언트, 세션 구성, 도구, 그리고 프로덕션에 출시하기 전에 Apidog에서 각 부분을 테스트하는 방법까지. 텍스트 전용 WebSocket 예제로 접근을 확인한 다음, output_modalities를 오디오로 전환하고, 실제 마이크를 사용할 준비가 되면 WebRTC로 이동하십시오. 스냅샷을 고정하고, 모델에게 간결하게 말하도록 지시하면, 청구서에서 놀랄 일이 없는 낮은 지연 시간의 음성 에이전트를 갖게 될 것입니다.
