음성 활동 감지와 턴테이킹(Voice Activity Detection & Turn-Taking) — Silero, Cobra, 그리고 Flush Trick

모든 음성 에이전트(voice agent)는 두 가지 결정 위에서 생사가 갈립니다. 사용자가 지금 말하고 있는가, 그리고 말이 끝났는가입니다. 음성 활동 감지(Voice Activity Detection; VAD)는 첫 번째 질문에 답합니다. 턴 감지(turn detection; VAD + silence-hangover + semantic endpoint model)는 두 번째 질문에 답합니다. 둘 중 하나라도 틀리면 어시스턴트는 사용자의 말을 자르거나 끝없이 말을 이어 갑니다.

유형: Build 언어: Python 선수 강의: Phase 6 · 11 (Real-Time Audio), Phase 6 · 12 (Voice Assistant) 예상 시간: 약 45분

학습 목표

  • VAD, 발화 시작 감지(onset detection), 종단점 검출(end-pointing)을 구분합니다.
  • 에너지 게이트(energy gate), Silero VAD, 의미 기반 턴 감지기(semantic turn detector)의 역할을 설명합니다.
  • 임계값(threshold), 최소 발화 길이(minimum speech duration), 침묵 행오버(silence hangover), 프리롤(pre-roll)을 조정(tuning)합니다.
  • 플러시 트릭(flush trick)이 스트리밍 STT(streaming STT)의 지연을 줄이는 방식을 이해합니다.

문제

음성 에이전트는 매 20 ms 청크(chunk)마다 서로 다른 세 가지 결정을 합니다.

  1. 이 프레임은 음성인가? VAD입니다. 프레임 단위의 이진(binary) 판정입니다.
  2. 사용자가 새 발화(utterance)를 시작했는가? 발화 시작 감지(onset detection)입니다.
  3. 사용자가 말을 끝냈는가? 종단점 검출(end-pointing, turn-end)입니다.

가장 단순한 답인 에너지 임계값(energy threshold)은 모든 종류의 잡음(noise)에서 실패합니다. 교통 소음, 키보드 소리, 군중 소음(crowd babble)이 모두 문제가 됩니다. 2026년의 답은 Silero VAD(open, deep-learned) + 턴 감지 모델(turn-detection model; semantic endpointing) + VAD에 맞춰 보정된 침묵 행오버(silence hangover) 조합입니다.

사전 테스트

2문제 · 이 강의를 시작하기 전에 얼마나 알고 있는지 확인해보세요

1.음성 활동 감지(Voice Activity Detection; VAD)와 턴 종료 감지(end-pointing)의 핵심 차이는 무엇인가요?

2.단순한 에너지 임계값(energy threshold) VAD가 실제 환경에서 실패하는 이유는 무엇인가요?

0/2 답변 완료

개념

three-tier VAD cascade + turn-end state machine Tier 1: energy gate cheap, fires on every noise if RMS > -40 dBFS → "speech" filters silence but NOT keyboard / cough / chair Tier 2: Silero VAD the 2020-2026 default 1M params · 1 ms / 30 ms chunk 87.7% TPR @ 5% FPR trained on 6000+ languages MIT · open · rejects transients Tier 3: semantic turn detector LiveKit turn-detector / custom VAD + recent-words classifier pauses mid-sentence vs done ("hmm, let me think..." stays) reduces false-interrupt by 5-10% turn-detection state machine state: "idle" ─ VAD fires > 250 ms of speech ─→ state: "speaking" (emit START) state: "speaking" ─ VAD silent for 500 ms ─→ state: "idle" (emit END) pre-roll buffer (300 ms): keep audio BEFORE VAD fires, else first word gets clipped min speech (250 ms): reject transients; silence hangover (500 ms): tune per use case the flush trick (Kyutai Unmute 2025) — sub-200 ms end-to-end 1. VAD fires end-of-speech at t=0 2. send buffered audio + flush signal to STT server 3. STT processes at 4× realtime → 500 ms look-ahead buffer → 125 ms wall time 4. transcript ready at t+125 ms — same latency as the VAD signal itself

세 단계 VAD 캐스케이드(cascade)

1단계(Tier 1): 에너지 게이트(energy gate). 가장 저렴합니다. -40 dBFS의 RMS 임계값을 적용합니다. 명확한 무음은 걸러 내지만, 임계값을 넘는 잡음에는 모두 반응합니다.

2단계(Tier 2): Silero VAD(2020-2026, MIT). 파라미터 100만 개 규모입니다. 6000개 이상의 언어로 학습되었습니다. 단일 CPU 스레드에서 30 ms 청크당 약 1 ms 만에 동작합니다. 5% FPR에서 87.7% TPR을 보입니다. 오픈소스 분야의 기본 선택지입니다.

3단계(Tier 3): 의미 기반 턴 감지기(semantic turn detector). LiveKit의 턴 감지 모델(turn-detection model, 2024-2026) 또는 직접 만든 작은 분류기(classifier)입니다. "문장 중간의 일시 정지"와 "말이 끝난 순간"을 구분합니다. 무음(silence)만 보지 않고 언어적 맥락(linguistic context), 즉 억양(intonation)과 최근 단어들(recent words)을 함께 사용합니다.

핵심 파라미터(parameter)와 기본값

  • 임계값(threshold). Silero는 확률(probability)을 출력합니다. 기본은 > 0.5로 음성을 판정하고, 민감하게 잡으려면 > 0.3을 씁니다. 임계값을 낮추면 첫 단어가 잘리는 일은 줄지만 거짓 양성(false positive)이 늘어납니다.
  • 최소 발화 길이(minimum speech duration). 250 ms보다 짧은 음성은 거부합니다. 대개 기침이나 의자 소음입니다.
  • 침묵 행오버(silence hangover; end-pointing). VAD가 0으로 돌아간 뒤 500-800 ms를 기다린 다음 발화 종료(end-of-turn)를 선언합니다. 너무 짧으면 사용자의 말을 끊고, 너무 길면 굼뜨게 느껴집니다.
  • 프리롤 버퍼(pre-roll buffer). VAD가 발동되기 전 오디오를 300-500 ms 보관합니다. "hey"의 첫소리가 잘리는 것을 막아 줍니다.

플러시 트릭(flush trick; Kyutai 2025)

스트리밍 STT 모델에는 미리 보기 지연(look-ahead delay)이 있습니다. Kyutai STT-1B는 500 ms, STT-2.6B는 2.5 s입니다. 일반적으로는 발화 종료(end-of-speech) 이후 그만큼 전사 결과(transcript)를 기다려야 합니다. 플러시 트릭은 VAD가 발화 종료를 감지한 순간 STT에 플러시 신호(flush signal)를 보내 즉시 결과를 강제로 내보내게 합니다. STT가 대략 4배속(realtime)으로 처리하면 500 ms 버퍼는 약 125 ms 안에 처리됩니다.

종단 간(end-to-end)으로 보면 125 ms VAD + 플러시 STT 조합이 대화형 지연(conversational latency)을 만들어 냅니다.

2026년 VAD 비교

VADTPR @ 5% FPR지연(Latency)라이선스(License)
WebRTC VAD(Google, 2013)50.0%30 msBSD
Silero VAD(2020-2026)87.7%약 1 msMIT
Cobra VAD(Picovoice)98.9%약 1 mscommercial
pyannote segmentation95%약 10 msMIT-ish

Silero가 합리적인 기본 선택입니다. Cobra는 규정 준수(compliance)나 정확도를 한 단계 끌어올리는 업그레이드입니다. 에너지만 사용하는 VAD는 2026년 운영 환경에는 들어갈 자리가 없습니다.

직접 만들기

Step 1: 에너지 게이트

def energy_vad(chunk, threshold_dbfs=-40.0):
    rms = (sum(x * x for x in chunk) / len(chunk)) ** 0.5
    dbfs = 20.0 * math.log10(max(rms, 1e-10))
    return dbfs > threshold_dbfs

Step 2: Python에서 Silero VAD 사용하기

from silero_vad import load_silero_vad, get_speech_timestamps

vad = load_silero_vad()
audio = torch.tensor(waveform_16k, dtype=torch.float32)
segments = get_speech_timestamps(
    audio, vad, sampling_rate=16000,
    threshold=0.5,
    min_speech_duration_ms=250,
    min_silence_duration_ms=500,
    speech_pad_ms=300,
)
for s in segments:
    print(f"{s['start']/16000:.2f}s - {s['end']/16000:.2f}s")

Step 3: 턴 종료 상태 기계(turn-end state machine)

class TurnDetector:
    def __init__(self, silence_hangover_ms=500, min_speech_ms=250):
        self.state = "idle"
        self.speech_ms = 0
        self.silence_ms = 0
        self.silence_hangover_ms = silence_hangover_ms
        self.min_speech_ms = min_speech_ms

    def update(self, is_speech, chunk_ms=20):
        if is_speech:
            self.speech_ms += chunk_ms
            self.silence_ms = 0
            if self.state == "idle" and self.speech_ms >= self.min_speech_ms:
                self.state = "speaking"
                return "START"
        else:
            self.silence_ms += chunk_ms
            if self.state == "speaking" and self.silence_ms >= self.silence_hangover_ms:
                self.state = "idle"
                self.speech_ms = 0
                return "END"
        return None

Step 4: 플러시 트릭 골격

def flush_on_end(stt_client, audio_buffer):
    stt_client.send_audio(audio_buffer)
    stt_client.send_flush()
    return stt_client.recv_transcript(timeout_ms=150)

이 방식이 동작하려면 STT(Kyutai, Deepgram, AssemblyAI)가 플러시를 지원해야 합니다. Whisper 스트리밍은 블록 기반(block-based)이라 동작하지 않습니다. 항상 청크가 채워지기를 기다리기 때문입니다.

사용하기

상황VAD 선택
오픈, 빠른 처리, 범용Silero VAD
상용 콜센터(commercial call center)Cobra VAD
온디바이스(on-device, phone)Silero VAD ONNX
연구 / 화자 분할(diarization)pyannote segmentation
의존성 없는 대체 수단WebRTC VAD(legacy)
높은 턴 종료 품질이 필요할 때Silero + LiveKit turn-detector 계층 결합

대원칙(rule of thumb)은 단순합니다. 정말 다른 선택지가 없는 경우가 아니라면 에너지만 사용하는 VAD를 배포하지 마십시오.

흔한 함정

  • 고정 임계값(fixed threshold). 조용한 환경에서는 잘 동작하지만 시끄러운 환경에서는 실패합니다. 기기 위에서 보정(on-device calibration)을 하거나 Silero로 전환합니다.
  • 너무 짧은 침묵 행오버. 에이전트가 문장 중간에 사용자를 끊습니다. 대화형 발화에서는 500-800 ms가 좋은 출발점입니다.
  • 너무 긴 침묵 행오버. 굼뜨게 느껴집니다. 목표 사용자로 A/B 테스트를 진행합니다.
  • 프리롤 버퍼 없음. 사용자 오디오의 첫 200-300 ms를 잃어 버립니다. 항상 롤링 프리롤(rolling pre-roll)을 둡니다.
  • 의미 기반 종단점(semantic endpointing) 무시. "Hmm, let me think..."에는 긴 정지가 들어갑니다. 생각이 끝나기도 전에 끊기면 사용자들은 매우 싫어합니다. LiveKit 턴 감지기나 유사한 모델을 함께 사용합니다.

산출물 만들기

outputs/skill-vad-tuner.md로 저장합니다. 워크로드에 맞는 VAD 모델, 임계값, 행오버, 프리롤, 턴 감지 전략을 고르는 스킬(skill)입니다.

연습문제

  1. 쉬움. code/main.py를 실행합니다. 발화 + 무음 + 발화 + 기침 시퀀스를 시뮬레이션하고 세 단계의 VAD 계층을 테스트합니다.
  2. 중간. silero-vad를 설치하고 5분짜리 녹음을 처리합니다. 첫 단어가 잘리는 현상과 거짓 트리거(false trigger)를 모두 줄이도록 임계값을 조정합니다. 정밀도(precision)와 재현율(recall)을 보고합니다.
  3. 어려움. 작은 턴 감지기를 만듭니다. Silero VAD에 최근 10개 단어의 임베딩(embedding)을 입력으로 하는 3-layer MLP(sentence-transformers 사용)를 결합하고, 직접 라벨링한 턴 종료 데이터셋에서 학습합니다. Silero 단독 대비 F1 점수를 10% 끌어올립니다.

핵심 용어

용어흔한 설명실제 의미
VAD음성 감지기(voice detector)프레임 단위의 이진 판정입니다. 이 프레임이 음성인지 답합니다.
턴 감지(turn detection)종단점 검출(end-pointing)VAD + 침묵 행오버 + 의미 기반 종단점의 결합입니다.
침묵 행오버(silence hangover)발화 뒤 대기 시간턴 종료를 선언하기 전 기다리는 시간으로, 보통 500-800 ms입니다.
프리롤(pre-roll)발화 직전 버퍼VAD가 발동하기 전 300-500 ms의 오디오를 보관합니다.
플러시 트릭(flush trick)Kyutai 해킹VAD → 플러시 STT 흐름으로 500 ms 지연을 125 ms 수준까지 낮춥니다.
의미 기반 종단점(semantic endpoint)"정말 멈추려는 것일까?"무음만이 아니라 단어를 함께 보는 ML 분류기입니다.
TPR @ FPR 5%ROC 점(point)표준 VAD 벤치마크입니다. Silero는 87.7%, WebRTC는 50%입니다.

더 읽을거리

실습 코드

이 강의의 실습 코드 1개

main
Code

산출물

이 강의에서 생성된 프롬프트, 스킬, 코드 산출물 1개

vad-tuner

Pick VAD model, threshold, silence hangover, pre-roll, and turn-detection strategy for a voice agent.

Skill

확인 문제

3문제 · 모두 맞추면 완료 표시가 가능합니다

1.음성 에이전트가 '음, 생각해 보면...' 같은 자연스러운 정지(pause) 중에 사용자의 말을 끊습니다. 이 문제를 가장 잘 해결하는 파라미터 조정 또는 추가는 무엇인가요?

2.플러시 트릭(flush trick)이 사용자의 발화 종료와 스트리밍 STT 모델의 전사 결과(transcript) 수신 사이의 지연을 줄이는 방식은 무엇인가요?

3.개발자가 프리롤 버퍼(pre-roll buffer) 없이 음성 에이전트를 배포했습니다. 사용자들이 발화의 첫 단어가 일관되게 잘린다고 보고합니다. 근본 원인은 무엇인가요?

0/3 답변 완료

추가 문제 풀기

AI가 강의 내용을 바탕으로 새로운 문제를 생성합니다