200ms 이하 실시간 음성 인식: 아키텍처 가이드
- 게시일
실시간 음성 인식(STT)은 사람이 말하는 즉시 오디오를 텍스트로 변환해 수백 밀리초 내에 결과를 반환합니다. 하지만 STT의 지연 시간을 낮게 유지하는 것은 모델뿐만 아니라 아키텍처의 문제이기도 합니다. 엔지니어는 전송, 청크 분할, 엔드포인팅, 캡처 경로 등 각 단계에서 발생하는 지연을 모두 고려해야 합니다. 이 중 어느 한 부분이라도 비효율적이면 200ms 목표를 초과할 수 있습니다.
이 가이드에서는 전송 계층부터 실시간 음성 인식 파이프라인을 구축할 수 있는 실질적인 시스템을 소개합니다. 기준으로 삼을 것은 Scribe v2 Realtime입니다. 이 모델은 약 150ms의 모델 지연 시간으로 부분 전사를 제공하며, 90개 이상의 언어를 지원하고, PCM(8kHz~48kHz) 및 mu-law 오디오를 받아들이며, 음성 활동 감지(VAD)와 수동 커밋 제어 기능을 통해 구간을 마무리할 수 있습니다.
오디오가 서버에 도달하는 과정, 가설이 확정된 텍스트로 발전하는 과정, 실시간 기능이 추가될 때의 비용, 오디오를 올바르게 캡처하고 전달하는 방법을 살펴봅니다.
요약
- 실시간 음성 인식 시스템을 만들려면 전체 파이프라인에서 지연 시간을 낮게 유지할 수 있도록 아키텍처를 세밀하게 조정해야 합니다.
- 대부분의 파이프라인에는 WebSocket이 기본값으로 적합하지만, WebRTC는 더 복잡한 대신 다양한 이점을 제공합니다.
- 음성 활동 감지(VAD)는 핸즈프리 구간 분할을 처리하며, 수동 커밋 기능을 통해 애플리케이션이 발화 종료를 직접 지정할 수 있습니다.
- 부분 전사는 임시 결과, 최종 전사는 확정 결과이므로 서로 다르게 표시해야 합니다.
- 약 100ms 크기의 작은 PCM 청크를 사용하면 첫 부분 전사까지의 지연 시간을 최소화할 수 있습니다.
실시간 음성 인식을 위한 WebSocket vs. WebRTC
전사가 시작되기 전에 오디오는 소스에서 인식기로 전송되어야 합니다. 어떤 채널을 선택하느냐에 따라 이후 모든 단계의 최소 지연 시간이 결정됩니다. 오디오가 전사 계층에 도달하는 방법에는 두 가지 주요 옵션이 있습니다.
WebSocket은 TCP 기반의 장시간 유지, 순서 보장, 신뢰성 있는 양방향 채널입니다. 연결을 열고, 바이너리 오디오 프레임을 전송하며, 전사 이벤트를 받아옵니다. 클라이언트와 서버 모두에서 구현이 간단하고, HTTPS를 허용하는 기업 프록시와 방화벽을 통과하며, 모든 브라우저와 서버 런타임에서 지원됩니다.
WebSocket의 한계는 TCP 위에서 동작한다는 점입니다. 패킷이 손실되면 TCP가 재전송을 시도하고, 이후 데이터는 손실된 부분이 복구될 때까지 대기합니다. 네트워크 상태가 좋을 때는 거의 느껴지지 않지만, 패킷 손실이 발생하면 오디오가 잠시 지연되었다가 한 번에 몰려 도착하는 현상이 생깁니다.
WebRTC는 실시간 미디어 전송을 위해 설계되었습니다. 미디어를 UDP(SRTP 사용)로 전송하므로 패킷이 손실되어도 스트림이 멈추지 않고 계속 진행됩니다. 패킷 도착 시간의 변동을 흡수하는 지터 버퍼가 있고, ICE/STUN/TURN을 통해 NAT 환경에서도 피어 간 연결이 가능하며, 자체 오디오 캡처 및 인코딩 기능도 포함되어 있습니다.
직접 연결이 불가능한 클라이언트에는 TURN 서버가 필요하며, 서버 측에서는 바이트 스트림이 아닌 미디어 스트림을 종료해야 합니다.
한눈에 보는 장단점:
대부분의 경우 WebSocket이 적합합니다. 클라이언트의 네트워크 상태가 양호하고 캡처 경로를 직접 제어할 수 있을 때 사용하세요. 예를 들어 서버 간 파이프라인, 데스크톱 앱, 브로드밴드 환경의 브라우저 앱, 이미 오디오가 서버에 도달하는 콜센터 백엔드 등에 적합합니다.
WebRTC는 신뢰할 수 없는 모바일 네트워크에서 소비자 기기로 직접 캡처할 때, 양방향 오디오(WebRTC 스택을 이미 사용하는 경우), 또는 손실 없는 실시간 동작이 구현의 단순성보다 더 중요할 때 선택하세요.
이 가이드의 나머지 부분에서는 인식기 연결에 WebSocket 전송을 사용합니다. 이는 동작 과정을 명확하게 보여주고 대부분의 팀에 적합한 출발점이기 때문입니다. WebSocket에만 국한된 내용은 아니므로, 나중에 WebRTC 미디어 구간을 앞단에 추가하고 서버에서 오디오를 PCM으로 디코딩해 동일한 청크를 파이프라인에 전달할 수 있습니다.
부분 전사와 최종 전사: 임시 결과의 의미
실시간 인식기는 완전한 문장이 끝날 때까지 기다리지 않습니다. 대신 오디오가 들어올 때마다 점점 더 정확해지는 추정 결과를 계속 내보내고, 이후 확정합니다. 이 두 상태의 차이를 이해하는 것이 생동감 있는 전사와 어색한 전사를 가르는 핵심입니다.
부분(임시) 가설은 지금까지 받은 오디오를 바탕으로 모델이 추정한 최선의 결과입니다. 부분 전사는 설계상 불안정합니다. 오디오가 더 들어오면 모델이 앞부분의 단어를 수정할 수 있습니다. 예를 들어 "I want to"가 이후 맥락에 따라 "I want two tickets"로 바뀔 수 있습니다. 부분 전사는 빠르게 도착하며(~150ms 지연), 덮어쓰기를 전제로 합니다.
최종 가설은 더 이상 변경되지 않는 확정된 구간입니다. 구간이 확정되면 인식기는 다음 오디오로 넘어가고, 이후 가설은 다음 오디오를 설명합니다. 최종 전사는 저장하거나 LLM에 전달하거나 전사본으로 보관하는 데이터입니다.
부분 전사와 최종 전사의 구분은 다음 세 가지에서 중요합니다:
- 사용자 경험: 부분 전사를 보여주면 사용자가 말하는 즉시 단어가 나타나 마이크가 정상 작동하고 시스템이 듣고 있음을 확인할 수 있습니다.
- 엔드포인팅: 부분 전사는 음성 활동의 연속 신호를 제공합니다. VAD와 결합하면 화자가 실제로 말을 멈췄는지 판단할 수 있습니다.
- 후속 타이밍: 음성 에이전트 파이프라인에서는 오디오 입력, 음성 인식, LLM, 텍스트 음성 변환, 오디오 출력 순서로 진행됩니다. 부분 전사 단계에서 미리 작업을 시작하고, 최종 전사에서 확정하면 응답 속도를 줄일 수 있지만, 가끔 미리 작업한 결과를 버려야 할 수도 있습니다.
부분 전사와 최종 전사는 다르게 렌더링하세요. 간단하고 효과적인 방법은 최신 부분 전사에 연결된 "현재 줄"을 하나 유지하다가, 최종 전사가 도착하면 전사본에 추가하는 것입니다:
시각적으로는 확정된 텍스트는 일반 스타일로, 현재 부분은 연하거나 이탤릭체로 표시해 아직 변경될 수 있음을 사용자에게 알려주세요.
엔드포인팅과 음성 활동 감지(VAD)
무엇을 말했는지 아는 것만큼이나, 언제 말이 끝났는지 아는 것도 중요합니다. 인식기는 생각이 끝난 시점을 파악해야 구간을 확정하고, 에이전트에서는 시스템이 응답을 시작할 수 있습니다.
엔드포인팅은 발화가 끝났다고 판단하는 결정입니다. 너무 일찍 확정하면 사용자의 말을 중간에 끊고, 너무 늦게 확정하면 사용자가 말을 끝냈는데도 에이전트가 한동안 조용하게 됩니다.
Scribe v2 Realtime에서는 두 가지 보완적인 메커니즘을 제공합니다:
- 음성 활동 감지(VAD)는 침묵을 기준으로 오디오를 분할합니다: 인식기가 음성이 지속적인 침묵으로 바뀌는 시점을 감지해 자동으로 구간을 확정합니다. VAD는 자연스러운 말의 리듬에 맞춰 동작하므로, 대화형 인터페이스에 기본값으로 적합합니다.
- 수동 커밋 제어: 수동 커밋 제어를 사용하면 침묵과 상관없이 애플리케이션이 직접 구간 확정 시점을 지정할 수 있습니다. 커밋 신호를 보내면 인식기가 현재 구간을 닫고 최종 전사를 내보냅니다. 예를 들어 푸시투토크 버튼을 뗄 때, "보내기" 액션을 할 때, 외부 턴테이킹 정책이 있을 때 적합합니다.
이 두 가지는 함께 사용할 수 있습니다. 일반적인 음성 에이전트는 VAD로 핸즈프리 동작을 하면서, 수동 커밋을 오버라이드로 제공해 사용자가 잠시 생각할 때는 끊기지 않고, 버튼을 누르면 즉시 구간이 나뉘도록 합니다.
침묵 임계값은 절대적으로 정해진 값이 없는 진짜 트레이드오프입니다:
- 짧은 발화 종료 타임아웃(예: 200~400ms 침묵 후 확정)은 시스템이 빠르게 반응하는 느낌을 줍니다. 하지만 사용자가 자연스럽게 쉬는 구간도 끊어 여러 구간으로 나누고, 에이전트가 너무 일찍 반응할 수 있습니다.
- 긴 타임아웃(예: 800~1200ms)은 자연스러운 쉼을 허용해 발화를 온전히 유지하지만, 시스템 반응이 느려질 수 있습니다.
여기에는 정답이 없으니, 상호작용에 맞게 임계값을 조정하세요:
- 받아쓰기나 메모 작성은 사용자가 중간에 생각하므로 긴 타임아웃도 괜찮습니다. 긴 타임아웃과 VAD를 활용하세요.
- 명령형 에이전트나 거래성 에이전트는 짧은 타임아웃과 수동 커밋이 유리합니다. 턴이 짧고 명확하기 때문입니다.
- 다국어 사용자나 비원어민은 더 자주 멈추므로, 확정 전 침묵 시간을 더 길게 잡으세요.
이 팁들을 참고하면 효과적인 엔드포인팅 시스템을 구축하고 실시간 음성 인식에 한 걸음 더 다가갈 수 있습니다.
실시간 기능: 언어 감지와 화자 분리
스트리밍 인식은 단순히 단어만 생성하는 것이 아닙니다. 하지만 추가 신호를 요청할수록 지연과 안정성에 영향을 줍니다. 실시간 경험에 꼭 필요한 기능만 켜고, 나머지는 배치 처리로 미루는 것이 원칙입니다.
자동 언어 인식 기능을 사용하면 Scribe v2 Realtime이 90개 이상의 지원 언어 중에서 말하는 언어를 자동으로 감지할 수 있습니다. 단, 모델이 확신을 갖기 위해 짧은 오디오 구간이 필요하므로, 스트림의 첫 부분 전사는 언어가 확정될 때까지 덜 안정적일 수 있습니다. 이미 언어를 알고 있다면 명시적으로 지정하는 것이 더 안정적인 결과를 얻는 데 도움이 됩니다.
화자 분리는 누가 어떤 말을 했는지 구분하는 기능입니다. 배치 전사에서는 전체 파일을 볼 수 있어 비교적 쉽지만, 스트리밍에서는 지금까지의 오디오만으로 화자 레이블을 지정해야 하므로 더 어렵습니다. 초반에 지정된 화자 레이블도 이후 오디오에 따라 수정될 수 있습니다. 스트리밍 화자 레이블도 부분 전사처럼 임시로 간주하고, 구간이 확정될 때까지는 변경될 수 있음을 염두에 두세요.
단어 단위 타이밍, 엔터티 정보 등도 마찬가지입니다. 토큰별 메타데이터를 많이 요청할수록 모델과 네트워크 모두 부담이 커집니다. 대부분의 실시간 UI에서는 텍스트와 구간 경계만 실시간으로 필요하고, 세부 메타데이터는 Scribe v2로 후처리할 수 있습니다.
스트리밍용 오디오 포맷: PCM과 mu-law
전송 및 인식 로직에 신경을 많이 쓰지만, 실제로는 오디오 인코딩과 청크 분할에서 많은 문제가 발생합니다. 포맷과 청크 크기를 올바르게 설정하는 것이 음성 인식 지연 시간을 줄이는 가장 쉬운 방법입니다.
PCM(리니어, 16비트 signed, 리틀 엔디안)은 캡처를 직접 제어할 때 사용하는 포맷입니다. 샘플레이트가 높을수록 음향 정보가 더 많이 담깁니다. 16kHz는 음성 인식의 표준 하한이며 대부분 충분합니다. 8kHz는 전화 품질로 고주파 정보가 손실됩니다. 소스에 맞는 샘플레이트를 사용하세요. 8kHz 오디오를 48kHz로 업샘플링해도 정보가 복구되지 않으므로 의미가 없습니다.
mu-law 8kHz는 전화 오디오 포맷입니다. Twilio 같은 공급업체에서 콜을 받아올 때 오디오는 8kHz mu-law로 도착하므로, 이 포맷 그대로 전달하는 것이 좋습니다. 소스 포맷을 그대로 유지하면 리샘플링 아티팩트와 불필요한 변환을 피할 수 있습니다.
청크 크기는 체감 지연 시간에 직접적인 영향을 줍니다. 오디오를 청크 단위로 보내면, 인식기는 청크가 도착할 때마다 부분 전사를 생성합니다. 청크가 작을수록 업데이트가 더 자주 발생하고 첫 부분 전사까지의 지연이 줄어듭니다. 청크가 크면 메시지 수는 줄지만, 추론당 맥락이 약간 늘어납니다. 실용적인 범위는 청크당 20~250ms 오디오입니다. 예를 들어 16kHz 모노 16비트 PCM에서 1초 오디오는 32,000바이트이므로, 100ms 청크는 약 3,200바이트입니다.
브라우저에서 마이크 입력 캡처하기
브라우저에서는 Web Audio API와 AudioWorklet을 사용하는 것이 가장 좋습니다. 워크릿은 오디오 렌더링 스레드에서 실행되어, 오디오를 작은 프레임 단위로 받아오며, 이전 ScriptProcessorNode와 달리 메인 스레드 지연의 영향을 받지 않습니다. 워크릿의 역할은 브라우저의 float 샘플을 16비트 PCM으로 변환해 메인 스레드로 전달하고, 메인 스레드는 이를 WebSocket으로 전송하는 것입니다.
워크릿 프로세서의 핵심은 float를 PCM으로 변환하는 부분입니다:
코드로 보는 파이프라인
파이프라인은 세 가지 주요 구성요소로 이루어집니다: 브라우저 클라이언트(마이크를 캡처해 PCM을 서버로 스트리밍), Node 서버(오디오를 Scribe v2 Realtime에 릴레이하고 전사 결과를 다시 전달), 그리고 파일이나 전화 브릿지에서 PCM을 스트리밍하는 스크립트형 클라이언트입니다.
서버가 인식기를 브라우저에 직접 노출하지 않고 릴레이 역할을 하는 가장 중요한 이유는 ElevenLabs API 키가 비밀이기 때문입니다. API 키는 반드시 서버에만 보관해야 하며, 브라우저에서 인식기와 직접 통신해야 한다면 서버에서 단일 사용 토큰을 발급해 클라이언트에 전달하세요.
브라우저 클라이언트
클라이언트는 서버에 WebSocket을 열고, 위에서 설명한 워크릿을 통해 마이크를 캡처해 생성된 PCM 프레임을 실시간으로 전송합니다. 서버에서 이미 정규화된 { type, text } 이벤트를 받아 부분/최종 상태를 관리합니다:
서버 릴레이
서버는 클라이언트마다 인식기 연결을 하나씩 열고, API 키를 서버에 보관하며, 바이너리 PCM을 그대로 전달하고, 인식기 이벤트를 클라이언트가 사용할 수 있도록 { type, text } 형태로 정규화합니다:
엔드포인트별 처리는 아래 두 어댑터 함수에만 국한되어 있습니다. 필드명은 Speech to Text 레퍼런스와 정확히 일치하도록 바꾸고, 나머지 파이프라인은 변경할 필요가 없습니다:
스크립트형 백엔드 클라이언트
백엔드 파이프라인이나 아래 벤치마크에서는 브라우저 없이도 동일한 인식기 연결을 사용할 수 있습니다. 어떤 소스에서든 PCM을 읽어 실시간 청크 속도로 전송하고, 이벤트를 받아오면 됩니다. API 키와 URL은 서버와 마찬가지로 환경 변수에서 가져옵니다.
음성 인식 지연 시간 및 단어 오류율 벤치마킹
지연 시간과 단어 오류율은 화자, 언어, 음향 환경, 오디오 길이, 각 공급업체의 최근접 리전까지의 네트워크 경로, 서비스의 현재 부하 등에 따라 달라집니다.
한 도시의 노트북에서 측정한 결과는 다른 환경의 실제 서비스에 일반화할 수 없습니다. 실제 서비스와 유사한 인프라에서, 실제 입력과 유사한 오디오로 테스트를 진행하고, 단일 수치가 아닌 범위와 분포를 보고하세요.
실제로 중요한 지연 시간과 정확도 수치는 실제 서비스와 유사한 인프라에서 직접 측정한 값뿐입니다. 아래는 음성 인식 지연 시간 벤치마킹 가이드입니다.
음성 인식 지연 시간 측정 항목
실시간 음성 인식 지연 시간 벤치마킹 시 측정해야 할 주요 지표는 다음과 같습니다:
- 첫 부분 전사까지의 시간: 첫 오디오 청크를 전송한 시점부터 첫 비어 있지 않은 부분 전사를 받을 때까지의 시간.
- 부분-최종 전사 지연: 발화의 마지막 오디오 청크부터 최종 가설이 도착할 때까지의 시간.
- 단어 오류율(WER): 최종 전사본과 사람 기준 전사본을 동일한 방식으로 비교해 계산합니다.
- 안정성 변화: 최종 확정 전까지 부분 전사가 몇 번 수정되는지. 이 값이 클수록 실시간 UI가 더 자주 바뀌어 보입니다.
컨트롤
신뢰할 수 없는 데이터를 피하려면, 실험에 여러 가지 컨트롤을 적용해 일관성을 유지해야 합니다.
음성 인식 지연 시간 벤치마킹 시 사용할 주요 컨트롤은 다음과 같습니다:
- 동일한 오디오: 모든 시스템에 동일한 파일, 동일한 샘플레이트, 동일한 인코딩을 사용하세요.
- 동일한 속도: 모든 시스템을 동일한 실시간 청크 속도(예: 100ms 청크)로 스트리밍하세요.
- 반복 및 분포 보고: 각 파일을 하루 동안 여러 번 실행하고, 중앙값 및 상위 구간(p50/p95)을 보고하세요.
- 동일한 기준 및 채점: WER 계산 전 텍스트를 동일하게 정규화(대소문자, 구두점, 숫자)하세요.
- 리전 및 네트워크 공개: 테스트를 실행한 위치와 각 공급업체까지의 경로를 명시하세요.
이 모든 요소를 동일하게 유지하면 더 정확한 지표를 얻을 수 있습니다.
하니스(테스트 스켈레톤)
측정의 핵심은 공급업체 어댑터를 받아 첫 부분 전사까지의 시간, 최종화 지연, 부분 전사 변화량을 기록하는 것입니다:
단어 오류율은 정규화된 텍스트에 대해 표준 토큰 단위 Levenshtein 거리로 계산합니다. 기준과 가설 모두 소문자로 변환하고 구두점을 제거한 뒤 계산해야, 모델이 아닌 정규화기의 성능을 측정하는 오류를 피할 수 있습니다. 각 파일을 공급업체별로 약 10회 반복해 중앙값(및 p50/p95)을 보고하세요. 단일 샘플은 네트워크 변동에 크게 좌우됩니다.
실행하려면 두 가지가 필요합니다. 첫째, 시스템별로 StreamFn 어댑터를 작성하세요. 위의 스크립트형 클라이언트가 이미 하나의 예시이며, 다른 어댑터도 (audioPath, onEvent, result) 계약을 따르고, 마지막 오디오 청크 전송 시 result.lastChunkSentAt을 설정합니다. 둘째, 오디오 파일과 기준을 불러와 측정 함수를 호출하세요. 실제 배포 환경과 유사한 머신에서, 실제 사용자와 유사한 오디오로 실행하면 재현 가능한 비교 결과를 얻을 수 있습니다.
실시간 음성 인식을 구현하는 방법 정리
이 글에서는 다양한 아키텍처 변경 사항을 다루며, 시스템을 점진적으로 개선해 실시간 음성 인식에 가까워질 수 있도록 안내했습니다.
실제 서비스용 실시간 STT 시스템은 몇 가지 핵심 결정에 달려 있습니다:
- 전송: 간단함과 네트워크 제어가 필요하면 WebSocket, 손실 허용과 소비자 기기 캡처가 필요하면 WebRTC를 선택하세요.
- 부분 전사와 최종 전사: 부분 전사는 임시, 최종 전사는 확정으로 다루고, 사용자 신뢰를 위해 서로 다르게 표시하세요.
- 엔드포인팅: 핸즈프리 분할에는 VAD, 오버라이드에는 수동 커밋을 사용하고, 침묵 임계값은 고정값이 아닌 상호작용에 맞게 조정하세요.
- 실시간 기능: 실시간 경험에 꼭 필요한 기능만 켜고, 나머지는 Scribe v2로 배치 처리하세요.
- 오디오 포맷: 작은 PCM 프레임으로 캡처하고, 약 100ms 청크로 전송하며, 전화 오디오는 소스 포맷을 그대로 사용하세요.
- 벤치마킹: 정확도와 지연 시간의 균형은 실제 오디오와 목표 지표에 맞게 직접 조정하세요.
- API 보안: API 키는 서버에만 보관하거나, 클라이언트 직접 연결 시 단일 사용 토큰을 발급하세요.
음성 에이전트에서 지연 시간을 최적화하는 방법 가이드도 준비되어 있습니다.
Scribe v2 Realtime으로 실시간 음성 인식 시스템 구축하기
Scribe v2 Realtime은 약 150ms의 모델 지연 시간으로 부분 전사를 제공합니다. 실제 사용자가 이 수치를 체감할 수 있을지는 주변 아키텍처에 달려 있으며, 이 부분은 여러분이 직접 제어할 수 있습니다. 이 글에서 소개한 전략을 활용하면 지연 시간을 줄이고 고객 경험을 개선하는 파이프라인 아키텍처를 구축할 수 있습니다.
더 자세한 내용은 음성 인식 기능 개요를 확인하고, 모델 레퍼런스에서 전체 기능 및 언어 목록을 살펴보세요. 그리고 실시간 제품 페이지도 방문해보세요: 실시간 음성 인식 API 및 실시간 음성 인식.
구현을 시작할 준비가 되셨다면, 무료 ElevenLabs 계정 만들기로 오늘 바로 첫 전사 스트리밍을 시작해보세요.

.webp&w=3840&q=80)
.webp&w=3840&q=80)
