포스트

실시간 음성 에이전트의 2026년 2월 스택 지도: STT/TTS/LLM을 “대화 지연 1초대”로 묶는 법

실시간 음성 에이전트의 2026년 2월 스택 지도: STT/TTS/LLM을 “대화 지연 1초대”로 묶는 법

들어가며

2026년 2월 기준, 음성 AI는 더 이상 “STT로 텍스트 만들고 LLM 돌린 뒤 TTS로 읽어주는” 데서 끝나지 않습니다. 사용자는 전화/앱/웹에서 끊김 없는 turn-taking, 중간 끼어들기(barge-in), 말하는 도중에도 생각하고 반응을 준비하는 경험을 기대합니다. 이때 승패를 가르는 건 모델 성능보다도 latency budget(지연 예산) 설계입니다.

Twilio가 공개한 실무 지표를 보면(2025년 11월 기준) “입에서 귀까지(mouth-to-ear)” 자연스러운 대화를 위해 turn gap ~1.1s(상한 1.4s) 정도를 목표로 잡고, 구성요소별로 STT 350ms, LLM TTFT 375ms, TTS TTFB 100ms 수준을 제시합니다. (twilio.com)
즉, 실시간 음성 에이전트는 모델 선택 + 스트리밍 + 오케스트레이션을 한 덩어리로 최적화해야 “대화가 된다”는 결론이 나옵니다.


🔧 핵심 개념

1) Cascaded vs Native audio (Speech-to-Speech)

  • Cascaded 파이프라인: STT → LLM → TTS. 디버깅/툴콜/로그가 쉬워서 여전히 주류지만, 직렬 처리로 인해 지연이 누적됩니다.
  • Native audio / Live API 계열: 오디오를 입력하면 모델이 (중간에 텍스트를 만들 수도 있지만) 실시간 음성 출력까지 스트리밍으로 처리합니다. Google은 Vertex AI에서 Gemini Live API GA를 발표하며 “중간 끼어들기 처리, 음성의 억양/속도 등 acoustic cue 이해” 같은 실시간 대화 특성을 강조했습니다. (cloud.google.com)

현업 감각으로 정리하면:

  • “콜센터/업무 자동화/툴 실행”처럼 정확한 제어와 감사(audit)가 필요하면 cascaded(+오케스트레이터).
  • “대화감/즉시성”이 최우선이면 native audio(Live/Reatime) 또는 cascaded라도 병렬화/스트리밍을 극단적으로 적용합니다.

2) 지연을 쪼개서 관리하기: TTFT, TTFB, Turn gap

  • LLM TTFT(Time To First Token): LLM이 첫 토큰을 내기까지.
  • TTS TTFB(Time To First Byte): 오디오 첫 바이트(첫 프레임)가 나오기까지.
  • Turn gap: 사용자가 말을 멈춘 뒤, 에이전트 첫 소리가 나오기까지의 체감 공백.

Twilio는 이걸 “core latency”로 정의하고, 네트워크/PSTN 같은 외부 지연과 분리해 측정하라고 가이드합니다. (twilio.com)
실전에서는 측정 지표를 코드에 박아 넣지 않으면 최적화가 아니라 “감”으로 튜닝하게 됩니다.

3) Streaming의 본질: “조각”이 아니라 “동시성”

2026년 연구 흐름도 이 방향입니다. LTS-VoiceAgent는 cascaded 구조의 한계를 지적하며, 사람이 대화할 때처럼 듣는 동안(Listen) 생각(Think)을 시작하고, 말하기(Speak)를 조율하는 프레임워크를 제안합니다. 핵심은 “VAD로 쪼개기” 같은 기계적 분할만으로는 한계가 있고, semantic trigger + incremental reasoning으로 병렬성을 높여야 한다는 점입니다. (arxiv.org)

4) 제품/플랫폼 트렌드(2025~2026초)

  • OpenAI Realtime API는 WebRTC 연결을 권장(브라우저/모바일 실시간 음성 앱에서 WebSocket보다 일관된 성능)하며, TypeScript용 Agents SDK를 출발점으로 제시합니다. (platform.openai.com)
  • Microsoft(Azure OpenAI)도 Realtime을 WebRTC로 쓰는 방법을 별도로 문서화하며, 저지연/미디어 처리 측면에서 WebRTC 선호 이유를 설명합니다. (learn.microsoft.com)
  • Twilio는 Real-Time Transcriptions GA로 통화 중 음성을 실시간 전사하고 LLM/에이전트로 넘기는 표준 패턴을 제시했고 (twilio.com), ConversationRelay 같은 “STT/TTS/LLM 오케스트레이션을 관리형으로” 가져가려는 흐름도 강합니다. (signal.twilio.com)

정리하면 2026년의 실시간 음성 에이전트는: 1) WebRTC로 오디오 스트리밍,
2) 서버는 인증/툴/상태만 관리,
3) 모델은 Realtime/Live로 스트리밍 응답,
4) VAD + barge-in + partial hypothesis 처리로 대화감을 만듭니다.


💻 실전 코드

아래 예시는 “브라우저 → OpenAI Realtime(WebRTC)”의 최소 동작 골격입니다. 핵심은 (1) ephemeral key를 서버에서 발급하고, (2) 브라우저에서 RTCPeerConnection을 만들어 마이크 트랙을 업링크, (3) 원격 오디오 트랙을 재생하는 것입니다. (Realtime API의 WebRTC 권장 흐름) (platform.openai.com)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
// language: TypeScript (Browser)
// 목표: 브라우저에서 WebRTC로 실시간 음성 대화 세션을 만들고,
//      마이크를 보내고(remote audio)를 재생한다.
//
// 전제:
// 1) /api/realtime-ephemeral 서버 엔드포인트가 ephemeral key(또는 session token)를 발급해줌
// 2) OpenAI Realtime WebRTC 연결 절차는 공식 가이드에 맞춘다.

async function startRealtimeVoice() {
  // 1) 마이크 확보
  const stream = await navigator.mediaDevices.getUserMedia({
    audio: {
      channelCount: 1,
      echoCancellation: true,
      noiseSuppression: true,
      autoGainControl: true,
    },
    video: false,
  });

  // 2) PeerConnection 생성
  const pc = new RTCPeerConnection();

  // 3) 원격 오디오 재생 준비 (모델이 보내는 TTS 오디오)
  const remoteAudio = new Audio();
  remoteAudio.autoplay = true;

  pc.ontrack = (event) => {
    // 보통 audio track이 도착함
    const [remoteStream] = event.streams;
    remoteAudio.srcObject = remoteStream;
  };

  // 4) 로컬 마이크 트랙 업링크
  for (const track of stream.getAudioTracks()) {
    pc.addTrack(track, stream);
  }

  // 5) (선택) DataChannel: partial transcript, events, tool call 신호 등을 받는 용도
  const dc = pc.createDataChannel("oai-events");
  dc.onmessage = (msg) => {
    // 여기로 partial transcript / timing event / state event 등이 올 수 있음
    console.log("event:", msg.data);
  };

  // 6) SDP offer 생성
  const offer = await pc.createOffer({
    offerToReceiveAudio: true,
  });
  await pc.setLocalDescription(offer);

  // 7) 서버에서 ephemeral key 받아오기 (클라이언트에 장기 키를 두지 않기 위함)
  const eph = await fetch("/api/realtime-ephemeral", { method: "POST" }).then(r => r.json());
  // eph = { client_secret: "..."} 같은 형태라고 가정 (구현/명칭은 서버에 맞게)

  // 8) Realtime API에 SDP를 보내고 answer를 받는다
  //    주의: 아래 URL/헤더/필드명은 서비스 문서에 맞춰 조정해야 함.
  const answer = await fetch("https://api.openai.com/v1/realtime?model=gpt-realtime", {
    method: "POST",
    headers: {
      "Content-Type": "application/sdp",
      "Authorization": `Bearer ${eph.client_secret}`, // ephemeral credential
    },
    body: offer.sdp!,
  }).then(r => r.text());

  await pc.setRemoteDescription({ type: "answer", sdp: answer });

  // 9) 이제부터:
  // - 사용자가 말하면 오디오가 업링크되고
  // - 모델이 음성으로 응답하면 ontrack으로 재생된다
  console.log("Realtime voice session started");
}

이 뼈대만으로도 “되긴” 하지만, 대화처럼 느끼려면 다음 섹션의 팁(특히 VAD/barge-in/버퍼링)을 반드시 추가해야 합니다.


⚡ 실전 팁

1) latency를 “측정”부터 자동화

  • STT first partial, final, LLM TTFT, TTS TTFB, first audio play 시점을 모두 timestamp로 찍어 turn gap 분해하세요.
  • Twilio의 지표 테이블(예: STT 350ms, LLM TTFT 375ms, TTS TTFB 100ms 목표)은 “어디가 병목인지”를 빠르게 가늠하는 기준점이 됩니다. (twilio.com)

2) barge-in(사용자 끼어들기)은 “오디오 중단 + 상태 정리”가 세트

  • 사용자가 말하기 시작하면(클라이언트 VAD 또는 서버 STT partial 상승) 현재 TTS 재생을 즉시 중단해야 합니다.
  • 동시에 “에이전트가 이미 말한 내용”과 “이제 무효가 된 생성”을 세션 상태에서 정리하지 않으면, 모델이 다음 턴에서 맥락을 오염시킵니다.
  • Gemini Live API는 “중간 끼어들기 처리”를 실시간 상호작용의 핵심으로 언급합니다. (cloud.google.com)

3) WebSocket보다 WebRTC가 유리한 구간이 분명히 있다

  • 브라우저 음성은 코덱/지터버퍼/패킷화가 품질과 지연을 좌우합니다.
  • OpenAI Realtime 가이드는 브라우저/모바일에서 WebRTC 권장을 명시하고, Azure 문서도 같은 이유(저지연, 미디어 핸들링)를 듭니다. (platform.openai.com)
    실무적으로는 “서버가 오디오를 프록시하지 말 것”이 1순위 최적화인 경우가 많습니다(프록시하면 버퍼가 늘어 3초대 왕복이 나오기 쉽습니다).

4) “Proactive / turn detection” 옵션은 비용·오탐과 맞바꾼다

  • Google은 Live API native audio에서 Proactive Audio(기기 지향 발화에만 반응) 같은 설계를 제공합니다. (cloud.google.com)
    이런 기능은 “항상 듣고 있으면서도 불필요한 응답을 안 한다”는 UX에 유리하지만, 회의실/잡음 환경에서는 오탐/미탐이 곧 UX 리스크입니다. 반드시 현장 음향에서 튜닝하세요.

5) 긴 TTS(몇 분 이상)는 “실시간 대화”와 다른 문제

  • 실시간 대화형 TTS는 보통 짧은 발화 최적화라, 10~15분 내레이션 품질/일관성과는 다른 이슈가 나옵니다(세그먼트 stitching, voice consistency, 누적 artifacts).
    필요하면 대화(TTS 스트리밍)와 내레이션(TTS 배치)을 모델/파이프라인 자체를 분리하는 편이 안전합니다.

🚀 마무리

2026년 2월의 실시간 음성 에이전트 구현은 “좋은 STT/TTS를 고르는 문제”가 아니라, 스트리밍/동시성/latency budget을 시스템적으로 설계하는 문제입니다. 제가 현장에서 가장 효과를 본 우선순위는 다음입니다.

1) WebRTC로 미디어 경로를 단순화(프록시/불필요한 버퍼 제거) (platform.openai.com)
2) turn gap을 계측하고 분해(TTFT/TTFB/partial-final) (twilio.com)
3) barge-in + 상태정리를 제품 요구사항으로 고정 (cloud.google.com)
4) 더 나아가면, 연구 흐름(LTS-VoiceAgent처럼)대로 Listen-Think-Speak 병렬화를 설계 (arxiv.org)

다음 학습으로는:

  • OpenAI Realtime WebRTC 가이드 기반으로 “ephemeral key 발급 서버 + 브라우저 세션 관리”를 완성하고 (platform.openai.com)
  • Twilio의 core latency 글을 체크리스트로 삼아 “지연 예산 표 + 대시보드”를 붙이는 것을 추천합니다. (twilio.com)
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.