中文翻译暂不可用,显示俄语原文。
RAG на 100 PDF
ТЕХНИЧЕСКОЕ ЗАДАНИЕ: RAG на 100 PDF
1. Цель задачи
Создать рабочую Retrieval-Augmented Generation (RAG) систему, способную отвечать на вопросы по коллекции из 100 PDF-документов. Система должна индексировать документы с помощью Docling и BGE-M3, хранить эмбеддинги в Qdrant, а генерацию ответов выполнять через Llama-3. Главный критерий успеха: на 10 заранее подготовленных вопросах модель даёт ответы, содержащие прямые цитаты из исходных PDF с указанием страницы.
Ключевой результат Воспроизводимый пайплайн RAG, демонстрирующий качественные ответы с цитатами на 10 вопросов.
2. Исходные данные
Перед началом необходимо подготовить:
| Что нужно | Откуда взять |
|---|---|
| 100 PDF-файлов | Открытые источники: arXiv (https://arxiv.org), технические отчёты, лицензионно-свободные книги (Project Gutenberg). Пример: 100 статей по NLP или AI. |
| Python 3.10+ | Официальный сайт Python или conda |
| Docker | Docker Desktop (https://www.[docker](/wiki/Docker).com/products/docker-desktop) |
| Ollama (для Llama-3) | https://ollama.com – скачать и установить, затем ollama pull llama3 |
| Qdrant (векторная БД) | Docker-образ Qdrant: docker pull qdrant/qdrant или облачный экземпляр (бесплатный tier) |
| Библиотеки Python | pip install: docling, qdrant-client, sentence-transformers, llama-cpp-python (или openai если через Ollama API), torch, transformers, pypdf2 (резерв) |
Если нет реального инструмента — симулируем:
- Нет 100 PDF – используем любые текстовые файлы (.txt) или конвертируем несколько PDF, размножив их копиями с разными названиями. Либо создать скрипт, который генерирует фейковые PDF через
reportlab. - Нет доступа к Qdrant – поднимаем локальный Docker-контейнер Qdrant по инструкции выше. Если Docker недоступен, используем SQLite с сохранением эмбеддингов (имитация векторной БД).
- Нет Ollama – используем API любой открытой LLM (например, через Hugging Face Inference API) или запускаем Llama-3 через llama.cpp локально.
- Docling не работает – извлекаем текст через PyMuPDF (fitz) или pdfplumber, а для изображений используем OCR (pytesseract).
3. Технологический стек
| Компонент | Инструменты | Назначение |
|---|---|---|
| Извлечение текста из PDF | Docling (AI-парсер), PyMuPDF (резерв) | Преобразование PDF в Markdown/текст с сохранением структуры (заголовки, таблицы) |
| Chunking (деление на чанки) | RecursiveCharacterTextSplitter из langchain_text_splitters или Docling | Нарезка документа на куски ~512 токенов с overlap 128 |
| Embedding модель | BGE-M3 (BAAI/bge-m3) | Генерация эмбеддингов для чанков (размерность 1024) |
| Векторная база данных | Qdrant (локально или облачно) | Хранение эмбеддингов и быстрый поиск по косинусной близости |
| LLM для генерации | Llama-3 (8B или 70B через Ollama) | Генерация ответа с цитатами на основе релевантных чанков |
| Оркестрация | Python (Jupyter notebook / скрипт) | Пайплайн индексации, запросов, оценки |
4. Этапы выполнения
Этап 1: Подготовка окружения и сбор данных (~2 часа)
Действия
- Установить Docker и запустить Qdrant
Проверить доступность:docker pull qdrant/qdrant docker run -p 6333:6333 -p 6334:6334 qdrant/qdrantcurl http://localhost:6333. - Установить Ollama и скачать Llama-3
Проверить:curl -fsSL https://ollama.com/install.sh | sh ollama pull llama3ollama run llama3 "Привет". - Создать Python-окружение
python -m venv rag_env source rag_env/bin/activate pip install docling qdrant-client sentence-transformers llama-cpp-python pypdf2 - Собрать 100 PDF
- Скачать из arXiv через
arxivPython библиотеку (например, последние 100 статей по выбранной теме). - Или использовать готовый набор PDF из репозитория (например, https://github.com/example/pdf-collection).
- Положить все файлы в папку
./pdfs.
- Скачать из arXiv через
- Создать файл с 10 тестовыми вопросами (
questions.txt):- Вопросы должны требовать поиска точной информации (цифры, даты, имена).
- Пример: "Какое количество слоёв в BERT-base?" (если есть статья про BERT).
Ожидаемый результат этапа Запущенный Qdrant, работающий Ollama, папка ./pdfs с 100 PDF, файл questions.txt.
Этап 2: Индексация документов (~3 часа)
Действия
- Написать скрипт
index.py, который делает:- Для каждого PDF из
./pdfs: - Для каждого чанка вычисляет эмбеддинг моделью BGE-M3:
from sentence_transformers import SentenceTransformer model = SentenceTransformer('BAAI/bge-m3', device='cuda') embeddings = model.encode([chunk.text], normalize_embeddings=True) - Загружает чанк и эмбеддинг в Qdrant:
from qdrant_client import QdrantClient client = QdrantClient(host='localhost', port=6333) client.upsert( collection_name='pdf_rag', points=[ PointStruct( id=idx, vector=embeddings[0].tolist(), payload={ 'text': chunk.text, 'source': pdf_name, 'page': chunk.metadata.page_number, 'chunk_id': chunk.chunk_id } ) ] ) - Использовать батчинг для ускорения (batch_size=32).
- Для каждого PDF из
- Создать коллекцию в Qdrant с настройками:
- Размерность вектора: 1024 (BGE-M3).
- Метрика:
Cosine. - Индекс: HNSW (по умолчанию).
- Учесть обработку ошибок – если PDF битый или Docling не справляется, использовать резервный PyMuPDF.
Ожидаемый результат этапа В Qdrant создана коллекция pdf_rag с ~10 000–30 000 чанков (зависит от размера PDF). Скрипт выводит статистику: количество проиндексированных документов и чанков.
Этап 3: Реализация Retrieval (~1 час)
Действия
- Написать функцию
retrieve(query, top_k=5):- Векторизовать запрос с помощью той же BGE-M3.
- Выполнить поиск в Qdrant:
client.search(collection_name='pdf_rag', query_vector=query_emb, limit=top_k). - Вернуть список чанков с текстом, источником и страницей.
- Выбрать оптимальный
top_k– протестировать на 3 вопросах изquestions.txt:- Попробовать
top_k=3,5,10. - Оценить релевантность первых чанков (субъективно).
- Попробовать
- Настроить фильтры – если необходимо ограничить поиск по определённым PDF (опционально).
Ожидаемый результат этапа Функция retrieve возвращает 5–10 чанков с хорошим покрытием информации для тестовых вопросов.
Этап 4: Интеграция с Llama-3 и генерация ответов (~2 часа)
Действия
- Написать функцию
generate_answer(query, chunks):- Сформировать промпт, содержащий:
- Инструкцию: «Ответь на вопрос, используя предоставленные фрагменты. Обязательно укажи цитаты из фрагментов и номер страницы. Если информации недостаточно, скажи "не знаю".»
- Список чанков (текст + источник + страница).
- Вопрос пользователя.
- Пример промпта:
Ты — эксперт, работающий с документами. Ниже приведены фрагменты из PDF-документов. Отвечай на вопрос на русском. Для каждого утверждения указывай ссылку на фрагмент и страницу. Фрагменты: [1] «...» (Источник: paper1.pdf, стр. 5) [2] «...» (Источник: paper2.pdf, стр. 12) Вопрос: {query} Ответ: - Отправить промпт в Llama-3 через Ollama API:
import requests response = requests.post('http://localhost:11434/api/generate', json={'model': 'llama3', 'prompt': prompt, 'stream': False}) - Распарсить ответ.
- Сформировать промпт, содержащий:
- Протестировать на 10 вопросах – проверить, что ответы содержат цитаты со ссылками.
- Добавить пост-обработку – если цитаты отсутствуют, можно повторить генерацию с более строгим промптом.
Ожидаемый результат этапа Скрипт rag_pipeline.py, который на вход принимает вопрос, а на выходе даёт ответ с цитатами.
Этап 5: Тестирование и валидация (~1 час)
Действия
- Прогнать 10 вопросов из
questions.txt– записать ответы в файлanswers.md. - Оценить качество по двум метрикам
- Наличие цитат каждый ответ должен содержать хотя бы одну прямую цитату из PDF с указанием страницы.
- Фактологическая точность сравнить ответ с истинным содержанием PDF (вручную).
- Зафиксировать результат – для каждого вопроса: PASS/FAIL.
- При необходимости итеративно улучшить – изменить промпт, увеличить
top_k, улучшить chunking.
Ожидаемый результат этапа Файл answers.md с 10 вопросами и ответами, оценка PASS/FAIL для каждого. Система готова к демонстрации.
5. Критерии приемки (Definition of Done)
- Все 100 PDF успешно проиндексированы в Qdrant (нет ошибок).
- Количество чанков в коллекции > 5000.
- Функция
retrieveвозвращает релевантные чанки для всех 10 тестовых запросов. - Для каждого из 10 вопросов получен ответ от Llama-3.
- Каждый ответ содержит как минимум одну прямую цитату из исходного PDF.
- Цитаты включают ссылку на имя файла PDF и номер страницы.
- Ответы не содержат грубых фактических ошибок (проверено вручную).
- Пайплайн (индексация + запрос) воспроизводим из
README.md. - Код опубликован в Git-репозитории с лицензией MIT.
- В репозитории присутствует файл
requirements.txtиDocker-compose.yml(опционально).
6. Ожидаемый результат
- Основной артефакт Папка проекта с файлами:
src/– скриптыindex.py,retrieve.py,generate.py,rag_pipeline.py.data/pdfs/– 100 PDF (или скрипт для их скачивания).questions.txt– 10 тестовых вопросов.answers.md– сгенерированные ответы с цитатами.README.md– описание, инструкция по запуску, примеры.requirements.txt– список зависимостей.- (Опционально)
docker-compose.ymlдля Qdrant.
- Содержание
answers.md# Ответы RAG-системы ## Вопрос 1: Какое количество слоёв в BERT-base? **Ответ:** В архитектуре BERT-base используется 12 слоёв (трансформерных блоков). > Цитата: "BERT-base имеет 12 трансформерных слоёв" (bert_paper.pdf, стр. 3) - Дополнительно Jupyter notebook с демонстрацией полного пайплайна.
7. Возможные сложности и их решение
| Сложность | Решение |
|---|---|
| Docling не парсит PDF с изображениями (сканы) | Использовать предварительный OCR (pytesseract) или пропустить такие файлы. Для чистоты эксперимента выбрать PDF с текстовым слоем. |
| BGE-M3 требует много памяти | Использовать device='cpu' или уменьшить batch_size. Модель можно загрузить в float16. |
| Qdrant падает при большой вставке | Увеличить лимиты памяти контейнера, использовать batch insert (до 1000 точек за раз). |
| Llama-3 галлюцинирует и не цитирует | Ужесточить промпт, добавить few-shot примеры. Проверить, что в чанках действительно есть ответ. |
| Медленная индексация 100 PDF | Распараллелить обработку (multiprocessing.Pool). Использовать GPU для эмбеддингов. |
| Вопросы не покрываются коллекцией | Добавить более релевантные PDF или расширить список вопросов. |
8. Бюджет времени (оценка)
| Этап | Время |
|---|---|
| Этап 1: Подготовка окружения и сбор данных | 2 часа |
| Этап 2: Индексация документов | 3 часа |
| Этап 3: Реализация Retrieval | 1 час |
| Этап 4: Интеграция с Llama-3 | 2 часа |
| Этап 5: Тестирование и валидация | 1 час |
| Итого | 9 часов |
Примечание Для первого раза заложите +3 часа на отладку и настройку окружения. Рекомендуется выполнять задачу в течение 2–3 дней по 4 часа.
9. Связанные вопросы из базы знаний
| Вопрос | Тема |
|---|---|
| 10 | Что такое RAG? |
| 45 | Как работают векторные базы данных? |
| 89 | Сравнение embedding моделей (BGE-M3 vs Ada) |
| 134 | Docling vs Unstructured для парсинга PDF |
| 201 | Chunking strategies для RAG |
| 278 | Подготовка данных для RAG (чистка, dedup) |
| 312 | Llama-3 vs GPT-4 для генерации ответов |
| 456 | Оценка качества RAG (RAGAS, Faithfulness) |
| 590 | Оптимизация поиска в Qdrant (HNSW, quantization) |
| 701 | Как реализовать автономный RAG-сервис с FastAPI |
10. Чек-лист самопроверки
- Я установил всё окружение (Docker, Ollama, Python) и запустил Qdrant.
- Я успешно проиндексировал все 100 PDF без ошибок.
- Я написал функцию retrieve, которая возвращает чанки с метаданными.
- Я протестировал генерацию ответов на нескольких вопросах, и ответы содержат цитаты.
- Я зафиксировал PASS/FAIL для 10 вопросов и исправил ошибки, если они были.
- Я проверил, что код воспроизводим на чистом окружении (документация, requirements.txt).
- Я выложил проект в репозиторий с README.