순차적 연결을 넘어선 스트리밍 아키텍처와 0.83초의 지연시간
현재 주요 제공업체의 음성-음성 시스템이 기록하는 첫 토큰 생성 시간(TTFT, Time to First Token)은 0.8초에서 3초 사이 분포한다. 500ms 이상의 지연이 발생하면 사용자는 즉각적으로 느리다고 체감하며, 3초를 초과하는 지연은 사용자의 이탈이나 시스템 고장 판단으로 이어진다. 이는 모델의 추론 성능보다 아키텍처 설계가 사용자의 유지 여부를 결정하는 결정적 요인임을 의미한다. 인간 대화의 자연스러운 간격인 200~300ms라는 기준점은 단순한 지향점이 아니라, 서비스가 자연스럽게 느껴지는 영역과 사용자가 전화를 끊어버리는 영역을 가르는 물리적 제약 조건이다.
순차적(Sequential) 패턴은 구현과 논리 파악이 가장 쉽지만 지연 시간이 누적되는 치명적인 단점이 있다. 사용자가 발화를 마치면 STT(Speech-to-Text, 음성-텍스트 변환)가 전체 문장을 전사하고, 이후 LLM(Large Language Model, 거대언어모델)이 전체 응답을 생성하며, 마지막으로 TTS(Text-to-Speech, 텍스트-음성 변환)가 전체 오디오를 합성하는 순서로 작동한다. 모든 단계가 이전 단계의 완전한 종료를 기다려야 하므로 각 공정의 대기 시간이 수직으로 쌓인다. 이 구조에서는 모델의 개별 속도를 높여도 각 단계 사이의 유휴 시간이 반드시 존재해 자연스러운 대화 흐름을 만들기 어렵다.
실제 서비스 환경의 표준인 스트리밍(Streaming) 패턴은 각 단계의 출력을 점진적으로 다음 단계에 전달해 대기 시간을 제거한다. STT는 전체 문장이 끝나기 전이라도 부분 전사 내용을 LLM에 스트리밍하고, LLM은 생성되는 토큰을 즉시 TTS로 보낸다. TTS는 LLM이 전체 응답을 생성하는 도중이라도 첫 번째 완성된 문장이 확인되는 즉시 합성과 재생을 시작한다. 사용자는 에이전트가 나머지 답변을 생성하는 동안 이미 첫 문장을 듣게 되며, 이를 통해 전체 프로세스가 병렬로 작동하는 효과를 얻어 체감 지연 시간을 획기적으로 낮춘다.
스트리밍 아키텍처의 핵심은 LLM 스트림에서 TTS 엔진으로 넘어가는 데이터의 전달 단위 설정에 있다. 전달 단위는 개별 토큰이나 전체 응답이 아니라 완성된 문장 단위로 정의한다. 누적되는 토큰 버퍼에서 문장 경계가 나타나는 즉시 이를 분리해 TTS로 넘기는 로직을 통해 합성 시작 시점을 최대한 앞당긴다. 이러한 설계는 모델의 지능과 무관하게 물리적인 응답 시작 시간을 단축하며, 결과적으로 사용자가 체감하는 지연 시간을 가용 범위 안으로 끌어내려 대화의 연속성을 유지하는 유일한 방법이다.
WebSocket 기반 스트리밍 STT의 부분 전사와 최종 확정 처리
실시간 음성 인식 시스템은 한 번의 요청으로 전체 텍스트를 받는 방식이 아니라 약 50ms 단위의 작은 오디오 청크(Chunk, 데이터 조각)를 지속적으로 전송하는 구조를 가진다. 이를 위해 서버와 클라이언트 사이에 끊김 없는 연결을 유지하는 WebSocket(웹소켓, 실시간 양방향 통신 프로토콜) 연결을 사용한다. 사용자가 말을 하는 도중에 오디오 데이터가 계속 흘러가고, 서버는 이를 즉시 처리해 전사 결과를 돌려보낸다. 이 방식은 전체 음성이 끝날 때까지 기다리는 블로킹 호출 방식의 지연 시간을 없애기 위한 필수 선택이다.
서버가 보내는 응답은 부분(Partial) 이벤트와 최종 확정(Final) 이벤트로 엄격히 나뉜다. 모델은 사용자의 발화를 실시간으로 추측하며 계속해서 부분 전사 결과를 내보내는데, 문맥이 파악됨에 따라 이전의 추측을 수정하며 텍스트를 갱신한다. 단어가 하나씩 쌓이며 가상 발화가 구성되는 동안 수많은 부분 전사가 발생하지만, 실제 동작 로직에서는 9개의 부분 전사가 지나가더라도 오직 하나의 FINAL 이벤트에만 반응하도록 설계해야 한다. 부분 전사는 사용자 화면에 실시간 피드백을 렌더링하는 용도로 쓰고, 실제 하위 함수 호출이나 LLM 전달은 확정된 텍스트가 도착했을 때만 수행하는 것이 표준이다.
AssemblyAI Voice Agent API 같은 프로덕션 엔드포인트(Production Endpoint, 실제 서비스 환경의 접속 지점)는 이러한 표준 구현 방식을 따른다. 특히 고유명사나 주문 번호, 전화번호 같은 엔티티(Entity, 의미 있는 최소 단위의 정보) 인식 정확도는 이후 단계인 함수 호출의 성공 여부를 결정짓는 핵심 변수가 된다. 텍스트가 확정되는 순간의 정확도가 낮으면 이후의 모든 자동화 워크플로가 실패하기 때문이다. 이러한 확정 시점과 필터링 기준은 아키텍처에 고정된 상수가 아니라 서비스의 유스케이스에 따라 튜닝 가능한 정책 결정 영역이다.
실무자는 스트리밍 STT 클라이언트를 구현할 때 오디오 스트림 전송과 이벤트 필터링 로직을 분리하여 작성한다. 아래 명령어로 스트리밍 STT의 기본 동작과 이벤트 흐름을 확인할 수 있다.
python streaming_stt.py이 코드를 통해 50ms 단위의 데이터 전송과 부분 전사-최종 확정 이벤트의 흐름을 직접 검증하며 지연 시간을 최적화한다. 확정 이벤트가 발생하기 전까지는 어떠한 외부 API 호출도 발생하지 않도록 제어하는 것이 오작동을 막는 실무적 판단 기준이다.
텍스트가 아닌 무음 패턴으로 제어하는 턴 감지(Turn Detection)
턴 감지는 STT(Speech-to-Text, 음성-텍스트 변환)가 내놓은 전사 텍스트가 아니라 오디오 스트림의 무음 패턴을 직접 분석해 응답 시점을 결정한다. 많은 설계자가 이를 STT 과정의 일부로 생각하지만 실제로는 독립된 제어 로직으로 분리해야 한다. 텍스트 내용이 아닌 정적의 길이를 소비하는 별도 로직으로 구성하면 대화의 호흡을 세밀하게 조정할 수 있다. 텍스트 기반 판단은 문맥 파악에 시간이 걸리지만 오디오 패턴 분석은 즉각적인 반응이 가능하기 때문이다.
최소 무음 지속 시간인 `min_silence_ms`는 보통 600ms로 설정해 불필요한 끼어들기를 막는다. 사용자가 말을 하다가 300ms에서 500ms 사이로 짧게 멈추는 경우 시스템은 이를 생각 중인 상태로 간주하며 silence_pending 상태를 유지한다. 이 짧은 멈춤이 최소 임계값을 넘지 않고 다시 발화로 이어지면 턴은 종료되지 않는다. 실제로 사용자가 700ms 지점에서 완전히 말을 멈추고 정적이 유지될 때만 시계가 작동해 1300ms 시점에 정확히 턴 종료 신호를 보낸다.
최대 무음 한도인 `max_silence_ms`는 보통 1500ms로 설정해 시스템의 응답 지연 상한선을 정한다. 텍스트 분석 결과 문장이 미완성된 것처럼 느껴지는 세만틱 신호가 있더라도 무음 시간이 이 하드 캡에 도달하면 시스템은 강제로 응답을 시작한다. 최소 임계값이 생각하는 시간을 보장한다면 최대 한도는 시스템이 먹통이 된 것처럼 보이는 상황을 방지하는 안전장치다. 이 두 수치를 단일 타임아웃이 아닌 독립적인 변수로 분리해 관리하는 것이 튜닝의 핵심이다.
이 로직은 복잡한 의존성 없이 단독으로 실행해 테스트할 수 있다.
python turn_detection.py실무자는 사용자의 발화 습관이나 도메인 특성에 따라 두 수치를 조정하며 최적의 지점을 찾아야 한다. 생각하는 시간이 긴 전문 상담 영역이라면 `min_silence_ms`를 높이고 빠른 응답이 필요한 단순 안내 서비스라면 `max_silence_ms`를 낮추는 판단 기준을 세우면 된다.
문장 단위 청킹(Chunking)을 통한 TTS 응답성 극대화
사용자는 LLM이 전체 답변을 생성하기 전, 첫 번째 완성된 문장이 나오는 즉시 에이전트의 음성을 듣게 된다. LLM 토큰 스트림(텍스트 조각의 연속적인 흐름)에서 문장 경계가 나타나는 즉시 버퍼에서 문장 단위로 분리해 TTS로 넘기는 방식이다. 예를 들어 "확인해 드리겠습니다"라는 첫 문장이 완성되면, 나머지 상세 내용을 생성하는 동안 이미 음성 합성과 재생이 시작된다. 전체 응답이 끝날 때까지 기다리지 않고 첫 조각을 먼저 내보내 체감 지연시간을 줄이는 것이 핵심이다.
이 과정은 텍스트 버퍼에 쌓이는 토큰들을 실시간으로 감시하며 마침표나 물음표 같은 문장 종결 표식을 찾는 로직으로 작동한다. 문장 단위 청킹(Chunking, 데이터를 작은 덩어리로 나누는 것)을 적용하면 TTS 엔진은 전체 텍스트가 아닌 짧은 문장 단위로 합성을 수행하므로 초기 응답 속도가 비약적으로 빨라진다. 개발자는 별도의 외부 라이브러리 없이도 기본 파이썬 환경에서 이 로직을 구현하고 테스트할 수 있다.
python sentence_chunker.py위 코드를 실행하면 토큰 스트림이 어떻게 문장 단위로 쪼개져 TTS로 전달되는지 그 흐름을 확인할 수 있다.
실무 관점에서 보면 이는 실제 생성 시간 자체를 줄이는 것이 아니라, 사용자가 느끼는 대기 시간을 제거하는 전략이다. LLM이 수백 개의 토큰을 생성하는 동안 사용자가 침묵을 견뎌야 하는 상황을 방지한다. 첫 문장이 재생되는 동안 LLM은 백그라운드에서 다음 문장들을 계속 생성하고, TTS는 앞선 문장의 재생이 끝나기 전에 다음 청크를 미리 준비하여 끊김 없는 음성을 제공한다. 이러한 증분적 데이터 전달 방식은 음성 인터페이스의 응답성을 결정짓는 핵심 요소다.
다만 문장 경계를 너무 엄격하게 잡으면 문장이 길어질 때 다시 지연이 발생하고, 너무 느슨하게 잡으면 문맥이 끊긴 어색한 음성이 출력된다. 따라서 적절한 문장 종결 식별자를 정의하고 버퍼의 크기를 조절하는 튜닝 과정이 필요하다. 이는 단순히 기술적인 구현을 넘어 실제 대화의 리듬과 자연스러움을 결정하는 설계 영역에 해당한다. 문장 단위로 쪼개어 내보내는 시점을 정교하게 제어할수록 사용자는 에이전트가 실시간으로 생각하며 말하고 있다는 인상을 받게 된다.
서비스 도메인별 턴 감지 임계값 설정 기준
고령자 케어 서비스에서는 최대 무음 한도를 2500ms까지 높게 잡고, 빠른 템포의 대화 환경에서는 최소 무음 지속 시간을 300ms까지 낮게 설정한다. 사용자의 발화 속도와 습관이 도메인마다 다르기 때문에 턴 감지 임계값은 고정된 상수가 아니라 서비스 정책에 따라 결정해야 하는 변수다. 무음 임계값이 너무 낮으면 사용자가 말을 잠시 멈춘 사이 AI가 끼어들어 말을 끊는 상황이 빈번하게 발생한다. 반대로 임계값이 너무 높으면 사용자가 말을 마쳤음에도 AI가 한참 뒤에 응답하여 대화의 흐름이 끊기고 어색한 정적이 흐른다. 이러한 턴 감지의 정밀도는 사용자가 AI를 지능적인 대화 상대자로 인식하는지, 혹은 단순한 기계로 인식하는지를 결정하는 기준이 된다.
헬스케어 도메인의 경우 고령 사용자가 적절한 단어를 선택하거나 호흡을 가다듬는 시간이 일반 성인보다 길어지는 특성이 있다. 일반적인 대화 기준보다 무음 허용 범위를 넓게 설정해야만 사용자가 문장을 완전히 끝내기 전에 시스템이 응답을 시작하는 실수를 줄일 수 있다. 실무적으로는 최대 무음 한도를 2500ms까지 상향 조정하여 발화의 완결성을 보장하는 방향으로 튜닝한다. 이는 모델의 추론 성능을 높이는 작업이 아니라 타겟 사용자의 신체적 특성을 반영한 정책적 UX 설계의 영역이다. 사용자가 말을 멈춘 순간을 성급하게 종료 신호로 해석하지 않는 인내심 있는 시스템을 구축하는 것이 핵심이다. 무음 임계값을 보수적으로 설정함으로써 불필요한 Barge-in(말 끊기) 현상을 억제하고 심리적 안정감을 제공한다.
반면 고객 센터의 빠른 질의응답이나 효율 중심의 비즈니스 툴에서는 응답 속도가 곧 사용자 경험의 핵심 지표가 된다. 이때는 최소 무음 지속 시간을 300ms 수준까지 하향 조정하여 사용자가 말을 마치자마자 즉각적으로 반응하도록 설계한다. 응답 지연이 길어질수록 사용자는 시스템이 고장 났거나 내 말을 듣지 않고 있다고 판단해 동일한 말을 반복하거나 짜증을 느끼는 경향을 보인다. 빠른 턴 전환은 대화의 리듬감을 살려 AI와의 상호작용을 더 인간답게 만든다. 특히 정보 습득이 목적인 서비스일수록 무음 시간을 극단적으로 줄여 대화의 밀도를 높이는 전략이 유효하며, 이는 사용자가 느끼는 체감 지연 시간을 물리적 시간보다 더 짧게 만드는 효과를 준다.
턴 감지 설정은 정답이 정해진 수치가 아니라 도메인별 사용자 데이터에 기반해 최적점을 찾는 과정이다. 실무자는 서비스 성격에 따라 최소 무음 지속 시간은 300~600ms, 최대 무음 한도는 1500~2500ms 범위 내에서 조정하며 최적의 턴 전환 시점을 결정해야 한다.




