courses
우리의 GPT-Realtime-2 개요 글은 출시 소식, 벤치마크 주장, 그리고 OpenAI가 실시간 보이스를 소형 모델 제품군으로 나눈 이유를 다뤘습니다. 이 튜토리얼은 그 글이 멈춘 지점에서 시작합니다: API에 연결하고 오디오를 전송하며 코드에서 무엇이 달라지는지 확인합니다.
이 분리는 실제로 중요합니다. 테스트 1은 gpt-realtime-whisper를 사용해 전사를 수행하고, 테스트 2는 gpt-realtime-translate 를 사용해 실시간 번역을 수행하며, 테스트 3은 gpt-realtime-2 로 보이스 어시스턴트를 만듭니다. 메인 모델도 번역이나 전사 같은 단순 작업에 사용할 수 있지만, 불필요한 수준의 추론과 응답 모드를 위해 비용을 지불하게 되므로 과한 선택이 됩니다.
Python에서 GPT-Realtime-2 API 설정하기
테스트에 앞서, 전송 방식, 인증, 오디오 형식을 분리해 두면 도움이 됩니다. 이 세부사항은 예제 전반에서 대부분 동일합니다. 문서가 텍스트 출력에서 번역된 음성, 그리고 완전한 보이스 루프로 이동함에 따라 바뀌는 것은 모델 엔드포인트와 이벤트 이름입니다.
WebRTC와 WebSocket 중 선택하기
OpenAI 문서는 간단한 규칙을 제시합니다: 브라우저와 모바일 클라이언트에는 WebRTC를, 서버 사이드 애플리케이션에는 WebSockets를 사용하세요. WebRTC는 지터 버퍼링과 오디오 전송을 처리합니다. 백엔드가 이미 전화 서비스나 미디어 파이프라인에서 원시 오디오를 받는 경우에는 WebSocket이 적합합니다.

Realtime API를 위한 두 가지 전송 경로. 이미지: 작성자.
이런 이유로 세 가지 Python 테스트 모두 WebSocket을 사용합니다. 이 경로는 이벤트 이름을 직접 보여 주므로 코드에서 모델 차이가 드러납니다. 브라우저 빌드를 할 때는 API 키가 프런트엔드로 넘어가지 않도록 단기(에페메럴) 클라이언트 시크릿을 사용하세요.
Python 환경과 패키지
Python 3.9 이상을 사용하세요. 네 개의 스크립트 전체 코드는 github.com/KhalidAbdelaty/gpt-realtime-api에서 확인할 수 있습니다. 먼저 클론한 뒤, 의존성을 설치하세요:
git clone https://github.com/KhalidAbdelaty/gpt-realtime-api.git
cd gpt-realtime-api
pip install websocket-client sounddevice numpy python-dotenv
websocket-client 는 소켓을 처리합니다. sounddevice 는 마이크 오디오를 캡처하고, numpy 는 버퍼를 변환하며 python-dotenv는 API 키를 로드합니다. macOS에서는 sounddevice가 동작하기 전에 brew install portaudio가 필요할 수 있습니다. Linux에서는 portaudio19-dev를 설치하세요.
프로젝트 루트에 .env 파일을 생성하세요:
OPENAI_API_KEY=sk-...
그런 다음 각 스크립트에서 이를 로드합니다:
import os
from dotenv import load_dotenv
load_dotenv()
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
인증과 WebSocket URL
서버 사이드 연결은 WebSocket 핸드셰이크 시 Authorization: Bearer 헤더를 사용합니다. 앱이 개별 사용자를 추적한다면 OpenAI-Safety-Identifier 를 추가하세요. 아래는 이후 테스트에서 사용하는 경로입니다:
# Voice agent
wss://api.openai.com/v1/realtime?model=gpt-realtime-2
# Translation
wss://api.openai.com/v1/realtime/translations?model=gpt-realtime-translate
# Transcription
wss://api.openai.com/v1/realtime?intent=transcription
번역 경로는 테스트 2에서 중요합니다. 이 엔드포인트만 /v1/realtime을 직접 사용하지 않기 때문입니다.
테스트 1: GPT-Realtime-Whisper로 실시간 오디오 전사
전사는 과하게 설계하기 쉬운 부분입니다. 출력이 텍스트만 필요하다면 전사용 모델로 충분합니다.
테스트 대상
gpt-realtime-whisper는 오디오를 입력으로 받아 전사 델타를 출력합니다. 추론을 하거나, 도구를 호출하거나, 되받아 말하지 않습니다. 작업 범위가 작기 때문에 gpt-realtime-2와 같은 토큰 기반 모델이 아니라 오디오 길이로 과금됩니다. 비용 섹션에서 요금으로 돌아갑니다.
코드 살펴보기
핵심 필드는 session.type: "transcription"입니다. 이는 API에 어시스턴트 응답을 건너뛰고 전사 이벤트만 내보내라고 지시합니다. 전체 스크립트는 마이크 캡처와 스레딩도 처리합니다. Realtime 세션 동작을 변경하는 부분은 다음과 같습니다:
session_config = {
"type": "session.update",
"session": {
"type": "transcription",
"audio": {
"input": {
"format": {"type": "audio/pcm", "rate": 24000},
"transcription": {
"model": "gpt-realtime-whisper",
"language": "en"
},
"turn_detection": None
}
}
}
}
ws.send(json.dumps(session_config))
ws.send(json.dumps({
"type": "input_audio_buffer.append",
"audio": audio_b64
}))
ws.send(json.dumps({"type": "input_audio_buffer.commit"}))
24 kHz PCM16 모노 오디오를 base64로 인코딩해 사용하세요. 보이스 에이전트 세션과 달리, 이 스크립트는 server_vad 턴 감지 대신 타이머로 입력 버퍼를 수동 커밋합니다. 비어 있는 커밋은 input_audio_buffer_commit_empty를 발생시키므로, 전체 스크립트는 실제 오디오가 전송된 뒤에만 커밋합니다.

전사 델타는 실시간으로 단어 단위로 도착합니다. 이미지: 작성자.
관찰된 동작
로컬 테스트에서 전사 결과는 커밋 윈도 내에 나타났고, 발화 시작 후 대략 3~4초였습니다. 이 설정은 VAD가 아닌 수동 커밋에 의존하므로 지연 시간은 커밋 간격과 연동됩니다.
또한 순서에 유의하세요: 겹치는 턴의 완료 이벤트는 순서가 바뀌어 도착할 수 있으므로, 스트림을 기반으로 UI를 만든다면 item_id로 정합성을 맞추세요.

전사는 무음 감지가 아니라 주기적인 수동 커밋으로 트리거됩니다. 이미지: 작성자.
판정: 합격. 서버 사이드 실시간 전사에서는 gpt-realtime-whisper가 이 테스트에 필요한 일을 수행했습니다. 다만 실제 마이크, 억양, 실내 소음에 대해 테스트를 거친 후 지연 목표를 정하겠습니다.
테스트 2: GPT-Realtime-Translate로 실시간 번역
라이브 음성 번역은 처음에는 전사와 비슷해 보이지만, 세션 라이프사이클이 다릅니다. 번역 엔드포인트는 어시스턴트 응답 루프를 제거하여 예제가 더 짧아집니다.
테스트 대상
번역 세션에는 어시스턴트 턴 루프와 response.create가 없습니다. 모델은 대화형 에이전트가 아니라 동시통역사처럼 동작합니다. 질의응답, 도구 사용, 대화 상태가 필요하다면 테스트 3에서 gpt-realtime-2로 전환합니다.

번역 세션은 전용 별도 엔드포인트를 사용합니다. 이미지: 작성자.
이 모델은 70개 이상의 입력 언어와 13개 출력 언어를 지원합니다. 대상 언어는 session.audio.output.language로 설정하며, 소스 언어는 자동 감지됩니다. 제약은 명확합니다: 사용자 프롬프트 커스터마이즈, 보이스 선택, 도메인 용어집은 지원하지 않습니다.
코드 살펴보기
앞서 언급했듯이 번역은 /translations WebSocket URL을 사용합니다. 두 가지 세부사항도 바뀝니다: session.audio.output.language 대상 필드와 session.input_audio_buffer.append 이벤트 이름입니다. session. 접두사에 주목하세요. 번역 세션은 여기에서 이를 사용합니다.
url = "wss://api.openai.com/v1/realtime/translations?model=gpt-realtime-translate"
session_config = {
"type": "session.update",
"session": {
"audio": {
"output": {"language": "es"},
"input": {
"transcription": {"model": "gpt-realtime-whisper"},
"noise_reduction": {"type": "near_field"}
}
}
}
}
ws.send(json.dumps(session_config))
ws.send(json.dumps({
"type": "session.input_audio_buffer.append",
"audio": audio_b64
}))
번역된 오디오는 session.output_audio.delta로 도착하며, 오디오 바이트는 event["delta"]에 있고 event["audio"]가 아닙니다. 소스 전사와 번역 전사는 별도로 도착합니다:
if event_type == "session.output_audio.delta":
audio_out_queue.put(base64.b64decode(event["delta"]))
elif event_type == "session.input_transcript.delta":
print("[EN]", event.get("delta", ""), end="")
elif event_type == "session.output_transcript.delta":
print("[ES]", event.get("delta", ""), end="")
한 가지 예외 케이스: 소스 오디오가 이미 대상 언어인 경우, 모델이 패스스루 대신 무음을 출력할 수 있습니다.
관찰된 동작
짧은 영어→스페인어 구절에서는 소스 발화가 끝나기 전에 번역 오디오가 시작되었습니다. 터미널에는 델타가 스트리밍되면서 [EN]과 [ES] 줄이 교차해 표시되었습니다. 언어 간 거리가 먼 쌍일수록 더 많은 문맥을 기다릴 수 있습니다. 번역 음성은 무리 없이 따라갈 수 있었지만, 보이스 커스터마이즈는 제공되지 않습니다.
판정: 조건부 합격. gpt-realtime-translate는 직접적인 실시간 번역에 적합했습니다. 다만 용어 통제나 보이스 브랜딩이 중요할 때는 유용성이 떨어집니다.
테스트 3: 턴테이킹과 바지인으로 보이스 어시스턴트 만들기
이번은 gpt-realtime-2 테스트입니다. 듣고, 말하고, 문맥을 유지하며, 도구를 호출할 수 있는 보이스 에이전트입니다. 또한 재생과 턴 상태가 엇갈릴 수 있어, 클라이언트 코드가 더 중요해지는 지점이기도 합니다.
테스트 대상
gpt-realtime-2는 음성-대-음성 추론 모델입니다. 별도의 STT→LLM→TTS 파이프라인을 피하며, 128K 컨텍스트 윈도우로 긴 세션에 여유를 줍니다. 추론 강도는 reasoning.effort로 제어합니다. 작업에 더 많은 추론이 필요하지 않다면 low부터 시작하세요. 높은 설정은 지연을 증가시킵니다.
코드 살펴보기
아래 설정은 semantic_vad를 사용합니다. 이는 무음만이 아니라 발화 신호를 보고 판단합니다. eagerness는 사용자가 말을 마쳤다고 모델이 판단하는 속도를 제어합니다. 주목할 부분은 모델 이름, 오디오 출력 설정, 수동 response.create, 그리고 어시스턴트 오디오 이벤트 이름입니다:
session_config = {
"type": "session.update",
"session": {
"type": "realtime",
"model": "gpt-realtime-2",
"output_modalities": ["audio"],
"audio": {
"input": {
"format": {"type": "audio/pcm", "rate": 24000},
"transcription": {"model": "gpt-realtime-whisper", "language": "en"},
"turn_detection": {
"type": "semantic_vad",
"eagerness": "medium",
"create_response": False,
"interrupt_response": True
}
},
"output": {
"format": {"type": "audio/pcm", "rate": 24000},
"voice": "marin"
}
},
"instructions": "You are a helpful voice assistant. Keep answers short.",
"reasoning": {"effort": "low"}
}
}
사용자 전사가 완료되면 클라이언트가 어시스턴트 응답을 생성합니다. 이후 어시스턴트 오디오는 response.audio.delta가 아니라 response.output_audio.delta로 도착합니다.
if event_type == "conversation.item.input_audio_transcription.completed":
ws.send(json.dumps({"type": "response.create"}))
elif event_type == "response.output_audio.delta":
audio_out_queue.put(base64.b64decode(event["delta"]))
바지인 처리
인터럽트 시퀀스는 실수하기 쉽습니다. 사용자가 어시스턴트 말을 가로채면 서버는 input_audio_buffer.speech_started를 보냅니다. 클라이언트는 재생을 멈추고, 재생된 오디오 길이를 기록한 뒤, conversation.item.truncate와 함께 audio_end_ms를 보내 어디에서 잘렸는지 추적합니다. 그렇지 않으면 서버는 사용자가 듣지 못한 텍스트를 계속 전사하게 되어 다음 턴이 어긋날 수 있습니다.
if current_response_item_id and playback_position_ms > 0:
ws.send(json.dumps({
"type": "conversation.item.truncate",
"item_id": current_response_item_id,
"content_index": 0,
"audio_end_ms": playback_position_ms
}))
노트북 스피커의 실무적 이슈: 마이크가 어시스턴트 오디오 출력을 다시 수음하여 모델로 보내는 경우가 있습니다. 샘플 스크립트는 어시스턴트가 말하는 동안과 짧은 쿨다운 동안 입력 스트림을 음소거하는 MUTE_MIC_DURING_ASSISTANT = True를 사용합니다. 헤드폰을 사용하며 인터럽트를 지원하고자 할 때만 False로 설정하세요.

트렁케이션은 서버와 클라이언트의 동기화를 유지합니다. 이미지: 작성자.
WebRTC와 SIP는 이러한 버퍼링을 더 많이 처리합니다. 이 튜토리얼에서 사용하는 WebSocket 경로에서는 클라이언트가 이를 담당합니다. 샘플 스크립트의 카운터로도 데모에는 충분하지만, 프로덕션 코드는 오디오 출력 스트림의 타임스탬프를 추적해야 합니다.
추론 지연을 위한 프리앰블 구성
reasoning.effort가 low 이상일 때는 정적이 두드러집니다. 시스템 프롬프트에 짧은 구어 프리앰블을 추가할 수 있습니다:
# Preambles
Use a short spoken update before longer tasks.
Keep preambles under five seconds.
Skip preambles for short factual questions.
이 동작은 gpt-realtime-2에 대해 문서화되어 있습니다.
관찰된 동작
조용한 환경에서는 기본 설정으로 턴테이킹이 잘 동작했습니다. 노트북 스피커 사용 시에는 마이크 음소거가 필요했습니다. 그렇지 않으면 모델이 자신의 출력을 듣고 에코 루프가 시작되었습니다.
더 시끄러운 환경에서는 VAD 설정과 마이크 위치가 더 중요했습니다. 10분 테스트 동안 대화 메모리는 일관되게 유지되었지만, 더 긴 앱을 출시한다면 재연결 계획 없이 진행하지는 않겠습니다.
판정: 핵심 보이스 루프는 합격. gpt-realtime-2는 낮은 추론 강도의 어시스턴트를 무난히 처리했습니다. 추가 작업은 클라이언트 측에 있습니다: 재생, 인터럽트 처리, 재연결, 그리고 필요 시 도구 호출입니다.
Streamlit 데모: 하나의 인터페이스에서 세 모델 비교
Streamlit 앱은 탭 선택기 뒤에 테스트를 배치합니다. 오디오를 녹음하고 대상 언어를 선택하며, 스크립트를 수정하지 않고도 모델 경로를 비교할 수 있습니다. 터미널 스크립트가 이벤트를 더 직접적으로 보여 주므로, 이 앱은 주요 학습 경로가 아닌 데모로 유지했습니다.

하나의 탭형 인터페이스에서 세 모델. 이미지: 작성자.
아래 데모 영상은 실제 API 키로 탭을 실행하는 모습을 보여 줍니다. 각 탭은 실제 Realtime WebSocket 호출을 사용합니다.
스크립트와 같은 폴더에서 앱을 실행하세요:
streamlit run demo_app.py
API 키는 사이드바에 입력하며 어디에도 저장되지 않습니다. 공개 앱이라면 Streamlit Secrets에 넣으세요.
실무에서의 GPT-Realtime-2 비용과 지연
테스트 1에서 언급했듯이, 가격은 두 그룹으로 나뉩니다. gpt-realtime-2는 토큰 기준으로, 번역과 전사는 분당 과금됩니다.

모델별 토큰/분당 과금. 이미지: 작성자.
전사와 번역의 비용은 길이에 비례합니다. 작성 시점 기준으로 30분은 gpt-realtime-whisper에서 약 $0.51, gpt-realtime-translate에서 약 $1.02입니다.
보이스 에이전트는 대화 양쪽에서 오디오 토큰이 누적되므로 추정이 더 어렵습니다. 세션 길이, 발화 비율, 추론 강도, 컨텍스트 크기가 모두 영향을 줍니다. 이전 턴이 안정적으로 유지될 때 프롬프트 캐싱은 비용을 줄일 수 있습니다.
라이브 상호작용이 필요하지 않다면 REST 전사 호출 + TTS는 다른 비교 대상입니다. 파일 전용이라면 whisper-1이 더 저렴하지만, 같은 유형의 API는 아닙니다.
GPT-Realtime-2 API 제한, 오디오 요구사항, 트러블슈팅
첫 시험 실행에 영향을 준 제한은 다음과 같습니다. 대부분의 실패는 모델 자체가 아니라 오디오 포맷팅이나 세션 라이프사이클 실수에서 발생했습니다.
전송 및 오디오 제약
첫 테스트에서 언급했듯이, WebSocket 오디오는 24 kHz의 PCM16, 모노, base64 인코딩이어야 합니다. 각 input_audio_buffer.append 이벤트는 15 MB로 제한되므로 50ms 청크는 한참 아래입니다. 전화용으로 G.711도 지원됩니다.
Realtime 세션은 OpenAI에서 60분, Azure OpenAI에서 30분 후 종료됩니다. 더 긴 앱은 재연결 계획과 상태 복원 방법이 필요합니다. 보이스는 첫 오디오 출력 전 선택되어야 하며, 세션 중 변경할 수 없습니다.
레이트 리밋과 쿼터
레이트 리밋은 티어 기반이며 프로젝트별로 다릅니다. 현재 티어 1은 gpt-realtime-2에 대해 분당 200 요청, 분당 40,000 토큰을 명시합니다. 무료 티어는 지원되지 않습니다.
일반적인 오류와 거친 모서리
가장 자주 겪은 오류는 빈 버퍼 커밋과 잘못된 오디오 포맷팅이었습니다. 보이스 에이전트의 경우, 마이크가 어시스턴트 스피커 출력을 수음하는 피드백 루프도 주의하세요. 헤드폰, 에코 캔슬레이션, 또는 마이크 음소거를 사용하세요.
긴 세션에서는 만료를 기다리지 말고 55분 즈음에서 재연결하세요. 문서의 한 가지 혼동 포인트: gpt-realtime-2 모델 페이지에는 일반적인 "Streaming: Not supported" 행이 있지만, Realtime 가이드는 /v1/realtime 사용법을 문서화합니다. 이 행은 Chat Completions 스트리밍에 관한 것이며, Realtime API 동작을 뜻하지 않습니다.
최종 결론
세 가지 테스트 전반에 같은 패턴이 나타납니다. 각 작업에는 고유한 모델과 엔드포인트가 있습니다. 이 분리는 모델이 할 수 있는 일, 과금 방식, 그리고 클라이언트 코드 소유 범위에 영향을 줍니다.
위에서 보았듯이, gpt-realtime-whisper는 라이브 텍스트를, gpt-realtime-translate는 직접 음성 번역을, gpt-realtime-2는 음성·추론·문맥을 갖춘 어시스턴트 동작을 담당합니다.
코드는 어느 한 모델이 다른 모델을 대체함을 보여 주지 않습니다. 실시간 보이스 앱이 세션 설계에 달려 있음을 보여 줍니다. 제 시작점은 작업에 부합하는 가장 작은 모델이며, 남은 엔지니어링 시간은 오디오 품질, 턴테이킹, 재연결, 클라이언트 상태에 투자하겠습니다.
더 많은 배경 지식은 아래 튜토리얼에서 관련 오디오 및 Realtime API 주제를 다룹니다: