I made my voice agent slower on purpose
개요
실시간 음성 AI 영업 교육 플랫폼은 사용자가 AI 구매자와 연습할 때 발생하던 AI의 발언 중단 문제를 해결하기 위해 음성 에이전트의 처리 속도를 의도적으로 늦추고, 예기치 못한 연결 끊김 문제로 인한 '듣지 못하는' 상태를 수정했습니다.
주요 내용
* AI의 발언 중단 문제: 기존 파이프라인은 너무 빨라서 사용자의 발언이 끝나기 전에 AI가 끼어들어 대화를 방해했습니다. 이는 빠른 처리 속도가 오히려 부정확한 발화 종료(endpointing) 결정으로 이어져 문제를 심화시킨 결과입니다.
* Endpointing과 파이프라인 지연 시간의 관계: 일반적으로 파이프라인 지연 시간을 최적화하는 데 중점을 두지만, 실제로는 발화 종료(endpointing) 설정이 사용자 경험에 더 큰 영향을 미칩니다. 파이프라인 속도를 줄이면 발화 종료 오류가 덜 눈에 띄게 됩니다.
* 수정 내용:
* Endpointing 설정 조정: VOICE_EOT_THRESHOLD를 0.5에서 0.7로, VOICE_EOT_TIMEOUT_MS를 700ms에서 1200ms로 늘렸습니다. 이로 인해 AI의 응답이 약 0.5초 늦게 나오지만, 자연스러운 대화 흐름으로 인식됩니다.
* 처리 시간 분리: 처리 p95(95번째 백분위수)는 1초 미만으로 유지하되, 사용자의 대기 시간을 '경청 인내심'으로 별도 관리하여 두 가지를 혼동하지 않도록 명확히 구분했습니다.
* TTS 청킹: 첫 번째 TTS 요청을 문장 전체가 아닌 4~8 토큰 단위로 분할하여 보내고, 최대 250ms 대기 시간을 설정함으로써 사용자에게 응답 속도 향상 효과를 제공합니다.
* 두 번째 버그: AI가 '듣지 못하는' 문제: Deepgram Flux 웹소켓이 예기치 않게 끊어질 때, 오류 감지 및 재연결 로직이 제대로 작동하지 않아 AI가 응답을 멈춘 상태에서도 계속 대화하는 것처럼 보이게 했습니다.
* 문제 원인: _startup_error 래치(latch)가 일단 설정되면 영구적으로 적용되었고, 감시자(watchdog)가 작동 중단 상태를 인지하지 못했으며, 실제로는 연결이 끊어졌음에도 _is_connected()는 참을 반환했습니다.
* 수정 내용: 래치는 첫 연결 성공 전에만 작동하도록 변경하고, 연결 끊김을 감지하면 _is_connected()가 거짓을 반환하도록 했습니다. 또한, 재연결 시도 시 유예 기간을 설정하고, 연결 끊김 시 감시자가 다시 활성화되도록 수정했습니다.
* 로깅 정책: 오류 발생 시 경고, Sentry 오류 1회, 복구 시 총 중단 시간 정보 등을 기록하여 문제 상황을 효과적으로 파악하도록 했습니다.
시사점
사용자는 단순히 빠른 응답 속도보다 사용자가 말을 끝까지 마칠 수 있도록 하는 자연스러운 대화 흐름을 더 중요하게 여깁니다. 실시간 음성 시스템 개발 시, 파이프라인 지연 시간과 발화 종료(endpointing) 로직을 분리하여 관리하고, 장기 실행되는 웹소켓 연결의 잠재적 끊김을 고려한 견고한 오류 처리 메커니즘을 구축하는 것이 중요합니다. 또한, 성능 지표를 제시할 때는 반드시 백분위수(percentile)를 명시해야 사용자 경험을 정확하게 반영할 수 있습니다.
댓글
GitHub Discussions