Sono appassionato di intelligenza artificiale e questo progetto nasce dalla curiosita' di capire come funziona davvero un sistema RAG costruendolo da zero, senza usare framework che nascondono i dettagli. Nessuna API esterna, nessun dato che lascia la macchina: tutto gira in locale.
Il risultato e' una pipeline completa che trasforma PDF in un assistente interrogabile in linguaggio naturale. L'ho sviluppato e testato principalmente su manuali tecnici di ingegneria — documenti densi, con formule, tabelle e gerarchie di sezioni profonde — ma funziona su qualsiasi PDF ben strutturato: paper accademici, documentazione tecnica, archivi personali.
L'idea e' semplice: MinerU estrae il testo dal PDF producendo un Markdown strutturato, il chunker lo divide in blocchi semantici coerenti, gli embedding li trasformano in vettori numerici, ChromaDB li indicizza, e Ollama genera le risposte partendo dai chunk piu' rilevanti per la domanda. Ogni componente e' sostituibile e configurabile.
Il notebook `mineru.ipynb` esegue MinerU su Colab sfruttando la GPU gratuita. E' la scelta piu' comoda se non hai una GPU locale o se i PDF sono pesanti.
Il chunker analizza il Markdown con un parser AST, identifica blocchi semantici (paragrafi, tabelle, formule, codice) e li impacchetta in chunk ottimizzati per il retrieval.
- **`max_chars` e `target_chars`**: dipendono dalla lunghezza media dei paragrafi del tuo documento e dalla finestra di contesto del modello di embedding. Con `bge-m3` (8192 token) i valori di default vanno bene per la maggior parte dei manuali tecnici. Se i tuoi paragrafi sono molto corti (documentazione stile reference), abbassa `target_chars` a 400–500 per evitare chunk troppo eterogenei. Se sono molto lunghi (testi narrativi), puoi salire fino a 1500–2000.
- **`context_depth`**: determina quanti livelli di heading vengono preposti al testo nell'embedding (es. "Capitolo 3 > Sezione 3.2 > contenuto"). Valore 2–3 e' ottimale per documenti con gerarchia profonda come manuali tecnici. Con documenti piatti (un solo livello di heading) metti 1.
- **`skip_headings`**: aggiungi i titoli delle sezioni che non vuoi indicizzare (indici, bibliografie, ringraziamenti). Il confronto e' case-insensitive e per prefisso, quindi `"appendice"` cattura anche "Appendice A", "Appendice B", ecc.
- **`min_chars`**: lascia il default a meno che il documento non abbia molti paragrafi di una riga (caption, label) che vuoi escludere — in quel caso alzalo a 150–200.
Con `--collection` tutti i documenti vengono indicizzati insieme e sono interrogabili con un'unica query — utile quando i temi si sovrappongono o vuoi fare confronti tra documenti.
**Attenzione:** se cambi `EMBED_MODEL` devi rieseguire l'ingest con `--force` su tutti i documenti — i vettori generati da modelli diversi non sono compatibili.
La GUI mostra le risposte con Markdown e formule matematiche renderizzate (KaTeX). Il tema chiaro/scuro e' selezionabile dal pulsante in alto a destra.
| `llama3.1:8b` | ~5 GB | Meta, ottimo ragionamento, inglese principalmente |
| `deepseek-r1:8b` | ~5 GB | Reasoning avanzato; piu' lento ma preciso su domande complesse |
- **`TOP_K`**: quanti chunk vengono recuperati e inclusi nel contesto. Valori bassi (3–4) danno risposte piu' precise ma rischiano di perdere informazioni distribuite su piu' sezioni. Valori alti (8–10) danno piu' contesto ma aumentano il tempo di generazione e possono introdurre rumore. 6 e' un buon default per manuali tecnici.
- **`TEMPERATURE`**: per domande fattuali su documenti tecnici tienila bassa (0.1–0.2). Valori piu' alti (0.5–0.7) sono utili solo se vuoi risposte piu' discorsive o comparative.
- **`NO_THINK`**: `True` rende le risposte piu' rapide disabilitando il ragionamento interno dei modelli Qwen3. Mettilo a `False` per domande complesse che richiedono ragionamento multi-step.
- **`SYSTEM_PROMPT`**: personalizzalo in base al tipo di documento. Il default e' calibrato per documenti tecnici in italiano. Se usi documenti in inglese o vuoi risposte piu' strutturate, modificalo direttamente nel file.