Привет, Хабр! Меня зовут Анатолий, занимаюсь диалоговыми системами и применением Искусственного Интеллекта в бизнесе.
Кейсовая задача — предоставить клиентам возможность составлять вопрос на естественном языке, а не искать вопрос в списке FAQ‑раздела сайта. При этом система должна выдавать ответ из существующей базызнаний «Вопрос‑Ответ» существующего FAQ-раздела.
Задача реализована с помощью определения контекстной близости вопросов.
Техническая реализация:
Все вопросы из базы знаний переводятся в векторные представления (embeddings) с помощью искусственной нейронной сети.
Поступающий вопрос также переводится в векторное представление, после чего рассчитывается контекстная (косинусная) близость между векторами вопросов из базы знаний и поступившим вопросом. Вопрос с максимальным показателем контекстной близости считается наиболее подходящим по смыслу. Выдается ответ из соответствующей пары.
Серверная часть реализована на Python в виде flask-приложения.
Для взаимодействия с сервером необходимо отправить на сервер POST-запрос в формате JSON. Сам вопрос необходимо присвоить переменной question.
Сервер выдает ответ в формате JSON. Ответ содержит три переменные: most_similar_question — ближайший по смыслу вопрос из базы знаний, answer — непосредственно текст ответа, similarity — показатель контекстной близости
Версия кода для серверной части:
import pandas as pd
from flask import Flask, request, jsonify
from flask_cors import CORS
from sentence_transformers import SentenceTransformer
import numpy as np
question_url = "..." # Адрес, с которого отправляются запросы
file = "..." # Файл базы знаний
# Функция для вычисления косинусной близости
def cosine_similarity(vec1, vec2):
return np.dot(vec1, vec2) / (np.linalg.norm(vec1) * np.linalg.norm(vec2))
# Создание датафрейма
df = pd.read_excel(file)
questions, answers = list(df.questions), list(df.answers)
# Загрузка модели
model = SentenceTransformer('cointegrated/rubert-tiny2')
# Перевод вопросов базы знаний в векторные представления
questions_embeddings = model.encode(questions)
app = Flask(__name__)
# Настройки CORS
CORS(app, resources={r"/*": {"origins": question_url}})
@app.route('/')
def hello_world():
return 'Hello, World!'
@app.route('/', methods=['POST'])
def find_similar():
data = request.get_json()
user_question = data.get('question', '')
if not user_question:
return jsonify({'error': 'Вопрос не найден в запросе'}), 400
user_emb = model.encode(user_question)
similarities = [cosine_similarity(user_emb, q_emb) for q_emb in questions_embeddings]
max_sim = max(similarities)
max_idx = similarities.index(max_sim)
return jsonify({
'most_similar_question': questions[max_idx],
'answer': answers[max_idx],
'similarity': float(max_sim)
})
if __name__ == '__main__':
app.run(debug=True)
Прямой запуск запускает приложение локально на порту 5000.
Для доступности с внешних интернет-ресурсов арендую облачный сервер ubuntu, устанавливаю все обновления, необходимые пакеты python плюс nginx и gunicorn и запускаю командой gunicorn -w 2 -b 0.0.0.0:8000 faqbot:app.
Приложение становится доступно для внешних POST-запросов на порту 8000.
При простом заходе браузером на порт 8000 в качестве проверки появится 'Hello, World!'
Версия кода для отправки POST-запроса со страницы сайта
Особенности и пояснения
Ближайший по смыслу вопрос определяется именно по смыслу, а не по ключевым словам, частям или подстрокам.
Система использует векторные представления текста, но не использует Генеративный Искусственный Интеллект. Ответы берутся из заранее составленной базы знаний, на один и тот же вопрос каждый раз будет один и тот же ответ.
Система не обращается к внешним ресурсам, то есть может работать в закрытом контуре, с чувствительными данными, не требует получения API ключей и оплаты за токены.
Система не учитывает контекст и историю предыдущих вопросов и ответов, каждый вопрос будет рассматривается как «с чистого листа».
Векторные представления вопросов из базы знаний создаются один раз, при загрузке и обновлении базы знаний, поэтому дорогие серверы с GPU не требуются - достаточно обычной производительности.
Систему можно использовать в качестве помощника оператора и предлагать оператору на выбор несколько вариантов ответа (например, три) по рейтингу контекстной близости вопросов. Это не совсем автоматизация, но может существенно ускорить выдачу ответа оператором.
Систему можно применять не только с сайтом, но и с мессенджерами, виджетами, электронной почтой, сборщиками сообщений и так далее. Необходимо и достаточно отправить на сервер POST-запрос с принятым вопросом, а затем вывести или переправить дальше полученный ответ.
С какими трудностями столкнулся
Теоретически, минимальное значение показателя контекстной близости должно быть примерно в интервала 0.7-0.8, чтобы вопрос из базы знаний принимать за релевантный, но как именно определить его точно - пока не понятно. Представляется, что только подбором при наборе определенной статистики, причем для каждой базы знаний минимальное значение может быть своим.
Модель обучена на общих сведениях о мире, поэтому в ряде случаев при наличии специфических профессиональных терминов модель может понимать их общий смысл и к чему они относятся, но не различать некоторые нюансы. Это означает, что в таких случаях при определении ближайшего по смыслу вопроса система может выбрать несколько не тот вопрос.
Перспективы развития
При больших объемах базы знаний следует разделить формирование векторных представлений и непосредственно выдачу ответа. Формировать векторные представления следует запуском отдельного файла и хранить векторные представления в соответствующий векторной базе данных.
Кажется, что для выбора ответа можно применять контекстную близость самих ответов, а не вопросов С другой стороны, вопрос может быть весьма коротким, а ответ весьма длинным и подробным, в этом случае показатели контекстной близости могут давать совершенно неприемлемые для данной задачи результаты. Для анализа ответов лучше применять другие нейронные сети и несколько иные подходы. Возможно, следует реализовать это отдельно и запустить «соревнование» между различающимися подходами.
Генеративный Искусственный Интеллект становится все мощнее, точнее и популярнее. Подход RAG (генерация с учетом добавленных данных) дает очень хорошие результаты для ответов по базе знаний. Однако для обращения к внешним LLM нужно отправлять свои данные на внешний ресурс, а это не всегда возможно по причинам информационной безопасности, плюс общая плата за токены при большом объеме отправлений может быть весьма существенна. А на своих серверах в общем случае разворачивают квантированные модели, и даже в этом случае понадобятся GPU, что резко влияет на экономику проекта. Поэтому RAG, Langchain, Генеративный Искусственный Интеллект и Агенты — все это также для отдельного проекта.
Представляется, что данную систему можно улучшить ведением журнала вопросов и ответов. Это позволит более точно определить, какие из часто встречающихся вопросов встречаются наиболее часто, даже с учетом вариативности формулировок клиентов.
Отдельным улучшением может быть фиксация вопросов, на которые максимальный показатель контекстной близости был ниже установленного минимального значения. В дальнейшем периодически прорабатывать такие вопросы и дополнять базу знаний.
Отдельным улучшением может быть предоставление клиенту возможности оценить, насколько ответ соответствовал вопросу. Это позволит более точно устанавливать минимальное значение и в ряде случаев своевременно корректировать базу знаний.
Выводы
Автоматизация поддержки клиентов на основе контекстной близости вопросов — это подход, при котором система принимает вопрос, определяет ближайший по смыслу вопрос в заранее составленной базе знаний, состоящей из пар «Вопрос‑Ответ», и выдает ответ из соответствующей пары.
Получился довольно экономичный и эффективный способ автоматизации поддержки клиентов, позволяющий обеспечивать релевантные и быстрые ответы, что может приводить к увеличению удовлетворенности клиентов, улучшению пользовательского опыта и повышению лояльности к бренду.
Благодарности
Спасибо за прочтение статьи. Буду признателен за любые комментарии, особенно за сообщения о том, с какими реальными трудностями сталкивались при автоматизации поддержки клиентов.
rPman
как хоть тестировали итоговый результат и есть ли какой-то фидбек от тестовой группы?
сделать RAG на имеющемся FAQ не сложно, проблема в сборе этого FAQ, хотя бы на основе уже имеющихся логах общения живого саппорта и реальных вопросов клиентов!