Услышал 30, оформил 20: нейросеть сверяет звонок с заказом
Клиент по телефону просит тридцать багетов, диспетчер оформляет двадцать. Никто не соврал: в конце смены на слух это норма. Ошибка всплывает утром на отгрузке, когда машина уже уехала.
Проблема
Оптовый заказ по телефону нигде не остаётся целиком. Есть запись разговора, которую никто не слушает, и есть строчки в системе, которые набрал человек с гарнитурой. Между ними есть разница: забытая позиция, не то количество, перенесённая дата, обещанная скидка, от которой в заказе не осталось следа.
Руководитель узнаёт об этом от клиента. Десяток разговоров можно послушать выборочно. Тысячу нельзя.
Как собран контур
Собрал демо на данных оптового хлебного производства. Контур работает в четыре шага.
Телефония отдаёт запись каждого разговора по вебхуку. Расшифровка делит реплики, поэтому видно, где говорит клиент, а где диспетчер. Модель достаёт из текста структуру просьбы: позиции, количества, дату отгрузки, адрес, обещания диспетчера и дословные цитаты. На четвёртом шаге обычный код сверяет эту структуру с тем, что попало в заказ.
Арифметику и вердикт считает код. Модель занимается тем, что умеет: превращает живую речь в структуру. Складывать числа ей не поручено, потому что вердикт видит руководитель, а проверить вывод модели нечем. Функция сверки покрыта юнит-тестами, их 42.
Сверка знает шесть видов расхождений:
| Что находит | Пример |
|---|---|
| Позиция потерялась | просил круассаны, в заказе их нет |
| Лишняя позиция | в заказе появилась оптовая корзина, которую никто не заказывал |
| Не то количество | услышал 30 багетов, оформил 20 |
| Другая дата отгрузки | договорились на четверг, стоит пятница |
| Другой адрес | назвал кофейню, заказ уехал в столовую |
| Обещание не зафиксировано | пообещал скидку, в заказе следа нет |
Руководитель видит карточку звонка: две колонки «просил» и «оформлено», подсвеченные расхождения, цитаты клиента и расшифровку целиком. Вердикт можно подтвердить или отклонить руками, чтобы копилась честная статистика по диспетчерам.
Вердиктов пять, и это важно для внедрения. «Совпало» закрывает звонок без чтения. «Внимание» и «расхождение» отличаются серьёзностью найденного. «Заказ не найден» означает, что рядом со звонком сравнивать не с чем: клиент звонил спросить, а не заказать. «Не удалось проверить» ставится, когда сломалось извлечение. Последний вердикт нужен ровно для того, чтобы сбой провайдера не выглядел как отсутствие расхождений. В сводке вердикты фильтруются, поэтому руководитель открывает утром только то, что требует решения.
Что сломалось на живом прогоне
В демо пять звонков с расшифровками. Первый прогон дал «заказ не найден» на четырёх из них, а пятый упал с ошибкой.
Причина оказалась в поиске: он смотрел только на дату создания заказа, а у заказов, заведённых заранее, она лежит далеко от звонка. Теперь поиск идёт тремя шагами, от точного к грубому. Заказ, созданный рядом со звонком. Заказ с отгрузкой рядом со звонком. Последний заказ клиента. «Не найден» остаётся, только если у клиента нет заказов совсем.
Дальше пришла беда пострашнее пропусков: ложные расхождения. Адреса «Улица Большая Покровская, дом 44» и «ул. Большая Покровская, 44 · столовая» система считала разными, поэтому сравнение свелось к ядру адреса: улица и номер дома, а город, тип заведения и хвосты отбрасываются. Обещания сыпались на каждом месте, где диспетчер просто пересказывал состав заказа. Теперь обещание без денежных и количественных маркеров при полном совпадении позиций считается выполненным, а скидка и отсрочка помечаются по-прежнему.
Третья проблема к нейросетям отношения не имела. Шлюз отвечал от 25 до 80 секунд, таймаут в 30 секунд рвал вызов, и два звонка из пяти получали вердикт «не удалось проверить». Извлечение переехало на быструю модель, бюджет времени вырос с 30 до 75 секунд, добавились две повторные попытки с паузами 1,5 и 4 секунды, причём только на таймауты и ошибки шлюза. Диагностический лог показал ещё одну деталь: ответ модели обрывался на середине JSON, потому что она писала длинные названия с фасовкой и длинные цитаты и упиралась в лимит 1500 токенов. Лимит поднят до 3000, промпт просит краткие названия и не больше двух цитат.
Что получилось
Проверку проходит каждый звонок, а руководитель работает со списком расхождений, где уже указано, что именно разошлось. Ручная разметка поверх автоматического вердикта копит статистику по диспетчерам, и разговор с сотрудником опирается на конкретные звонки, а не на память обеих сторон.
Сбой провайдера контур не роняет: звонок получает вердикт «не удалось проверить» и остаётся в очереди, поэтому такую сверку можно ставить на живой поток без риска потерять данные.
Напишите @eldarmarketing, обсудим вашу задачу.
