Files
rag-from-scratch/README.md
T
davide b4e64ccedb docs: riscrive README con struttura passo-passo
Abstract, requisiti minimi, setup venv, MinerU (Colab + locale),
chunking, ingest, interrogazione (terminale + GUI) con tabelle
parametri per ogni config.py.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 10:04:38 +02:00

221 lines
7.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# RAG from scratch
Esercizio pratico per costruire una pipeline RAG (Retrieval-Augmented Generation) completa a partire da documenti PDF, interamente in locale senza dipendenze cloud. L'obiettivo è avere un assistente che risponde a domande sui tuoi documenti usando solo il contenuto di quei documenti, senza allucinazioni.
**Stack:** Python · MinerU · ChromaDB · Ollama
**Chunking:** AST-based, deterministico, senza LLM
**Embedding + Generazione:** Ollama (locale, nessun dato inviato a server esterni)
```
PDF
└─ MinerU ──► sources/<stem>.md
└─ chunker.py ──► chunks/<stem>/chunks.json
└─ ingest.py ──► chroma_db/
└─ rag.py / GUI
```
---
## Requisiti minimi
| Risorsa | Minimo | Note |
|---------|--------|------|
| Python | 3.10 3.13 | testato su 3.11 |
| RAM | 8 GB | 16 GB+ per modelli LLM grandi |
| Disco | 5 GB liberi | + spazio modelli Ollama |
| GPU | non necessaria | accelera MinerU e modelli LLM |
| OS | Linux, macOS, Windows (WSL2) | |
**Dipendenze Python** — installate via `requirements.txt`:
- `chromadb` — database vettoriale locale
- `markdown-it-py` + `mdit-py-plugins` — parser Markdown AST-based per il chunking
- `PySide6` — interfaccia grafica desktop (opzionale, solo per la GUI)
**Dipendenze esterne:**
- [Ollama](https://ollama.com) — server locale per embedding e generazione LLM
- [MinerU](https://github.com/opendatalab/MinerU) — conversione PDF → Markdown (opzionale se hai già i file `.md`)
---
## Setup ambiente
```bash
# Crea e attiva il virtual environment
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
# Installa le dipendenze
pip install -r requirements.txt
```
---
## Passo 1 — Converti i PDF con MinerU
MinerU estrae il testo dai PDF producendo un Markdown strutturato con tabelle, formule ed immagini. Ci sono due modalità:
### Opzione A — Google Colab (consigliata, usa la GPU gratuita di Google)
Il notebook `mineru.ipynb` esegue MinerU su Colab sfruttando la GPU messa a disposizione gratuitamente. Utile se non hai una GPU locale o se i PDF sono pesanti.
1. Apri `mineru.ipynb` su Google Colab
2. Carica i PDF nella cartella `input/` indicata nelle celle
3. Esegui tutte le celle — al termine viene scaricato uno ZIP per ogni documento
4. Decomprimi gli ZIP nella cartella `sources/` del progetto:
```
sources/
└── <stem>_output/
└── auto/
├── <stem>.md ← questo è l'input della pipeline
└── images/
```
### Opzione B — Installazione locale
```bash
pip install "mineru[all]" # installa MinerU (scarica ~15 GB di modelli al primo avvio)
mineru -p documento.pdf -o sources/<stem>_output/ -b pipeline
# Con GPU:
mineru -p documento.pdf -o sources/<stem>_output/ -b hybrid-auto-engine
```
---
## Passo 2 — Chunking
Il chunker analizza il Markdown con un parser AST, divide il testo in blocchi semantici e li impacchetta in chunk ottimizzati per il retrieval.
```bash
# Singolo documento
python chunks/chunker.py --stem <stem>
# Tutti i documenti presenti in sources/ in una volta
python chunks/chunker.py
# Rigenera anche se chunks.json esiste già
python chunks/chunker.py --stem <stem> --force
```
Output in `chunks/<stem>/`: `chunks.json`, `meta.json`, `report.json`.
### Configurazione — `chunks/config.py`
Modifica i parametri nella classe `ChunkerConfig` se necessario:
| Parametro | Default | Descrizione |
|-----------|---------|-------------|
| `max_chars` | `1200` | Dimensione massima di un chunk (caratteri) |
| `min_chars` | `80` | Soglia minima; chunk piu' piccoli vengono accorpati |
| `target_chars` | `800` | Dimensione target per il packing greedy |
| `context_depth` | `3` | Livelli di heading inclusi come prefisso nel testo per l'embedding |
| `skip_headings` | vedi file | Sezioni saltate completamente (indice, sommario, ecc.) |
| `skip_pre_heading` | `True` | Salta il contenuto prima del primo heading (frontespizi, ecc.) |
| `atomic_types` | `table, code, list, math, html` | Tipi di blocco che non vengono mai spezzati |
---
## Passo 3 — Vettorizzazione (ingest)
Genera gli embedding dei chunk e li indicizza in ChromaDB. Richiede Ollama attivo.
```bash
# Avvia Ollama (se non e' gia' in esecuzione)
ollama serve
# Installa il modello di embedding (una volta sola)
ollama pull bge-m3
# Indicizza un singolo documento
python ingestion/ingest.py --stem <stem>
# Indicizza piu' documenti in una collection condivisa (RAG cross-documento)
python ingestion/ingest.py --collection <nome> --stems doc1 doc2 doc3
# Rigenera dopo aver aggiornato i chunk o cambiato modello embedding
python ingestion/ingest.py --stem <stem> --force
```
### Configurazione — `ingestion/config.py`
| Parametro | Default | Descrizione |
|-----------|---------|-------------|
| `EMBED_MODEL` | `bge-m3` | Modello Ollama per gli embedding. Se lo cambi, riesegui l'ingest con `--force` |
| `EMBED_MAX_CHARS` | `6000` | Caratteri massimi inviati al modello per ogni chunk |
| `OLLAMA_URL` | `http://localhost:11434` | URL del server Ollama |
---
## Passo 4 — Interrogazione
### Da terminale
```bash
# Installa il modello LLM (una volta sola)
ollama pull qwen3.5:4b
# RAG interattivo — retrieval + risposta generata dal modello
python rag/rag.py --collection <nome>
python rag/rag.py --stem <stem> # scorciatoia per collection a documento singolo
# Retrieval puro senza LLM (utile per debug)
python rag/retrieve.py --collection <nome>
python rag/retrieve.py --stem <stem> --top-k 10
```
Nel loop interattivo: digita la domanda e premi Invio. Aggiungi `-v` alla fine per vedere i chunk recuperati con i relativi score di similarita'.
### Con la GUI desktop
```bash
python gui/main.py
python gui/main.py --collection <nome> # apre direttamente la collection
```
La GUI mostra le risposte con Markdown e formule matematiche renderizzate. Il tema chiaro/scuro e' selezionabile dal pulsante in alto a destra.
### Configurazione — `rag/config.py`
| Parametro | Default | Descrizione |
|-----------|---------|-------------|
| `OLLAMA_MODEL` | `qwen3.5:4b` | Modello LLM per la generazione |
| `TOP_K` | `6` | Numero di chunk recuperati per ogni domanda |
| `TEMPERATURE` | `0.2` | 0 = deterministico, valori alti = piu' creativo |
| `NO_THINK` | `True` | Disabilita il reasoning interno (piu' veloce; solo modelli Qwen3) |
| `OLLAMA_URL` | `http://localhost:11434` | URL del server Ollama |
| `SYSTEM_PROMPT` | vedi file | Istruzioni di sistema inviate al modello prima del contesto |
---
## Struttura del repository
```
rag/
├── sources/ ← output MinerU (una cartella per documento)
├── chunks/
│ ├── chunker.py ← orchestrazione pipeline AST
│ ├── config.py ← parametri di chunking
│ ├── parser.py ← markdown-it-py + dollarmath
│ ├── segmenter.py ← token stream -> Block[]
│ ├── packer.py ← Block[] -> Chunk[]
│ └── validator.py ← invarianti e metriche
├── ingestion/
│ ├── ingest.py ← embedding -> ChromaDB
│ └── config.py ← parametri embedding
├── rag/
│ ├── rag.py ← loop RAG interattivo
│ ├── retrieve.py ← retrieval puro (debug)
│ └── config.py ← parametri RAG e system prompt
├── gui/
│ ├── main.py ← entry point GUI
│ ├── chat_window.py ← finestra principale PySide6
│ ├── worker.py ← thread per il pipeline RAG
│ └── chat.html ← template HTML (Markdown + KaTeX)
├── chroma_db/ ← database vettoriale (non tracciato da git)
├── mineru.ipynb ← notebook Colab per conversione PDF
└── requirements.txt
```