Голосовой агент on-prem: закрытый контур и полсекунды
TL;DR: Голосовой аватар ломается там, где разговор перестает быть разговором: ответ запаздывает, агент говорит поверх человека, рот не попадает в звук, видеокарта задыхается. Дальше - исследовательская архитектура закрытого контура: как мерить задержку, ловить конец реплики, гасить старые ответы через
generation_idи проверять все живым звуком.
![]()
Микрофон, конец фразы, ранний ответ, стоп-сигнал и мимика живут в одном номере ответа.
В живом разговоре пауза между репликами составляет примерно 200 миллисекунд: такова кросс-языковая медиана в работе Stivers et al. 2009. Машине нужно распознать речь, придумать ответ, озвучить его и пошевелить губами аватара в тот же момент, когда пользователь слышит звук. Вопрос в том, насколько далеко можно отставать, чтобы разговор не умер.
На бумаге голосовой агент выглядит простой цепочкой: пользователь сказал, модель ответила, синтез озвучил. На живом микрофоне цепочка превращается в систему реального времени: пользователь делает паузы посреди мысли, перебивает, ловит эхо собственных колонок, меняет формулировку на середине - и ждет поведения собеседника. Автоответчик с правильным текстом тут проигрывает: он поздно понимает конец реплики, говорит поверх пользователя или шевелит ртом на 150 ms раньше звука.
Эта статья о закрытом контуре: без облачных API, на своем железе, с проверяемой приватностью. rula здесь лабораторный стенд: источник цифр, провалов и архитектурных гипотез. Публичный адрес ai.igor-ya.ru показывает интерфейс; продуктовая топология остается локальной.
Что такое on-prem голосовой агент
В этой статье on-prem голосовой агент - это система, где микрофон, распознавание речи, LLM, синтез, аватар, метрики и журналы работают внутри локального периметра. Закрытый контур означает, что аудио, расшифровки и модельные артефакты не уходят в облачный API, а релиз проверяется технически: сеть, лицензии, контрольные суммы, задержка и длительный прогон.
Базовая цепочка выглядит просто: речь -> STT -> LLM -> TTS -> звук и мимика. Инженерная сложность появляется в промежутках: когда считать реплику законченной, что делать при перебивании, как выкинуть старый звук, как не дать рту аватара уехать от голоса и как держать несколько моделей на одной GPU.
Исследовательский стенд rula
Стенд нужен, чтобы не писать статью из общих слов. В контуре стоят LiveKit/WebRTC, Silero VAD, GigaAM-v3, Qwen3-14B-FP8 через vLLM, Qwen3-TTS, Audio2Face-3D и VRM-аватар. Железо - одна RTX 5090 32 GB.
Ключевые измерения: когда система решила, что человек закончил мысль; когда появился первый звук; что произошло при перебивании; насколько рот попал в слышимый звук; выдержала ли видеокарта общий пик нагрузки.
Почему on-prem голосовой агент сложнее облачного
В облаке часть сложности спрятана у провайдера: сеть, масштабирование, лицензии моделей, запас видеокарт, журналы и эксплуатация. В закрытом контуре все это становится частью приемки. Аудио и расшифровки не покидают периметр, веса и образы сверяются по контрольным суммам, исходящий трафик запрещается проверяемо, юридические подтверждения по моделям и голосу собираются до релиза.
Самая практичная разница - видеокарта. В облаке распознавание, LLM, TTS и мимика могут жить на разных ресурсах. В on-prem варианте они часто давят друг друга на одной карте, и средняя задержка ничего не обещает: ломается p95.
Рыночная рамка тоже полезна. Облачные speech-to-speech системы покупают низкую задержку ценой чужого дата-центра: по сводке Softcery с опорой на Artificial Analysis весной 2026 время до первого звука у лидеров лежало примерно от 0.78 s до 3 s. Локальная цель 600-700 ms агрессивна, но физике не противоречит: сетевой путь до провайдера исчезает, взамен приходит жесткая дисциплина железа.

Закрытый контур: звук входит в локальный периметр, а внешний облачный путь заблокирован.
Три архитектуры: быстрый голос, управляемый каскад и гибрид
К 2026 году сложились три архитектуры.
| Архитектура | Где сильна | Цена |
|---|---|---|
| Native speech-to-speech | минимум ручной склейки, естественный полнодуплексный разговор, интонации | меньше прозрачности, сложнее аудит и замена компонентов |
| Каскад STT -> LLM -> TTS | контроль, наблюдаемость через расшифровку, локальные модели, отладка по фазам | последовательный бюджет задержки, трудно чистить старые куски ответа, нужен общий контракт состояния |
| Гибрид | речевой входной тракт плюс явный текстовый контур для инструментов и политики | больше движущихся частей, сложная сверка состояний |
Руководство OpenAI по голосовым агентам разводит speech-to-speech и цепочку как разные способы строить агента; LiveKit поддерживает оба пути. Speech-to-speech выигрывает там, где главный критерий - естественность разговора. Каскад выигрывает там, где нужны локальные веса, проверяемая расшифровка, заменяемость компонентов, юридические подтверждения по каждому артефакту и возможность передавать куски озвучки в расчет мимики. Для закрытого русскоязычного контура каскад пока остается самым управляемым стартом.
Один номер ответа вместо хаоса после перебивания
Пользователь перебил агента, агент вроде замолчал, а через полсекунды в браузер доехал старый кусок звука или мимики. Это гонка между текстом, звуком, лицом и памятью диалога.
Практика, которая выдерживает такие гонки: каждое событие несет session_id, turn_id, generation_id, состояние ветки, порядковый номер и время внутри ответа. При перебивании generation_id увеличивается. Все, что пришло со старым номером, можно считать в метриках, но нельзя озвучивать, показывать лицом или записывать как услышанное.
Такой контракт важнее конкретной модели. Он позволяет агрессивно начинать ответ до финального подтверждения реплики: если гипотеза верная, экономятся сотни миллисекунд; если человек продолжил говорить, старая ветка просто не имеет права попасть к пользователю.
Почему полсекунды набегают из мелочей
Пользователь слышит только итог: собеседник ответил живо или завис. Инженеру нужна трасса по фазам: конец речи, старт раннего ответа, подтверждение конца реплики, первый токен модели, первый кусок озвучки, первый звук, конец воспроизведения.
| Метрика | Цель профиля | Прогон: 119 реплик / 15 мин | Статус |
|---|---|---|---|
| Первый звук p50 | 600-700 ms | 947.3 ms | не проходит |
| Первый звук p95 | <= 1100 ms | 1504.7 ms | на границе провала релиза |
| Подтверждение конца реплики p95 | <= 250 ms в старом профиле | 826.2 ms | порог некорректен |
| Спекуляция, доля попаданий | >= 70% | 90.6% | проходит |
| Устаревшие кадры после перебивания | 0 | 0 | проходит |
| Невосстановленные ошибки | 0 | 1 | не проходит |
Здесь легко ошибиться в трактовке. E2E-прогон может быть зеленым как проверка жизнеспособности: ответы приходят, старые кадры не показываются, сессия не развалилась. Latency acceptance строже. По сохраненному 15-минутному soak ранний старт и отбрасывание старых событий уже работают, а пользовательская задержка еще за пределами цели.
Отдельный вывод - пороги тоже надо ревьюить. Цель 250 ms для подтверждения конца реплики ниже минимальной тишины 256 ms в быстрой ветке, поэтому сама формулировка метрики спорная.
Вторая находка - двугорбое распределение первого звука. Быстрый кластер около 85 ms возникает на детерминированных ответах из кэша. Основной путь живет в районе 700-1500 ms. Если смешать их в одной медиане, график украшает себя кэшем и прячет боль p95. Практика: считать первый звук по классам ответов.
Третья находка - инференс-инженерия решает не меньше выбора модели. Ранний ответ стартует после ~128 ms тишины, первый кусок TTS ограничен короткой фразой и дедлайном 280 ms, CUDA-графы дают коэффициент реального времени 0.29-0.43. Обычный режим исполнения около 1.8 уже не держит воспроизведение.
Как понять, что человек закончил мысль
Конец реплики нельзя надежно вывести из одной тишины. Рабочая схема состоит из трех слоев: VAD отвечает, есть ли речь; пороги тишины дают первичное окно; семантический или аудиодетектор решает, закончена ли мысль.
Сдвиг рынка хорошо виден по Turn Detector v1.0 от LiveKit, вышедшему 17 июня 2026: модель слушает речь напрямую и объединяет акустический и смысловой сигнал. Для закрытого контура особенно интересна облегченная v1-mini с открытыми весами и CPU-инференсом.
В реактивной политике стенда быстрое подтверждение включается после ~256 ms тишины только при пунктуации и минимум трех словах; обычное - после ~384 ms; незаконченные хвосты вроде “потому что” ждут до ~1152 ms. Это компромисс против ранних срабатываний русского распознавания: GigaAM может поставить точку там, где человек еще не закончил мысль.
Как агент должен уступать слово
Когда человек начинает говорить поверх агента, первая обязанность системы проста: перестать мешать. Полная остановка ответа может подождать проверки, но звук должен уступить место быстро. Поэтому barge-in делится на две фазы: раннее приглушение и подтвержденная остановка старого ответа.
Одна метрика здесь слишком грубая. Старая проверка мерила путь от начала речи пользователя до полной очистки воспроизведения и дала p95 477.9 ms при пороге 300 ms. Но пользователь слышит первую реакцию раньше: приглушение срабатывает примерно через 128 ms устойчивой речи. Поэтому нужны две метрики: уступка хода, где разумный p95 <= 200 ms, и полная очистка состояния, где разумный p95 <= 600 ms.
VAD сам по себе не отличает пользователя от эха колонок. Кандидат на остановку проверяется распознаванием: пустая расшифровка отклоняется, команды “стоп” и “хватит” принимаются сразу, сильное пересечение с текущим ответом считается эхом. В терминах OpenAI Realtime это три разные операции: response.cancel, output_audio_buffer.clear и conversation.item.truncate. Их надо связывать одним контрактом, иначе агент будет помнить фразу, которую пользователь не слышал.
Рот аватара должен попадать в слышимый звук
Потоковый TTS надо резать на речевые фрагменты: первый короткий, чтобы быстрее зазвучать, следующие - до границ предложений. Практический смысл шире красоты речи: длинный первый фрагмент двигает весь ответ вправо, слишком мелкая нарезка звучит как склейка.
Мимика считается от синтезированного звука через Audio2Face-3D. Точку отсчета надо брать из момента, когда браузер реально начал воспроизведение. WebRTC, буферы, AudioContext, bluetooth-наушники и политика autoplay двигают звук у каждого пользователя по-своему.
Поэтому сервер отправляет кадры мимики с pts_ms, а клиент ставит точку отсчета по энергии входящей звуковой дорожки. Ошибка тогда ограничена шагом детектора, обычно десятками миллисекунд, вместо догадки о сетевой задержке.
Одна видеокарта, пять моделей и p95
Закрытый рантайм на одной видеокарте проваливается по p95, если планировать его по средней задержке компонентов поодиночке. Надо планировать совместное проживание: STT, LLM, TTS, VAD и мимика борются за память, вычисления и тепловой бюджет.

Одна GPU держит сразу несколько трактов, поэтому p95 ломается раньше средней задержки.
| Решение в профиле | Практический смысл |
|---|---|
gpu_memory_utilization: 0.50 для vLLM |
0.49 оказался ниже минимума KV-кэша для Qwen3-14B-FP8 в этой сборке; 0.50 - нижнее подтвержденное рабочее значение |
min_free_vram_gb_after_load: 1.5 |
готовность падает закрыто, если после загрузки моделей не остается запаса |
| KV-кэш в FP8 | экономия видеопамяти для локальной модели |
| Кэширование префикса | меньше повторной работы на стабильном системном промпте |
Тепловой режим - архитектурное ограничение. Если карта уходит в устойчивый сброс частот, короткая демонстрация выглядит нормально, а длинный прогон деградирует. Поэтому готовность проверяется не только первым звуком, но и ростом памяти, невосстановленными ошибками и температурой.
Один удачный разговор ничего не доказывает
Голосового агента нельзя принимать по одному удачному диалогу. Нужна матрица проверок: задержка, перебивание, устаревшие события, длительный прогон, air-gap, лицензии, тепловой режим. По сохраненным артефактам стенда ранний старт и старые кадры уже выглядят хорошо, но latency-gate и полноценный 60-минутный soak еще не доказаны.
Отдельная находка - цена публичного демо-пути через VPS:
| Путь | Реплик | Первый звук p50 | Первый звук p95 |
|---|---|---|---|
| Локальный контур | 119 | 947.3 ms | 1504.7 ms |
| Публичный путь через VPS | 10 | 1688.2 ms | 3947.9 ms |
Туннель годится для доступа к демо, но не должен становиться частью целевого закрытого контура. Проверять систему нужно безголовым участником комнаты: он публикует заранее сгенерированную речь, слушает ответ, ловит события аватара и считает процентили. Текстовые тесты не ловят jitter, эхо, провалы буфера и рот, уехавший от звука.
Девять способов сломать голосового агента
Самая полезная часть исследования - дефекты, которые удалось изолировать.
- Отправка данных внутри звукового цикла. Симптом: заикание посреди слова. Лечение: подачей звука владеет один компонент, лицо и метрики уходят с критического пути.
- Жадное декодирование в TTS. 30 секунд шипения вместо 4-секундного предложения. Сэмплирование обязательно, кэш замораживает удачную реализацию.
- Доверие пунктуации распознавания. Агент отвечает до конца мысли, потому что распознавание охотно ставит точку после фрагментов. Быстрое подтверждение - только при пунктуации и минимум трех словах.
- Перебивание только по VAD. Эхо колонок срезает ответ агента. Нужен строгий порог во время речи агента плюс проверка расшифровкой.
- Бесконечное ожидание воспроизведения. Состояние реплики зависает. Бюджет ожидания считается от собственной шкалы звука, очередь чистится по таймауту.
- Синхронизация по времени отправки. Рот едет относительно звука, потому что серверное время не равно времени воспроизведения. Точка отсчета - на клиенте, по реальному началу звука.
- Дырки по 20 ms при провале буфера. Речь режется пулеметом. Лучше одна пауза до восстановления буфера.
- Микросервисы на критическом пути. p95 растет, остановка ответа рассинхронизируется. Модульный монолит держится до измеренного давления масштаба.
- Юридическая и air-gap проверки “потом”. Закрытый контур остается лозунгом без подтверждений, контрольных сумм и офлайн-прогона. Проверки закрыты по умолчанию с первого дня.
Эти дефекты маскируются под нормальную модель: текст может быть хорошим, а пользователь все равно слышит обрывки, эхо и видит уехавший рот. Поэтому готовность голосовой системы проверяется по поведению звука и лица вместе с качеством текста.
Итог: где тут настоящая инженерия
Голосовой агент в закрытом контуре - система реального времени. Ее надо проектировать вокруг фаз задержки, номера ответа, двухфазного перебивания, мимики по фактическому звуку и конкуренции за одну видеокарту.
Стенд подтвердил скелет: ранний ответ дает 90.6% попаданий, устаревшие кадры не доходят до пользователя. Он же показал недоказанные места: p95 первого звука 1504.7 ms в 15-минутном soak, прогон короче требуемого, часть порогов надо пересмотреть. Исследовательская ценность как раз в этой карте узких мест.
Смежные контуры уже разобраны отдельно: voice AI для контакт-центра, выбор между агентом и workflow, evals для LLM-агентов, релизные гейты MLOps и production-логи как данные для post-training.
Источники
- Rula GitHub repository
- LiveKit: Solving end-of-turn detection - Turn Detector v1.0
- LiveKit turn detector docs
- LiveKit: Configuring Turn Detection and Interruptions
- OpenAI: Voice agents guide
- OpenAI: Realtime conversations
- Softcery: Real-Time S2S vs Cascading Voice Agent Architecture
- NVIDIA: Audio2Face-3D GitHub
- NVIDIA Audio2Face-3D-v3.0 model card
- NVIDIA: open-sourcing Audio2Face
- Silero VAD GitHub
- GigaAM GitHub
- Qwen3-14B-FP8 model card
- vLLM OpenAI-compatible server docs
- Stivers et al. 2009: Universals and cultural variation in turn-taking in conversation
- ITU-T J.248 appendix referencing ITU-R BT.1359 lip-sync thresholds
- MDN: RTCInboundRtpStreamStats jitterBufferDelay
- W3C WebRTC Stats
- OpenTelemetry GenAI semantic conventions
FAQ
Что такое голосовой агент в закрытом контуре?
Это голосовой AI-агент, у которого микрофонный поток, распознавание речи, LLM, синтез, аватар, метрики и журналы работают внутри локального периметра. Аудио и расшифровки не уходят в облачный API, а релиз проверяется через air-gap, лицензии, задержку, GPU-профиль и длительные прогоны.
Когда on-prem голосовой агент лучше cloud API?
On-prem лучше, когда аудио, расшифровки, модельные артефакты и логи должны оставаться внутри периметра, когда нужен проверяемый air-gap или когда сетевой путь до облака съедает бюджет задержки. Цена этого выбора: команда сама отвечает за расчет GPU, юридические подтверждения, checksums, наблюдаемость и релизные проверки.
Почему для закрытого контура часто выбирают cascaded STT -> LLM -> TTS?
Каскадная схема дает контроль над каждым слоем: распознаванием, диалоговой моделью, озвучкой, аудитом текста, лицензиями, локальным инференсом и мимикой аватара. Speech-to-speech модели быстрее и естественнее, но в закрытом русском контуре сложнее получить прозрачность, заменяемость компонентов и юридические подтверждения.
Какие метрики нужны для релиза голосового realtime-агента?
Минимум: первый звук p50/p95 по классам ответов, задержка подтверждения конца реплики, отдельные метрики уступки хода и полной очистки при перебивании, доли ранних и поздних срабатываний, speculative hit rate, устаревшие кадры после перебивания, провалы буфера звука, рассинхрон звука и лица, WER, стабильность длинного прогона, рост памяти и результат юридической и air-gap проверок.
Что такое first-audio latency в голосовом агенте?
First-audio latency - это время от конца реплики пользователя до первого слышимого звука ответа. Для голосового агента это более важная пользовательская метрика, чем время полного ответа модели, потому что именно она определяет ощущение живого диалога.
Что такое barge-in?
Barge-in - это способность пользователя перебить агента во время его речи. Хорошая реализация сначала быстро приглушает звук, затем проверяет, что это не эхо собственного ответа, и только после этого очищает очередь звука, останавливает генерацию и выравнивает память диалога.
Почему мимику аватара надо привязывать к воспроизведению?
Пользователь видит лицо в момент, когда браузер реально проигрывает звук. Сервер может отправить кусок озвучки раньше, а jitter в WebRTC, буферы браузера, AudioContext, bluetooth и политика autoplay сдвигают воспроизведение. Поэтому кадры лица должны идти с pts_ms, а клиент должен ставить точку отсчета по реально услышанному началу звука.