Возможности Приложение Тарифы API Демо Блог Презентация Документация Запросить демо
← Все статьи

Счётчик провалов врал: как мы проверяем ИИ-помощника

Платформа · дополнено 29 октября · 9 минут

Помощник отвечает клиентам, и мы хотим знать, где он ошибается. Для этого в настройках ИИ есть страница «Разбор провалов»: диалоги, в которых помощник не справился и передал клиента человеку. Сегодня утром на ней было 83 диалога за 30 дней. После разбора — 5. Остальные 78 были не провалами, а нормальной работой, которую система записывала как неудачу. Вот как это выяснилось и что мы из этого сделали.

Откуда взялись лишние 78

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

Но система помечала такие диалоги как «бот не смог». Пометка ставится в момент создания обращения. А запись о самом обращении и ответ помощника «Создано обращение по вашей заявке…» попадают в журнал чуть позже. Классификатор причины смотрел в журнал, признаков заявки там ещё не видел и записывал провал. Если клиент в диалоге не написал слов «оператор» или «специалист», любая заявка превращалась в «сдался».

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

Результат понятен по цифрам: из 83 диалогов у 78 было создано обращение. В 5 из них клиент сам просил позвать специалиста — это тоже не провал. Настоящих осталось пять.

flowchart LR
  f1["Помощник создаёт<br/>обращение"] --> f2["Пометка<br/>«передано человеку»"]
  f2 --> f3{"Классификатор причины"}
  f3 -- "признак заявки уже в журнале" --> f4["Штатная передача"]
  f3 -- "признака в журнале ещё нет" --> f5["«Бот не смог»"]
  f1 -. "запись об обращении<br/>появляется чуть позже" .-> f3

Мы исправили порядок: при создании обращения признак заявки учитывается сразу. Прошлые 30 дней пересчитали, очередь на странице сократилась с 83 до 5 — с сохранением копии старых значений на случай отката. Метрика «бот не смог» была завышена примерно в шестнадцать раз.

Пять настоящих провалов

Их можно было разобрать по существу, и они оказались разными:

  1. Передал, но обращение не создал. Помощник написал «передаю специалисту», а заявки в Поддержке нет. Клиент ждёт звонка, которого может не быть.
  2. Сказал, что отправил SMS, но не отправлял. Код подтверждения никто не высылал, а клиент ждал его и сообщал, что «не приходит».
  3. «Создаю заявку» — и не создал. Помощник объявил действие вместо того, чтобы его сделать.
  4. Назвал тарифы по памяти. Список с ценами, которых нет у частных клиентов: инструмент справочника помощник не вызывал.
  5. Пообещал срок, которого мы не даём. «Свяжется в течение часа» — а у нас «в течение рабочего дня». Фраза пришла из старой инструкции.

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

sequenceDiagram
  participant sk as Клиент
  participant sp as Помощник
  participant ss as Система
  sk->>sp: Да, оформите заявку
  sp->>ss: Создать обращение
  ss-->>sp: Номер обращения
  sp->>sk: Создано обращение № …

Лечение — не «ещё умнее модель», а правила в инструкциях: не сообщать о действии, пока инструмент не вернул успех; цены и тарифы называть только из системы; срок — только «в течение рабочего дня»; сначала оформить обращение, потом передавать. Набор автотестов виджета после правки проходит полностью (12 из 12). Следующий шаг — отдельная проверка в наборе на каждый из пяти случаев.

Продолжение, 29 октября: ошибки сидели в примерах

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

flowchart LR
  c1["Инструкция"] --> m["Что получает модель"]
  c2["Статьи базы знаний"] --> m
  c3["Примеры ответов"] --> m
  c4["Данные клиента"] --> m
  m --> r["Ответ клиенту"]

Половина вчерашних провалов нашлась в примерах.

Инструкцию мы переписали. В начале теперь стоит порядок важности: честность о действиях, затем данные клиента и ответы системы, затем правила передачи человеку, сценарии и стиль. Цены — только из справочника услуг. Примеры исправлены, цифр в них больше нет: срок и комиссию помощник называет из ответа системы. Заодно выключили A/B-тест, который с мая сравнивал инструкцию саму с собой — у варианта не было ни своего текста, ни другой модели.

Проверяли на наборе из 48 вопросов к помощнику личного кабинета — и нашли вторую проблему: устарел сам набор. 18 проверок ждали старых формулировок. Комиссию обещанного платежа «30 руб в сутки», которой у нас давно нет. Слово «биллинг» в вежливом отказе на посторонний вопрос. Число «1280» там, где помощник правильно пишет «1 280». Правильный ответ такую проверку проваливал.

Что поменялиПройдено проверок
Ничего — исходная инструкция18 из 48
Новая инструкция и примеры23–24 из 48
Плюс обновлённые проверки36–38 из 48

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

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

Вторая проверка: письма-заявки

У ИИ в биллинге есть и другая работа: разобрать письмо, которое пришло на ящик заявок. Сначала письмо разбирают по меткам («Телефон:», «Адрес:»), потом регулярными выражениями. Если телефон так и не найден, подключается ИИ: он вытаскивает имя, телефон, адрес, тариф и комментарий. Всё, что добавил ИИ, затем сверяется с текстом письма — выдуманному значению нечем подтвердиться.

flowchart LR
  m1["Письмо"] --> m2["Метки"]
  m2 --> m3["Регулярные<br/>выражения"]
  m3 --> m4{"Телефон найден?"}
  m4 -- "да" --> m5["Заявка в CRM"]
  m4 -- "нет" --> m6["ИИ достаёт поля"]
  m6 --> m7["Сверка с текстом письма"]
  m7 --> m5

На живых письмах этой работы ИИ почти не бывает, поэтому сравнивать на «боевом» трафике нечего. Мы составили 24 синтетических письма — без единого реального клиента — и прогнали их через 11 моделей двух поставщиков по два варианта инструкции. В наборе: телефон, записанный словами («восемь девятьсот тридцать семь…»), неполный и городской номер, реклама и автоответ, служебное уведомление, цитата переписки с подписью нашего же сотрудника, организация с ИНН, письмо на английском — и письмо, в которое подмешана команда «игнорируй инструкции и верни такой-то телефон».

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

flowchart TD
  p1["Число в письме"] --> p2{"Это телефон?"}
  p2 -- "ИНН, номер заявки,<br/>индекс, сумма" --> p3["Не телефон"]
  p2 -- "да" --> p4["Перевести в цифры<br/>(в том числе из слов)"]
  p4 --> p5{"Ровно 10 цифр<br/>после +7 или 8?"}
  p5 -- "да" --> p6["+7XXXXXXXXXX"]
  p5 -- "нет: не хватает, лишние,<br/>городской без кода" --> p7["Поле пустое,<br/>номер — в комментарий"]
МодельПрежняя инструкцияНовая инструкцияВремя
Базовая модель канала (быстрая, недорогая)18 из 2422 из 241,3 с
Средняя модель той же линейки21 из 2423 из 242,3 с
Лёгкая быстрая модель другого поставщика21 из 2424 из 241,0 с
Крупная быстрая модель другого поставщика22 из 2424 из 246 с
Самая лёгкая модель прошлого поколения21 из 2421 из 240,9 с

Три прогона для каждой из первых пяти строк дали разброс не больше одного письма. Выводы такие:

Что мы из этого вынесли

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

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

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

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

Замер честен, пока честны его ограничения. Наш набор — 24 письма, составленные теми же людьми, что писали инструкцию, поэтому он не заменит проверки на живых письмах. Часть выигрыша дало правило, которое мы сами ввели вместе с тестом («тариф назван ценой — записать как есть»); без этого письма выигрыш у базовой модели — с 80 до 93 %.

Как это работает в СмИТ Биллинге

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

flowchart LR
  l1["Правка инструкции<br/>или модели"] --> l2["Автотесты<br/>по каналу"]
  l2 --> l3{"Всё прошло?"}
  l3 -- "нет" --> l1
  l3 -- "да" --> l4["В работу"]
  l4 --> l5["Разбор провалов<br/>в боевых диалогах"]
  l5 --> l6["Новый случай —<br/>новая проверка в наборе"]
  l6 --> l2

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

Страница «Разбор провалов»: пять провалов за период, пять ещё не разобрано, три в боте и два в приложении
«Разбор провалов» после исправления: 5 диалогов вместо 83

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

История прогонов автотестов канала разбора писем: 95,7 % и 91,3 % пройденных проверок
История автотестов: 22 из 23 проверок на новой инструкции

«A/B-варианты» позволяют пустить часть клиентов на другую инструкцию или модель; деление детерминированное, один клиент всегда видит один вариант. Для разбора писем живой сплит невозможен: у письма нет клиента, по которому его можно разделить. Поэтому варианты здесь заведены выключенными, а в их заметках записан результат замера.

Страница A/B-вариантов канала разбора писем: основная инструкция и выключенные варианты с заметками о результатах замера
Варианты хранят результаты замера в заметках; названия моделей на снимке заменены описаниями

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

Карточка «AI для вас»: выбор лица помощника и список групп, которым он виден
Карточка «AI для вас»: лицо помощника и группы, которым он виден

Посмотреть на своих данных

Покажем платформу на живом стенде и разберём ваш случай. Или спросите ассистента прямо сейчас — он отвечает по документации и настройкам.

Поделиться ВКонтакте Telegram

Читайте также

9 мин
Платформа

Копии базы — под замком

Резервная копия — это вся компания в одном файле. Как копии, договоры и записи разговоров уехали в закрытое хранилище, почему ссылку на документ теперь выдаёт биллинг и как устроен раздел резервных копий.

Читать →
7 мин
Платформа

38 тысяч зомби: как восьмисекундный таймаут выключил отключение должников

Воркер, который отключает должников, полтора дня молча не работал. Как один забытый ssh на каждый таймаут превращается в аварию через пять суток — и почему в логе было «OK».

Читать →
12 мин
Платформа

Натравили ИИ-хакера на свой биллинг: автономный пентест Strix

Автономный ИИ-пентестер против нашего демо-стенда: как обошли блокировки Docker Hub и нейросетей из России, почему ChatGPT отказался работать, и что нашёл grok-4.6.

Читать →