음성 활동 감지와 턴테이킹(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)의 역할을 설명합니다.
플러시 트릭(flush trick)이 스트리밍 STT(streaming STT)의 지연을 줄이는 방식을 이해합니다.
문제
음성 에이전트는 매 20 ms 청크(chunk)마다 서로 다른 세 가지 결정을 합니다.
이 프레임은 음성인가? VAD입니다. 프레임 단위의 이진(binary) 판정입니다.
사용자가 새 발화(utterance)를 시작했는가? 발화 시작 감지(onset detection)입니다.
사용자가 말을 끝냈는가? 종단점 검출(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 답변 완료
개념
세 단계 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 비교
VAD
TPR @ 5% FPR
지연(Latency)
라이선스(License)
WebRTC VAD(Google, 2013)
50.0%
30 ms
BSD
Silero VAD(2020-2026)
87.7%
약 1 ms
MIT
Cobra VAD(Picovoice)
98.9%
약 1 ms
commercial
pyannote segmentation
95%
약 10 ms
MIT-ish
Silero가 합리적인 기본 선택입니다. Cobra는 규정 준수(compliance)나 정확도를 한 단계 끌어올리는 업그레이드입니다. 에너지만 사용하는 VAD는 2026년 운영 환경에는 들어갈 자리가 없습니다.
직접 만들기
Step 1: 에너지 게이트
defenergy_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")
이 방식이 동작하려면 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)입니다.
연습문제
쉬움.code/main.py를 실행합니다. 발화 + 무음 + 발화 + 기침 시퀀스를 시뮬레이션하고 세 단계의 VAD 계층을 테스트합니다.
중간.silero-vad를 설치하고 5분짜리 녹음을 처리합니다. 첫 단어가 잘리는 현상과 거짓 트리거(false trigger)를 모두 줄이도록 임계값을 조정합니다. 정밀도(precision)와 재현율(recall)을 보고합니다.
어려움. 작은 턴 감지기를 만듭니다. Silero VAD에 최근 10개 단어의 임베딩(embedding)을 입력으로 하는 3-layer MLP(sentence-transformers 사용)를 결합하고, 직접 라벨링한 턴 종료 데이터셋에서 학습합니다. Silero 단독 대비 F1 점수를 10% 끌어올립니다.