목록으로
AI

실시간 음성에서 "언제 멈출까"를 정하는 법

콜봇에게 말하는 도중에 끼어들 수 있는지는 통화 품질을 크게 가릅니다. 소리로 끊는 방식에서 시작해 무슨 말을 했는지까지 보고 끊는 방식으로 옮겨온 과정을 정리했어요.

2026-09-10

실시간 음성에서 "언제 멈출까"를 정하는 법

TL;DR

  • 사람 말을 끊을 수 없는 콜봇은 통화가 아니라 안내방송이 됩니다.
  • 소리가 들리면 재생을 멈추는 방식으로 시작했는데, 이러면 맞장구에도 봇이 멈춰요.
  • 그래서 소리로는 멈추지 않고, 그 소리가 무슨 말이었는지 확인한 다음에 멈출지 정합니다.
  • 의미를 알려면 기다려야 하고, 기다리는 사이에 통화 상황은 계속 달라져요.
  • 그래서 모든 발화를 그 말이 시작된 순간을 기준으로 해석합니다.

저희가 만드는 콜봇

대학 대표번호로 전화를 걸면 사람 대신 받는 AI 상담봇이에요. 학사 일정이나 장학금 문의를 듣고 안내하고, 필요하면 담당 부서로 연결해줍니다. 지금도 여러 기관에서 쓰이고 있어요.

전화에는 화면이 없어요. 앞으로 되돌려 다시 읽을 수도 없고, 두 사람이 동시에 말하면 양쪽 다 안 들립니다. 채팅에서는 신경 쓸 일이 없던 것들이 여기서는 설계가 필요한 문제가 돼요. 언제 말을 멈출 것인가도 그중 하나입니다.


끼어들 수 없는 콜봇

AI 콜봇에 전화를 걸면 순서가 대충 정해져 있습니다. 봇이 안내를 시작하고, 내가 궁금한 건 두 번째 문장쯤에서 이미 지나가고, 그런데도 나머지를 끝까지 듣게 되죠. 중간에 "아 그건 아니고요" 해봐야 봇은 하던 말을 마칩니다.

몇 번 겪으면 요령이 생겨요. 봇이 문장을 끝낼 때까지 기다렸다가 말하는 겁니다. 사람하고 통화하면서 이런 요령을 익힐 일은 없죠.

저희가 콜봇을 만들면서 초반에 붙인 것도 이 기능이었습니다. 막상 붙이려니 생각보다 고려해야 할 게 많더라고요.


목소리가 들리면 일단 멈춘다

처음 만든 방식은 단순했습니다. 통화 오디오에서 사람 목소리가 잡히는 순간 재생을 멈추는 거예요. 음성이 있는지 없는지 판별하는 기술은 오래됐고 가벼워서, 아주 짧은 주기로 계속 돌릴 수 있습니다.

이것만으로도 통화가 꽤 달라져요. 사람이 입을 열면 봇이 곧바로 조용해지니까, 적어도 안내방송처럼 느껴지지는 않습니다.


"네네"도 소리다

그런데 통화 기록을 보다 보니 이상한 장면이 자주 나왔어요.

봇 — 장학금 신청은 매 학기 초에 받고 있고요, 신청은 사람 — 네네 봇 — (멈춤) 사람 — ...네? 계속 말씀하세요

한국어 통화에서 사람이 내는 소리의 상당수는 "말을 자르겠다"가 아니라 "듣고 있어요"입니다. "네", "아 그렇군요", "네네" 같은 것들이요. 그런데 오디오 레벨에서 이건 진짜 끼어들기와 똑같이 생겼어요. 둘 다 사람 목소리니까요.

호응을 잘해주는 사람일수록 통화가 자꾸 끊겼습니다. 봇 입장에서는 말을 잘 들어주는 사람을 제일 자주 자르는 셈이었죠.

프롬프트를 고쳐서 될 일도 아니었어요. 멈출지 말지는 LLM에 닿기 한참 전에 오디오 레이어에서 결정되니까요. 소리는 무슨 일이 일어났다는 것만 알려주고, 그 사람이 무슨 의도였는지는 알려주지 않습니다.


이게 드문 장면이 아니에요. 최근 60일 통화에서 사람이 한 발화 5,717건 중 11.2%(641건)가 "네", "네네", "응" 한 마디였습니다. 열 번에 한 번꼴로 봇이 멈출 이유가 없는 자리에서 멈추고 있었던 거예요.

소리로 끊을 때·의미로 끊을 때·판정이 늦게 도착할 때를 같은 5초 구간 위에 나란히 그린 타임라인


그럼 무엇으로 끊어야 할까?

기준을 옮겼습니다. 소리가 들려도 재생은 그대로 두고, 그 소리가 무슨 말이었는지 확인한 다음에 멈출지 정하는 방식이에요.

사람 목소리가 잡히면 판정 대기 상태만 걸어둡니다. 음성 인식이 내용을 알려주면 맞장구인지 진짜 할 말인지 보고 결정해요. 맞장구면 봇은 하던 말을 이어가고, 할 말이면 그때 멈추고 새 발화로 받습니다.

이 방향 자체는 저희만의 발명이 아니에요. 요즘은 semantic VAD, turn detection, intelligent endpointing 같은 이름으로 여러 팀이 비슷한 결론에 닿고 있습니다.

설계에서 두 가지를 먼저 정했습니다. 하나는 판정을 본 응답과 분리한 것. 답을 만드는 모델은 바쁘고, 이 판정은 짧은 시간 안에 멈춤이냐 계속이냐 한 마디만 돌려주면 되는 일이라 따로 뒀어요. 다른 하나는 실패했을 때 어느 쪽으로 넘어질지 정해둔 것입니다. 판정이 늦거나 실패하면 봇은 계속 말합니다. 잘못 멈추는 쪽보다 잘못 계속하는 쪽이 통화에서 회복하기 쉬웠거든요.

끼어들기 판정 구조 — 소리는 판정 대기만 걸고 의미로 결정하며, 인식이 침묵할 때를 위한 안전망 경로가 따로 있다


기다리는 동안 상황은 계속 변한다

방향을 정하고 나서 마주친 문제들은 대체로 뿌리가 같았습니다. 의미를 알려면 기다려야 하는데, 기다리는 사이에 통화가 계속 흘러간다는 것.

인식 결과가 아예 안 올 때가 있어요. 회선 상태가 나쁘거나 봇 목소리가 섞여 들어오면 결과가 늦게 오거나 끝내 안 옵니다. 무엇을 보고 판단할지가 없는 거죠. 그래서 인식을 거치지 않는 경로를 하나 더 뒀어요. 사람이 충분히 오래 말하고 있으면 내용이 뭐든 재생을 멈춥니다. 이 정도로 계속 말하고 있으면 맞장구는 아니라는 상식을 규칙으로 옮긴 겁니다. 소리로 하던 판단은 이렇게 안전망 역할로 남았습니다.

문장이 끝나기를 기다리면 늦습니다. 음성 인식은 사람이 말을 마쳐야 결과를 확정해요. 확정된 문장만 보고 판단하면 "잠깐만요"라고 말한 사람이 봇이 멈출 때까지 한참을 기다립니다. 통화에서 그 정도 지연이면 이미 대화가 어긋난 뒤예요.

그래서 확정을 기다리지 않고 중간 결과를 계속 판단합니다. 인식은 사람이 말하는 동안 조금씩 길어진 텍스트를 계속 보내줍니다. 처음엔 "아"였다가 "아 제가"가 되고 "아 제가 장학금"이 되는 식으로요. 조각을 볼 때마다 새로 판정하고, 멈춰야 한다는 판정이 하나라도 나오면 그때 멈춥니다. 한 번에 정확히 맞히는 판단보다 계속 갱신되는 판단이 필요했어요.

판정이 도착한 시점에는 상황이 달라져 있을 수 있어요. 판정을 따로 돌리는 동안에도 통화는 흘러갑니다. 결과가 왔을 때 봇의 말은 이미 끝나 있을 수도 있고, 다른 경로가 먼저 그 발화를 처리했을 수도 있어요. 그 상태에서 멈추라는 판정을 그대로 적용하면 엉뚱한 문장을 자르게 됩니다.

그래서 판정 결과를 쓰기 직전에, 그 판정이 전제로 삼았던 상황이 아직 그대로인지 확인해요. 지금 멈추려는 말이 판정할 때 듣고 있던 그 말이 맞는지, 아직 소리가 나가고 있는지 같은 것들입니다.


같은 "네네", 다른 뜻

봇 — (안내 문장을 말하는 중) … 이때 사람이 "네네"를 시작 봇 — 담당 부서로 연결해드릴까요? (여기서 "네네"의 인식 결과가 도착)

사람은 앞 문장에 맞장구를 쳤습니다. 그런데 그 말이 확정돼 도착한 시점에는 봇이 이미 다음 문장을 말한 뒤예요. 판정 로직이 지금 봇이 무슨 말을 했는지를 기준으로 보면, 질문에 "네"라고 답한 것으로 읽게 됩니다. 사람은 연결해달라고 한 적이 없는데 말이죠.

음성 인식은 사람이 말을 마친 뒤에 확정되니까, 판정하는 시점과 말이 시작된 시점의 상황이 어긋나는 건 실시간 음성에서 예외적인 일이 아닙니다. 오히려 기본값에 가까워요.

그래서 원칙을 하나 세웠습니다.

모든 발화는, 그 말이 시작된 순간에 사람이 실제로 듣고 있던 것을 기준으로 해석한다.

이 원칙을 세우고 나니 흩어져 있던 문제들이 같은 자리에서 정리됐어요. 맞장구가 엉뚱한 질문에 붙어 해석되던 것도 결국 이 말이 어느 문장에 속하는지를 잘못 잡고 있던 거였습니다. 원칙 하나로 여러 개가 한꺼번에 정리될 때가 있는데, 대체로 그건 원래 같은 문제였다는 뜻이더라고요.


정리하면

끼어들기는 붙였느냐 안 붙였느냐로 끝나는 기능이 아니었습니다. 소리로 끊으면 맞장구에 멈추고, 의미로 끊으려면 기다려야 하고, 기다리는 사이에 상황이 변해요. 무엇으로 말을 끊을지가 통화 전체의 자연스러움을 결정하더라고요.

저희는 소리를 신호로 쓰고 의미로 결정하는 쪽으로 정리했습니다. 소리 기반 판단은 인식이 침묵할 때를 대비한 안전망으로 남겨뒀어요. 그 위에 발화를 시작 시점 기준으로 해석한다는 원칙을 얹으니, 판정이 늦게 도착해서 생기던 어긋남까지 같이 풀렸습니다.

지금 저희 콜봇은 사람이 "네", "아 그렇군요" 하고 호응해도 하던 안내를 계속하고, 진짜 요청이 들어오면 말을 멈추고 그 말을 받습니다. 사람이 봇의 말이 끝나기를 기다릴 필요가 없어요. 통화가 조금 더 사람 사이의 대화처럼 굴러갑니다.


같은 콜봇에서 만난 다른 문제도 하나 적어뒀어요. 봇이 금액과 전화번호를 잘못 읽는 문제, 그리고 그걸 LLM에게 맡겼다가 규칙으로 돌아온 이야기입니다. → 규칙으로 끝나는 일을 확률에 맡기지 마라