Технологии

Ключевые слова, эмбеддинги или LLM: как понять, что сказал абонент

← Все статьи

Робот спрашивает: «Придёте завтра на приём?» В сценарии три ветки — «да», «нет», «перезвонить позже». А человек на том конце говорит: «ну я постараюсь, но если только после обеда».

Вот в этом зазоре и живёт вся сложность интерактивного обзвона. Распознавание речи отработало идеально — текст на руках, слово в слово. Осталась мелочь: понять, что человек имел в виду. Это отдельная задача, и решают её принципиально разными способами.

Речь ≠ смысл

Первое, что стоит развести: распознавание речи (STT) и классификация намерения — это два разных этапа, и второй нельзя получить бесплатно вместе с первым.

STT превращает звук в строку. Всё. Дальше у вас есть текст «ну я постараюсь, но если только после обеда» и список веток, по которым надо пойти. Соединить одно с другим — работа, которую кто-то должен сделать: или ваш код, или отдельная модель.

«Да» — легко, ровно то, что ждали
«Ага, конечно» — синоним, но уже не дословный
?«Ну да, наверное» — согласие с сомнением
?«А чё, надо прям?» — вопрос вместо ответа
?«Я не против» — двойное отрицание = согласие
«Да не, не приду» — начинается с «да», означает «нет»

Последняя строка — любимая ловушка. Наивный поиск слова «да» в тексте уверенно отправит человека в ветку согласия, и завтра его будут ждать в клинике.

Четыре подхода

1 Точное совпадение по словам

Вы перечисляете ожидаемые слова для каждой ветки, система ищет их в распознанном тексте. Никакого машинного обучения — обычный поиск подстроки.

Работает мгновенно, стоит ноль, полностью предсказуемо и отлаживается глазами: видно, какое слово сработало и почему. На коротких закрытых вопросах закрывает большую часть ответов — люди в разговоре с роботом действительно чаще отвечают односложно.

Ломается на: синонимах, которых нет в списке, отрицаниях («да не»), развёрнутых ответах и любой фразе, до которой автор сценария не додумался.

2 Нечёткое сравнение

Тот же поиск, но умнее: слова приводятся к начальной форме («придёте», «приду», «придём» → один корень), считается расстояние между строками, чтобы пережить оговорки и огрехи распознавания.

Всё ещё быстро и бесплатно, всё ещё объяснимо. Заметно расширяет охват по сравнению с дословным поиском, особенно на русском с его склонениями.

Ломается на: том же, на чём и первый подход. Морфология — это про форму слова, а не про смысл. «Я не против» и «я против» отличаются одной частицей, а значат противоположное.

3 Эмбеддинги и векторное сравнение

Здесь начинается смысл. Модель превращает фразу в вектор — набор чисел, положение которого отражает значение, а не написание. Вы заранее считаете векторы для эталонных фраз каждой ветки, а на звонке ищете ближайший к тому, что сказал абонент.

Главный плюс — перефразировки. «Ага, конечно», «разумеется», «а как же» окажутся рядом с «да», хотя ни одной общей буквы там нет. Модели такого класса небольшие, их реально держать у себя, и тогда данные не покидают периметр — весомый аргумент, если у вас медицина или финансы.

Цена вопроса: инфраструктура. Модель надо где-то держать, обновлять, мониторить, а качество на вашем домене — проверять самим. И принципиальное ограничение остаётся: близость векторов не понимает контекста вопроса. «После обеда» одинаково близко и к «приду», и к «перезвоните позже» — а правильный ответ зависит от того, что именно спрашивали.

4 Языковая модель с закрытым списком

Модели дают вопрос, который задал робот, список веток и фразу абонента — и просят выбрать одну ветку. Не пересказать, не объяснить, а именно выбрать из перечисленного.

Это единственный из четырёх подходов, который видит контекст. «После обеда» на вопрос «придёте?» и на вопрос «когда вам удобно перезвонить?» — разные намерения, и модель это различает. Она же вытянет смысл из «да не, не приду» и из «я не против».

Цена вопроса: задержка и деньги на каждом обращении. Плюс отдельная инженерная задача — заставить модель отвечать строго одним вариантом из списка, а не рассуждением на три абзаца.

Сравнение

Что важно Слова Нечёткое Эмбеддинги LLM
Понимает перефразировку Нет Почти нет Да Да
Понимает отрицание Нет Нет Частично Да
Учитывает вопрос Нет Нет Нет Да
Задержка в разговоре Незаметна Незаметна Небольшая Ощутимая
Стоимость обращения Нет Нет Своё железо За каждый вызов
Понятно, почему так решил Полностью Полностью Через расстояния Не всегда
Что чинить при промахе Дописать слово Дописать слово Эталоны, порог Формулировку веток

Три вещи, которые решают именно в звонке

В статьях про классификацию текста обычно сравнивают точность и на этом заканчивают. В телефонии точность — не главный критерий, и вот почему.

Пауза стоит дороже ошибки

В переписке подумать секунду — норма. В разговоре тишина после вашей реплики читается как «связь оборвалась», и человек начинает говорить поверх, переспрашивать или просто кладёт трубку. Классификатор, который отвечает точнее, но с заметной задержкой, на практике проигрывает быстрому и чуть более тупому.

Отсюда простое следствие: бюджет времени на решение фиксирован, и он маленький. Всё, что в него не влезает, не имеет значения, каким бы умным оно ни было.

Умный этап должен быть исключением, а не правилом

Если гонять тяжёлый классификатор на каждую реплику, вы платите за все ответы, включая те самые «да», которые разобрал бы поиск по словам. А таких — большинство.

Разумная схема двухступенчатая: сначала дешёвая проверка, и только когда она не дала уверенного совпадения — умный этап. Тогда расходы и задержка появляются лишь на действительно сложных ответах, а на простых сценарий работает как раньше.

Побочный эффект приятный: чем лучше автор сценария подобрал ожидаемые слова, тем реже включается дорогой этап. Аккуратно составленный сценарий буквально дешевле в эксплуатации.

Сбой не должен ронять звонок

Человек на линии, реплику надо выдать сейчас. Повторить запрос, как в вебе, нельзя — разговор идёт в реальном времени и ждать не будет.

Поэтому у классификатора обязан быть жёсткий таймаут и понятное поведение при отказе. Правильный отказ — это уход в ветку «ничего из перечисленного», ту самую, куда сценарий и так попадает, когда не разобрал ответ. Тогда даже полностью недоступный классификатор означает всего лишь «работаем как без него», а не оборванный звонок.

Это стоит закладывать в архитектуру с самого начала. Классификатор, который при недоступности бросает исключение вместо «не знаю», превращает внешний сервис в единую точку отказа для всех ваших разговоров.

Как это работает в AutoCall.kz

В интерактивных сценариях у каждого элемента распознавания есть ветка «Иначе» — куда уходит абонент, чей ответ не совпал ни с одним из ожидаемых слов. Она и есть точка подключения умного этапа: сначала отрабатывает сопоставление по словам, которые вы задали, и только не совпавшие ответы разбираются дальше — с учётом самого вопроса, а не одной лишь фразы.

Результат всегда одна из ваших веток или «Иначе» — придумать новую ветку классификатор не может по построению. А при любом сбое или превышении времени звонок уходит в «Иначе», то есть ведёт себя ровно так, как вёл бы без всякой классификации.

Практический совет для тех, кто собирает сценарии: формулируйте вопрос так, чтобы на него хотелось ответить коротко. «Придёте завтра — да или нет?» соберёт куда больше односложных ответов, чем «Хотелось бы уточнить ваши планы на завтра». Чем чётче вопрос, тем реже нужен умный этап.

Что дальше

Всё описанное — про сценарии, где ветки заданы заранее. Соседняя история — голосовые ИИ-агенты, где никаких веток нет вообще: агент ведёт разговор целиком и сам решает, что делать с ответом. Про разницу между этими подходами мы писали отдельно.

Отдельная тема, к которой мы вернёмся, — выбор омни-модели: одной модели, которая принимает звук и сразу отдаёт и текст, и смысл, без разделения на распознавание и классификацию. Это меняет расклад целиком, потому что убирает из цепочки один этап, а вместе с ним и его задержку. Про то, как мы выбираем такую модель для AutoCall.kz, будет отдельная статья.

Соберите сценарий и послушайте сами

Тестовый звонок приходит прямо в браузер — запускать обзвон не нужно.

Попробовать бесплатно →