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

7.9 KiB
Raw Blame History

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 — server locale per embedding e generazione LLM
  • MinerU — conversione PDF → Markdown (opzionale se hai già i file .md)

Setup ambiente

# 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

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.

# 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.

# 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

# 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

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