LabHub
시작하기
배우기 러닝패스 코스

음성 AI 에이전트 — 듣고, 찾고, 말하는 파이프라인

말하기 — 첫 소리까지의 시간과 '읽을 글' 만들기

LabHub 에서 이어서 보기

한 줄 요약

TTS 의 속도는 RTF(합성 시간 ÷ 소리 길이)로 잰다. RTF 가 1보다 작아도 답 전체를 한 번에 합성하면 첫 소리가 늦다. 문장(또는 절) 단위로 잘라 첫 조각부터 합성하면 첫 소리가 몇 배 당겨진다. 그리고 TTS 는 쓰인 대로 읽는다 — '911' 은 '구백십일', '14:30' 은 '십사 삼십', 인용 표시 '[kb-hours]' 는 '비 아워스' 가 된다. 화면용 글을 귀로 들을 글로 바꾸는 단계가 따로 있어야 한다.

왜 이게 필요했나

LabHub 회화 연습은 TTS 에 한 문장당 2.3초가 들었다(2026-09-23 실측, GPU 서버). 답을 다 받은 뒤 통째로 합성하니 모델이 다섯 문장을 쓰면 12초를 기다려야 했다 — 그 파일의 주석이 말하듯 '그 순간 대화가 아니라 낭독' 이 된다. 이 코스의 TTS 는 CPU 에서 훨씬 빠르지만(아래), 원리는 같다. 첫 소리까지의 시간은 첫 조각의 길이에 비례한다.

어떻게 동작하나

Piper 와 VITS. 이 이미지의 TTS 는 Piper 의 en_US ljspeech medium 음성이다. 글을 espeak-ng 로 음소로 바꾼 뒤 VITS(Kim et al., 2021) 신경망이 파형을 바로 만든다. 출력은 22,050 Hz 다(모델 카드). 학습 자료 LJ Speech 는 한 사람이 읽은 약 13,100개 클립으로, 퍼블릭 도메인이다. VITS 는 합성할 때마다 소음 항을 뽑아 같은 문장도 매번 조금 다른 파형이 나온다 — 채점기가 여러분의 WAV 를 샘플 단위로 비교하지 않는 이유다.

RTF 와 첫 소리. CPU 2코어 파드(nuc1)에서 이 모델의 RTF 는 약 0.04 였다 — 10초 분량을 0.4초에 만든다. 같은 모델의 int8 양자화 판은 파일이 3분의 1 인데도 RTF 0.12 로 세 배 느렸다. 동적 양자화는 계산하는 동안 정수와 실수를 오가는 비용이 들고, 이 CPU·이 연산자 조합에서는 그 비용이 이득보다 컸다. 크기만 보고 고르면 안 되는 예다. 통째로 합성하면 세 문장 답의 첫 소리가 전체 합성이 끝날 때 나오지만, 문장으로 잘라 첫 문장만 먼저 합성하면 그 시간만큼만 기다린다.

문장 나누기. 마침표마다 자르면 'Dr. Rivera' 와 '$3.50' 에서 부서진다. 규칙은 이렇다 — 끝 부호 뒤에 공백과 대문자(또는 글 끝)가 와야 문장 끝이고, 'Dr.'·'Mr.'·'No.' 처럼 뒤에 이름·숫자가 오는 약어는 끝이 아니다. 'a.m.' 은 문장 끝일 수도 있다('…at 7:30 a.m. Results take…').

LLM 과 겹치기. LLM 스트림에서 글이 들어오는 대로 조각을 잘라 TTS 에 넘기면, LLM 이 다음 문장을 쓰는 동안 앞 문장을 합성한다. 작은 모델은 '짧게 답하라' 를 잘 어기므로 문장이 길 수 있다. 그래서 문장 끝이 없어도 쉼표 앞 절(다섯 낱말 이상) 이나 열두 낱말째에서 잘라 첫 조각의 길이를 코드가 정한다. 주의할 점이 하나 있다. 이 파드의 CPU 는 2코어이고 LLM 서버도 2스레드를 쓴다. 겹쳐 돌리면 두 일이 같은 코어를 나눠 쓴다 — 첫 소리는 당겨지지만 각각은 혼자 돌 때보다 느려진다. 겹치기의 이득은 여유 코어가 있을 때 가장 크다(모듈 8 에서 잰다).

읽을 글 만들기(텍스트 정규화). 이 이미지의 TTS 로 합성하고 ASR 로 다시 받아 적어 보면 무엇이 틀리는지 보인다(실측): "Call 911" → "NINE HUNDRED ELEVEN", "at 14:30 [kb-hours]" → "FOURTEEN THIRTY B HOURS", "09:00" → "NINE ZERO ZERO". 그래서 합성 전에 인용 표시를 지우고, 24시간 시각을 오전·오후로(14:30 → two thirty p m), 긴 숫자는 한 자리씩(911 → nine one one), 금액은 말로($80 → eighty dollars) 바꾼다. 효과는 TTS → ASR 왕복 WER 로 잰다 — 사람 귀 대신 ASR 을 듣는 사람으로 쓰는 것이다.

전송 형식. 합성한 22.05 kHz 소리는 전송 계층이 약속한 모양(16 kHz · s16le · 20 ms)으로 바꿔 내보낸다. 22050 을 16000 인 것처럼 그대로 보내면 1.38배 느리고 낮은 소리가 된다.

현장에서 만나는 모습

TTS 의 첫 소리 지연에서 흔히 놓치는 것이 첫 합성의 준비 시간이다. 모델을 읽은 뒤 첫 호출은 계산 그래프를 준비하느라 느리다. 그래서 서비스는 시작할 때 짧은 글을 한 번 합성해 둔다(이 코스의 정답지가 'warm up' 을 먼저 부르는 이유). LabHub 가 ASR 에 무음을 보내 미리 올려 두는 것과 같은 생각이다.

읽을 글 만들기는 언어와 지역을 탄다. '14:30' 을 미국 영어는 'two thirty p m' 으로, 영국 방송은 'half past two' 로 읽는다. 날짜('9/10')는 나라마다 뜻이 다르다. 그래서 규칙을 한곳에 모으고, 새 모양을 볼 때마다 왕복 WER 시험에 한 줄씩 더한다. 이 코스의 규칙은 미국 영어 음성 하나를 위한 최소한이다.

다음 실습에서 할 것

한 문장을 합성해 RTF 를 재고, 약어·소수에서 부서지지 않는 문장 나누기를 만든다. 세 문장 글의 첫 소리를 통째로와 문장 단위로 비교하고, LLM 스트림을 조각으로 잘라 TTS 와 겹쳐 돌린다. 읽을 글로 바꾸는 함수를 만들어 왕복 WER 로 효과를 재고, 합성한 소리를 16 kHz 20 ms 프레임으로 바꾼다.