19 – Prima del RAG: come un PDF diventa una fonte affidabile

Copertina Dentro l’IA 19: Prima del RAG. Dal PDF alla fonte affidabile. Su un pannello avorio, pagine con colonne e tabella, schede color petrolio e una lente in ottone, nello studio con libri e mappamondo della collana.

Carichiamo un PDF, lo dividiamo in frammenti, calcoliamo gli embedding e chiediamo al modello di rispondere citando le fonti. Sembra una sequenza lineare. Ma quando compare una risposta sbagliata, il guasto può essere avvenuto prima ancora della ricerca: una colonna letta nel posto sbagliato, una cifra separata dalla sua unità, una nota lasciata fuori dal contesto.

La domanda di questo episodio è precisa: che cosa dobbiamo conservare perché il passaggio dalla pagina al testo indicizzato non cambi il significato? Non riprendiamo il funzionamento generale del RAG. Seguiamo invece il documento attraverso estrazione, riconoscimento ottico, ricostruzione della struttura e controlli, fino al momento in cui può diventare una fonte utilizzabile.

In breve

  • Un PDF leggibile a video può essere difficile da interpretare automaticamente: posizione e significato sono due livelli diversi.
  • Estrazione del testo, OCR e ricostruzione di tabelle e note risolvono problemi distinti.
  • Un numero richiede intestazione, unità e qualificazioni: la sola presenza delle cifre non basta.
  • Ogni frammento deve poter tornare al documento, alla versione e alla zona della pagina da cui proviene.
  • La qualità va verificata prima dell’indicizzazione e poi sulla risposta finale, con domande di cui conosciamo la soluzione.

La pagina non è una sequenza di frasi

Il PDF nasce per rappresentare una pagina. In molti file il testo è descritto mediante elementi posizionati: le righe di una tabella possono apparire come caratteri allineati, senza una struttura tabellare esplicita. Esistono PDF con informazioni strutturali utili, ma non possiamo presumere che siano sempre presenti o corrette. La documentazione di pypdf spiega perché testo, tabelle e note rendono ambigua l’estrazione.

Conviene classificare le pagine, non soltanto i file. Una relazione può contenere pagine nate digitalmente, allegati scansionati e pagine miste con testo e immagini. Il testo selezionabile è un indizio, non una garanzia: potrebbe essere un livello OCR nascosto che non coincide perfettamente con ciò che vediamo. Conserviamo quindi l’originale e una sua rappresentazione visiva, prima di trasformarlo.

Una prova piccola, con un errore osservabile

Per questo articolo ho costruito ed elaborato un documento sintetico di una pagina, con dati interamente inventati. Contiene due colonne, una tabella e una nota. La colonna sinistra introduce l’assistenza; quella destra ne esclude i giorni festivi. La tabella riporta importi in migliaia di euro e precisa che il valore 2026 della formazione è un tetto massimo, non una spesa sostenuta.

Pagina dimostrativa con requisito ed eccezione in due colonne, tabella degli importi 2025 e 2026 e nota sul tetto massimo della formazione.
Documento originale sintetico: dati inventati, non una procedura reale. Colonne, tabella e nota sono i tre elementi da conservare insieme al loro significato.

Il PDF usato nella prova è scaricabile qui. Nella sua costruzione ho alternato deliberatamente le operazioni di scrittura tra sinistra e destra: visivamente le colonne sono distinte, mentre l’ordine degli oggetti nel file le intreccia. È un caso controllato per mostrare il problema, non un campione rappresentativo dei PDF in circolazione.

Con pypdf 6.10.0, l’estrazione semplice restituisce questo passaggio:

1. Requisito
2. Eccezione
Il servizio include assistenza.
Il servizio NON include
Durata: dodici mesi.
assistenza nei giorni festivi.

Le parole sono presenti, ma il loro ordine non ricostruisce i due paragrafi. Un sistema che segmentasse subito questo testo potrebbe mettere «Durata: dodici mesi» dentro l’eccezione. Ho poi ritagliato la regione sinistra con pdfplumber 0.11.9: in quel riquadro l’estrazione restituisce requisito, inclusione dell’assistenza e durata nell’ordine atteso. Le coordinate risolvono questo layout noto; non costituiscono un riconoscitore universale di colonne.

La tabella: recuperare i numeri non basta

Nello stesso file, l’estrazione tabellare di pdfplumber ricostruisce correttamente intestazioni e celle:

Voce20252026*
Formazione1218
Assistenza80
Risultato effettivo della prova. Unità: migliaia di euro. * Per la formazione, il valore 2026 è un tetto massimo, non una spesa sostenuta.

Alla domanda «Quanto è stato speso per la formazione nel 2026?» la risposta «18.000 euro» sarebbe ingiustificata. Il documento indica un massimo di 18.000 euro; non fornisce la spesa effettiva. È un controesempio verificabile senza interrogare un modello: basta confrontare la domanda con la nota. Non ho misurato quanto spesso un LLM commetterebbe questo errore.

Una rappresentazione utile dell’ultima cella della formazione contiene quindi almeno: voce = formazione; anno = 2026; valore = 18; unità = migliaia di euro; natura = tetto massimo; fonte = pagina 1, tabella 1 e nota. Non bisogna dedurre che la stessa qualificazione valga per ogni altra cella: la nota ha un ambito preciso. Con celle unite o intestazioni su più livelli, anche quel rapporto va ricostruito e controllato.

La scansione: l’OCR aggiunge un altro passaggio

Ho trasformato la stessa pagina in un’immagine a 144 dpi e inserito soltanto quell’immagine in un secondo PDF. Su questa versione pypdf estrae zero caratteri. Tesseract 5.3.4, eseguito con lingua eng e segmentazione automatica --psm 3, recupera il testo e i valori della tabella. Compare anche una piccola confusione tra la I maiuscola e la l minuscola nell’inizio di una frase. La negazione «NON» e il testo della nota sono invece presenti.

È una scansione simulata pulita e un controllo su una sola pagina: non misura l’accuratezza generale dell’OCR, né confronta motori o lingue. In una procedura italiana sceglierei un pacchetto linguistico appropriato e ne registrerei la versione. Il manuale di OCRmyPDF distingue correzione dell’orientamento, raddrizzamento e aggiunta del livello testuale; avverte anche che alcune pulizie possono rimuovere contenuti. Serve un controllo visivo dopo il trattamento.

L’OCR può leggere «18» senza sapere che è un massimo espresso in migliaia di euro. Perciò non basta ottenere una pagina finalmente ricercabile. Verifichiamo anche segni meno, separatori decimali, apici, negazioni e associazioni tra celle. Un punteggio di confidenza del motore non va trattato automaticamente come probabilità calibrata che il dato sia corretto.

Ripetere i controlli sul PDF

Scaricando il documento e salvandolo come documento.pdf, questo codice ripete l’estrazione semplice, il ritaglio della colonna e il controllo delle celle. Le coordinate sono in punti PDF, con origine in alto a sinistra per il ritaglio di pdfplumber. L’ambiente usato nella prova impiegava le versioni indicate:

pip install pypdf==6.10.0 pdfplumber==0.11.9
from pypdf import PdfReader
import pdfplumber
pdf = "documento.pdf"
raw = PdfReader(pdf).pages[0].extract_text()
print(raw)
with pdfplumber.open(pdf) as d:
p = d.pages[0]
area = p.crop((35, 100, 310, 180))
print(area.extract_text())
t = p.extract_tables()[0]
assert t[1] == ["Formazione", "12", "18"]
assert t[2] == ["Assistenza", "8", "0"]

Per ricreare anche il PDF con la sola immagine, nella prova ho usato PyMuPDF 1.26.6. Il codice seguente produce inoltre il PNG su cui eseguire Tesseract:

pip install PyMuPDF==1.26.6
import fitz
d = fitz.open("documento.pdf")
pix = d[0].get_pixmap(matrix=fitz.Matrix(2, 2))
pix.save("pagina.png")
s = fitz.open()
p = s.new_page(width=600, height=560)
p.insert_image(p.rect, pixmap=pix)
s.save("scansione.pdf")
s.close()
text = PdfReader("scansione.pdf")
assert text.pages[0].extract_text() == ""
tesseract pagina.png ocr -l eng --psm 3

I confronti automatici verificano soltanto proprietà dichiarate: due righe della tabella e l’assenza di testo nel PDF rasterizzato. Non certificano il significato della nota, la correttezza di qualunque documento o la qualità di una risposta RAG. Quei livelli richiedono controlli diversi.

Dalla struttura ai frammenti: dove tagliare

Prima del taglio conviene costruire una rappresentazione intermedia: paragrafi nell’ordine di lettura, titoli, tabelle, didascalie, note e relativi collegamenti. DoclingDocument, per esempio, prevede elementi documentali, gerarchie, informazioni di layout e provenienza. Sono strumenti per rappresentare il risultato, non una garanzia che ogni conversione sia corretta.

Nel nostro esempio indicizzerei la tabella con titolo, unità e nota pertinente. Per una tabella molto grande potrei creare frammenti per gruppi di righe, ripetendo le intestazioni e le qualificazioni necessarie. Il budget va misurato con il tokenizer del modello che riceve quei testi. La documentazione dei chunker di Docling mostra come combinare struttura documentale e limiti in token.

Aggiungere una sovrapposizione tra frammenti può aiutare ai confini, ma non corregge una colonna già mescolata né assicura che una nota lontana accompagni la cella. Se serve, il sistema deve recuperare anche elementi collegati: una riga richiama intestazione e nota; un paragrafo richiama l’eccezione. Meglio un legame esplicito che la speranza che tutto cada nello stesso intervallo di caratteri.

Una fonte deve poter essere ritrovata

Per ogni elemento conserviamo identificativo del documento, impronta del file originale, versione, pagina, riquadro di origine, metodo di estrazione e versione degli strumenti. Per i dati normalizzati manteniamo anche la forma originale: «18» nella tabella e «18.000 euro» nella rappresentazione applicativa. La trasformazione deve essere spiegabile e reversibile fino alla fonte.

Quando cambia il PDF, ricostruiamo o invalidiamo i frammenti della versione precedente. I filtri dell’indice devono rispettare validità e permessi di accesso, oltre alla somiglianza semantica. La citazione finale dovrebbe aprire la pagina corretta e rendere riconoscibile il passaggio, non puntare soltanto a un file di centinaia di pagine.

Fedeltà dell’estrazione e autorevolezza della fonte restano distinte. Possiamo copiare perfettamente un documento superato o inesatto. La pipeline documentale deve conservare il contenuto; la politica delle fonti deve decidere se quel contenuto è aggiornato e utilizzabile per la domanda.

Quanto controllo conviene pagare?

Su documenti semplici, nati digitalmente e ripetitivi, estrazione ordinaria e regole locali possono bastare. Le scansioni richiedono OCR; layout complessi possono giustificare riconoscimento della struttura o modelli visivi, con maggiori costi e tempi. Una conversione generativa va comunque confrontata con la pagina: potrebbe omettere dettagli o introdurre interpretazioni.

La scelta va misurata sul proprio insieme di documenti. Registriamo costo e tempo per pagina accettata, quota di pagine inviate a revisione e frequenza degli errori decisivi. Processare tutto con la tecnica più costosa non garantisce il risultato migliore; processare tutto come semplice testo può nascondere perdite sistematiche. Le pagine non affidabili possono essere escluse temporaneamente dalla ricerca e segnalate per revisione.

Una checklist prima dell’indice

  • Preparare un piccolo insieme di riferimento con pagine a colonne, tabelle, note e scansioni, annotato controllando gli originali.
  • Verificare separatamente ordine di lettura, coppie intestazione-cella, unità e collegamenti alle note; includere controlli su negazioni e cifre critiche.
  • Per la prova di questo articolo chiedere: «L’assistenza copre i festivi?» e «Conosciamo la spesa effettiva per formazione nel 2026?». Le risposte attese sono no e no.
  • Controllare poi che la ricerca recuperi anche le prove necessarie e che la risposta finale le usi correttamente: una buona estrazione può ancora essere seguita da un cattivo retrieval.
  • Dopo ogni modifica di parser, OCR o segmentazione, ripetere questi casi e rivedere gli errori introdotti prima di sostituire l’indice.

Prima di chiedere al modello di essere fedele alle fonti, dobbiamo verificare di avergli consegnato una rappresentazione fedele della pagina.

DALLA MIA BIBLIOTECA

Ingegneria dell’IA di Chip Huyen, presente nel catalogo Libri del blog, offre il quadro più ampio della progettazione di applicazioni con modelli di base, RAG e valutazione. È una lettura pertinente per collegare il trattamento dei documenti alla qualità del sistema completo.

Per approfondire

Le prove sopra sono originali e circoscritte al documento sintetico; le pagine di documentazione possono evolvere rispetto alle versioni usate nel laboratorio.

Episodi propedeutici: 03 — Context engineering, per il progetto del contesto; 04 — Quando la ricerca vettoriale non basta, per la scelta del recupero; 09 — LLM in produzione, per costi e misure operative.


← Torna al percorso Dentro l’IA

Commenti

Lascia un commento