Голосовой AI в реальном мире: задержки, перебивания и другие грабли
Описание Практический разбор разработки голосового AI-оператора с архитектурой: MTT/Exolve → Asterisk → AudioSocket → STT → LLM → TTS На примере работающего проекта расскажу, как мы создавали роботов для холодного обзвона на базе локального AI и масштабировали систему до 30+ одновременных разговоров. Поговорим о том, как боролись с задержкой голоса, шумами и перебиваниями, снижали нагрузку на серверы, выбирали LLM и настраивали промты. Отдельно разберём решения, которые хорошо выглядели на бумаге, но не выдержали реальной эксплуатации, и подходы, которые сначала казались «костылями», но в итоге помогли довести проект до продакшена. Также расскажу, как полученный опыт мы использовали при создании IP-звонилки для Windows с AI-суфлёром для менеджеров продаж.
Тезисы - Архитектура голосового AI-оператора: от телефонии до STT, LLM и TTS. - Как уменьшить задержки, бороться с перебиваниями и шумами. - Как выбирать LLM и настраивать промты без потери скорости. - Как снизить нагрузку на серверы при 30+ одновременных разговорах. - Какие решения сработали в продакшене, а какие пришлось отбросить. - Почему временные «костыли» иногда оказываются лучшим практическим решением.
Коллеги, вопрос по тишине после 200 OK на объёме. Прошу проверить логику, всё своё уже перебрал.
Стенд: Asterisk 20.21 в докере, host network, предиктивный дайлер через ARI. Два транка, Билайн и МТС, alaw. Внешний детектор автоответчика работает петлёй: мы шлём INVITE детектору, он встречным вызовом набирает абонента через наш же транк.
Симптом. При темпе выше примерно 15 вызовов в секунду часть исходящих приходит с 200 OK, тарифицируется, а голоса после ответа нет. Это не «нет пакетов»: RTP идёт непрерывно, 50 пакетов в секунду, без потерь и без разрывов последовательности, один SSRC, в нагрузке alaw-тишина 0xD5. Громкость (RMS после декодирования, окно +1..+9 с от ответа) равна 8 из 32768 против 900-2400 на нормальных вызовах.
Зависимость от темпа резкая: до 15 вызовов в секунду доля таких вызовов около процента, на 15-20 — 21%, свыше 20 — 44%. Порог одинаковый у двух независимых операторов связи.
Что проверено на своей стороне и оказалось чистым: - Asterisk работает зеркалом: по вызовам с тишиной 95,9% «тишина на входе от оператора связи — тишина на выходе», медиана громкости 8 на входе и 8 на выходе, свои потери 2%; - сигнализация под нагрузкой: 2827 вызовов, повторных отправок 0%, задержка первого ответа 24 мс медиана и не растёт на пике, SDP приходит по всем отвеченным, адрес медиа единственный; - ICE на транках выключен, strictrtp = no, taskprocessors без очередей, CPU 3 ядра из 24; - ядро: ноль отброшенных и ноль переполнений буферов за трое суток, на интерфейсе ноль ошибок; - канал 546 Мбит/с, используется около пятой части; пинг до обоих операторов под нагрузкой 0% потерь, задержка не растёт.
Две детали, из-за которых и пишу:
1. У части таких вызовов КПВ (гудок от оператора связи) слышен нормально ДО ответа и пропадает ровно в момент 200 OK. То есть тракт был, и рвётся он именно на переключении на абонента. 2. С ростом темпа первым исчезает живой дозвон (доля живых разговоров падает втрое), а доля автоответчиков держится. Похоже, что вызовы, которые обслуживает платформа самого оператора связи, механизм не задевает, а те, где нужно доанкеровать медиа до абонента, — задевает.
Вопросы: 1. Сталкивался ли кто-то с таким на объёме? Это переанкеровка медиа на их SBC/медиашлюзе под нагрузкой, антифрод, CAC по CPS — или что-то ещё? 2. Как правильно формулировать запрос оператору связи, чтобы не получить «вызов доставлен и оттарифицирован, у нас всё хорошо»? Какие доказательства они реально принимают: pcap с нашей стороны, список Call-ID с временем, что-то ещё? 3. Отдельно про петлю детектора автоответчика: при одном и том же среднем темпе прямой набор в транк даёт 6-11% вызовов без звука, а через петлю — 37%. Есть подозрение, что петля рвёт равномерность и мгновенный темп на транке становится всплесками. Кто-нибудь мерил мгновенный CPS на транке корзинами по 100-200 мс и видел разницу с тем, что показывает свой дайлер?
Дампы обоих плеч и сигнализации есть, готов показать выдержки.
Коллеги, вопрос по тишине после 200 OK на объёме. Прошу проверить логику, всё своё уже перебрал.
Стенд: Asterisk 20.21 в докере, host network, предиктивный дайлер через ARI. Два транка, Билайн и МТС, alaw. Внешний детектор автоответчика работает петлёй: мы шлём INVITE детектору, он встречным вызовом набирает абонента через наш же транк.
Симптом. При темпе выше примерно 15 вызовов в секунду часть исходящих приходит с 200 OK, тарифицируется, а голоса после ответа нет. Это не «нет пакетов»: RTP идёт непрерывно, 50 пакетов в секунду, без потерь и без разрывов последовательности, один SSRC, в нагрузке alaw-тишина 0xD5. Громкость (RMS после декодирования, окно +1..+9 с от ответа) равна 8 из 32768 против 900-2400 на нормальных вызовах.
Зависимость от темпа резкая: до 15 вызовов в секунду доля таких вызовов около процента, на 15-20 — 21%, свыше 20 — 44%. Порог одинаковый у двух независимых операторов связи.
Что проверено на своей стороне и оказалось чистым: - Asterisk работает зеркалом: по вызовам с тишиной 95,9% «тишина на входе от оператора связи — тишина на выходе», медиана громкости 8 на входе и 8 на выходе, свои потери 2%; - сигнализация под нагрузкой: 2827 вызовов, повторных отправок 0%, задержка первого ответа 24 мс медиана и не растёт на пике, SDP приходит по всем отвеченным, адрес медиа единственный; - ICE на транках выключен, strictrtp = no, taskprocessors без очередей, CPU 3 ядра из 24; - ядро: ноль отброшенных и ноль переполнений буферов за трое суток, на интерфейсе ноль ошибок; - канал 546 Мбит/с, используется около пятой части; пинг до обоих операторов под нагрузкой 0% потерь, задержка не растёт.
Две детали, из-за которых и пишу:
1. У части таких вызовов КПВ (гудок от оператора связи) слышен нормально ДО ответа и пропадает ровно в момент 200 OK. То есть тракт был, и рвётся он именно на переключении на абонента. 2. С ростом темпа первым исчезает живой дозвон (доля живых разговоров падает втрое), а доля автоответчиков держится. Похоже, что вызовы, которые обслуживает платформа самого оператора связи, механизм не задевает, а те, где нужно доанкеровать медиа до абонента, — задевает.
Вопросы: 1. Сталкивался ли кто-то с таким на объёме? Это переанкеровка медиа на их SBC/медиашлюзе под нагрузкой, антифрод, CAC по CPS — или что-то ещё? 2. Как правильно формулировать запрос оператору связи, чтобы не получить «вызов доставлен и оттарифицирован, у нас всё хорошо»? Какие доказательства они реально принимают: pcap с нашей стороны, список Call-ID с временем, что-то ещё? 3. Отдельно про петлю детектора автоответчика: при одном и том же среднем темпе прямой набор в транк даёт 6-11% вызовов без звука, а через петлю — 37%. Есть подозрение, что петля рвёт равномерность и мгновенный темп на транке становится всплесками. Кто-нибудь мерил мгновенный CPS на транке корзинами по 100-200 мс и видел разницу с тем, что показывает свой дайлер?
Дампы обоих плеч и сигнализации есть, готов показать выдержки.
мне не нравится такая тема. давайте ее где-то обсудите, где у меня нет банхаммера