172 lines
8 KiB
Markdown
172 lines
8 KiB
Markdown
# 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`)
|
||
|
||
Специалист вводит проблему клиента. Приложение:
|
||
|
||
1. **Векторизует вопрос** той же моделью эмбеддингов
|
||
2. **Ищет 5 похожих чанков** в ChromaDB по косинусной близости
|
||
3. **Формирует контекст** из найденных тикетов
|
||
4. **Отправляет в LM Studio** (чат-модель Qwen2.5-7B) с промптом:
|
||
> "Ответь на основе ТОЛЬКО переданного контекста. Не придумывай, не отсылай в другую поддержку"
|
||
5. **Показывает ответ** и исходные тикеты для проверки
|
||
|
||
## Установка и запуск
|
||
|
||
### Требования
|
||
|
||
- Python 3.11+
|
||
- NVIDIA GPU с 8+ GB VRAM (для эмбеддингов и LLM)
|
||
- [LM Studio](https://lmstudio.ai/) (для чат-модели)
|
||
|
||
### Установка
|
||
|
||
```bash
|
||
pip install -r requirements.txt
|
||
```
|
||
|
||
Установить PyTorch с CUDA (если ещё не):
|
||
```bash
|
||
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu124
|
||
```
|
||
|
||
### Подготовка базы знаний
|
||
|
||
```bash
|
||
python prepare_data.py
|
||
```
|
||
Скрипт создаст папку `chroma_db/` с векторной базой.
|
||
|
||
### Запуск
|
||
|
||
```bash
|
||
streamlit run app.py --server.headless true
|
||
```
|
||
Открыть в браузере: http://localhost:8501
|
||
|
||
### Запуск чат-модели
|
||
|
||
Для генерации ответов нужна чат-модель в LM Studio:
|
||
1. Открыть LM Studio
|
||
2. Вкладка Developer → загрузить модель (например, `Qwen2.5-7B-Instruct`)
|
||
3. Нажать Start Server
|
||
4. 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`:
|
||
|
||
```python
|
||
SYSTEM_PROMPT = """Ты — специалист техподдержки. Отвечай клиенту, используя ТОЛЬКО информацию из переданных тикетов (контекст).
|
||
|
||
Правила:
|
||
- Если контекст содержит подходящее решение — напиши ответ своими словами, адаптируя под вопрос
|
||
- Если контекст не относится к вопросу — напиши: «Недостаточно информации в истории обращений»
|
||
- НЕ придумывай ответы, НЕ используй общие знания
|
||
- НЕ говори «обратитесь в службу поддержки» — ты сам и есть поддержка
|
||
- Укажи в конце: «Основано на тикете №...»"""
|
||
```
|
||
|
||
Именно этот промпт управляет тем, **как LLM отвечает** на вопрос специалиста. Если нужно изменить стиль ответа, тон, правила или требования к формату — редактировать здесь.
|
||
|
||
Промпт отправляется в LM Studio как `system`-сообщение при каждом запросе генерации ответа (строка `app.py:120-127`).
|
||
|
||
### Фильтрация тикетов без решения
|
||
|
||
Паттерны для отбраковки пустых тикетов — в **`prepare_data.py:19-22`**, переменная `NON_SOLUTION`:
|
||
|
||
```python
|
||
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
|
||
|
||
```bash
|
||
git remote add origin https://git.itoservice.ru/dosnav/support-bot.git
|
||
git push -u origin master
|
||
```
|