완벽한 전사(Transcript)라도 잘못된 통화일 수 있습니다: 음성 에이전트 평가하기
요약
음성 에이전트가 완벽한 전사(transcript)를 생성하더라도 실제 통화에서는 실패할 수 있는 문제를 해결하기 위한 평가 도구 'voiceeval'을 소개합니다. 텍스트 기반 평가의 한계를 넘어 타이밍, STT 오류, 실제 발화 내용(truth)을 비교하여 에이전트의 성능을 정밀하게 검증합니다.
핵심 포인트
- 전사(transcript)만으로는 음성 에이전트의 실제 통화 품질을 평가하기 어려움
- STT 오류로 인한 숫자 오인식 등 텍스트에 드러나지 않는 실패 사례 포착
- 타이밍 정보와 실제 발화(truth)를 포함한 JSON 기반의 평가 방식 제안
- 심각도(severity)에 따른 체커를 통해 에이전트의 상호작용 오류를 식별
저는 voiceeval이라는 작은 도구를 만들었습니다. 왜냐하면 저는 계속해서 똑같은 사각지대에 부딪혔기 때문입니다: 음성 에이전트(voice agent)가 결점 없이 읽히는 전사(transcript)를 생성하더라도, 실제로는 통화에 실패할 수 있다는 점입니다.
문제점
이것이 그 시작이 된 통화 내용입니다. 발신자가 환불을 요청합니다. 에이전트는 금액을 환불하고 그렇게 말했다고 말합니다. 전사를 읽어보면 모든 문장이 서로 일치합니다. 발신자는 50달러를 요청했고, 에이전트는 50달러를 환불했습니다, 끝입니다.
하지만 발신자는 **15(fifteen)**라고 말했습니다.
"Fifteen"과 "fifty"는 강세가 없는 음절 하나 차이입니다. 음성-텍스트 변환(Speech-to-text, STT)은 둘 중 하나를 선택하며, 에이전트는 자신이 받은 결과에 대해 정확히 동일한 확신을 가지고 행동합니다. 전사에 도달할 때쯤이면, 실수는 이미 고착화되어 내부적으로 일관성을 갖게 됩니다. 전사에는 실제로 무엇이 발화되었는지에 대한 기억이 없고, 발신자가 얼마나 기다렸는지에 대한 시계 정보가 없기 때문에, 이후의 어떤 단계(downstream)에서도 이를 알아챌 수 없습니다.
그것이 진짜 문제입니다. 만약 전사를 읽음으로써 음성 에이전트를 평가한다면, 당신은 단지 소리 내어 읽혔을 뿐인 텍스트 에이전트를 평가하는 것입니다. 발신자가 4초간의 침묵 중에 전화를 끊었을 때나, 에이전트가 확신을 가지고 잘못된 금액을 환불하여 아무도 알아차리지 못했을 때도 당신은 그 통화를 완벽하다고 점수를 매길 것입니다.
누구나 음성 에이전트를 데모할 수는 있습니다. 저는 제 에이전트가 점점 나빠지고 있는지 알려줄 무언가를 원했습니다.
핵심 아이디어
voiceeval은 통화를 실행하지 않습니다. 통화를 심판합니다. 당신은 타이밍이 포함된 턴(timed turns) 형태로 통화를 제공합니다. 각 턴에는 누가 말했는지, STT가 무엇을 들었는지, 언제 시작하고 멈췄는지, 그리고 발신자의 턴에 대해서는 선택 사항인 truth 필드(발신자가 실제로 말한 내용)를 포함합니다. 이 도구는 텍스트 평가(text eval)에서는 보이지 않는 일련의 체크 항목들을 실행하며, 각 사례별 심각도(severity)와 함께 결과(findings)를 반환합니다.
입력값은 의도적으로 단순한 JSON 형식으로 설계되어, 통화를 생성하는 무엇이든(LiveKit, Vapi, Twilio, 테스트 스크립트 등) 몇 줄의 연결 코드(glue code)만으로 이를 내보낼 수 있습니다:
{
"id": "refund-happy-path",
"policy": {"max_refund": 50},
...
작동 방식
통화에 대해 체커(checker)를 실행하면 심각도 순으로 정렬된 결과(findings)를 얻게 됩니다:
$ voiceeval check fixtures/misheard_call.json
FAIL refund-misheard-fifty (7s call)
...
두 가지 별개의 실패 사례가 발생했으며, 두 사례 모두 텍스트상으로는 보이지 않습니다.
첫 번째인 misheard_number는 해당 턴(turn)에 truth 필드가 포함되어 있었기 때문에 발생했습니다. 이 체크는 두 문자열을 정규화(normalise)하고, 만약 두 문자열이 다르면 각 측면에서 숫자를 추출하여 집합(set)을 비교합니다. 들린 숫자(heard numbers)가 말한 숫자(spoken numbers)와 일치하지 않으면 이는 심각도가 높은 '잘못 들은 숫자(misheard number)'로 분류됩니다. 에이전트가 잘못된 숫자를 바탕으로 행동하는 것은 음성 서비스에서 가장 비용이 많이 발생하는 실패이기 때문입니다. 만약 단어는 다르지만 숫자가 일치한다면, 이는 일반적인 중간 수준의 misheard로 등급이 낮아집니다.
두 번째인 no_confirmation은 단어 자체보다는 상호작용의 형태에 관한 것입니다. 이 체크는 턴(turn)을 따라가며 consequential(중대한 영향을 미치는)로 표시된 모든 액션을 찾고,
voiceeval run calls/*.json --label v1 -o v1.json
# ... 프롬프트(prompt) 변경 ...
voiceeval run calls/*.json --label v2 -o v2.json
...
--strict 옵션을 사용하면, 회귀(regression) 발생 시 diff가 0이 아닌 값으로 종료됩니다. 따라서 프롬프트 변경으로 인해 통과율(pass rate)이 조용히 떨어질 경우, 제품이 배포되는 대신 CI(지속적 통합) 단계에서 실패하게 됩니다.
한 가지 솔직한 한계점
잘못 들은 숫자(misheard-number) 체크는 truth 필드의 품질에 의존합니다. 발신자가 실제로 무엇을 말했는지에 대한 정답(ground truth)이 없다면, 구조적으로 잘못 듣는 현상을 감지할 수 없으며, 테스트 스위트에는 정확히 이 점을 문서화한 테스트가 포함되어 있습니다. 실제 운영 환경(production)에서 이러한 실패는 소리 없이 발생하며, 어떤 도구도 이를 대신 해결해 줄 수 없습니다. 이것이 스크립트 기반 테스트 호출(scripted test calls)을 권장하는 이유입니다. 피스처(fixture)에 정답을 한 번 제공하면, 체크 과정에서 STT(음성 인식)가 그 정답에 부합하는지 책임을 물을 수 있습니다. 만약 가공되지 않은 실제 운영 기록(raw production transcripts)만 가지고 있다면, 이 특정 체크는 비교할 대상이 없게 됩니다.
또한, 평가(eval) 로직이 프로젝트의 핵심이며 API 키나 네트워크 없이도 완전히 테스트된다는 점을 솔직하게 밝힙니다. 반면, 오디오를 시간 정보가 포함된 턴(timed turns)으로 변환하는 STT 어댑터(adapter)는 해당 테스트들로 검증되지 않습니다. 만약 귀하의 플랫폼이 이미 시간 정보가 포함된 전사(timed transcript)를 제공한다면, 이 부분은 건드리지 않게 됩니다.
마치며
voiceeval은 의도적으로 작게 설계되었습니다. 이 도구는 한 가지 일만 수행합니다. 시계와 실제로 말한 기록을 바탕으로, 발신자가 경험한 방식 그대로 음성 통화를 살펴보고, 전사(transcript)상으로는 통과한 것처럼 보여도 실제로는 실패한 통화가 무엇인지 알려줍니다. 만약 음성 에이전트(voice agent)를 출시하면서 전사 내용만 읽고 있다면, 15대 50의 통화 비율 문제는 이미 로그 어딘가에 '통과(green)'로 기록된 채 존재하고 있을 것입니다.
코드 및 피스처(fixtures): https://github.com/royalpinto007/voiceeval
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기