Show GN: 생성형 LLM 없이 만든 실시간 음성 예약 봇 데모 - jev 활용기
[원문 본문]

Jev
Ai Voice Agent
LLM
생성형 LLM 없이 만든 음성 예약 데모: jev 활용기
afaics
18 min read ·
18 hours ago
--
Share
저희는 AI와 사람 간의 실시간 음성 통신 기술을 개발하며, ChatGPT로 대변되는 광범위한 일상 대화가 아니라 AI 콜센터나 예약 접수처럼 실제 비즈니스 업무를 수행하는 음성 에이전트의 실현 가능성을 검토해 왔습니다. 생성형 LLM이 등장해 사람과 자연스럽게 대화하는 모습을 보였기에 음성 통화 또한 쉽게 구현할 수 있을 것이란 기대를 갖게 되었습니다.
텍스트 입출력을 하는 챗봇과 달리, 실제 업무를 수행하는 음성 봇은 직면해야 할 문제부터가 다릅니다. 화면을 보며 클릭하는 UI와 달리 음성 통화는 짧은 침묵에도 사용자가 장애를 의심하며, 노이즈와 말실수, 갑작스런 변심, 어순이 꼬인 구어체 문장이 실시간으로 들어옵니다.
가장 문제가 되는 부분은 LLM의 응답 시간입니다. 침묵이 길어지면 통화는 답답해지고, 이를 메우기 위해 억지로 넣는 필러(“잠시만요…”)와 같은 회피 방법은 반복될수록 피로감과 짜증을 유발합니다. 따라서 무거운 프론티어 모델을 사용할 수 없고 최대한 빠른 모델을 사용할 수밖에 없습니다. 이는 단순한 최적화 문제가 아닌 아키텍처 레벨에서 해결해야 할 구조적 제약입니다.
이 까다로운 환경에서 비즈니스 규칙을 어기지 않고 임무를 수행할 수 있을지 검토했던 과정을 소개해 봅니다. 실제 저희 검토 과정에서는 여러가지 비즈니스 시나리오를 생각해 보았지만 최종적으로 식당 예약 시나리오를 기준으로 합니다.
사용자가 전화를 걸어 AI와 통화는 하는 기본 시나리오로, 사용자가 원하는 시간대에 예약을 하는 과정이며,
간단한 문의 사항을 질의 할 수 있어야 하고
한번에 모든 예약 사항을 말해서 빠르게 예약하고 끝내거나 예약시 필요한 정보를 사용자가 원하는 순서로 채워나가는 방식으로 예약 확정에 도달할 수 있는 자유가 있어야 하고
잔여 좌석 같은 예약 정보를 가상으로 구현해 아무 시간대나 예약이 되는 것처럼 엉터리 데모는 만들지 않는다는 것입니다.
그리고 모든 구조는 STT -> 비즈니스 서비스 -> TTS 로 이어지는 파이프라인형태이며, “비즈니스 서비스”에 해당하는 부분의 구조입니다.
기존의 구현 방법
단일 LLM 에이전트
음성 통화 봇을 만들 때 가장 먼저 떠오르는 방법은 거대한 프롬프트에 비즈니스 규칙과 도구 호출(Tool Calling) 등을 몰아넣고, 단일 LLM이 통화 전체의 상태 판단과 응답 생성을 모두 책임지는 구조입니다.
이 방법에는 문제가 너무나 많았지만 무엇보다 업무를 끝까지 완수하려는 일관성이 부족했습니다.
예약이라는 명확한 목적이 있음에도 대화가 조금만 길어지면 엉뚱한 주제로 빠지기 일쑤였고, 날짜와 시간, 인원이라는 필수 정보를 순서대로 채워나가는 통제력을 잃어버렸습니다.
“친절하고 전문적인 예약 담당자” 같은 페르소나 설정은 아무런 의미가 없었습니다. 정작 필요한 업무 수행에는 전혀 도움이 되지 않고, 오히려 모델의 쓸데없는 수다와 자의적인 친절함만 부추겨 있지도 않은 정책을 지어내는 환각의 빌미가 되었습니다.
이런 붕괴를 막아보고자 여러 가지 프롬프트 엔지니어링 기법을 동원했습니다.
모델의 어텐션을 유지하고 지침 누락을 방어하기 위해 대화 턴마다 시스템 프롬프트를 동적으로 변경해 끼워 넣거나 대화 이력에 필요한 내용을 주입하는 방식을 사용했고, 턴마다 현재 상태를 외부에서 확인해 비즈니스 로직에 맞게 대응하도록 복잡한 출력 스키마를 강제하고 프롬프트 주입으로 보완하는 방식을 시험해 보기도 했습니다. 하지만 이러한 구현 방식의 시도는 상태 관리와 구현 복잡도만 증가시켰고, 텍스트 프롬프트와 백엔드 코드가 뒤엉켜 더 이상 진행하기 어려웠습니다. 게다가 수많은 수정으로 특정 모델에서 어느 정도 동작을 맞춰 놓더라도, 모델을 변경하게 되면 모든 제어가 무너졌습니다.
그리고 비즈니스 정책을 검수하겠다고 함수 호출을 남발하면 지연 시간이 발목을 잡습니다. 단순한 잔여 테이블 조회 하나를 처리하려 해도 도구 호출 판단을 위한 1차 추론, 백엔드 API 실행, 그 결과를 받아 최종 응답 문장을 작문하는 2차 추론까지 거쳐야 합니다. 이 과정의 지연 시간은 음성 통화에서는 허용하기 어려운 수준입니다.
워크플로우 도구
자연스럽게 다음으로는 단일 LLM이 모든 역할을 맡는 대신 비즈니스 흐름에 따라 상태를 나누고 각각 분리된 프롬프트와 LLM 제어 기법을 사용할 수 있는 워크플로우 방식을 검토하게 됩니다.
코드로 흐름을 강제하므로 안정적이고, 단계별 정보를 코드가 검증하므로 비즈니스 로직을 강조하면서 오동작 위험이 줄어들어 기본적인 단일 정보 입력 방식의 시나리오는 매끄럽게 넘어갈 수 있습니다.
하지만 이 방식은 본질적으로 기존의 번호를 선택해 누르는 자동응답(ARS) 방식과 크게 다르지 않습니다. 비록 LLM이라 자유도가 있다고 해도 버튼 대신 음성을 이용해 선택하는 느낌을 받게 됩니다.
여기서 AI라면 뭘 더 할 수 있는지 고민이 생깁니다. 예외 케이스를 생각합니다. 고객이 현재 AI가 요구하는 항목이 아닌 다른 내용을 말하는 경우, 정확하게 답변을 하지 않고 복수 선택을 하는 경우 등입니다.
사용자가 AI의 일방적 요구사항에 답변하는 대신 실제 통화처럼 자유롭게 말하기 시작하면 문제가 발생합니다.
단일 값 위주의 변수 스키마로는 다중 후보 입력을 유연하게 담기 어려워 예외를 담당하는 노드를 계속 늘려야 했고,
중간에 인원을 변경하거나
현재 단계에 맞지 않는 문의가 끼어들었을 때 문의 노드와 원래 진행 중이던 노드를 자연스럽게 오가는 전환 로직 등 이러한 예외를 억지로 구현하려다 보면 ‘왜 굳이 LLM을 쓰면서 코드와 프롬프트를 동시에 디버깅해야 하나’ 하는 회의감이 들 만큼 쉽지 않은 작업입니다. 구조 자체가 고객의 자유는 생각하지 않는 방식이니까요.
의도 판별기
워크플로우의 경직성을 피하고 사용자에게 자유를 주기 위해서 파이프라인 입구에 의도 판별기를 배치하는 방식을 사용할 수 있습니다.
여기서 의도 판별기는 단순히 발화의 의도만 포착해 다른 LLM에 넘기는 방식이 아니라, 예약 정보의 획득/갱신(슬롯 필링), 자연스러운 대화를 위한 의도 추출, 그리고 문의 사항을 다른 전담 LLM에 넘기는 역할까지 수행하도록 했습니다.
그리고 뒷단에서 LLM이 답변을 생성해 주는 대신, 의도 판별기가 채워 넣는 예약 정보 슬롯의 변화를 근거로 비즈니스 로직을 수행하는 코드를 작성하고 고정된 템플릿 위주로 응답하도록 구성했습니다. 이 방법을 통해 비록 답변은 기계 같긴 하지만 전체 지연 시간을 크게 줄일 수 있었습니다.
하지만 여기서의 문제는 또다시 의도 판별기 역할을 맡은 LLM의 응답 속도였습니다. 문장을 생성하지 않는 의도 판별기는 응답 속도가 빨라야 합니다. 하지만 한국어 구어체 의도 분류는 영어에 비해 훨씬 큰 모델이 필요했고 그만큼 느렸습니다.
음성 통화의 허용 속도를 맞추기 위해 한국어 지원이 우수한 가장 빠른 10B급 경량 LLM을 사용했으나, 실전에서는 여러 장벽에 부딪혔습니다.
이 작은 모델은 컨텍스트가 조금만 쌓여도 엄격한 JSON 출력을 유지하는 것조차 힘겨워했습니다. 결국 JSON을 포기하고 가벼운 자체 텍스트 포맷을 직접 구현해 사용해야 했습니다.
또한 슬롯에 엉뚱한 값을 채워 넣기 일쑤였습니다. 단일 값도 오류가 있는데, “내일이나 모레” 같은 다중 선택을 배열로 추출해 내는 것은 기대하기 어려웠습니다.
우여곡절 끝에 시나리오를 단순화하고 프롬프트를 수정하여 겉보기에 안정적인 수준을 만들어 보았지만, 경량 모델인 만큼 조금 어긋나면 오류가 생길까 하는 불안함은 남습니다. 그렇다고 인식률이 안정적인 상위 모델로 눈을 돌리면 지연시간이 크게 늘어나서 사용이 불가능합니다.
그래도 의도 판별기 및 답변용 경량 LLM을 해당 비즈니스 영역에 맞게 파인 튜닝하여 속도와 정확도를 보완한다면 이런 구조는 비즈니스에 적용할 수준이 될수 있다고 보았습니다. 의도 판별기가 대부분의 지능을 담당하면서 고객의 의도 판별 만을 수행하고, 명확한 코드로 실제 비즈니스 로직을 수행하기에 역할 분리가 잘 되고 로직 보완이 쉽기 때문입니다.
하지만 LLM튜닝은 데이터 확보부터 그 자체로 고부하 작업인데다 작은 모델의 튜닝은 부작용이 생길 수도 있는 한계가 있습니다. 동일한 예약용 인공지능임에도 비즈니스 영역이 바뀔 때마다 별도로 튜닝 해야 한다는 점 역시 큰 부담이었습니다.
jev를 의도 판별기로 사용하기
비생성형 판별 모델 jev는 생성형 LLM이 가진 비용과 지연 시간, 환각 문제를 피할 수 있는 매력적인 대안입니다. 특히 의도 판별기로 사용하기에 더없이 적합한 판별 모델의 특성을 갖추고 있습니다.
그러나 jev는 판별만 가능할 뿐, 문장에서 날짜나 인원수를 직접 추출해 내는 능력은 없습니다. 따라서 저희는 추출은 가벼운 전처리기가 담당하고, 추출된 데이터를 바탕으로 jev가 발화의 의도를 판단하도록 역할을 분리했습니다. jev가 담당하는 것은 전처리기가 추출한 후보를 이용하여 만들어진 선택지가 사용자의 발화 의도와 부합하는지 만을 판단하는 작업입니다.
Press enter or click to view image in full size
전처리 계층: 문장 정규화와 날짜 추출
STT가 생성한 불완전한 문장을 판별 모델에 곧바로 입력하지 않고, 1차 책임을 전처리 계층이 맡도록 했습니다. 원래 취지는 jev가 사용할 판단 재료만을 공급하는 역할이었으나, STT가 생성하는 문장을 1차로 정규화함으로써 STT 생성 문장의 오류와 jev가 지닌 한국어 인식의 한계 사이에서 완충 장치로 동작하도록 구성했습니다.
한국어 형태소 분석기인 Kiwi를 이용해 형태소 분석을 수행한 후 그 결과를 토대로 입력된 문장을 다듬습니다. 대표적으로 날짜, 시간 등의 표현은 정규화 해 놓지 않으면 판단에 오류가 발생합니다. 또한 이 과정에서 날짜와 관련된 단어들은 따로 추출/조합하여 jev가 판단할 수 있는 선택지로 별도 공급합니다. 또한 “내일 저녁”, “이번 주 금요일” 같은 상대적 표현은 시스템 시각 기준으로 명확한 날짜/시간 데이터로 변환하여 사용자의 발화와 함께 제공합니다.
모든 날짜 표현을 다 뽑아내는 이유는 형태소 분석만으로는 발화자의 의도를 알 수 없기 때문입니다. 가령 ‘화요일이나 수요일’ 같은 다중 선택인지, ‘화요일 아니 수요일이네요’ 같은 말 바꾸기인지는 jev가 판단할 수 있도록 발견되는 모든 날짜를 추출하여 전달합니다. 전처리 과정은 일반 서버에서도 밀리초 내에 끝나는 매우 빠른 작업입니다.
판별 계층: 대화 컨텍스트를 유지한 jev 판별
전처리기가 다듬은 문장과 추출한 데이터를 통해, jev는 본연의 강점인 ‘순수한 판별’에만 연산을 집중할 수 있습니다.
jev 역시 LLM과 마찬가지로 이전 대화 컨텍스트를 입력해 주면 최종 의도 판별이 더욱 정확해집니다.
jev가 판별하는 내용은 대략 다음과 같습니다. 사용자의 최종 발화 만을 대상으로 한다는 전제를 달아 놓고 다음과 같은 질문을 던집니다:
예약 항목을 새로 채우거나 변경하려는 의도가 있는가.
어느 날짜에 예약 의도가 있는가 (전처리기가 제공한 날짜를 선택지로 제공)
몇시에 예약 의도가 있는가 (가능 시간대 선택지 제공)
예약 인원수는 몇명인가 (인원수 선택지 제공)
예약 업무 외의 문의 사항이 있는가 (Bol)
모든 선택지에는 ‘해당 없음’과 같은 항목을 두어 종합적으로 최종 의도 판단이 가능하도록 합니다.
자체 테스트 결과, 문맥을 통한 의도 판별과 말 바꾸기 등 기존 LLM이 판별하던 내용들은 문제없이 판별해 냈습니다. 또한 경량 LLM에서는 제대로 수행하지 못했던 두 개의 복수 선택도 판별했습니다.
중요한 것은, 판별 능력만 놓고 보면 jev는 이전에 의도 판별기로 사용한 작은LLM보다는 더 상위 모델을 사용했을 때의 수준과 동일한 능력을 보인다는 것입니다.
결론적으로 LLM을 의도 판별기로 사용할 때 보다, 더 정확하게 판별하면서도, 질문지의 항목이 늘어나도 속도저하 없이 더 빠르고, 비용도 저렴했습니다.
복수 선택지 재질의
사용자가 복수 선택을 시도하면 단일 선택용 질문지 구조상 jev는 언급된 선택 항목에 매우 낮은 score를 매깁니다. 이를 토대로 사용자가 복수 선택을 했다고 단정하는 것은 결코 옳은 방법이 아니므로 선택지를 따로 생성하여 jev에 다시 질의하는 것이 정석입니다.
하지만 우리가 만드는 것은 음성 통화 서비스이므로 굳이 지연을 증가 시켜 가며 추가 질의를 할 필요가 없습니다. 에이전트가 낮은 score의 항목들을 후보로 고객에게 재 질문을 하게 하면, 어차피 이어질 대화를 통해 고객이 최종 선택으로 수정해 줄 것이므로 아예 잘못된 판별이라고 해도 업무 수행에 치명적이지는 않을 것이란 판단입니다.
로직상으로는 예약 항목 슬롯 자체가 배열에 정확도 속성을 가집니다. 이때 시스템은 임의로 하나를 특정해 넘기지 않고, 사용자에게 어떤 항목을 선택할지 되묻는 흐름을 구성합니다.
데모에서는 2개의 선택지까지 추출해 사용합니다. jev의 결과에서 복수 선택을 감지하면 시스템 코드는 실제 예약 장부를 확인하여 유효한 선택지만을 답변하도록 분기합니다.
내일과 모레 모두 잔여석이 있다면: “내일과 모레 둘 다 가능하신데요, 어느 날로 잡아드릴까요?”
내일은 마감이고 모레만 가능하다면: “내일은 마감되었고 모레 가능하신데, 모레로 진행해 드릴까요?”
이러한 답변 시나리오가 가능합니다. LLM 추론에 무리하게 의존하지 않고, 실제 비즈니스 업무에서 대화를 주고받으며 선택지를 좁혀나가는 구조입니다.
문의사항(FAQ)의 처리
예약 중간에 나오는 문의 사항(“주차 되나요?”, “아기 의자 있나요?”) 역시 기존에는 전담 LLM에 발화 문장을 전달하여 답변하고자 했습니다. 그 시간 동안 필러 음성을 송출해 시간을 버는 것은 불가피했습니다. 그러나 테스트 과정에서 간혹 치명적인 환각이 발생하는 문제가 있었습니다.
가령, 고객의 발화는 “내일 7시에 4명 갈 건데요, 혹시 주차는 되나요?”처럼 들어오는 경우,
전담 LLM에게 답변을 요구하기 위해 넘기는 입력 문장에는 주차 문의뿐 아니라 앞뒤의 날짜, 시간, 인원수 같은 온갖 단어들이 섞여 있습니다. 이 불필요한 단어들이 LLM의 주의를 분산시켜, 질문에는 답변하는 것과 동시에 묻지도 않은 예약 관련 답변을 지어내는 환각이 발생하곤 합니다.
또한 의도 판별기가 고객의 발화에 문의사항이 없는데도 문의사항이 있다고 오판한 경우, 문의 LLM이 예약 절차를 지어내서 답변하는 경우도 있습니다.
의도 판별기가 전담 LLM에 문의사항만 분리해 전달하는 방식은 의도 판별기의 지능이 높다면 가능한 일입니다. 하지만 의도 판별기는 빠른 응답을 위해 모델의 체급이 낮았습니다.
문의 사항에 대한 답변은 비즈니스 정책이 민감하게 적용되는 영역입니다. 애초에 LLM의 환각에 대비한 안전장치가 필수적인 영역이기도 하지만, 문의 전담 LLM으로 체급이 높은 모델을 사용하더라도 환각이 완전히 해소되지 않았으며 추가 비용이 발생하는 구조로의 보완은 바람직해 보이지 않습니다.
이를 해결하기 위해 문의사항 처리는 비용을 대폭 절감하는 다음과 같은 방식으로 구현했습니다.
매장이 미리 등록해 둔 표준 질문을 사전 임베딩하여 검증된 답변과 1:1 쌍으로 관리합니다.
jev는 발화 내에 문의사항이 포함되어 있는지 여부만 판별합니다.
문의가 감지되면 해당 발화 텍스트를 백엔드의 경량 ColBERT 모듈로 전달하여 유사한 질문이 있는지 확인합니다.
ColBERT의 토큰 단위 Late Interaction을 통해 복합 발화 내에서도 각 문의를 정확하게 매칭하고, 해당하는 정적 답변 텍스트들을 추출해 사용합니다.
단일 벡터 임베딩 API는 한 문장에 질문이 2개 이상 혼합되면 벡터가 평균화되어 엉뚱한 FAQ를 매칭하기 쉽습니다. 반면 ColBERT는 토큰 단위 매칭을 수행하므로, 사용자가 한 문장에서 주차와 아기 의자를 동시에 문의하더라도 언어 모델 없이 단 한 번의 연산으로 여러 개의 독립된 답변 텍스트를 매칭할 수 있습니다. 대규모 지식베이스에서의 토큰 단위 매칭은 매우 오래 걸리지만, 본 시나리오의 FAQ 수준에서 만들어 낼 수 있는 질문의 갯수는 수십~수백개 수준에 불과하므로 별 문제가 되지 않습니다.
텍스트 생성형 방식이 아닌 [ jev 감지 -> 경량 ColBERT 매칭 -> 검증된 정적 답변 획득 ] 으로 이어지는 방식을 사용하여 비즈니스 정책을 위반하는 답변 생성을 완벽히 차단하고 일반 서버에서도 수십 밀리초 수준의 빠른 답변 텍스트 추출 속도를 확보해 필러 음성 없이도 답변할수 있습니다.
비즈니스와 음성을 위한 추가 고려
발화를 위한 텍스트 추출까지는 위 단계에서 완료되었으며, 이제 발화할 텍스트를 조합해 TTS를 통해 송출하면 되는데, 이 과정에서 단문 조각들을 자연스러운 하나의 문장으로 합쳐서 내보내고 싶다는 생각이 들 수 있습니다.
물론 이를 위해 BART같은 생성형 모델을 학습시켜 사용하는 것을 고려해 볼 수 있겠습니다. 코드 레벨에서 연결될 문장을 고려해서 하드코딩하지 않아도 매끄럽게 다듬어 줄 수 있고, 단순한 문장 연결이라면 사실과 다른 내용을 지어내는 환각은 발생하지 않을 것을 기대할 수 있기 때문입니다.
그러나 비즈니스와 음성 통화의 고유한 특성을 고려해 몇 가지 추가적인 구조를 적용했으며, 이를 ‘AI의 비동기 발화’라 지칭할 수 있습니다.
텍스트 기반 채팅은 한 턴에 최대한 많은 정보를 제공하는 방식이 자연스럽습니다. 사용자가 여러 조건을 전달하면 AI 역시 긴 답변을 화면에 표시하고, 사용자는 이를 시각적으로 빠르게 훑어보면 됩니다. 이 과정에서 문장이 자연스럽게 연결되는 것은 매우 중요합니다.
반면 음성 통화에서는 이러한 방식보다는 ‘기계가 어색하게 말한다’는 느낌을 주더라도 짧고 빠르게 턴을 주고받으며 필요한 항목을 채워나가는 구조가 훨씬 자연스럽습니다. (물론 단일 문장이더라도 BART같은 생성 모델을 활용해 문장을 보다 다듬는 것이 나쁘지 않다고 생각합니다)
기존 LLM의 1:1 턴 기반 응답처럼 한 턴 안에 모든 제안과 답변을 한 번에 생성하는 것보다, AI의 발화를 분할하여 비동기 방식으로 순차 전송할 때 얻을 수 있는 이점은 다음과 같습니다.
사용자 발화 복창
텍스트가 제공되지 않는 음성 통화 환경에서는 AI가 사용자의 발화를 정확히 인지했는지 확인시켜 주는 복창(고객의 주문을 다시 읽는 행위) 기능이 매우 유용합니다. 이는 예약 정보 슬롯에 새로운 정보가 채워지거나 업데이트되는 시점에 수행되도록 구현했습니다. 만약 답변을 하기 위해 처리 시간이 소요되는 백엔드 작업이 수반된다면 이러한 복창은 유의미한 필러 음성Filler)의 역할도 겸하게 됩니다. (현재 데모는 단순화를 위해 매번 DB 조회를 거치지 않도록 구성되었습니다. )
이 지점에서부터 발화 텍스트를 기존의 1:1 턴 방식이 아닌 비동기 발화 방식으로 처리해야 할 필요성이 발생합니다. 단일 사용자 발화에 대한 응답이더라도 그 역할에 따라 발화 단위를 물리적으로 분할하여 순차적으로 송출하는 것입니다.
Press enter or click to view image in full size
발화 1 (복창/확인): 발화자의 의도를 판별하여 추출된 내용을 먼저 송출 합니다. 고객에게 “정확히 알아들었는지 확인해 달라는”는 신호를 빨리 주면서 동시에 침묵을 지우는 역할입니다.
발화 2 (조회 결과 및 역제안): DB에서 긁어온 잔여 좌석 시간대를 바탕으로 다음 선택지나 추가 슬롯을 채우기 위한 발화를 준비합니다. (데모는 고정 가용 시간을 응답합니다)
사용자 개입을 고려한 발화 중요도 제어
발화를 독립된 단위로 분할해 두면, 사용자가 AI의 발화를 끊고 개입하는(Barge-in) 상황에서 유연한 상태 제어가 가능해집니다. 모든 발화를 동일하게 취급할 경우, 사용자가 말을 끊었을 때 무조건 출력을 중단하고 입력을 수신하거나, 반대로 기계적으로 끝까지 읽어주는 경직된 동작에 그치게 됩니다. 이에 발화 큐에 적재되는 메시지마다 중요도를 부여했습니다. 문장의 특정 지점까지 사용자에게 재생되었음을 추적하는 원론적인 방식에 비해 구현이 용이하며 실무적으로 훨씬 유용합니다.
저중요도 발화: 가령 봇이 “내일, 10월 21일 수요일 점심 예약이시…”라고 복창하는 도중 고객이 “아, 1시로 해주세요”라고 끼어든다면, 기존 복창을 마저 재생할 필요가 없습니다. 시스템은 송출 중이던 오디오를 즉시 폐기하고, 고객이 방금 입력한 ‘1시’라는 새로운 슬롯 값 처리로 곧바로 전환합니다.
고중요도 발화: 반면 “내일 1시, 4분 예약 확정되었습니다”나 “해당 시간은 만석이라 예약이 불가능합니다”와 같은 중요한 발화는 고객의 단순 개입으로 인해 누락되어서는 안 됩니다. 이 경우 고객의 끼어들기를 처리한 이후에도 해당 핵심 상태를 다시 명확히 반복 송출하도록 코드로 강제합니다.
실전에서의 레이턴시 현실과 비용
프로덕션 환경에서 음성 파이프라인의 성패는 결국 현실적인 지연 시간과 비용, 그리고 유지보수성에서 결정됩니다.
한국어 처리가 우수한 가장 빠른 10B급 경량 LLM을 판별기(슬롯 필링)로만 활용하더라도 실제 지연 시간은 400ms에서 900ms 사이로 심하게 요동칩니다. 발화가 조금만 복잡해져 인식률이 안정적인 상위 모델을 적용하면 몇배의 지연을 감수해야 합니다. 반면 jev는 300ms ~ 500ms 선에서 안정적으로 판별을 완료합니다.
최근 주목받는 S2S(Speech-to-Speech) 모델들은 대형 LLM모델이 텍스트 대신 음성토큰을 직접 처리하면서 지연 시간을 크게 단축하긴 했습니다. 하지만 간과하지 말아야 할 점은 아키텍처 관점에서 S2S모델 또한 본질적으로는 1장에서 실패했던 ‘단일 LLM 에이전트’에 모든 것을 위임하는 구조와 다르지 않다는 사실입니다. 업무 처리 능력이 개선되었더라도, 거대한 블랙박스 하나에 예약 규칙과 도구 호출, 상태 전이를 통째로 맡기고 프롬프트 엔지니어링으로 제어하는 방식은 오작동과 비즈니스 정책 위반이라는 리스크에서 벗어나기 어렵습니다. 결정적으로 매우 높은 운영 비용이 비즈니스 도입의 가장 큰 장벽입니다.
판별 모델과 코드 기반으로 상태를 통제하는 구조에서는 추론 연산 비용이 극히 미미하여, AI 음성 통화 운영 비용의 대부분은 STT와 TTS가 차지하게 됩니다. 전체 인프라 비용을 예측 가능하고 안정적인 수준으로 유지할 수 있습니다.
코드로써 비즈니스 로직을 구현하는 과정이 어려워 보이거나 코드 땜질 투성이가 된다는 비난이 있을 수 있습니다. 하지만 프롬프트를 사용해서 비즈니스 로직을 구현하는 것은 훨씬 더 어렵고 가드레일 땜질과 운에 맡기는 일입니다. 요즘같이 AI의 도움을 받아 코드를 작성할 수 있는 환경에서는 AI가 극적인 도움을 주지 못하는 프롬프트 엔지니어링 보다는 코드로 비즈니스 로직을 만드는 것이 훨씬 쉽습니다. 코드 기반의 비즈니스 로직은 디버깅이 명확하고 수정과 검증이 빠르게 이루어 질 수 있습니다. 결과적으로 시스템 구축부터 운영, 유지 보수에 이르는 전 과정의 비용을 크게 절감하는 것을 기대할 수 있습니다.
실제 복합 발화 환경에서 jev가 어떻게 판단하고 시스템이 사용자 개입을 처리하는지는 아래 데모 링크를 통해 확인하실 수 있습니다. (한국어만 지원합니다)
[음성 예약 봇 데모 링크]
https://raixact.com/#live-demo2
[GeekNews 페이지 요약]
안녕하세요. 저희는 AI와 사람 간의 실시간 음성 통신 기술을 개발하고 있습니다. "단순 일상 대화가 아니라 식당 예약처럼 실제 비즈니스 업무를 수행하는 음성 에이전트를 만드는 게 가능한가?"라는 의문에서 출발해, 실제 데모를 구현하며 겪은 생성형 LLM의 한계와 이를 비생성형 판별 모델인 jev 중심의 파이프라인으로 해결한 과정 및 라이브 데모를 공유합니다. 실시간 음성 예약 데모 (한국어만 가능) : https://raixact.com 아래 요약본의 전체 전문 : Medium 왜 생성형 LLM을 걷어냈는가? (직접 구축하며 겪은 시행착오) 화면 UI가 없는 음성 통화는 1초 남짓한 침묵에도 사용자가 장애를 의심하며, 구어체 노이즈와 말실수, 변심이 실시간으로 들어옵니다