Всё чаще в реализации проектов встречается потребность в классификации входящего текста для дальнейшей обработки. До недавнего бума нейросетей задачи по классификации текста были достаточно трудоемкими, дорогостоящими и требовали глубоких знаний NLP. А готовые решения не давали желаемой точности ответов. К счастью, сейчас практически моментально можно внедрить множество решений. Представьте, автодилер ежедневно получает сотни сообщений от клиентов. Как быстро и точно определить, что хочет клиент? С помощью классификации текста.
Всем привет, меня зовут Иван Четвериков, я архитектор ИИ-направления в компании Raft, мы занимаемся внедрением передовых AI-технологий в процессы множества компаний во многих отраслях. Поделюсь нашим опытом внедрения нового подхода для классификации текста в чат-ботах. Сравним три подхода к реализации классификатора: классический ML-классификатор, LLM-классификатор и библиотеку semantic-router, но перед этим немного войдем в контекст проекта.
Выбор классификатора
В первую очередь определимся, какой классификатор выбрать, чтобы как можно скорее запустить mvp. Для этого мы провели небольшой анализа и выяснили, что у нас есть около 20 различных топиков, на которые нужно классифицировать запросы пользователя. Можно подумать, что для статичных топиков отлично подходит ML-классификатор, но его разработка может растянуться на несколько месяцев. Поэтому мы решили запускать MVP с LLM-классификатором, а после его разработки переезжать на ML-классификатор.
Преимущества LLM-классификатора:
Нет необходимости в датасете: для разработки LLM-классификатора не требуется предварительно собирать и размечать большой объем данных. Достаточно написать промпт, что значительно ускоряет процесс.
Быстрая разработка: время на разработку LLM-классификатора значительно меньше по сравнению с классическим ML-классификатором. Это позволяет быстрее запустить MVP и начать тестирование.
Недостатки LLM-классификатора:
Ограниченная точность: без предварительно обученного датасета точность LLM-классификатора может быть ниже, чем у ML-классификатора.
Стоимость на большом потоке сообщений: использование LLM-классификатора может быть высокой при высоконагруженном сервисе, вследствие чего расход токенов для облачных моделей будет перекрывать все плюсы от его использования. Хотя в данном случае можно развернуть локальную LLM.
Преимущества ML-классификатора:
Высокая точность: при наличии хорошо размеченного датасета ML-классификатор может обеспечить высокую точность классификации.
Автономность: ML-классификатор может быть развернут on-prem, что исключает зависимость от сторонних сервисов.
Недостатки ML-классификатора:
Длительное время разработки: разработка и обучение ML-классификатора требует значительных временных и ресурсных затрат.
Необходимость в датасете: для обучения ML-классификатора требуется большой объем размеченных данных, что может быть трудоемким процессом.
Долгие процессы обновления: обновление модели занимает время и требует подключения ML-инженера.
Я обещал сравнить три подхода к реализации классификатора, но на текущем этапе внедрения наличие semantic-router еще не подразумевалось. Пока параллельно с LLM-классификатором началась разработка ML.
Этап 1: LLM-классификатор
При внедрении LLM-классификатор рассчитывался как временное решение. Поэтому решили не реализовывать все топики, а ограничится следующим набором:
Поиск информации об автомобиле по VIN-номеру;
Подбор автомобиля;
Информация из базы знаний компании (кредит, трейд-ин, рассрочка и т.п.);
Информация о работе офисов;
Вопросы с переключением на оператора.
Это было сделано для ускорения процесса разработки и облегчения размера промпта. Промпт написали с использованием паттерна few-shot (метод при котором нейросети предоставляется только несколько примеров), итоговый размер варьировался от 800 до 1000 токенов для целевой модели gpt-3.5-turbo
. Стоимость одного запроса составляла примерно 0.002$ - 0.003$.
Исходя из этих данных, сравнивать LLM-классификатор с классификаторами ML и semantic-router было сложно, но мы всё же попробовали.
Его главный плюс — скорость реализации. У нас от старта проекта до создания рабочего DEV стенда прошло не больше одной-двух недель. Для стадий PoC или MVP это довольно быстро.
Для повышения точности мы использовали Few-Shot промптинг с 3-4 примерами для каждого из топиков. Также классификатор может послужить хорошей прослойкой для защиты от промпт-инъекций, так как он отбрасывает все сообщения, не относящиеся к целевым.
Часть промпта с описанием категорий, за исключением бизнес правил, правил обработки входящего текста и формата ответа, выглядит следующим образом:
"""
You need to classify user input and return the best category that it match.
You must return exact name of the most appropriated category.
Only these categories are available:
"car-search-by-vin", "cars-search", "info", "office-info", "switch-to-operator"
Rules for categories:
Category "car-search-by-vin" - Any description
Category "cars-search" - Any description
Category "info" - Any description
Category "office-info" - Any description
Category "switch-to-operator" - Any
Examples of user input:
Ex. 1
Question: what's the mileage? how much does it cost?
VIN number: XXXXXXXXXXXXXXXXX
Expected category: "car-search-by-vin"
Ex. 2
Question: Any trade-in options?
Expected category: "info"
Ex. 3
Question: Need to discuss personal discount and car customization
Expected category: "switch-to-operator"
"""
Из метрик для LLM-классификатора мы рассчитывали только точность ответа на вопросы (precision) которая, к слову, была достаточно хорошей при дешевизне модели и составляла 75-80%. Также стоит отметить, что на все вопросы, которые бот не смог обработать, система автоматически переключалась на оператора.
При необходимости можно работать и с локальной LLM, развернув инференс любой модели с открытым исходным кодом на сервере, но стоит учитывать, что для достижения большей точности нужно задействовать ML-инженеров и вкладывать больше усилий в разработку промпта. Такой подход будет актуален, если в проекте уже есть локально развернутая LLM или она будет использоваться не только для классификации текстовых данных.
Этап 2: ML-классификатор
Как и было сказано, модели машинного обучения часто лучше подходят для задач классификации, чем большие языковые модели, когда есть датасет для обучения.
На данном этапе проекта у нас был подготовленный датасет и определена модель (distilbert/distilbert-base-multilingual-cased
) которую мы будем обучать.
Bert — это state-of-the-art модель от Google для классификации текстов. Кроме того, она мультиязычна, а значит подходит для русского языка и уже была обучена на нем. За счет дистилляции модель занимает меньше места, чем ее не дистиллированная версия. Она обучается быстрее при минимальной потере в качестве.
Топиков на этом этапе уже было не 5, как раньше, а все полноценные 20 штук. Размеченный датасет был собран в Excel-файл. Для наглядности ниже приведены примеры на некоторые из топиков:
clean_text |
topic_name |
topic |
как можно с вами связаться? |
Обратная связь |
1 |
а авто в наличии? |
Авто в наличии |
2 |
авто за наличный расчёт продается? |
Условия оплаты |
3 |
в кредит можно? |
Кредит |
4 |
2.500.000 готов забрать |
Торг и обсуждение цены |
6 |
крашенные детали есть? |
Состояние авто |
7 |
можете прислать отчет по автомобилю? |
Запрос диагностики |
10 |
вин можно посмотреть? |
Запрос VIN |
19 |
После обучения на подготовленном и отфильтрованном датасете получился следующий результат. Отчет сформирован на основе библиотеки scikit-learn и подготовленном тестовом датасете:
После внедрения модели в сервис результаты ответов стали лучше, чем при использовании LLM модели. Но нам хотелось достичь большего результата по точности определения для полной разгрузки оператора на стандартных вопросах клиентов.
Этап 3: Классификатор на базе semantic-router
Итак, мы подошли к моменту, когда стало понятно, что процесс обновления ML-модели достаточно долгий и трудоемкий. Это сильно замедляло все процессы работ по проекту. Поэтому мы решили искать альтернативу. Решения на основе pytorch
или nltk
нам не подошли из-за того, что создавали большую нагрузку в процессе развертывания приложения из-за разворачивания локальной модели, а также создавали большую нагрузку на CPU. Самым подходящим из существующих решений показался semantic-router. Так как нашей основой был Python и уже была реализована интеграция с OpenAI.
Библиотека semantic-router является "слоем для принятия решений", то есть классифицирует текст на темы. Работает она на основе LLM и Эмбеддинг-моделей с поддержкой локальных моделей, а также облачных: OpenAI и Cohere.
Для реализации версии бота с использованием semantic-router был использован тот же датасет, что и для ML-классификатора. Для хранения эмбеддингов взяли OpenAI и модель text-embedding-3-large (стоимость составляет $0.130 / 1M tokens).
Логика работы для запуска классификатора:
Оптимизация исходного датасета.
Здесь мы использовали метод K-средних, реализованный в библиотеке scikitlearn. Лучший результат был достигнут при следующих параметрах: размер батча данных = 1000, количество итоговых записей на один класс = 300, score threshold = 0.1.Загрузка оптимизированного датасета в эмбеддинги и создание класса для нашего классификатора.
На этом этапе необходимо создать список маршрутов для наших эмбеддингов. Для этого мы использовалиsemantic_router.Route
. Затем эти маршруты оборачиваются вsemantic_router.layer.RouteLayer
.
Пример для создания semantic-router классификатора загружен на github, с ним можно ознакомиться тут.
При запуске приложения стоимость загрузки датасета в эмбеддинг-модель составляет примерно 0.003$ на датасет из 5 000 записей (29 043 токенов). Один запрос для классификации расходует меньше 50 токенов (0.65$ на ~10k запросов).
Точность ответов (precision) с использованием данного подхода изначально составила 89%. После этого была произведена ручная оптимизация датасета для эмбеддингов, в рамках которой мы добавили больше примеров для некоторых топиков, точность которых в чатах с клиентами нас не устраивала. После оптимизации общая точность стала достигать 92-96%.
В итоге полученный отчет из scikit-learn выглядит следующим образом:
Безопасность решений на классификаторах
Дополнительно классификаторы, реализованные по перечисленным методам, обладают разной устойчивостью к атакам. Но это уже тема для отдельной статьи. Сейчас мы говорим о реализации данных классификаторов, поэтому могу только привести примеры нескольких основных видов атак:
Итоги
Безусловно, для данного кейса с определением тематик для автодилера, semantic-router показал самый лучший результат. Однако стоит отметить, что для получения высокой точности необходимо также вручную размечать датасет и подбирать параметры для перевода данных в эмбеддинги.
Исходя из полученного опыта, можно составить небольшие рекомендации:
LLM-классификатор стоит использовать в случаях, когда нет подготовленного датасета, а также хочется запустить проект в кратчайшие сроки. Стоит отметить, что для большого количества сообщений данный классификатор может быть достаточно дорогим. При использовании облачных моделей latency тоже будет выше, чем у остальных решений.
ML-классификатор подойдет для развертывания on-prem или исходя из запрета использовать какие-либо сторонние сервисы на проекте (как OpenAI в нашем примере). Требует размеченный датасет, а также дополнительные ресурсы на сервере. Соответственно, все сообщения будут обработаны без дополнительной стоимости. Latency зависит от выделенных на классификатор ресурсов.
Классификатор на базе semantic-router также требует размеченный датасет, однако его развертывание можно произвести значительно быстрее, так как модель не нужно обучать, а только положить данные в эмбеддинги и обернуть в функционал данного фреймворка. Стоимость данного решения будет низкой, что позволяет увеличить пропускную способность и не платить как за LLM-классификатор. Latency в данном случае будет ближе к ML-классификатору, нежели к LLM, так как обращение к Эмбеддинг-модели происходит гораздо быстрее.
Стоимость решений:
LLM-классификатор: на OpenAI модели
gpt-3.5-turbo-1106
0.002$ - 0.003$ за один запрос с промптом в 1000 токенов, 20-30$ за 10k запросов.ML-классификатор: 0$ так как он работает на мощностях сервера.
semantic-router классификатор: на OpenaI модели
text-embedding-3-large
0.003$ при каждом запуске приложения и ~0.65$ на 10k запросов.
Также хочется добавить, что у Яндекса недавно вышла легкая модель обучаемого классификатора, и в ближайшее время мы хотим её протестировать и сравнить с уже полученными результатами.
Классификация текста — это мощный инструмент, который может значительно улучшить качество обслуживания клиентов и оптимизировать процессы. Попробуйте один из подходов в своих проектах и поделитесь своими результатами в комментариях!