Чому голосовий AI перебиває людей: як ми відмовилися від зв’язки VAD + ASR + Turn Detector і скоротили фальстарти на 98%

— Загальна сума становитиме... е-е...

Людина на тому кінці дроту робить паузу — звичайну людську паузу, бо щось рахує подумки. За кількасот мілісекунд наш агент вирішує, що репліку завершено, і починає говорити. Людина продовжує фразу. Далі — те, що в логах називалося recovery: агент замовкає на півслові, людина збивається, обоє починають заново, і десь у цій метушні губиться цифра, заради якої ми й телефонували.

Найнеприємніше: система автоматичного розпізнавання мовлення (ASR, Automatic Speech Recognition) розпізнала всі слова правильно, LLM згенерувала змістовну відповідь, система синтезу мовлення (TTS, Text-to-Speech) озвучила її природно. Кожен компонент був «зеленим» на дашборді — а розмова вийшла поганою.

Мене звати Єгор, я Data Scientist у DATAFOREST і працюю над голосовим AI-агентом для вихідних дзвінків, який повністю веде діалог у реальному часі. У цій статті я розповідаю, як ми тестували два підходи до визначення кінця репліки (end-of-turn detection) і чому кожен із них уперся в стелю. Вона не лише для тих, хто будує voice-агентів: дві головні історії тут — про те, як межі pipeline тихо викидають інформацію, потрібну наступному компоненту, і про proxy-метрику, яка після зміни архітектури почала означати щось інше.

Усе, що ми робили далі, крутилося навколо одного питання: як системі визначити не момент, коли людина замовкла, а момент, коли вона справді передала слово?

Ми акуратно розв’язували не ту задачу

У першій версії ми звели це питання до тривалості паузи: якщо людина мовчить достатньо довго, агент може відповідати. Таке припущення природно вкладалося в канонічний pipeline:

Audio — VAD — ASR — Turn Detector — Agent (LLM — TTS)

VAD розмічає, де є мовлення. ASR перетворює його на текст. Turn Detector у першій версії — по суті, таймер: якщо тиша триває довше за silence_threshold, вважаємо репліку завершеною. Схема дешева, кожен компонент оцінюється окремо — і саме тому дефект довго лишався невидимим.

VAD відповідає на питання «чи є мовлення в поточному фрагменті аудіосигналу?». Ми ж із його допомогою намагалися відповісти на інше питання — «чи завершила людина думку?». Перше питання стосується наявності мовлення, друге — наміру співрозмовника. Самої паузи недостатньо, щоб визначити, чи людина завершила думку.

  • «Так.»
  • «Я, мабуть...»

Після обох може бути 600 мс тиші. Для VAD ці 600 мс ідентичні. Для співрозмовника вони означають протилежне.

Люди роблять це інакше. У дослідженні turn-taking на матеріалі десяти мов найтиповіші переходи між репліками припадали на інтервал 0–200 мс. Водночас психолінгвістичні оцінки часу, потрібного на підготовку мовленнєвої відповіді, дають понад 600 мс — це вже інша лінія досліджень, не та сама робота. Арифметика не сходиться — і не має сходитися: люди не чекають на тишу, а прогнозують кінець репліки й починають готувати відповідь заздалегідь. Наш pipeline працював як silence — detect — think — respond; людина — як predict — prepare — respond. Ми не робили те саме, тільки повільніше — ми робили інше.

І пауза сама несе зміст: затримки близько 700 мс і довші асоціюються з відповідями, що суперечать очікуваному розвитку розмови — відмовою, незгодою, відповіддю із застереженням. Крутячи silence_threshold, інженер змінює не лише швидкість системи, а й соціальну семантику діалогу.

Налаштування порога не усуває проблему

Низький поріг — швидкий, але нахабний бот. Високий — ввічливий, але повільний. Адаптивні правила трохи допомагають, але ускладнюють конфігурацію.

Але це не проблема неправильного числа. Один скаляр намагається описати людей із принципово різними мовленнєвими патернами: того, хто читає номер з документа, того, хто думає вголос, того, хто нервує. Правильного числа не існує, бо воно залежить не від системи, а від співрозмовника в конкретний момент.

Галузь рухається в тому самому напрямку: OpenAI Realtime поряд зі Server VAD пропонує Semantic VAD із динамічним очікуванням, а AssemblyAI поєднує семантичне визначення кінця репліки з налаштовуваними межами тиші. Фіксований поріг нікуди не зник — але дедалі частіше стає не єдиним критерієм, а одним із сигналів або fallback-механізмом.

Ми додали семантику — і це допомогло менше, ніж мало б

Нашим наступним кроком теж було додати семантику. Якщо тривалість паузи не пояснює, чи людина завершила думку, можливо, це підкаже зміст її слів. Так з’явилася друга версія:

Audio — VAD — ASR — text-based end-of-turn classifier — Agent

Класифікатор отримує транскрипт з кількома попередніми репліками й оцінює завершеність. І він справді вловлює різницю — це не був поганий підхід. Зовнішні результати показують той самий напрямок: перша текстова EOU-модель LiveKit у внутрішньому тестуванні зменшила ненавмисні перебивання на 85% порівняно з VAD-only, а рік по тому LiveKit повідомив уже про 39,23% відносного зниження false-positive interruption rate між двома версіями текстової моделі за фіксованого TPR. Це різні бази й різні методики — складати ці відсотки не можна. Але обидві цифри свідчать про покращення, і ми теж побачили позитивний ефект.

А потім якість перестала зростати, і один клас помилок не зник узагалі: пауза-роздум усередині незавершеної думки, де текст уже виглядає граматично завершеним; продиктована цифра, після якої людина звіряється з документом; фрази, після яких людина явно збиралася додати «але». Плюс класифікатор справно успадкував усі нюанси STT: сорок два проти 42, помилки й затримку транскрипції.

Ми дали моделі семантику — саме те, чого бракувало VAD. Чому ж ефект такий обмежений?

Тому що потрібну інформацію ми викинули двома кроками раніше

Щоб зрозуміти цю межу, треба подивитися, що саме доходило до класифікатора. Ми додали йому зміст слів, але не включили до вхідних даних інформацію про те, як людина їх вимовила. А саме там могла бути різниця між завершеною думкою і паузою перед продовженням.

Необроблений аудіосигнал містить pitch contour, динаміку інтенсивності, тривалість складів, темп, точний таймінг пауз і — коли він акустично помітний — шум вдиху. До текстового класифікатора доходять переважно слова. Іноді — пунктуація, яку відновив ASR.

«Гадаю, я візьму це.» — спадний завершальний контур, подовжений фінальний склад

«Гадаю, я візьму це...» — незавершальний контур, інша ритміка й динаміка перед паузою

Дві акустично різні репліки — ідентична транскрипція. Жодна кількість параметрів цього не виправить: проблема не в ємності моделі, а в браку інформації у вхідних даних.

Тут важливо не спрощувати: проблема не в тому, що ASR «поганий». Типовий ASR оптимізований насамперед на якісну транскрипцію, тому його текстовий вихід не зберігає значної частини акустичної інформації, не потрібної для розпізнавання слів. Помилка була наша: downstream-задачі знадобилася саме ця втрачена частина.

Дослідження turn-taking показують, що єдиного сигналу «людина договорила» не існує: синтаксична й прагматична завершеність, pitch, інтенсивність, подовження фінального складу, дихальні цикли — а в очному спілкуванні ще й погляд та жести — працюють сукупно, і ймовірність передачі слова зростає, коли кілька з них збігаються. У телефонному каналі візуальних сигналів немає взагалі, тож акустичні стають важливішими: у нас менше надлишковості. VAD бачив одну проєкцію цього простору, текстовий класифікатор — іншу. Жоден не бачив збігу. LiveKit пізніше назвав це структурною межею текстового EOT.

Ми намагалися розв’язати мультимодальну задачу, залишивши класифікаторові лише транскрипт, а від акустики — грубий VAD-сигнал про наявність мовлення.

І це урок не про голос. Розділяючи ML-систему на етапи, ви визначаєте, яка інформація втрачається на кожному переході. Наслідки цього рішення непомітні — аж до моменту, коли наступній задачі знадобляться саме ці втрачені дані.

Що ми змінили — і чому не зробили цього одразу

Для нас із цього випливала конкретна вимога до наступної версії: зберегти акустичні ознаки до моменту рішення про кінець репліки й поєднати їх зі змістом та контекстом розмови. Замість ще одного налаштування детектора ми змінили шлях, яким інформація доходить до нього.

Різниця не в тому, що «модель краща»: рішення про кінець репліки тепер враховує одночасно три речі — що людина сказала, як вона це сказала і як розвивалася розмова. Схожий принцип fusion уже застосовують production-моделі: LiveKit Turn Detector v1 поєднує семантичну й акустичну гілки перед end-of-turn prediction, і транскрипт для самого рішення йому не потрібен. Важлива відмінність: їхня v1 працює лише з поточним user turn і навмисно відмовилася від попередніх реплік — тобто це підтвердження ідеї fusion, а не саме нашої схеми з conversational context.

Питання «а чому одразу так не зробили?» знімає хронологія ринку: текстовий EOT-трансформер LiveKit — грудень 2024; fused Conversational Speech Recognition (Deepgram Flux) — жовтень 2025; audio-native Turn Detector v1 — червень 2026. Коли ми проєктували першу версію, готових до використання audio-native-рішень ще не було. Тож ми обирали не між pipeline і audio-native, а між pipeline і відсутністю придатної альтернативи. Згодом, коли такі рішення стали доступними, ми перейшли до іншого підходу. Тому чесне формулювання: ми вперлися в стелю архітектури, яка до того справді працювала.

Як ми перевіряли

Нова схема усувала виявлене обмеження, але ще належало перевірити, чи покращує вона саму розмову. Для цього було недостатньо послухати кілька вдалих дзвінків: ми паралельно запустили дві версії на реальному трафіку й рандомізували на рівні дзвінка. Часове вікно, промпти, LLM і TTS були однаковими. Телеметрію впровадили в обох версіях до розподілу трафіку. Усі метрики рахували як середні в межах дзвінка, а потім порівнювали між двома групами.

Такий дизайн давав змогу порівняти версії, але залишалося визначити, що саме вважати покращенням. Оскільки початкова проблема була в зірваному ритмі діалогу, ми обрали поведінкові метрики, які фіксують перебивання та фрагментацію реплік:

  • перервана репліка бота — репліка бота не закінчується кінцевим розділовим знаком, оскільки її було перервано посеред речення;
  • заїкання бота — урізана репліка, що складається лише з кількох символів: бот був перебитий людиною ще під час першого-другого слова, через що виник фальстарт, який сприймається як збій;
  • фрагмент репліки людини — репліка починається з розділового знака або малої літери, що характерно для мовлення, перерваного посеред фрази.

Жодна з них не є еталонною оцінкою якості розмови. Однакове визначення дає змогу механічно порахувати їх для обох версій — але це ще не гарантує однакової інтерпретації: якщо архітектура змінила вікно, у якому подія взагалі може статися, та сама формула починає вимірювати щось інше.

Результати

Метрика

Зміна

Перервані репліки бота

—57%

False starts бота

—98%

Фрагментовані репліки людини

—73%

Це відносні зміни. Важливо, що три поведінкові метрики зрушили в узгодженому напрямку. Водночас це не три незалежні докази: false start і обрізана репліка бота можуть породжуватися одним і тим самим збоєм взаємодії.

Зменшення збоїв на боці бота ще не пояснює, що змінилося для співрозмовника. Тому далі ми подивилися на людські репліки: середня кількість слів у них зросла приблизно на 66%, а кількість самих реплік на дзвінок зменшилася приблизно на 20%. Довші репліки та менша їх кількість на дзвінок — це саме те, чого треба очікувати, коли перестаєш перебивати людей посеред речення. Якщо перемножити коефіцієнти цих змін — 1,66 × 0,80 ≈ 1,33 — отримаємо орієнтир у +33% більше слів користувача за один дзвінок. Це арифметика над двома середніми, а не пряме вимірювання приросту загальної кількості слів на дзвінок: добуток середніх може відрізнятися від середнього добутку.

Тому за цим розрахунком не можна визначити, яку частку мовлення втрачав старий детектор. Довші репліки та менша їх кількість узгоджуються з тим, що система стала рідше розривати мовлення людини. Водночас користувачі могли отримувати більше простору й говорити довше. Ці дані не дають змоги відокремити зміну сегментації від зміни поведінки людей.

Парадокс latency: компонент став утричі повільнішим, а хвіст end-to-end — коротшим

Ці зміни поставили наступне питання: якою ціною система дає людині більше часу завершити думку? Довше чекати перед відповіддю здавалося неминучим компромісом, і ми були готові піти на більшу latency заради ввічливості. Вийшло інакше: сам end-of-turn detection став утричі повільнішим на медіані, end-to-end медіана майже не змінилася, а P90 покращився більш ніж на 40%, P95 — на третину.

Trace breakdown пояснив чому. Старий pipeline мав локальне рішення з низькими обчислювальними витратами, але спричинені ним помилки дорого обходилися всій системі:

Помилкове спрацювання детектора кінця репліки (хибний EOT) — передчасний старт TTS — людина продовжує — barge-in— скасування TTS і генерації — recovery — повторний inference

Це не плюс 50 мс, а повний додатковий раунд. У нашому експерименті медіана відображала типовий сценарій, а значну частину P90/P95 формували recovery paths після хибного EOT. Це не універсальний закон — хвіст може формуватися й мережею, і чергами, і мінливістю часу обробки в STT і TTS. Але в нашому трафіку домінував саме цей механізм, і оптимізація самої лише медіани приховувала ціну помилок.

Ширший урок: latency компонента і latency взаємодії — різні задачі. Друга включає вартість скасування хибних рішень. Якщо у вашій системі є що відкочувати — скасована генерація, retry, fallback — шукайте хвіст саме там, а не в повільному компоненті.

Метрика, яка «погіршилася», бо система стала кращою

Із latency ми побачили, як уповільнення одного компонента може супроводжуватися прискоренням взаємодії. Інший показник виявив ще одну пастку: після зміни архітектури звична метрика могла змінити сам зміст.

Показник «користувач продовжив говорити до першого слова бота» ми рахували від VAD-endpoint — моменту, коли людина фактично замовкла, — до першого слова бота. У новій системі він зріс у кілька разів.

Це прямий наслідок виправлення. Нова архітектура довше витримує паузу до рішення про кінець репліки, тобто вікно між зупинкою мовлення і відповіддю бота стало ширшим, і люди ним користуються, бо не договорили. У старій системі число було низьким не тому, що люди не хотіли продовжувати, а тому, що бот встигав заговорити раніше. Метрика вимірювала не «чи правильно ми визначили кінець», а ширину вікна, яке ми залишаємо відкритим.

Тут критична точна часова прив’язка: якби той самий показник рахували не від VAD-endpoint, а від фінального EOT-рішення, зростання пояснювалося б зовсім інакше. Порівнювати raw rate між версіями можна лише тоді, коли exposure window визначене однаково.

Proxy-метрика відображає не лише явище, яке вас цікавить, а й процес вимірювання та умови, за яких спостереження взагалі може виникнути. Змініть процес — і може змінитися навіть напрямок зв’язку proxy з реальною якістю.

Практично: після зміни архітектури визначення та інтерпретацію кожної метрики треба перевіряти заново, перш ніж порівнювати дашборди. Інакше ви відкотите вдале рішення, бо графік почервонів. Разом із +66% слів і —20% реплік цей показник дає три числа, сумісні з гіпотезою, що нова система дає людині більше простору завершити думку — сумісні, але самі по собі її не доводять.

А може, річ просто в сильнішій моделі?

Ця межа між спостереженням і поясненням стосується всього експерименту. Результати показують, що змінилося після переходу, але залишають два питання: яку частину виграшу дала саме архітектура і наскільки великий ефект стоїть за відносними відсотками.

«Виграш дала не архітектура, а просто новіша модель». Повністю відокремити ці фактори в нашому експерименті не можна. На користь архітектурного пояснення свідчить те, що найбільше зменшилися саме помилки, у яких транскрипти однакові, а акустика різна. Але це аргумент, а не доказ. Для чистої перевірки потрібен контрольний експеримент: навчити й оцінити ту саму модель за тією самою схемою, але без доступу до акустичних ознак.

«—98% — занадто гарно». Базова частота цієї події була на порядок нижчою, ніж в інших поведінкових метрик. Тому відносне зниження на 98% виглядає драматичніше за абсолютний ефект. Найінформативніші показники тут усе одно не —98%, а P90 і приріст слів на репліку.

З урахуванням цих обмежень із кейсу все ж можна винести практичні правила: що перевіряти на межах компонентів і як оцінювати результат, коли змінюється вся взаємодія. Для нас таких правил чотири.

Чотири уроки

  1. Не плутати спостережуваний сигнал із задачею. VAD не був поганим — він відповідав саме на своє питання: чи є в сигналі мовлення. Поганим було припущення, що цього достатньо для нашого питання.
  2. Дивитися, що гублять межі pipeline. Для кожного стику випишіть, що на ньому стає недоступним назавжди.
  3. Інтегрована модель змінює потік інформації, а не лише один компонент. Тому оцінювати її треба і component-level, і end-to-end метриками: наш EOT-детектор став утричі повільнішим, і за його власною метрикою це регресія, хоча взаємодія покращилася.
  4. Після зміни архітектури схему evaluation треба переглянути, а не механічно переносити. Метрика, яка «погіршилася», іноді сумісна з покращенням системи — якщо змінився процес, що її породжує.

Висновок

Ми починали з питання «який таймаут поставити після VAD». Універсальної правильної відповіді на нього немає. Справжнє питання: як оцінити, чи завершила людина комунікативну дію? Для цього корисні акустичні й просодичні сигнали, семантика та контекст розмови. Не обов’язково обробляти їх однією монолітною моделлю — модульна система теж працює, якщо потрібні представлення доживають до точки fusion.

Визначення кінця репліки — мультимодальна задача. Текст добре передає семантику, аудіо — просодію й точний таймінг, контекст допомагає інтерпретувати обидва. Ми програли першу спробу не тому, що обрали модульність, а тому, що викинули один із каналів надто рано.

Збереження цього каналу усунуло конкретне обмеження нашої системи. Але навіть із доступом до аудіо залишаються складніші ситуації: одночасне мовлення та виправлення користувача вже під час відповіді агента. Тому наш результат — лише один крок у ширшій задачі turn-taking: Full-Duplex-Bench-v2 показує, що full-duplex системи досі плутаються під час одночасного мовлення і мають труднощі з коректною обробкою виправлень користувача. Дослідження вже просунулися далі: SHANKS дає мовленнєвій моделі змогу формувати внутрішні міркування, поки користувач ще говорить, і, схоже, наступне покоління взагалі перестане вважати EOT бар’єром між «слухати» і «думати». Тобто зробить те, що робить людина.

Питання до спільноти: де для вас проходить межа між модульністю ML-системи і втратою контексту між її компонентами? І чи траплялася у вас метрика, яка після зміни архітектури почала означати щось інше?

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті

👍ПодобаєтьсяСподобалось17
До обраногоВ обраному6
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

А не розглядали варіант замінити ваш кастомний каскад (VAD -> ASR і т.д.) на speech-to-speech LLM типу AWS Nova 2 Sonic (чи gpt-realtime-2 чи Gemini Live тощо)?

Так, тестували. Але це half-duplex моделі, у яких turn-taking не нативний — перед генерацією стоїть той самий VAD чи semantic VAD, що й у каскаді, але його не замінити. Також у S2S моделей є два обмеження, які для нас були критичні: фіксований LLM backbone, який плаває на складних інструкціях і сценаріях, та фіксований TTS, що обмежує контроль над голосом, вимовою й темпом тим, що дає вендор.

Але це half-duplex моделі

Чому half-duplex («walkie-talkie» режим, обробка починається тільки після того, як юзер закінчив говорити)? Там же (в AWS Nova 2 Sonic наприклад) bidirectional WebSocket-based audio streaming — бот і говорить, і слухає, його можна перебивати, він замовкає і відповідає на новий інпут.

той самий VAD чи semantic VAD, що й у каскаді, але його не замінити

Тут так, там повний black box.

Також у S2S моделей є два обмеження, які для нас були критичні: фіксований LLM backbone, який плаває на складних інструкціях і сценаріях

Ну до речі той же AWS Nova 2 Sonic допускає архітектуру, де speech-to-speech модель робить тільки STT/TTS, і завжди смикає один і той же tool, за яким може бути будь-яка інша LLM для основної логіки (якщо Sonic недостатньо «розумний»).

фіксований TTS, що обмежує контроль над голосом, вимовою й темпом тим, що дає вендор.

Тут, звісно, справа смаку/вимог, але звучать ці speech-to-speech моделі вельми добре/натурально, покраще ніж багато TTS варіантів (хоча може і гірше ніж Elevenlabs).

Там же (в AWS Nova 2 Sonic наприклад) bidirectional WebSocket-based audio streaming — бот і говорить, і слухає, його можна перебивати, він замовкає і відповідає на новий інпут.

Так, але це про інтерфейс взаємодії з моделлю, AWS у своїй документації називають його «full-duplex streaming interface». Сама модель half-duplex.

AWS Nova 2 Sonic допускає архітектуру, де speech-to-speech модель робить тільки STT/TTS, і завжди смикає один і той же tool, за яким може бути будь-яка інша LLM для основної логіки

GPT Live 1 теж використовує цей підхід, коли S2S модель може делегувати певні завдання іншим LLM, але це підходить для ситуацій, коли треба зробити певні фонові дії та отримати результат. У багатокрокових та складних сценаріях моделі необхідно надати коректну відповідь якомога швидше, а логіка формування відповідей через виклик LLM тулою створює зайвий хоп та збільшує затримку.

Дуже інформативно, дякую!

Правильно я зрозумів, що у новій версії класифікатора ви додали audio encoder:
На вході PCM/audio, далі він переводить сигнал у Mel-spectrogram / audio embedding, і цей acoustic representation разом із текстом подається у classifier?

— Як ви організовували fusion акустичних і семантичних ознак? І чи спостерігали, що модель занадто покладається на один із цих сигналів, наприклад на текст замість акустики?

— Це повністю ваша модель, чи ви використовували готовий / audio encoder і вже поверх нього робили EOT classifier?

— Чи пробували запускати двох агентів у voice-to-voice loop, щоб оцінити якість end-to-end діалогу? Цікаво, чи відрізняється якість розмови залежно від tone of voice і чи допомагає такий підхід виявляти проблеми, які не видно за метриками?

Крута стаття, дякую!

Дякую за відгук та запитання!

Була використана пропрієтарна модель одного з ASR вендорів, яка з одного аудіопотоку віддає і транскрипцію, і сигнал кінця репліки, тому свою модель не тренували і не дотреновували, робота була в діагностиці, чому перші підходи впиралися в стелю і в методології оцінки на реальному трафіку.

Щодо fusion ознак: архітектура моделі не публічна, тому можна оцінити лише поведінку моделі. Якби модель домінантно спиралася на текстові ознаки, то кейси з однаковою транскрипцією і різною інтонацією нікуди б не поділися, а вони майже зникли. Другим непрямим доказом є довший етап визначення кінця репліки на медіані, тобто модель чекає на щось, чого в тексті немає. Щоб перевірити перекіс у зворотний бік, треба ізолювати акустику від тексту.

По Voice-to-Voice тестуванню: так, робили перед виходом у прод. Це добре ловить низку інтеграційних проблем, але саме проблему виявлення кінця репліки воно не показало. TTS видає чисті завершені фрази, які мають термінальну просодію, а проблеми були саме на паузах посеред думки та незавершеній інтонації. SSML теги придатні для тесту на «чи спрацює turn detection у відомій паузі», але не для оцінки, оскільки це тестування власних припущень про те, як звучить вагання. І поведінка моделі, навченої на людській мові, не гарантує ту саму поведінку на синтетичних паузах — і це працює в обидва боки.

Щодо тону голосу: у Voice-to-Voice змінювали персон, а не просодію, і згоден, що це цікаво, але радше для оцінки реакції LLM частини системи на роздратованого чи невпевненого співрозмовника. Для задачі turn detection все-таки ключова варіативність саме в ритмі, і поки що її краще дають живі люди, ніж синтез.

Потужно та інформативно