2026-05-20 16:08:00 +02:00
|
|
|
|
# RAG su documenti accademici
|
2026-04-12 23:53:13 +02:00
|
|
|
|
|
2026-05-20 16:08:00 +02:00
|
|
|
|
Pipeline completa per trasformare PDF accademici in un sistema RAG interrogabile in linguaggio naturale.
|
2026-04-12 23:53:13 +02:00
|
|
|
|
|
2026-05-20 16:08:00 +02:00
|
|
|
|
**Stack:** Python · MinerU · ChromaDB · Ollama
|
|
|
|
|
|
**Chunking:** rule-based, deterministico, senza LLM
|
|
|
|
|
|
**Embedding + Generazione:** Ollama (locale)
|
2026-04-12 23:53:13 +02:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-05-20 16:08:00 +02:00
|
|
|
|
## Prerequisiti
|
2026-04-12 23:53:13 +02:00
|
|
|
|
|
2026-06-04 14:29:06 +02:00
|
|
|
|
### 1. MinerU — conversione PDF → Markdown
|
2026-04-12 23:53:13 +02:00
|
|
|
|
|
2026-06-04 14:29:06 +02:00
|
|
|
|
MinerU è il tool esterno che converte i PDF in Markdown strutturato.
|
2026-05-20 16:08:00 +02:00
|
|
|
|
Repository: [https://github.com/opendatalab/MinerU](https://github.com/opendatalab/MinerU)
|
2026-05-11 15:46:52 +02:00
|
|
|
|
|
2026-05-20 16:08:00 +02:00
|
|
|
|
#### Requisiti di sistema
|
2026-05-11 15:46:52 +02:00
|
|
|
|
|
2026-05-20 16:08:00 +02:00
|
|
|
|
| Risorsa | Minimo | Raccomandato |
|
|
|
|
|
|
|---------|--------|--------------|
|
|
|
|
|
|
| Python | 3.10–3.13 | 3.11 |
|
|
|
|
|
|
| RAM | 16 GB | 32 GB+ |
|
|
|
|
|
|
| Disco | 20 GB (modelli inclusi) | 40 GB+ |
|
|
|
|
|
|
| GPU | opzionale | 4–8 GB VRAM (CUDA) |
|
2026-06-04 14:29:06 +02:00
|
|
|
|
| OS | Linux, macOS, Windows | Linux / WSL2 |
|
2026-05-11 15:46:52 +02:00
|
|
|
|
|
2026-05-20 16:08:00 +02:00
|
|
|
|
#### Installazione
|
|
|
|
|
|
|
2026-04-12 23:53:13 +02:00
|
|
|
|
```bash
|
2026-06-04 14:29:06 +02:00
|
|
|
|
pip install "mineru[all]"
|
2026-04-12 23:53:13 +02:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-06-04 14:29:06 +02:00
|
|
|
|
Al primo avvio scarica automaticamente i modelli (~15 GB).
|
2026-05-11 15:46:52 +02:00
|
|
|
|
|
2026-05-20 16:08:00 +02:00
|
|
|
|
#### Uso — CLI
|
2026-04-12 23:53:13 +02:00
|
|
|
|
|
|
|
|
|
|
```bash
|
2026-06-04 14:29:06 +02:00
|
|
|
|
mineru -p <documento.pdf> -o <output_dir> -b pipeline
|
2026-04-15 13:33:56 +02:00
|
|
|
|
```
|
2026-04-12 23:53:13 +02:00
|
|
|
|
|
2026-06-04 14:29:06 +02:00
|
|
|
|
| Flag | Descrizione |
|
|
|
|
|
|
|------|-------------|
|
|
|
|
|
|
| `-p` | Percorso PDF o cartella |
|
|
|
|
|
|
| `-o` | Cartella di output |
|
|
|
|
|
|
| `-b` | Backend: `pipeline` (CPU), `hybrid-auto-engine` (GPU raccomandato) |
|
|
|
|
|
|
| `-m` | Metodo: `auto`, `txt`, `ocr` |
|
2026-05-11 15:46:52 +02:00
|
|
|
|
|
2026-05-20 16:08:00 +02:00
|
|
|
|
#### Output di MinerU
|
|
|
|
|
|
|
|
|
|
|
|
```
|
2026-06-04 14:29:06 +02:00
|
|
|
|
<stem>_output/
|
2026-05-20 16:08:00 +02:00
|
|
|
|
└── auto/
|
2026-06-04 14:29:06 +02:00
|
|
|
|
├── <stem>.md ← Markdown (input della pipeline)
|
|
|
|
|
|
├── <stem>_content_list_v2.json
|
|
|
|
|
|
├── <stem>_model.json
|
|
|
|
|
|
└── images/
|
2026-05-11 15:46:52 +02:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-06-04 14:29:06 +02:00
|
|
|
|
Il file usato dalla pipeline è **`<stem>.md`** nella cartella `auto/`.
|
2026-05-20 16:08:00 +02:00
|
|
|
|
|
|
|
|
|
|
### 2. Ollama — embedding e generazione
|
|
|
|
|
|
|
|
|
|
|
|
Scarica e avvia [Ollama](https://ollama.com), poi installa i modelli:
|
2026-05-11 16:05:23 +02:00
|
|
|
|
|
|
|
|
|
|
```bash
|
2026-05-20 16:08:00 +02:00
|
|
|
|
ollama pull nomic-embed-text # embedding (obbligatorio)
|
|
|
|
|
|
ollama pull qwen3.5:4b # generazione LLM (o altro modello)
|
|
|
|
|
|
```
|
2026-05-11 16:05:23 +02:00
|
|
|
|
|
2026-05-20 16:08:00 +02:00
|
|
|
|
---
|
2026-05-12 11:21:24 +02:00
|
|
|
|
|
2026-05-20 16:08:00 +02:00
|
|
|
|
## Setup
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
git clone <questo-repo>
|
|
|
|
|
|
cd rag
|
2026-05-11 16:05:23 +02:00
|
|
|
|
|
2026-05-20 16:08:00 +02:00
|
|
|
|
python -m venv .venv
|
|
|
|
|
|
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
|
|
|
|
pip install -r requirements.txt
|
2026-05-11 16:05:23 +02:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-05-20 16:08:00 +02:00
|
|
|
|
---
|
2026-05-12 11:21:24 +02:00
|
|
|
|
|
2026-05-20 16:08:00 +02:00
|
|
|
|
## Flusso completo
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
PDF
|
|
|
|
|
|
│
|
2026-06-04 14:29:06 +02:00
|
|
|
|
▼ MinerU (esterno — vedi sotto)
|
|
|
|
|
|
sources/<stem>_output/auto/<stem>.md
|
2026-05-20 16:08:00 +02:00
|
|
|
|
│
|
|
|
|
|
|
▼ python chunks/chunker.py --stem <stem>
|
2026-06-04 14:29:06 +02:00
|
|
|
|
chunks/<stem>/chunks.json
|
2026-05-20 16:08:00 +02:00
|
|
|
|
│
|
|
|
|
|
|
▼ python chunks/verify_chunks.py --stem <stem>
|
2026-06-04 14:29:06 +02:00
|
|
|
|
(verifica qualità — opzionale ma consigliato)
|
2026-05-20 16:08:00 +02:00
|
|
|
|
│
|
|
|
|
|
|
▼ python ingestion/ingest.py --stem <stem>
|
2026-06-04 14:29:06 +02:00
|
|
|
|
chroma_db/<stem>/
|
2026-05-20 16:08:00 +02:00
|
|
|
|
│
|
|
|
|
|
|
▼ python rag.py --stem <stem>
|
2026-06-04 14:29:06 +02:00
|
|
|
|
Interrogazione in linguaggio naturale
|
2026-05-20 16:08:00 +02:00
|
|
|
|
```
|
2026-05-11 16:05:23 +02:00
|
|
|
|
|
2026-05-11 14:44:16 +02:00
|
|
|
|
---
|
2026-04-12 23:53:13 +02:00
|
|
|
|
|
2026-06-04 14:29:06 +02:00
|
|
|
|
## Passo 1 — Converti il PDF con MinerU
|
2026-04-12 23:53:13 +02:00
|
|
|
|
|
2026-06-04 14:29:06 +02:00
|
|
|
|
**Opzione A — Google Colab (nessuna installazione locale)**
|
2026-05-28 15:48:08 +02:00
|
|
|
|
|
2026-06-04 14:29:06 +02:00
|
|
|
|
Usa il notebook incluso:
|
2026-05-28 15:48:08 +02:00
|
|
|
|
|
|
|
|
|
|
```
|
2026-06-04 14:29:06 +02:00
|
|
|
|
mineru.ipynb
|
2026-05-28 15:48:08 +02:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-06-04 14:29:06 +02:00
|
|
|
|
Aprilo su Google Colab, carica il PDF e segui le celle. Al termine scarica automaticamente lo ZIP con l'output. Decomprimi la cartella in `sources/`:
|
2026-04-17 18:51:09 +02:00
|
|
|
|
|
2026-05-20 16:08:00 +02:00
|
|
|
|
```
|
|
|
|
|
|
sources/
|
2026-06-04 14:29:06 +02:00
|
|
|
|
└── <stem>_output/
|
2026-05-20 16:08:00 +02:00
|
|
|
|
└── auto/
|
2026-06-04 14:29:06 +02:00
|
|
|
|
├── <stem>.md ← usato dalla pipeline
|
|
|
|
|
|
├── <stem>_content_list_v2.json
|
|
|
|
|
|
├── <stem>_model.json
|
2026-05-28 15:48:08 +02:00
|
|
|
|
└── images/
|
2026-05-11 15:46:52 +02:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-06-04 14:29:06 +02:00
|
|
|
|
**Opzione B — Installazione locale**
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
mineru -p documento.pdf -o sources/<stem>_output/ -b pipeline
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
2026-04-12 23:53:13 +02:00
|
|
|
|
|
2026-06-04 14:29:06 +02:00
|
|
|
|
## Passo 2 — Chunking
|
2026-05-20 16:08:00 +02:00
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# Singolo documento
|
|
|
|
|
|
.venv/bin/python chunks/chunker.py --stem <stem>
|
2026-04-12 23:53:13 +02:00
|
|
|
|
|
2026-05-20 16:08:00 +02:00
|
|
|
|
# Tutti i documenti in sources/
|
|
|
|
|
|
.venv/bin/python chunks/chunker.py
|
2026-05-12 10:39:27 +02:00
|
|
|
|
|
2026-06-04 14:29:06 +02:00
|
|
|
|
# Rigenera anche se chunks.json esiste già
|
2026-05-20 16:08:00 +02:00
|
|
|
|
.venv/bin/python chunks/chunker.py --stem <stem> --force
|
2026-05-12 10:39:27 +02:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-06-04 14:29:06 +02:00
|
|
|
|
Il chunker legge `sources/<stem>_output/auto/<stem>.md` e produce `chunks/<stem>/chunks.json`.
|
2026-05-12 10:39:27 +02:00
|
|
|
|
|
2026-06-04 14:29:06 +02:00
|
|
|
|
**Regole applicate:**
|
|
|
|
|
|
|
|
|
|
|
|
- 1 paragrafo = 1 chunk; paragrafi di sezioni diverse non si mescolano
|
|
|
|
|
|
- Split a confine di frase se il paragrafo supera `MAX_CHARS` (mai a metà frase)
|
|
|
|
|
|
- Frasi spezzate tra paragrafi consecutivi vengono ri-fuse automaticamente
|
|
|
|
|
|
- Paragrafi brevi (< `MIN_CHARS`) vengono accorpati al successivo (stesso contesto)
|
|
|
|
|
|
- Sezioni configurabili vengono saltate (indice, sommario, frontespizio)
|
|
|
|
|
|
- Tabelle, liste e code block sono blocchi atomici (non si spezzano)
|
2026-05-20 16:08:00 +02:00
|
|
|
|
|
|
|
|
|
|
Output in `chunks/<stem>/`:
|
2026-05-12 10:39:27 +02:00
|
|
|
|
|
2026-05-20 16:08:00 +02:00
|
|
|
|
| File | Contenuto |
|
|
|
|
|
|
|------|-----------|
|
2026-06-04 14:29:06 +02:00
|
|
|
|
| `chunks.json` | Chunk con testo, sezione, titolo, n_chars |
|
|
|
|
|
|
| `meta.json` | Parametri usati |
|
2026-05-20 16:08:00 +02:00
|
|
|
|
| `report.json` | Statistiche e anomalie (generato da verify) |
|
2026-05-12 10:39:27 +02:00
|
|
|
|
|
2026-06-04 14:29:06 +02:00
|
|
|
|
---
|
2026-05-20 16:08:00 +02:00
|
|
|
|
|
2026-06-04 14:29:06 +02:00
|
|
|
|
## Passo 3 — Verifica i chunk (opzionale)
|
2026-05-12 10:39:27 +02:00
|
|
|
|
|
2026-05-20 16:08:00 +02:00
|
|
|
|
```bash
|
2026-06-04 14:29:06 +02:00
|
|
|
|
.venv/bin/python chunks/verify_chunks.py --stem <stem>
|
2026-05-20 16:08:00 +02:00
|
|
|
|
```
|
2026-05-12 10:39:27 +02:00
|
|
|
|
|
2026-06-04 14:29:06 +02:00
|
|
|
|
| Verdict | Significato |
|
|
|
|
|
|
|---------|-------------|
|
|
|
|
|
|
| `ok` | Nessun problema — procedi |
|
|
|
|
|
|
| `warnings_only` | Solo avvisi minori — puoi procedere |
|
|
|
|
|
|
| `blocked` | Problemi strutturali — rivedi il sorgente `.md` |
|
2026-05-20 16:08:00 +02:00
|
|
|
|
|
2026-06-04 14:29:06 +02:00
|
|
|
|
---
|
2026-05-20 16:08:00 +02:00
|
|
|
|
|
2026-06-04 14:29:06 +02:00
|
|
|
|
## Passo 4 — Vettorizzazione
|
2026-05-12 10:39:27 +02:00
|
|
|
|
|
|
|
|
|
|
```bash
|
2026-05-20 16:08:00 +02:00
|
|
|
|
# Singolo documento → collection omonima
|
|
|
|
|
|
.venv/bin/python ingestion/ingest.py --stem <stem>
|
|
|
|
|
|
|
2026-06-04 14:29:06 +02:00
|
|
|
|
# Più documenti → collection condivisa (RAG cross-documento)
|
2026-05-20 16:08:00 +02:00
|
|
|
|
.venv/bin/python ingestion/ingest.py --collection <nome> --stems doc1 doc2 doc3
|
2026-05-12 10:39:27 +02:00
|
|
|
|
|
2026-05-20 16:08:00 +02:00
|
|
|
|
# Rigenera dopo aver aggiornato i chunk o cambiato modello embedding
|
|
|
|
|
|
.venv/bin/python ingestion/ingest.py --stem <stem> --force
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-06-04 14:29:06 +02:00
|
|
|
|
> Se cambi `EMBED_MODEL` in `config.py` devi rieseguire l'ingestion con `--force`.
|
2026-05-20 16:08:00 +02:00
|
|
|
|
|
2026-06-04 14:29:06 +02:00
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Passo 5 — Interrogazione
|
2026-05-20 16:08:00 +02:00
|
|
|
|
|
|
|
|
|
|
```bash
|
2026-06-04 14:29:06 +02:00
|
|
|
|
# RAG interattivo (retrieval + generazione LLM)
|
2026-05-20 16:08:00 +02:00
|
|
|
|
.venv/bin/python rag.py --stem <stem>
|
|
|
|
|
|
.venv/bin/python rag.py --collection <nome>
|
2026-05-12 11:21:24 +02:00
|
|
|
|
|
2026-06-04 14:29:06 +02:00
|
|
|
|
# Retrieval puro (debug, senza LLM)
|
2026-05-20 16:08:00 +02:00
|
|
|
|
.venv/bin/python retrieve.py --stem <stem>
|
|
|
|
|
|
.venv/bin/python retrieve.py --stem <stem> --top-k 10
|
2026-05-12 10:39:27 +02:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-05-20 16:08:00 +02:00
|
|
|
|
## Configurazione
|
2026-05-12 10:39:27 +02:00
|
|
|
|
|
2026-06-04 14:29:06 +02:00
|
|
|
|
### Chunking — `chunks/config.py`
|
2026-05-12 10:39:27 +02:00
|
|
|
|
|
2026-05-20 16:08:00 +02:00
|
|
|
|
| Parametro | Default | Descrizione |
|
|
|
|
|
|
|-----------|---------|-------------|
|
2026-06-04 14:29:06 +02:00
|
|
|
|
| `MAX_CHARS` | 1200 | Lunghezza massima chunk (caratteri) |
|
2026-05-20 16:08:00 +02:00
|
|
|
|
| `MIN_CHARS` | 80 | Soglia minima (warning sotto questa soglia) |
|
2026-06-04 14:29:06 +02:00
|
|
|
|
| `CONTEXT_DEPTH` | 3 | Livelli heading inclusi nel prefisso chunk (1–3) |
|
|
|
|
|
|
| `SKIP_HEADINGS` | set italiano | Sezioni saltate completamente (indice, sommario…) |
|
|
|
|
|
|
| `SKIP_PRE_HEADING` | `True` | Salta contenuto prima del primo heading (frontespizio) |
|
|
|
|
|
|
| `MERGE_SHORT_PARAGRAPHS` | `True` | Accorpa paragrafi brevi fino a `MIN_CHARS` |
|
|
|
|
|
|
| `SENTENCE_SPLIT_RE` | regex | Confine di fine frase per lo split |
|
|
|
|
|
|
| `ATOMIC_TYPES` | `table, code, list` | Blocchi mai spezzati |
|
2026-05-12 11:21:24 +02:00
|
|
|
|
|
2026-06-04 14:29:06 +02:00
|
|
|
|
### RAG — `config.py`
|
2026-05-12 10:39:27 +02:00
|
|
|
|
|
2026-05-20 16:08:00 +02:00
|
|
|
|
| Parametro | Default | Descrizione |
|
|
|
|
|
|
|-----------|---------|-------------|
|
|
|
|
|
|
| `OLLAMA_MODEL` | `qwen3.5:4b` | Modello LLM per la generazione |
|
|
|
|
|
|
| `EMBED_MODEL` | `nomic-embed-text` | Modello embedding |
|
2026-06-04 14:29:06 +02:00
|
|
|
|
| `EMBED_MAX_CHARS` | 6000 | Caratteri massimi inviati al modello embedding |
|
2026-05-20 16:08:00 +02:00
|
|
|
|
| `TOP_K` | 6 | Chunk recuperati per domanda |
|
|
|
|
|
|
| `TEMPERATURE` | 0.2 | Creatività del modello (0 = deterministico) |
|
|
|
|
|
|
| `OLLAMA_URL` | `localhost:11434` | URL server Ollama |
|
2026-05-12 10:39:27 +02:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-05-20 16:08:00 +02:00
|
|
|
|
## Struttura del repository
|
2026-04-12 23:53:13 +02:00
|
|
|
|
|
2026-05-20 16:08:00 +02:00
|
|
|
|
```
|
|
|
|
|
|
rag/
|
2026-06-04 14:29:06 +02:00
|
|
|
|
├── sources/ ← output MinerU (una cartella per documento)
|
|
|
|
|
|
│ └── <stem>_output/auto/
|
2026-05-20 16:08:00 +02:00
|
|
|
|
├── chunks/
|
2026-06-04 14:29:06 +02:00
|
|
|
|
│ ├── chunker.py ← chunking da MD pulito
|
|
|
|
|
|
│ ├── config.py ← parametri di chunking
|
|
|
|
|
|
│ └── verify_chunks.py ← verifica qualità chunk
|
2026-05-20 16:08:00 +02:00
|
|
|
|
├── ingestion/
|
2026-06-04 14:29:06 +02:00
|
|
|
|
│ └── ingest.py ← embedding → ChromaDB
|
|
|
|
|
|
├── chroma_db/ ← database vettoriale (ignorato da git)
|
|
|
|
|
|
├── config.py ← parametri RAG (modelli, TOP_K, prompt)
|
|
|
|
|
|
├── rag.py ← loop RAG interattivo
|
|
|
|
|
|
├── retrieve.py ← retrieval puro (debug)
|
|
|
|
|
|
└── mineru.ipynb ← notebook Colab per conversione PDF
|
2026-04-12 23:53:13 +02:00
|
|
|
|
```
|