docs: add PARSER agent documentation and implementation plan

- Add formal PARSER agent description (dots.ocr-based)
- Add detailed TODO-PARSER-RAG.md with implementation tasks
- Update agents README to include PARSER
- PARSER = Document Ingestion & Structuring Agent for RAG
This commit is contained in:
Apple
2025-11-15 13:09:58 -08:00
parent e0cb3ddbdb
commit 2fc1894b26
3 changed files with 667 additions and 0 deletions

386
TODO-PARSER-RAG.md Normal file
View File

@@ -0,0 +1,386 @@
# TODO: PARSER Agent + RAG Haystack Stack
Детальний план реалізації PARSER-агента на базі `dots.ocr` та RAG-системи на базі Haystack.
**Статус:** 🟡 Планування
---
## G. PARSER Agent (dots.ocr)
### G.1. Runtime моделі PARSER
- [ ] **G.1.1** Обрати runtime для dots.ocr
- [ ] Варіант A: HuggingFace Transformers + vLLM/SGLang
- [ ] Варіант B: llama.cpp / GGUF (якщо буде GGUF-версія)
- [ ] Варіант C: Ollama (якщо підтримується)
- **Примітка:** Обрати найпростіший варіант для старту
- [ ] **G.1.2** Створити `parser-runtime/` сервіс
- [ ] `parser_runtime/__init__.py`
- [ ] `parser_runtime/model_loader.py` (lazy init, GPU/CPU fallback)
- [ ] `parser_runtime/inference.py` (функції: `parse_image`, `parse_pdf`)
- [ ] `parser_runtime/config.py` (конфігурація моделі)
- [ ] **G.1.3** Додати конфіг
- [ ] `PARSER_MODEL_NAME=rednote-hilab/dots.ocr`
- [ ] `PARSER_DEVICE=cuda` / `cpu`
- [ ] `PARSER_MAX_PAGES=100`
- [ ] `PARSER_MAX_RESOLUTION=4096x4096`
- [ ] `PARSER_BATCH_SIZE=1` (для початку)
---
### G.2. HTTP-сервіс `parser-service`
- [ ] **G.2.1** Створити сервіс `services/parser-service/` (FastAPI)
- [ ] `main.py` — FastAPI додаток
- [ ] `schemas.py` — Pydantic моделі (ParsedDocument, ParsedBlock, ...)
- [ ] `config.py` — конфігурація
- [ ] `Dockerfile` — Docker образ
- [ ] `requirements.txt` — залежності
- [ ] **G.2.2** Ендпоінти
- [ ] `POST /ocr/parse` — повертає raw JSON
- Request: `{doc_url, file_bytes, output_mode: "raw_json"}`
- Response: `ParsedDocument`
- [ ] `POST /ocr/parse_qa` — Q&A-представлення
- Request: `{doc_url, file_bytes}`
- Response: `{qa_pairs: [...]}`
- [ ] `POST /ocr/parse_markdown` — Markdown-версія
- Request: `{doc_url, file_bytes}`
- Response: `{markdown: "..."}`
- [ ] `POST /ocr/parse_chunks` — семантичні фрагменти для RAG
- Request: `{doc_url, file_bytes, dao_id, doc_id}`
- Response: `{chunks: [...]}`
- [ ] `GET /health` — health check
- [ ] **G.2.3** Підтримати типи файлів
- [ ] PDF (розбиття по сторінках → зображення)
- Використати `pdf2image` або `PyMuPDF`
- [ ] PNG/JPEG
- Пряма обробка через `PIL` / `Pillow`
- [ ] TIFF (опційно)
- [ ] WebP (опційно)
- [ ] **G.2.4** Додати pre-/post-processing
- [ ] Нормалізація розміру зображень (resize до max resolution)
- [ ] Конвертація PDF → зображення (по сторінках)
- [ ] Mapping вихідного JSON dots.ocr → внутрішню структуру `ParsedBlock`
- [ ] Валідація структури (перевірка наявності обов'язкових полів)
- [ ] **G.2.5** Додати базові тести
- [ ] Створити `tests/fixtures/docs/` з тестовими документами
- [ ] 12 короткі PDF-файли (23 сторінки)
- [ ] 12 PNG зображення з текстом
- [ ] Snapshot-тести JSON-структури (без чутливості до точного тексту)
- [ ] Тести на обробку помилок (невалідний PDF, занадто великий файл)
- [ ] **G.2.6** Додати в `docker-compose.yml`
- [ ] Сервіс `parser-service` з залежностями
- [ ] Environment variables
- [ ] Health check
- [ ] Volumes для тимчасових файлів
---
### G.3. Інтеграція PARSER у DAGI Router
- [ ] **G.3.1** Додати LLM-профіль у `router-config.yml`
```yaml
llm_profiles:
parser_dots_ocr:
model: "dots.ocr"
base_url: "http://parser-runtime:11435" # або Ollama/vLLM endpoint
timeout_s: 120
```
- [ ] **G.3.2** Додати provider
```yaml
providers:
parser:
type: ocr
base_url: "http://parser-service:9400"
```
- [ ] **G.3.3** Додати routing rule
```yaml
routing:
- id: doc_parse
when:
mode: doc_parse
use_provider: parser
```
- [ ] **G.3.4** Розширити `RouterRequest` (в `router_client.py` або `types/api.ts`)
- [ ] Поля `doc_url: Optional[str]`
- [ ] Поля `doc_type: Optional[str]` (`pdf`, `image`)
- [ ] Поля `output_mode: Optional[str]` (`raw_json|qa_pairs|markdown|chunks`)
- [ ] Поля `file_bytes: Optional[bytes]` (для прямого завантаження)
- [ ] **G.3.5** E2E curl-тест
```bash
curl -X POST http://localhost:9102/route \
-H "Content-Type: application/json" \
-d '{
"mode": "doc_parse",
"dao_id": "daarion",
"user_id": "test",
"payload": {
"doc_url": "https://.../example.pdf",
"output_mode": "qa_pairs"
}
}'
```
---
### G.4. Опис агента PARSER
- [ ] **G.4.1** Створити `docs/agents/parser.md` ✅ (вже створено)
- [x] Роль: **Document Ingestion & Structuring Agent**
- [x] Вхід: `doc_url`, `file_id`, `raw bytes`
- [x] Вихід: `ParsedDocument { blocks[], tables[], qa_pairs[] }`
- [x] Обмеження: max pages, max file size
- [ ] **G.4.2** Додати `parser_agent` у CrewAI/оркестратор
- [ ] Створити `orchestrator/agents/parser_agent.py`
- [ ] Задачі:
- [ ] `parse_for_rag` — підготовка chunk'ів для індексації
- [ ] `parse_for_summary` — підготовка структурованого огляду doc'а
- [ ] `parse_for_qa` — Q&A базу для SecondMe/microDAO
- [ ] Інтеграція з CrewAI workflow
- [ ] **G.4.3** Зв'язати PARSER з RBAC
- [ ] Перевірка прав на інжест документів (`role: admin`, `role: researcher`)
- [ ] Обмеження на приватні/публічні документи
- [ ] Перевірка `dao_id` для ізоляції даних
- [ ] Додати в `microdao/rbac.py` (якщо потрібно)
---
## H. RAG Haystack Stack (PARSER як головний агент)
Тут PARSER — **головний агент інжесту**, а RAG шар — **Haystack-пайплайни для пошуку відповідей**.
### H.1. Вибір стеку RAG
- [ ] **H.1.1** Обрати фреймворк
- [ ] Варіант A: **deepset Haystack 2.x** (pipelines, retrievers, document stores)
- Переваги: готові компоненти, добра документація
- Недоліки: може бути overkill для простого випадку
- [ ] Варіант B: власний RAG поверх `pgvector`/Qdrant + простий код
- Переваги: легше, більше контролю
- Недоліки: треба писати більше коду
- **Рекомендація:** Почнути з варіанту B (pgvector вже є), потім можна перейти на Haystack
- [ ] **H.1.2** Обрати векторне сховище
- [ ] Postgres + pgvector (вже є в `city-db`)
- [ ] Або [ ] Qdrant / Weaviate / Milvus (якщо потрібна краща продуктивність)
- **Рекомендація:** Використати `pgvector` (вже налаштовано)
- [ ] **H.1.3** Обрати embedding-модель
- [ ] Варіант A: `sentence-transformers/all-MiniLM-L6-v2` (легка, швидка)
- [ ] Варіант B: `intfloat/multilingual-e5-base` (краще для української)
- [ ] Варіант C: Qwen embedding (якщо є)
- **Рекомендація:** Почнути з `multilingual-e5-base`
---
### H.2. Інджест-пайплайн (PARSER → RAG)
- [ ] **H.2.1** Створити `services/rag_ingest_pipeline.py`
- [ ] Функція `ingest_document(doc_id, doc_url, dao_id, user_id)`
- [ ] Функція `ingest_chunks(chunks: List[ParsedChunk], dao_id, doc_id)`
- [ ] **H.2.2** Кроки пайплайну
- [ ] Виклик PARSER (`mode=doc_parse`, `output_mode=chunks`)
- [ ] Нормалізація блоків у формат для індексації:
- [ ] `content` — текст блоку
- [ ] `meta` — `dao_id`, `doc_id`, `page`, `bbox`, `section_type`
- [ ] Обчислення ембеддингів (окремий embedding-модель/провайдер)
- [ ] Створити `services/embedding_service.py` або використати `sentence-transformers`
- [ ] Запис у document store (Postgres + pgvector)
- [ ] Створити таблицю `document_chunks`:
```sql
CREATE TABLE document_chunks (
id UUID PRIMARY KEY,
doc_id TEXT NOT NULL,
dao_id TEXT NOT NULL,
chunk_text TEXT NOT NULL,
embedding vector(768), -- або інший розмір
page_num INTEGER,
bbox JSONB,
section_type TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
```
- [ ] **H.2.3** Тест
- [ ] Індексувати 1 PDF (наприклад, "Токеноміка MicroDAO")
- [ ] Перевірити, що в storage з'явилися Documents з meta `[dao_id=... , doc_id=...]`
- [ ] Перевірити, що embeddings обчислені та збережені
---
### H.3. Query-пайплайн (RAG-відповіді)
- [ ] **H.3.1** Створити `services/rag_query_pipeline.py`
- [ ] Функція `answer_query(dao_id, user_id, question: str) -> RAGResponse`
- [ ] **H.3.2** RAG-пайплайн (якщо використовуємо Haystack)
- [ ] `retriever` → top-k документів/фрагментів по `dao_id`
- [ ] Використати `pgvector` для similarity search
- [ ] Фільтр по `dao_id` для ізоляції даних
- [ ] (опційно) `ranker` → rerank за релевантністю
- [ ] `generator` → LLM (qwen3:8b або PokeeResearch-7B)
- [ ] Формувати промпт з контекстом: `question + retrieved_chunks`
- [ ] **H.3.3** Вихід `RAGResponse`
```python
class RAGResponse:
answer: str
citations: List[Citation]
confidence: float
class Citation:
doc_id: str
doc_title: str
page: int
excerpt: str
bbox: Optional[Dict] # для виділення в PDF
```
- [ ] **H.3.4** E2E-тест
- [ ] `mode="rag_query"` запит до Router:
```json
{
"mode": "rag_query",
"dao_id": "daarion",
"user_id": "test",
"payload": {
"question": "Поясни токеноміку microDAO і роль стейкінгу."
}
}
```
- [ ] Очікування: відповідь + 23 посилання на індексовані документи
---
### H.4. Оркестрація: PARSER як головний агент
- [ ] **H.4.1** Додати в CrewAI workflow `doc_ingest_workflow`
- [ ] Agent `parser_agent`:
- [ ] Перевіряє тип документа
- [ ] Вирішує: локальний PARSER vs хмарний (якщо важкі PDF)
- [ ] Викликає `rag_ingest_pipeline`
- [ ] Agent `validation_agent`:
- [ ] Робить sanity-check: кількість блоків, чи є таблиці, чи коректна мова
- [ ] Перевіряє якість розпізнавання (confidence scores)
- [ ] **H.4.2** Додати в workflow `rag_answer_workflow`
- [ ] Крок 1: `retrieval_agent` (Haystack/pgvector)
- [ ] Пошук релевантних фрагментів
- [ ] Крок 2: `answer_agent` (LLM)
- [ ] Генерація відповіді на основі контексту
- [ ] Крок 3: (опційно) `citation_checker`
- [ ] Верифікація відповідей по фрагментах
- [ ] Перевірка на галлюцинації
---
### H.5. Інтеграція з DAARWIZZBot / microDAO
- [ ] **H.5.1** Додати команди для бота (в `gateway-bot/http_api.py`)
- [ ] `/upload_doc` → інжест документу в RAG через PARSER
- [ ] Підтримка завантаження файлів через Telegram
- [ ] Виклик `doc_ingest_workflow`
- [ ] `/ask_doc` → питання до бази документів DAO
- [ ] Виклик `rag_answer_workflow`
- [ ] Відправка відповіді з цитатами
- [ ] **H.5.2** RBAC
- [ ] Хто може інжестити документи (`role: admin`, `role: researcher`)
- [ ] Хто може ставити питання до приватних документів
- [ ] Перевірка прав в `microdao/rbac.py`
- [ ] **H.5.3** UI для Console (опційно)
- [ ] Сторінка `/console/documents` — список документів DAO
- [ ] Завантаження документів через drag-and-drop
- [ ] Перегляд розпарсених документів
- [ ] Чат-інтерфейс для питань до документів
---
## Порядок виконання (рекомендований)
### Фаза 1: PARSER Runtime (1-2 дні)
1. G.1.1 — Обрати runtime
2. G.1.2 — Створити `parser-runtime/`
3. G.1.3 — Додати конфіг
### Фаза 2: PARSER Service (2-3 дні)
1. G.2.1 — Створити FastAPI сервіс
2. G.2.2 — Реалізувати ендпоінти
3. G.2.3 — Підтримка PDF/зображень
4. G.2.4 — Pre/post-processing
5. G.2.5 — Тести
6. G.2.6 — Docker Compose
### Фаза 3: Інтеграція з Router (1 день)
1. G.3.1 — LLM-профіль
2. G.3.2 — Provider
3. G.3.3 — Routing rule
4. G.3.4 — Розширити RouterRequest
5. G.3.5 — E2E тест
### Фаза 4: RAG Ingest (2-3 дні)
1. H.1.1 — Обрати стек
2. H.2.1 — Створити ingest pipeline
3. H.2.2 — Реалізувати кроки
4. H.2.3 — Тест
### Фаза 5: RAG Query (2-3 дні)
1. H.3.1 — Створити query pipeline
2. H.3.2 — Реалізувати RAG-пайплайн
3. H.3.3 — Вихід з цитатами
4. H.3.4 — E2E тест
### Фаза 6: Оркестрація (1-2 дні)
1. H.4.1 — `doc_ingest_workflow`
2. H.4.2 — `rag_answer_workflow`
### Фаза 7: Інтеграція з ботом (1-2 дні)
1. H.5.1 — Команди `/upload_doc`, `/ask_doc`
2. H.5.2 — RBAC
**Загальний час:** ~10-15 днів (залежить від складності моделі та налаштування)
---
## Залежності та ресурси
### Python пакети
- `qwen3-asr-toolkit` (якщо доступний)
- `transformers` / `torch` (для моделі)
- `pdf2image` / `PyMuPDF` (для PDF)
- `Pillow` (для зображень)
- `sentence-transformers` (для embeddings)
- `pgvector` (вже є)
- `haystack` (якщо використовуємо)
### Системні залежності
- `ffmpeg` (може знадобитися)
- `poppler` (для PDF → images)
### GPU
- Рекомендовано GPU для dots.ocr (можна CPU fallback)
---
## Посилання
- [PARSER Agent Documentation](./docs/agents/parser.md)
- [DAGI Router Documentation](./docs/agents/dagi-router.md)
- [CrewAI Orchestrator](./docs/agents/crewai-orchestrator.md)

View File

@@ -16,6 +16,9 @@
- `crewai-orchestrator.md` — архітектура CrewAI - `crewai-orchestrator.md` — архітектура CrewAI
- `crewai-integration.md` — інтеграція з системою - `crewai-integration.md` — інтеграція з системою
### PARSER Agent
- `parser.md` — Document Ingestion & Structuring Agent (dots.ocr)
## Посилання ## Посилання
- [MicroDAO документація](../microdao/README.md) - [MicroDAO документація](../microdao/README.md)

278
docs/agents/parser.md Normal file
View File

@@ -0,0 +1,278 @@
# PARSER Agent (dots.ocr)
**Document Ingestion & Structuring Agent** для DAARION / microDAO / SecondMe.
## Роль та призначення
PARSER — це агент, який перетворює неструктуровані документи (PDF, зображення) у структуровані дані для RAG (Retrieval-Augmented Generation) та знань-орієнтованих систем.
**Основна мета:** Забезпечити якісний інжест документів у базу знань зі збереженням структури, layout та семантики.
## Технічна база
### Модель: `rednote-hilab/dots.ocr`
- **Тип:** Image-Text-to-Text VLM (Vision Language Model)
- **Орієнтація:** Документ-орієнтований OCR з layout detection
- **GitHub:** https://github.com/QwenLM/Qwen3-ASR-Toolkit (або відповідний репозиторій)
### Ключові можливості моделі
1. **Мультимовний OCR + Layout**
- Розпізнає текст на багатьох мовах (включаючи low-resource)
- Правильно відновлює **reading order** (колонки, блоки, змішаний макет)
- Підтримка складних макетів (наукові статті, звіти, форми)
2. **Єдиний VLM для всього**
- Один модельний стек для **layout detection + OCR**
- Не потребує окремих моделей для таблиць/тексту/формул
- Уніфікований підхід до різних типів контенту
3. **Структурований вихід**
- JSON з блоками (`paragraph`, `heading`, `table`, `formula`, `figure_caption`, ...)
- Bbox-координати, сторінка, читальний порядок
- Окремі структури для таблиць (рядки/колонки, merged cells)
- Markdown/HTML-подібний текст (таблиці можна відтворювати як Markdown)
4. **Орієнтація на документи**
- Підтримка форм, інвойсів, звітів, наукових статей, презентацій
- Добре працює із змішаним контентом (текст навколо формул, підписи до рисунків)
## Вхідні дані
### Підтримувані формати
- **PDF:**
- Скани (зображення сторінок)
- "Цифрові" PDF (текст + векторна графіка)
- Багатосторінкові документи
- **Зображення:**
- PNG, JPEG, TIFF
- Підтримка різних роздільних здатностей
- **Документи зі змішаним контентом:**
- Текст + таблиці + схеми + формули
- Наукові статті, звіти, презентації
## Режими виводу
PARSER підтримує кілька режимів виводу (конфігурується через промпт/параметри):
### 1. `raw_json`
Повний структурований JSON з усіма блоками:
```json
{
"pages": [
{
"page_num": 1,
"blocks": [
{
"type": "heading",
"text": "Заголовок",
"bbox": [x, y, width, height],
"reading_order": 1
},
{
"type": "paragraph",
"text": "Текст параграфу...",
"bbox": [...],
"reading_order": 2
},
{
"type": "table",
"rows": [...],
"columns": [...],
"merged_cells": [...]
}
]
}
]
}
```
### 2. `markdown`
Таблиці/розділи у Markdown форматі:
```markdown
# Заголовок
Текст параграфу...
| Колонка 1 | Колонка 2 |
|-----------|-----------|
| Значення 1 | Значення 2 |
```
### 3. `qa_pairs`
Парсер одразу повертає Q&A-пари по документу (через LLM-постпроцес):
```json
{
"qa_pairs": [
{
"question": "Що таке токеноміка microDAO?",
"answer": "Токеноміка microDAO включає...",
"source_page": 1,
"source_bbox": [...]
}
]
}
```
### 4. `chunks`
Масив семантичних фрагментів для RAG:
```json
{
"chunks": [
{
"text": "Фрагмент тексту...",
"page": 1,
"bbox": [...],
"section": "introduction",
"metadata": {
"dao_id": "daarion",
"doc_id": "tokenomics_v1"
}
}
]
}
```
## Вихідні дані
### Структура `ParsedDocument`
```typescript
interface ParsedDocument {
doc_id: string;
doc_url?: string;
doc_type: "pdf" | "image";
pages: ParsedPage[];
metadata: {
dao_id: string;
user_id: string;
uploaded_at: string;
file_size: number;
page_count: number;
};
}
interface ParsedPage {
page_num: number;
blocks: ParsedBlock[];
width: number;
height: number;
}
interface ParsedBlock {
type: "paragraph" | "heading" | "table" | "formula" | "figure_caption" | "list";
text: string;
bbox: [x: number, y: number, width: number, height: number];
reading_order: number;
// Для таблиць:
table_data?: {
rows: string[][];
columns: string[];
merged_cells?: Array<{row: number, col: number, rowspan: number, colspan: number}>;
};
}
```
## Обмеження
- **Max pages:** Конфігурується через `PARSER_MAX_PAGES` (за замовчуванням: 100)
- **Max resolution:** Конфігурується через `PARSER_MAX_RESOLUTION` (за замовчуванням: 4096x4096)
- **Max file size:** Залежить від runtime (рекомендовано: до 50MB для PDF)
- **Підтримка мов:** Залежить від моделі dots.ocr (українська підтримується)
## Інтеграція з системою
### 1. DAGI Router
PARSER інтегрується як окремий провайдер:
```yaml
providers:
parser:
type: ocr
base_url: "http://parser-service:9400"
```
**Routing rule:**
```yaml
routing:
- id: doc_parse
when:
mode: doc_parse
use_provider: parser
```
### 2. CrewAI Orchestrator
PARSER як агент у CrewAI workflow:
- **`doc_ingest_workflow`:** Перевірка типу документа → виклик PARSER → інжест у RAG
- **`rag_answer_workflow`:** Використання розпарсених документів для відповідей
### 3. RBAC Integration
- Перевірка прав на інжест документів (`role: admin`, `role: researcher`)
- Обмеження на приватні/публічні документи
- Перевірка `dao_id` для ізоляції даних
## Використання
### Приклад запиту до PARSER
```bash
curl -X POST http://parser-service:9400/ocr/parse \
-H "Content-Type: application/json" \
-d '{
"doc_url": "https://example.com/tokenomics.pdf",
"output_mode": "chunks",
"dao_id": "daarion",
"user_id": "user123"
}'
```
### Приклад через DAGI Router
```bash
curl -X POST http://router:9102/route \
-H "Content-Type: application/json" \
-d '{
"mode": "doc_parse",
"dao_id": "daarion",
"user_id": "user123",
"payload": {
"doc_url": "https://example.com/tokenomics.pdf",
"output_mode": "qa_pairs"
}
}'
```
## Архітектура сервісу
```
parser-service/
├── main.py # FastAPI сервіс
├── parser_runtime/ # Runtime для dots.ocr
│ ├── __init__.py
│ ├── model_loader.py # Lazy init, GPU/CPU fallback
│ └── inference.py # parse_image, parse_pdf
├── schemas.py # Pydantic моделі
└── config.py # Конфігурація
```
## Залежності
- **Runtime:** HuggingFace Transformers + vLLM/SGLang (або llama.cpp/GGUF)
- **Модель:** `rednote-hilab/dots.ocr`
- **Python:** 3.11+
- **GPU:** Рекомендовано (можна CPU fallback)
## Посилання
- [TODO: PARSER + RAG Implementation](../TODO-PARSER-RAG.md)
- [DAGI Router Documentation](./dagi-router.md)
- [CrewAI Orchestrator](./crewai-orchestrator.md)