- Add rag_indexer.py: build LightRAG index from OCR with OpenCode API - Add rag_query.py: query the knowledge graph - Add vlm_describer.py: generate VLM descriptions via LM Studio - Add test_model.py: quick check for LightRAG-compatible models - Add run_pipeline.sh and run_pipeline.bat: full OCR → VLM → RAG pipeline - Fix rapidocr import (rapidocr_onnxruntime) - Fix process_any_pdf.py paths for cross-platform use - Add .env.example, README_RAG.md, AGENTS.md - Update .gitignore for outputs and secrets
10 KiB
RAG / LightRAG для анализа чертежей
Этот модуль добавляет Retrieval-Augmented Generation (RAG) поверх существующего OCR-pipeline. Он превращает распознанный текст из full_ocr_results.json в граф знаний и позволяет задавать вопросы по чертежам на естественном языке.
Архитектура
PDF -> PyMuPDF + RapidOCR -> full_ocr_results.json
|
v
rag_indexer.py (LightRAG)
|
v
lightrag_cache/ (граф знаний)
|
v
rag_query.py (вопросы)
Почему LightRAG?
- Строит граф сущностей и отношений (этажи, оси, размеры, помещения)
- Поддерживает 4 режима поиска:
naive,local,global,hybrid - Для чертежей рекомендуется
hybrid— объединяет локальный поиск по соседним сущностям и глобальный контекст проекта
Установка
# 1. Установите зависимости
pip install -r requirements.txt
# 2. Выберите LLM backend:
Вариант A: OpenAI (быстро, требует интернет)
export OPENAI_API_KEY="sk-..."
# или в Windows: set OPENAI_API_KEY=sk-...
Вариант B: Ollama (локально, приватно, требует RAM/VRAM)
# Установите Ollama: https://ollama.com
# Скачайте модели (пример)
ollama pull qwen2.5:14b # LLM для ответов
ollama pull nomic-embed-text # embeddings
# Запустите сервер
ollama serve
Вариант C: LM Studio (локальный GUI, подходит для VLM)
# Установите LM Studio: https://lmstudio.ai
# 1. Загрузите VLM модель (например, qwen3-vl-4b) и запустите Local Server
# 2. Убедитесь, что сервер доступен: http://127.0.0.1:1234/v1
# Переменные окружения (при необходимости)
export LMSTUDIO_URL="http://127.0.0.1:1234/v1"
export LMSTUDIO_API_KEY="lm-studio"
Вариант D: OpenCode API (DeepSeek V4 Flash Free)
# Требуется API-ключ OpenCode (бесплатный тариф)
# 1. Получите ключ на https://opencode.ai
# 2. Экспортируйте переменные:
export OPENCODE_API_KEY="ваш-ключ"
export OPENCODE_URL="https://opencode.ai/zen/v1" # опционально, уже задан по умолчанию
Использование
Шаг 1: OCR (если еще не сделано)
python process_any_pdf.py "Кронштадтский 16-18 НК1_ОСК (v3).pdf" output_kronshtadt
Результат: папка output_kronshtadt/ с full_ocr_results.json.
Шаг 2: Построение индекса
OpenAI:
python rag_indexer.py output_kronshtadt --backend openai --model gpt-4o-mini
Ollama (локально):
python rag_indexer.py output_kronshtadt --backend ollama --model qwen2.5:14b --embed-model nomic-embed-text
Результат: папка output_kronshtadt/lightrag_cache/ с графом знаний.
LM Studio (VLM для описаний):
# Сгенерировать VLM-описания PNG (локальная Qwen)
python vlm_describer.py output_kronshtadt --model qwen/qwen3-vl-4b
# Построить индекс через OpenCode API (LLM)
python rag_indexer.py output_kronshtadt --backend opencode --vlm-desc
OpenCode API (DeepSeek V4 Flash Free):
# Построение индекса через бесплатный DeepSeek
python rag_indexer.py output_kronshtadt --backend opencode --model opencode/deepseek-v4-flash-free
# С VLM-описаниями (локальная Qwen + бесплатный DeepSeek)
python rag_indexer.py output_kronshtadt --backend opencode --vlm-desc
Шаг 3 (опционально): VLM-описания через LM Studio
Если у вас в LM Studio загружена VLM модель (например, qwen3-vl-4b), можно сгенерировать текстовые описания PNG перед индексацией:
python vlm_describer.py output_kronshtadt --model qwen/qwen3-vl-4b
Это создаст output_kronshtadt/vlm_descriptions.json — текстовое описание каждой страницы. При --vlm-desc в rag_indexer.py эти описания добавятся к OCR-тексту, давая RAG понимание пространственной компоновки.
Важно: 4B VLM хороша для базовых описаний, но на сложных А0-чертежах может галлюцинировать. Для лучшего качества используйте 7B+ VLM (Qwen2-VL 7B, InternVL 8B).
Шаг 4: Запросы
# Через OpenCode API (рекомендуется — бесплатно)
python rag_query.py output_kronshtadt "На каких страницах показан план 3-го этажа?" --backend opencode --mode hybrid
python rag_query.py output_kronshtadt "Какие размеры указаны между осями А и Б?" --backend opencode --mode hybrid
python rag_query.py output_kronshtadt "Какие квартиры есть на этаже 2?" --backend opencode --mode hybrid
# Режим local — ищет соседей сущностей в графе
python rag_query.py output_kronshtadt "Что находится рядом с осью В?" --backend opencode --mode local
# Режим global — общий контекст проекта
python rag_query.py output_kronshtadt "Опиши общую структуру здания по чертежам." --backend opencode --mode global
Как это работает под капотом
1. Формирование документов
rag_indexer.py читает full_ocr_results.json и для каждой страницы создает текстовый документ вида:
=== Чертеж: страница 5 из 120 ===
Изображение: page_005.png
--- Текстовый слой PDF ---
План 3-го этажа...
--- Распознанный текст (OCR) ---
"3-й этаж" (confidence=0.95, bbox=[100, 200, 150, 220])
"Ось А" (confidence=0.88, bbox=[300, 400, 350, 420])
"5400 мм" (confidence=0.92, bbox=[500, 600, 580, 620])
--- Извлеченные сущности ---
Этажи: 3-й этаж
Оси: А
Размеры: 5400 мм
2. Построение графа (LightRAG)
LightRAG пропускает каждый документ через LLM и извлекает:
- Entities:
3-й этаж,Ось А,5400 мм - Relationships:
3-й этаж -> содержит -> Ось А,Ось А -> имеет размер -> 5400 мм
Это сохраняется в lightrag_cache/ как граф + векторные эмбеддинги.
3. Поиск ответа
При запросе "Какие размеры между осями А и Б?":
- Hybrid = Local (ищет узлы "Ось А", "Ось Б" и их соседей) + Global (общий контекст "размеры между осями")
- LLM генерирует ответ на основе найденных фрагментов
Советы по использованию для чертежей
- Качество OCR критично — если RapidOCR пропускает цифры размеров, RAG не найдет их. Проверяйте
full_ocr_results.json. - Структурируйте сущности — в
rag_indexer.pyуже встроен парсер этажей, осей, размеров. При необходимости расширьте регулярные выражения под ваши ГОСТ-овские обозначения. - Страницы как узлы — если чертеж очень большой (А0), можно разбить PNG на фрагменты и индексировать их отдельно.
- VLM для сложных схем — если нужно понимать геометрию (а не только текст), добавьте описания от зрительной модели (Qwen2-VL, LLaVA) в текст документов перед индексацией.
Расширение: добавление VLM-описаний
Если у вас есть GPU, можно улучшить понимание чертежей:
# Псевдокод — добавить в rag_indexer.py перед insert
from transformers import Qwen2VLForConditionalGeneration, AutoProcessor
vlm = Qwen2VLForConditionalGeneration.from_pretrained("Qwen/Qwen2-VL-7B-Instruct")
processor = AutoProcessor.from_pretrained("Qwen/Qwen2-VL-7B-Instruct")
desc = vlm_describe_image(page_image_path, "Опиши этот чертеж: этажи, оси, размеры, помещения.")
doc_text += f"\n--- Описание модели зрения ---\n{desc}\n"
await rag.ainsert(doc_text)
Это даст RAG понимание пространственной компоновки, даже если OCR плохо распознал текст.
Файлы
| Файл | Назначение |
|---|---|
rag_indexer.py |
Построение индекса LightRAG из OCR-результатов |
rag_query.py |
Запросы к индексу |
requirements.txt |
Зависимости (lightrag-hku, openai, etc.) |