500ms 미만의 AI 음성 에이전트: STT, LLM, TTS의 실제 아키텍처
요약
500ms 미만의 초저지연 AI 음성 에이전트를 구축하기 위한 아키텍처와 최적화 전략을 다룹니다. 지연 시간의 주요 원인인 endpointing 문제를 해결하기 위한 의미론적 엔드포인팅과 스트리밍 방식의 중요성을 강조합니다.
핵심 포인트
- 지연 시간의 핵심 병목은 LLM이 아닌 endpointing과 CRM 호출임
- 의미론적 엔드포인팅을 통해 불필요한 침묵 대기 시간을 단축해야 함
- 모든 구성 요소(STT, LLM, TTS)는 반드시 스트리밍 방식으로 연결되어야 함
- 사용자 경험을 위해 전체 응답 완료 전 첫 문장부터 즉시 재생하는 구조가 필요함
500ms. 이는 발화자가 말을 멈춘 순간부터 응답의 첫 소리가 들리기까지의 총 예산(budget)입니다. 800ms를 넘어가면 귀가 거부감을 느낍니다. 대화가 로봇처럼 들리고, 발화자가 말을 끊거나 전화를 끊어버립니다.
고객 서비스를 위한 음성 에이전트는 세 가지 직렬 구성 요소인 음성 인식 (STT), 언어 모델 (LLM), 음성 합성 (TTS)과 CRM을 조회하기 위한 도구 루프(tool loop)로 이루어집니다. 이 예산을 지키는 것은 두 가지 요소에 달려 있으며, 이는 우리가 생각하는 것과는 거의 다릅니다. LLM은 병목 현상 (bottleneck)의 원인이 아닙니다. 모든 것을 망치는 것은 발화 종료 감지 (endpointing)와 루프 내의 CRM 호출입니다. 여기 우리가 프로덕션에 배포하는 아키텍처, 중요한 코드, 그리고 한 번 겪으면 다시는 겪고 싶지 않은 함정들을 소개합니다.
지연 시간 (latency)은 실제로 어디에서 발생하는가?
"즉각적인" 응답을 분해해 보면 시간이 어디에서 낭비되는지 알 수 있습니다:
- 발화 종료 감지 (endpointing): 200–800 ms — 진정한 살인마
- 최종 STT: 50–150 ms (발화자가 말하는 동안 스트리밍 (streaming) 방식으로 대부분의 작업이 수행됨)
- LLM, 첫 번째 토큰 (TTFT): 모델에 따라 200–600 ms
- TTS, 첫 번째 오디오 바이트 (TTFB): 100–300 ms
- 네트워크 및 전화 왕복 (round-trip): 2 × 50–150 ms
아무것도 최적화하지 않고 직렬로 더하면 1.5초에서 2초 사이가 됩니다. 플레이가 불가능한 수준입니다. 예산을 지켜주는 규칙은 한 단어로 요약됩니다: 다음 단계를 시작하기 전에 이전 단계가 끝나기를 절대 기다리지 마십시오. 모든 것은 스트리밍되어야 하며, endpointing은 밀리초 단위로 조정되어야 합니다.
진정한 살인마: endpointing
VAD (Voice Activity Detection, 음성 활동 감지)는 누군가 말하고 있는지를 알려줍니다. endpointing은 _언제 말이 끝났는지_를 결정합니다. 순진하게도, 우리는 발화 순서가 끝났다고 간주하기 전에 고정된 침묵(예: 700ms)을 기다립니다. 결과적으로, STT가 판결을 내리기도 전에 매 응답마다 700ms가 추가됩니다.
이 설정에는 가혹한 트레이드오프 (trade-off)가 존재합니다. 임계값(threshold)이 너무 짧으면 사용자가 머뭇거리거나 번호를 철자대로 말할 때 말을 중간에 끊어버립니다. 반대로 임계값이 너무 길면 매 턴마다 지연 시간(delay)이 추가됩니다. 고정된 침묵 시간을 300~500ms로 낮추고 **의미론적 엔드포인팅 (semantic endpointing)**을 추가합니다. 즉, 부분 전사(partial transcription)가 완전한 문장(예: "제 주문을 확인하고 싶어요")을 형성하면 일찍 끊고, "음... 제 번호는"과 같이 끝나면 기다리는 방식입니다. Deepgram과 LiveKit은 이 설정을 노출하고 있으며, 그렇지 않더라도 STT의 구두점(punctuation)을 활용한 휴리스틱 (heuristic)만으로도 이미 80%의 효과를 볼 수 있습니다.
스트리밍 (Streamer), 그렇지 않으면 모든 것이 무너집니다
두 번째 레버는 LLM의 응답이 끝날 때까지 기다리지 않고 말하는 것입니다. 문장이 완성되자마자 모델이 다음 내용을 생성하는 동안 해당 문장을 TTS로 보냅니다:
async def stream_reply(llm_stream, tts, audio_out):
buffer = ""
async for token in llm_stream: # LLM의 스트리밍 토큰 (tokens)
...
사용자는 LLM이 세 번째 문장을 작성하는 동안 첫 번째 문장을 듣게 됩니다. 세 문장으로 구성된 응답의 경우, 이 변화 하나만으로 체감상 600~900ms를 절약할 수 있습니다. Pipecat이나 LiveKit Agents와 같은 프레임워크가 이 파이프라인 (pipeline)을 대신 구축해 주지만, 그 내부 동작 원리를 이해해야 합니다. 그렇지 않으면 운영 환경에서 발생하는 첫 번째 지연 시간 버그 때문에 하루를 통째로 허비하게 될 것입니다.
CRM 호출: 침묵의 함정
이 지점이 바로 데모의 절반이 실제 환경과 맞닥뜨렸을 때 무너지는 구간입니다. "고객님의 주문은 목요일에 도착합니다"라고 답변하려면 통화 중에 CRM을 조회해야 합니다. LLM이 함수 호출을 결정하면, API를 조회하고, 그 결과를 다시 LLM에 전달하여 답변을 이어가게 합니다. 이 과정에서 모델의 왕복(round-trip) 두 번과 CRM의 지연 시간이 더해집니다. 이는 쉽게 1~2초의 완전한 침묵으로 이어지며, 사용자는 이를 연결이 끊긴 것으로 인식합니다.
해결책은 단 한 줄로 요약됩니다: CRM을 호출하기 전에 공백을 채우는 것.
if response.stop_reason == "tool_use":
call = response.tool_calls[0]
# 네트워크 호출 '후'가 아니라, 호출 '전'에 말을 합니다
...
전환 문구(transition phrase)는 단순히 미적인 요소가 아닙니다. 이는 도구 호출(tool turn) 과정에서 발생하는 모든 지연 시간(latency)을 가려주는 역할을 합니다. 또한 tool 스키마를 가볍게 유지하세요. 500ms 대신 200ms 만에 응답하는 CRM은 그 어떤 모델 변경보다 사용자 경험을 크게 개선합니다.
반복하게 만들지 않고 상담원에게 연결하기
정직한 에이전트는 자신의 한계를 알고 있습니다. 우리는 세 가지 신호에 따라 에스컬레이션(escalation)을 트리거합니다: 명시적인 요청, 두 차례 연속으로 신뢰도 임계값(confidence threshold) 미만인 경우, 또는 좌절감(frustration) 감지 시입니다. 코드는 단순하지만, 함정은 다른 곳에 있습니다.
def should_escalate(intent, confidence, turns_low_conf):
if intent == "parler_a_un_humain":
return True
...
진짜 함정은 '콜드 트랜스퍼(cold transfer, 냉정한 연결)'입니다. 에이전트가 전화를 넘기면 상담원은 아무런 맥락 없이 전화를 받게 됩니다. 그러면 발신자는 처음부터 모든 내용을 다시 반복해야 합니다. 이것이 사람들이 보이스봇(voicebots)을 싫어하는 첫 번째 이유입니다. '핫 트랜스퍼(hot transfer, 따뜻한 연결)'를 구현하세요. 상담원에게 대화 요약본을 전달해야 합니다(CRM 팝업, 사전 작성된 티켓, 또는 SIP REFER 헤더 활용). 상담원이 기계가 멈춘 지점부터 대화를 이어갈 수 있게 하면, 발신자는 이를 실패로 느끼지 않습니다.
프랑스어, 주문 번호, 그리고 DTMF
프랑스어 STT(음성 인식)는 일상 언어의 실제 환경에서 93~95%의 정확도에 도달합니다. 하지만 영숫자(alphanumeric) 조합에서는 성능이 급락합니다. 철자를 불러주는 주문 번호("A는 Anatole의 A, B, 1, 2, 3")나 구두로 불러주는 이메일 주소는 엉망이 되기 일쑤이며, 어떤 재질의(re-prompt) 요청으로도 이를 신뢰성 있게 복구할 수 없습니다.
이런 경우 음성 인식에 고집하지 마세요. 키패드 입력(DTMF)으로 전환하세요: "전화기 키패드로 주문 번호를 입력해 주세요." 키 입력은 결정론적(deterministic)이며 인식률이 완벽합니다. 발신자 또한 번호를 세 번 반복하는 것보다 여덟 자리를 누르는 것을 선호합니다. 순수한 대화 방식보다 덜 우아할 수는 있지만, 이것이 바로 실제로 작동하는 방식입니다.
AI Act가 강제하는 경계선
2026년 8월 2일부터 유럽 AI 법(AI Act) 제50조에 따라, 대화 상대방에게 기계와 대화하고 있음을 명확히 알려야 할 의무가 발생합니다. 이는 절대적인 금지 사항입니다. 만약 발신자가 "사람인가요?"라고 묻는다면, 거짓말을 하는 것은 위반 행위가 됩니다. 위반 시 과징금은 최대 3,500만 유로 또는 전 세계 연간 매출액의 7%에 달할 수 있으며, 음성 데이터를 처리하기 때문에 GDPR(개인정보보호법) 또한 추가로 적용됩니다.
직접적인 기술적 결과: 이 의무를 LLM에 위임하지 마세요. 확률론적 모델(Probabilistic model)은 천 번의 통화 중 한 번은 결국 해당 문구를 잊어버릴 것입니다. 고지는 첫 번째 토큰(Token)이 생성되기 전에 실행되도록 하드코딩(Hard-coded)되어야 합니다:
GREETING = ("안녕하세요, [기업명]의 음성 비서와 연결되었습니다. 제가 답변을 드리거나 상담원에게 연결해 드릴 수 있습니다.")
await tts.speak(GREETING, audio_out) # 하드코딩됨, 모델에 의해 생성되지 않음
컴플라이언스(Compliance, 규제 준수)는 확률에 맡겨서는 안 됩니다.
자주 묻는 질문 (FAQ)
프랑스어에는 어떤 STT/TTS가 적합한가요? STT 측면에서는 Deepgram과 Whisper large가 일반적인 대화에서 93~95%의 정확도를 유지합니다. TTS 측면에서는 Cartesia나 ElevenLabs가 스트리밍 시 TTFB(Time to First Byte)를 300ms 미만으로 낮춰줍니다. 스튜디오 데모가 아닌 실제 통화 환경에서 테스트하십시오.
LLM을 파인튜닝(Fine-tuning)해야 하나요? 드문 경우입니다. 절차를 포함한 잘 짜여진 시스템 프롬프트(System prompt)와 CRM으로의 도구 호출(Tool-calling)만으로도 대부분의 레벨 1 케이스를 커버할 수 있습니다. 파인튜닝은 비즈니스 전문 용어가 매우 특수한 경우에만 정당화됩니다.
SaaS인가요, 맞춤형(Custom)인가요? 호출량이 적고 표준적인 케이스라면 월 200유로 미만의 노코드(No-code) SaaS로 충분하며, 직접 코딩하지 마세요. 자체 정보 시스템(SI)을 연결해야 하거나, 데이터를 직접 제어해야 하거나, 벤더 종속(Lock-in)을 피해야 하는 시점부터는 맞춤형 방식이 유리해집니다. 이 선택 기준에 대한 자세한 내용은 전체 가이드에서 다룹니다.
끼어들기(Barge-in)는 어떻게 관리하나요? TTS가 재생되는 동안 음성을 감지하고, 즉시 합성을 중단하며 오디오 버퍼(Buffer)를 비워야 합니다. 그렇지 않으면 에이전트가 발신자의 말을 무시하고 계속 말을 하게 되며, 이는 단 1초 만에 로봇임을 들통나게 만드는 결함이 됩니다.
우리는 이 아키텍처를 여러 번 구축해 보았으며, 어려움은 결코 "Hello World" 수준의 구현이 아닙니다. 진짜 문제는 엔드포인팅 (Endpointing), CRM의 지연 시간 (Latency), 그리고 깔끔한 데이터 전송입니다. 만약 Claude Code를 사용하여 파이프라인부터 도구 호출 (Tool-calling)까지 이러한 종류의 에이전트를 구축하는 방법을 배우고 싶다면, 우리의 Claude Code 교육 과정에서 코드 관점의 주제를 다룹니다. 그리고 만약 우리가 이를 귀사의 정보 시스템 (SI)에 직접 연결하기를 원하신다면, 그것이 바로 우리 스튜디오의 전문 분야입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기