| .opencode/plans | ||
| .gitignore | ||
| app.py | ||
| prepare_data.py | ||
| README.md | ||
| requirements.txt | ||
| tickets-202511.json | ||
| tickets-202512.json | ||
| tickets-202601.json | ||
| tickets-202602.json | ||
| tickets-202603.json | ||
| tickets.json | ||
RAG-ассистент техподдержки
Система поиска решений по истории обращений в техподдержку. Основана на RAG (Retrieval-Augmented Generation) — находит похожие решённые тикеты и формирует ответ на их основе.
Архитектура
tickets.json (792 тикета)
│
▼
prepare_data.py ← фильтрация, очистка, нарезка чанков
│
▼
sentence-transformers ← векторизация (intfloat/multilingual-e5-small, GPU CUDA)
│
▼
chroma_db/ ← векторная база данных (416 чанков)
│
▼
app.py ← Streamlit-интерфейс
│
├── вопрос специалиста → embedding → поиск топ-5
│ │
│ ▼
└── контекст → LM Studio (qwen2.5-7b) → ответ
Как это работает
1. Подготовка данных (prepare_data.py)
Что делает скрипт:
- Читает все файлы
tickets*.jsonв папке проекта (сейчас 6 файлов, ~3300 тикетов) - Чистит текст: удаляет цитаты
[q]...[/q], ссылки, лишние пробелы - Фильтрует: оставляет только тикеты с реальным решением. Отбрасываются:
- тикеты, где последнее сообщение support — просьба уточнить / прислать скрин
- тикеты без ответа / с закрытием "нет обратной связи"
- слишком короткие сообщения (< 100 символов)
- Формирует чанки: каждый тикет = один чанк вида:
Категория: ... Проблема: <описание> Решение: <все сообщения support> - Векторизует: превращает текст в вектор (384 числа) через
intfloat/multilingual-e5-smallна GPU - Сохраняет в ChromaDB (папка
chroma_db/)
Результат: 416 чанков с реальными решениями (376 тикетов отфильтровано как бесполезные).
2. Поиск и генерация (app.py)
Специалист вводит проблему клиента. Приложение:
- Векторизует вопрос той же моделью эмбеддингов
- Ищет 5 похожих чанков в ChromaDB по косинусной близости
- Формирует контекст из найденных тикетов
- Отправляет в LM Studio (чат-модель Qwen2.5-7B) с промптом:
"Ответь на основе ТОЛЬКО переданного контекста. Не придумывай, не отсылай в другую поддержку"
- Показывает ответ и исходные тикеты для проверки
Установка и запуск
Требования
- Python 3.11+
- NVIDIA GPU с 8+ GB VRAM (для эмбеддингов и LLM)
- LM Studio (для чат-модели)
Установка
pip install -r requirements.txt
Установить PyTorch с CUDA (если ещё не):
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu124
Подготовка базы знаний
python prepare_data.py
Скрипт создаст папку chroma_db/ с векторной базой.
Запуск
streamlit run app.py --server.headless true
Открыть в браузере: http://localhost:8501
Запуск чат-модели
Для генерации ответов нужна чат-модель в LM Studio:
- Открыть LM Studio
- Вкладка Developer → загрузить модель (например,
Qwen2.5-7B-Instruct) - Нажать Start Server
- API будет доступен на
http://localhost:1234/v1
Без чат-модели приложение работает в режиме поиска — показывает похожие тикеты без генерации ответа.
Структура проекта
support-bot/
├── tickets*.json # исходные данные (несколько файлов)
├── prepare_data.py # подготовка и векторизация
├── app.py # Streamlit-интерфейс + RAG
├── requirements.txt # зависимости
├── chroma_db/ # векторная БД (создаётся prepare_data.py)
└── .gitignore
Системные промпты
Главный системный промпт — в файле app.py:15, переменная SYSTEM_PROMPT:
SYSTEM_PROMPT = """Ты — специалист техподдержки. Отвечай клиенту, используя ТОЛЬКО информацию из переданных тикетов (контекст).
Правила:
- Если контекст содержит подходящее решение — напиши ответ своими словами, адаптируя под вопрос
- Если контекст не относится к вопросу — напиши: «Недостаточно информации в истории обращений»
- НЕ придумывай ответы, НЕ используй общие знания
- НЕ говори «обратитесь в службу поддержки» — ты сам и есть поддержка
- Укажи в конце: «Основано на тикете №...»"""
Именно этот промпт управляет тем, как LLM отвечает на вопрос специалиста. Если нужно изменить стиль ответа, тон, правила или требования к формату — редактировать здесь.
Промпт отправляется в LM Studio как system-сообщение при каждом запросе генерации ответа (строка app.py:120-127).
Фильтрация тикетов без решения
Паттерны для отбраковки пустых тикетов — в prepare_data.py:19-22, переменная NON_SOLUTION:
NON_SOLUTION = re.compile(
r"(уточнит|приложите скрин|какая ошибка|с какой проблемой"
r"|нет обратной связи|запрос завершу|открыть его снова"
r"|откройте новый|обратиться в службу поддержки"
r"|свяжитесь с технической"
r"|напишите нам|позвоните нам)", re.I
)
Если в последнем сообщении support встречается одно из этих слов — тикет считается бесполезным и не попадает в базу знаний. Можно расширять или уточнять список.
Технологии
| Компонент | Технология |
|---|---|
| Эмбеддинги | intfloat/multilingual-e5-small (384d, GPU) через sentence-transformers |
| Векторная БД | ChromaDB |
| Чат-модель | Qwen2.5-7B-Instruct через LM Studio (OpenAI-совместимый API) |
| Фреймворк | LangChain + Streamlit |
| Язык | Python 3.11 |
| GPU | CUDA 12.4+ |
Git
git remote add origin https://git.itoservice.ru/dosnav/support-bot.git
git push -u origin master