- включение qdrant в контур - использование нормальной эмб-модели - векторизация текста - README и туча мелочей
221 lines
13 KiB
Markdown
221 lines
13 KiB
Markdown
# Базовый RAG для локального запуска
|
||
|
||
Этот проект представляет собой систему RAG, которая позволяет преобразовывать документацию из Confluence или других источников в формат, пригодный для работы с локальной Ollama, и задавать вопросы по содержимому документов.
|
||
|
||
## Быстрый старт
|
||
|
||
```bash
|
||
cd ..; ./up; cd -
|
||
python3 -m venv .venv
|
||
source ./venv/bin/activate
|
||
pip install beautifulsoup4 markdownify sentence-transformers qdrant-client langchain transformers hashlib
|
||
pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu
|
||
./download.sh 123456789
|
||
python3 convert.py
|
||
python3 vectorize.py
|
||
python3 rag.py --interactive
|
||
```
|
||
|
||
## Что такое RAG?
|
||
|
||
RAG (Retrieval-Augmented Generation) — это архитектура, которая расширяет возможности генеративных языковых моделей (LLM) за счет интеграции внешних источников знаний.
|
||
Вместо того, чтобы полагаться исключительно на информацию, полученную во время обучения, RAG сначала извлекает релевантные фрагменты из внешней базы знаний, а затем использует их для генерации более точных и информативных ответов.
|
||
|
||
Основные шаги подготовки RAG:
|
||
- **Индексация**: Документы преобразуются в векторные представления (эмбеддинги) и сохраняются в векторной базе данных
|
||
- **Поиск**: При поступлении запроса система ищет наиболее релевантные фрагменты из индексированной базы
|
||
- **Генерация**: Найденные фрагменты используются как контекст для генерации ответа с помощью языковой модели
|
||
|
||
Преимущества RAG:
|
||
- Повышает точность ответов засчёт использования актуальной и специфической информации
|
||
- Позволяет отвечать на вопросы, требующих знаний, не входящих в обучающие данные модели
|
||
- Дает возможность проверить источник информации в сгенерированном ответе
|
||
- Может работать с проприетарными или конфиденциальными данными без дообучения модели
|
||
|
||
## Структура проекта
|
||
|
||
```
|
||
rag/
|
||
├── input_html/ # Входные файлы HTML, загруженные из Confluence
|
||
├── input_md/ # Входные (конвертированные) файлы Markdown
|
||
├── download.sh # Скрипт для загрузки страниц из Confluence
|
||
├── convert.py # Скрипт конвертации HTML в Markdown
|
||
├── vectorize.py # Скрипт векторизации Markdown
|
||
├── rag.py # Основной скрипт RAG системы
|
||
├── clear.sh # Скрипт очистки html/md файлов
|
||
└── README.md # Этот файл
|
||
```
|
||
|
||
## Стек
|
||
|
||
* bash
|
||
* python, venv, pip
|
||
* [ollama](https://ollama.com)
|
||
* [qdrant](https://qdrant.tech)
|
||
* [open-webui](https://docs.openwebui.com)
|
||
|
||
## Предварительные требования
|
||
|
||
1. Запустить среду из корня репозитория: [../README.md](../README.md)
|
||
2. Установить ПО: `curl`, `jq`, `python3`, `pip`
|
||
3. Установить зависимости python:
|
||
|
||
```bash
|
||
python3 -m venv .venv
|
||
source ./venv/bin/activate
|
||
pip install beautifulsoup4 markdownify sentence-transformers qdrant-client langchain transformers
|
||
pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu
|
||
```
|
||
|
||
4. Установить в ollama генеративную модель -- читай ниже.
|
||
|
||
## Подготовка данных
|
||
|
||
### Выгрузка из Confluence
|
||
|
||
Открыть страницу (раздел) Confluence, который необходимо получить.
|
||
Например, `https://conf.company.ltd/pages/viewpage.action?pageId=123456789`.
|
||
|
||
Скопировать значение `pageId` и подставить в команду `./download.sh <pageId>`.
|
||
Например,
|
||
|
||
```bash
|
||
./download.sh 123456789
|
||
```
|
||
|
||
В результате сама страница и все её дочерние будут сохранены в директорию `./input_html/`.
|
||
Файлы будут названы по заголовкам страниц.
|
||
|
||
> [!IMPORTANT]
|
||
> В начале каждого файла будет сохранена исходная ссылка в формате `@@https://conf.company.ltd/pages/viewpage.action?pageId=123456789@@`.
|
||
> Это сделано для того, чтобы в диалоге с моделью источники информации отображались в виде ссылок, а не названий файлов.
|
||
|
||
> [!IMPORTANT]
|
||
> Confluence не позволяет получить готовые макросы в HTML-виде.
|
||
> В файлах будет находиться HTML-текст с готовыми к загрузками макросами, но не загруженными.
|
||
> Хотя в них часто есть очень полезная информация, но её приходится выбрасывать просто потому, что загрузка макросов происходит при загрузке страницы браузером.
|
||
> Поэтому, например, содержания, списки дочерних страниц, встраиваемые диаграммы и пр. плюшечки будут вырезаны.
|
||
>
|
||
> Да, можно запросить страницы простым curl/wget, но (1) см. предыдущее замечание и (2) даже после очистки HTML-тегов в тексте останется очень много мусора (меню, футер, навигация...)
|
||
|
||
### Конвертация страниц в Markdown
|
||
|
||
Этот формат наиболее хорошо подходит для цитирования, потому что не содержит лишних символов, которые будут мешать хорошей токенизации и векторизации.
|
||
|
||
Для конвертации следует выполнить команду:
|
||
|
||
```bash
|
||
python3 convert.py
|
||
```
|
||
|
||
В результате все html-файлы будут сохранены в директорию `./input_md/`.
|
||
Файлы будут названы по заголовкам страниц, внутри также сохранится ссылка на исходную страницу `@@...@@`.
|
||
|
||
Для получения справки по скрипту выполни команду:
|
||
|
||
```
|
||
python3 convert.py --help
|
||
```
|
||
|
||
### Векторизация (индексирование)
|
||
|
||
Файлы `./input_md/*.md` должны быть проиндексированы.
|
||
|
||
Для того, чтобы проиндексировать Markdown-документы, выполнить команду:
|
||
|
||
```bash
|
||
python3 vectorize.py
|
||
```
|
||
|
||
Весь текст делится на отрезки (чанки) с некоторым перекрытием.
|
||
Это делается для оптимизации количества информации, которое будет делиться на токены.
|
||
Перекрытие обеспечивает смысловую связь между чанками.
|
||
|
||
Каждый чанк разбивается на токены, которые в виде векторов сохраняются в векторную СУБД Qdrant.
|
||
При работе RAG, близость векторов токенов обеспечивает наибольшее смысловое совпадение разных слов => чанков => предложений => абзацев => документов.
|
||
Как следствие:
|
||
- наибольшее смысловое совпадение с вопросом пользователя;
|
||
- молниеносный поиск по индексу чанков (частям документов);
|
||
- корректное насыщение контекста для генеративной модели.
|
||
|
||
Впоследствии embedding-модель будет встраивать эти данные в диалог с генеративной моделью.
|
||
Каждый запрос сначала будет обрабатывать именно она, находя подходящие по векторам документы, и подставлять их в контекст генеративной модели.
|
||
Последняя будет всего лишь генерировать ответ, опираясь на предоставленные из документов данные, ссылаясь на них в ответе.
|
||
|
||
Для получения справки по скрипту выполни команду:
|
||
|
||
```
|
||
python3 vectorize.py --help
|
||
```
|
||
|
||
## Запуск
|
||
|
||
Для работы с RAG в интерактивном режиме (симуляция диалога) следует выполнить команду:
|
||
|
||
```
|
||
python3 rag.py --interactive
|
||
```
|
||
|
||
> [!IMPORTANT]
|
||
> Модель не запоминает ничего, поскольку сам диалог не попадает в контекст!
|
||
> В целом, это похоже на гуглёж.
|
||
|
||
Для разового запуска RAG следует выполнить команду:
|
||
|
||
```
|
||
python3 rag.py --query "твой запрос здесь"
|
||
```
|
||
|
||
Для получения справки по скрипту выполни команду:
|
||
|
||
```
|
||
python3 rag.py --help
|
||
```
|
||
|
||
### Кастомный системный промпт
|
||
|
||
Если хочется уточнить роль генеративной модели, можно создать файл `sys_prompt.txt` и прописать туда всё необходимое, учитывая следующие правила:
|
||
|
||
1. Шаблон `{{context}}` будет заменён на цитаты документов, найденные в qdrant
|
||
2. Шаблон `{{query}}` будет заменён на запрос пользователя
|
||
3. Если этих двух шаблонов не будет в промпте, результаты будут непредсказуемыми
|
||
4. Каждая цитата в списке цитат формируется в формате:
|
||
```
|
||
--- Source X ---
|
||
Lorem ipsum dolor sit amet
|
||
<пустая строка>
|
||
```
|
||
5. Если в этой директории нет файла `sys_prompt.txt`, то будет применён промпт по умолчанию (см. функцию `generate_answer()`).
|
||
|
||
Посмотреть полный промпт можно указав аргумент `--show_prompt` при вызове `rag.py`.
|
||
|
||
### Неплохие лёгкие модели
|
||
|
||
Для эмбеддинга:
|
||
|
||
- `sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2` (по умолчанию, хорошо адаптирована под русский язык)
|
||
- `nomad-embed-text` (популярная)
|
||
- ...
|
||
|
||
Для генерации ответов:
|
||
|
||
- `qwen2.5:3b` (по умолчанию)
|
||
- `gemma3n:e2b`
|
||
- `phi4-mini:3.8b`
|
||
- `qwen2.5:1.5b`
|
||
- ...
|
||
|
||
## Дисклеймер
|
||
|
||
Проект родился на энтузиазме из личного любопытства.
|
||
|
||
**Цель:** изучить современные технологии.
|
||
|
||
**Задачи:**
|
||
1. облегчить поиск информации о проекте среди почти 2000 тысяч документов в корпоративной Confluence, относящихся к нему;
|
||
2. обеспечить минимум телодвижений для развёртывания RAG с нуля внутри команды.
|
||
|
||
Здесь не было задачи сделать всё по красоте.
|
||
|
||
Частично (в качестве агентов) в проекте участвовали семейства qwen3, clause-sonnet-4 и семейство chatgpt-4.
|