Меня зовут Анатолий, занимаюсь автоматизацией бизнес-процессов и применением Искусственного Интеллекта в бизнесе.
Кейсовая задача – создать Систему генерации ответов на основе существующей истории тикетов. При этом Система должна работать в закрытом контуре.
Это вторая часть.
В первой части был рассмотрен подход Question-Answering с timpal0l/mdeberta-v3-base-squad2 (модификация BERT для задач Question-Answering) – модели, умеющей “читать” текст и “вытаскивать” ответы.
В этой части переходим к семантическому поиску, контекстному сходству и SentenceTransformer.
SentenceTransformer
SentenceTransformer – библиотека для преобразования текста в векторные представления (эмбеддинги). SentenceTransformer позволяет преобразовывать слова и предложения в числовые представления, которые учитывают смысл, а не только лексическое совпадение. Это ключевое отличие от классического поиска по ключевым словам.
Поиск релевантных тикетов
-
Формирование базы знаний
Ответы сотрудников из истории тикетов собрали в массив answers. Этот массив становится нашей базой знаний для дальнейшей векторизации. -
Загрузка модели
Использовали модель deepvk/USER-bge-m3, оптимальное решение для русскоязычных текстов. Модель специализируется на понимании контекста и преобразовании текста в векторные представления, сохраняя его смысловую нагрузку. . -
Векторизация истории тикетов
Каждый текст из массива answers проходит через модель и превращается в вектор фиксированной размерности. Это позволяет перейти от сравнения строк к анализу векторов, что дает возможность находить ответы, близкие по смыслу, даже если они сформулированы иначе. -
Векторизация вопроса
Вопрос пользователя также векторизуется с использованием той же модели. Теперь вопрос и ответы представлены в одном векторном пространстве. -
Вычисление косинусного сходства
После преобразования вопроса и ответов в векторы основная задача – найти наиболее релевантные тикеты. Для этого применяется косинусное сходство – метрика, показывающая степень близости векторов вопроса и ответа в многомерном пространстве. Значения варьируются от -1 (противоположные по смыслу) до 1 (полностью идентичные).
Вычисляется косинусное сходство между вектором вопроса и всеми векторами ответов. -
Ранжирование результатов
Ответы сортируем по убыванию косинусного сходства, чтобы определить TOP-N релевантных тикетов.
Код на python
import torch
from sentence_transformers import SentenceTransformer
import numpy as np
# Инициализация модели
model_name = "deepvk/USER-bge-m3"
model = SentenceTransformer(model_name)
# Перемещение модели на GPU, если доступно
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model = model.to(device)
# Преобразование текстов тикетов в эмбеддинги
embeddings_answers = model.encode(answers, normalize_embeddings=True)
# Преобразование текста вопроса в эмбеддинг
embeddings_question = model.encode(question, normalize_embeddings=True)
# Вычисление косинусного сходства
scores = embeddings_question @ embeddings_answers.T
# Создание массива с показателями и текстами
answers_scores = np.column_stack((scores, answers))
# Сортировка массива по убыванию косинусного сходства
sorted_answers_scores = sorted(answers_scores, key=lambda x: x[0], reverse=True)
Примечание
Согласно карточке deepvk/USER-bge-m3 на huggingface, модель поддерживает окно контекста 8194 токена – этого достаточно для обработки большинства текстов ответов в тикетах без разбиения на чанки. Это упрощает реализацию и ускоряет обработку. В будущем можно добавить чанкинг, если при оптимизации качества анализ покажет такую необходимость. На текущем этапе разбиение не делали.
В результате формируется двумерный массив, в котором каждая строка содержит значения косинусного сходства, отсортированные по убыванию, и соответствующие тексты ответов из истории тикетов. Такой формат обеспечивает мгновенный доступ к TOP-N релевантных текстов для дальнейшей работы или выдачи.
Интеграция и веб-сервис
На основе предыдущего кода и Flask создали веб-сервер, который обрабатывает входящие HTTP-запросы с вопросами и возвращает JSON-ответ с TOP-N релевантных тикетов.
Варианты применения
Данное решение легко адаптируется под разные задачи – от помощи сотрудникам до полной автоматизации ответов.
Два ключевых варианта применения:
-
Ассистент для сотрудников
Сотрудники могут отправлять на сервер вопросы и моментально получать TOP-N релевантных тикетов, ранжированных по косинусному сходству. Это позволяет сотрудникам не искать информацию вручную, упрощает формирование собственных ответов, помогает более быстрой адаптации новому сотруднику. -
Полная автоматизация ответов
Для полной автоматизации ответов разворачивается Ollama с квантизованной Llama3.2 (оптимизирована для работы на CPU/GPU средней мощности) и генерируется автоматический ответ на основе полученных TOP-N релевантных тикетов, ранжированных по косинусному сходству.
Оптимизация хранения и загрузки данных
Также мы создавали массив answers не только из текстов тикетов, но и включали в него идентификаторы тикетов. И в таком случае в sorted_answers_scores хранили не тексты тикетов, а идентификаторы тикетов. Это давало некоторые преимущества, так как комбинация “эмбеддинги + идентификаторы” занимают значительно меньше места по объему памяти, чем “эмбеддинги + полные тексты”.
В финальной версии мы использовали MySQL для хранения таблицы: идентификаторы, тексты, эмбеддинги.
При запуске Системы загружались только идентификаторы и эмбеддинги (минимальная нагрузка на память и передачу данных). После вычисления косинусного сходства тексты по идентификаторам подгружались только для TOP-N релевантных тикетов.
Выявленные критические проблемы
До этого момента все было хорошо, однако в дальнейшем были выявлены две критические проблемы, напрямую влияющие на качество, актуальность и достоверность ответов:
-
Проблема достоверности: противоречия в исторических ответах
Изначально предполагалось, что ответы сотрудников в истории тикетов корректны и согласованы. Однако на практике выявилось, что иногда разные сотрудники дают различающиеся ответы на один и тот же вопрос. Например:
“Срок обработки заявки – до 3 дней”
“Срок обработки заявки – до 5 дней”
Система не может определить, какой ответ верный, так как для Системы оба варианта считаются одинаково корректными с точки зрения семантического сходства. Отсутствует механизм валидации – алгоритм только ищет сходство по смыслу, но не проверяет правильность. -
Проблема актуальности: устаревание информации в истории тикетов
История тикетов – это статичный снимок прошлого. Если процессы, правила или документация изменяются, то Система все равно продолжает выдавать устаревшие ответы, не учитывая обновления.
Стратегическое решение: отказ от истории тикетов в пользу валидированной документации
Технически Система функционировала корректно, но упомянутые критические проблемы сделали ее непригодной для реального использования.
Важно, что противоречивость и устаревание исходной информации никак не решаются технически – ни увеличением размера окна контекста, ни улучшением эмбеддингов, ни масштабированием аппаратных мощностей. Это недостаток самого подхода, но не техническая проблема. Без валидации данных Система не может гарантировать достоверность и актуальность ответов.
Поскольку валидация истории тикетов не планировалась, в итоге мы отказались от использования истории тикетов в пользу более надежного решения: поиску TOP-N релевантых фрагментов аналогичным образом, но в валидированной документации.
Автор: AnatolyBelov


