Привет, Хабр! Меня зовут Анатолий, занимаюсь диалоговыми системами и применением Искусственного Интеллекта в бизнесе.

Кейсовая задача — предоставить клиентам возможность составлять вопрос на естественном языке, а не искать вопрос в списке 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, Генеративный Искусственный Интеллект и Агенты — все это также для отдельного проекта.

  • Представляется, что данную систему можно улучшить ведением журнала вопросов и ответов. Это позволит более точно определить, какие из часто встречающихся вопросов встречаются наиболее часто, даже с учетом вариативности формулировок клиентов.

  • Отдельным улучшением может быть фиксация вопросов, на которые максимальный показатель контекстной близости был ниже установленного минимального значения. В дальнейшем периодически прорабатывать такие вопросы и дополнять базу знаний.

  • Отдельным улучшением может быть предоставление клиенту возможности оценить, насколько ответ соответствовал вопросу. Это позволит более точно устанавливать минимальное значение и в ряде случаев своевременно корректировать базу знаний.

Выводы

Автоматизация поддержки клиентов на основе контекстной близости вопросов — это подход, при котором система принимает вопрос, определяет ближайший по смыслу вопрос в заранее составленной базе знаний, состоящей из пар «Вопрос‑Ответ», и выдает ответ из соответствующей пары.

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

Благодарности

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

Комментарии (1)


  1. rPman
    29.07.2025 04:55

    как хоть тестировали итоговый результат и есть ли какой-то фидбек от тестовой группы?

    сделать RAG на имеющемся FAQ не сложно, проблема в сборе этого FAQ, хотя бы на основе уже имеющихся логах общения живого саппорта и реальных вопросов клиентов!