Home
» domini
»
Come automatizzare l'estrazione dei dati dai PDF utilizzando modelli AI locali senza un'API cloud
Come automatizzare l'estrazione dei dati dai PDF utilizzando modelli AI locali senza un'API cloud
Il workflow di estrazione PDF locale più affidabile è solitamente una pipeline, non un singolo prompt AI: prima recupera testo e layout affidabili dal PDF, poi chiedi a un modello locale di mappare quel contenuto in uno schema rigoroso e infine valida i campi prima di salvarli. Inviare ogni pagina del PDF direttamente a un modello di visione può funzionare, ma è spesso più lento, più intensivo in termini di hardware e più difficile da auditare rispetto all'utilizzo del testo nativo del PDF o dell'OCR quando questi sono sufficienti.
Questa distinzione è importante se il tuo obiettivo è “nessuna API cloud”. Puoi comunque utilizzare un'API locale sulla tua macchina, ad esempio l'endpoint HTTP di Ollama su localhost, senza inviare i contenuti dei documenti a un servizio ospitato. Ollama dichiara che prompt e risposte non vengono inviati a Ollama quando i modelli vengono eseguiti localmente e fornisce una modalità solo locale che disabilita le funzionalità cloud. Anche Docling mantiene i servizi remoti disabilitati per impostazione predefinita, sebbene i file dei modelli possano comunque dover essere scaricati durante la configurazione a meno che non vengano pre-fetchati per l'uso offline.
Lo stack giusto dipende dal PDF. Le fatture nate digitali con testo selezionabile richiedono un approccio diverso rispetto alle ricevute scansionate, alle tabelle finanziarie complesse o ai moduli ricchi di immagini. Questa guida confronta queste opzioni e fornisce un modello di automazione in quattro fasi che puoi adattare a fatture, contratti, ordini di acquisto, moduli di domanda, report e altri documenti ricorrenti.
Raccomandazione rapida: scegli la pipeline in base al tipo di documento
Tipo di PDF
Pipeline locale pratica
Vantaggio principale
Compromesso principale
PDF nato digitale con testo selezionabile pulito
PyMuPDF → LLM di testo locale → validazione JSON
Veloce e relativamente leggero sull'hardware
L'estrazione semplice può perdere l'ordine di lettura o le relazioni delle tabelle
PDF scansionato con pagine semplici
OCRmyPDF/Tesseract → PyMuPDF → LLM di testo locale
Trasforma le immagini delle pagine in testo ricercabile prima dell'estrazione AI
Gli errori OCR diventano errori di input del modello
PDF misto con testo, scansioni e tabelle
Docling o OCRmyPDF in modalità skip/redo → LLM locale
Migliore controllo sul contenuto misto e sulla struttura del documento
Più dipendenze e tempi di elaborazione
Moduli, tabelle, diagrammi o pagine visivamente significative con layout pesante
Pipeline locale Docling o modello di visione locale → output strutturato
Preserva più contesto visivo/di layout
Di solito richiede più potenza di calcolo e una validazione più rigorosa
Non esiste un vincitore universale. Se i tuoi documenti sono prevedibili e contengono testo incorporato, un parser più un piccolo modello linguistico locale potrebbe superare un workflow di visione molto più grande in termini di costi, velocità e riproducibilità. Se la posizione del testo fa parte del significato, ad esempio una tabella con celle unite o un modulo dove etichette e valori sono accoppiati spazialmente, l'elaborazione consapevole del layout diventa più preziosa.
Fase 1: Classifica il PDF prima di scegliere OCR o AI
Inizia determinando se il documento contiene già testo utilizzabile. Nato digitale significa che il PDF è stato generato da software e di solito contiene oggetti di testo che possono essere selezionati e copiati. Un PDF scansionato può contenere solo immagini delle pagine, quindi un normale parser di testo restituisce poco o nulla.
La documentazione ufficiale di PyMuPDF mostra l'estrazione diretta del testo con page.get_text(). Un test locale minimo è simile a questo:
import pymupdf
def extract_native_text(pdf_path: str) -> str:
pages = []
with pymupdf.open(pdf_path) as doc:
for page in doc:
pages.append(page.get_text())
return "\f".join(pages)
text = extract_native_text("invoice.pdf")
print(text[:1000])
Vedi le basi ufficiali di PyMuPDF. PyMuPDF avverte anche che il testo PDF semplice potrebbe non apparire nell'ordine naturale di lettura e potrebbe contenere interruzioni di riga inaspettate. Questa è una limitazione del parser, non necessariamente un problema di AI.
Migliore adattabilità: fatture, estratti conto, report e moduli dove la copia/incolla del testo funziona già e i campi sono facili da identificare dalle etichette vicine.
Attenzione a: una pagina può contenere un minuscolo livello di testo più una grande immagine scansionata. Controllare semplicemente se “esiste del testo” non è quindi un rilevatore di scansioni perfetto. Per l'automazione di produzione, ispeziona documenti rappresentativi piuttosto che affidarti a una soglia universale di conteggio dei caratteri.
Azione: prendi 20–50 PDF rappresentativi e classificali in gruppi nati digitali, scansionati, misti e con layout pesante. La tua pipeline dovrebbe instradare in base al comportamento del documento, non solo all'estensione del file.
Illustrazione generata da AI della fase di input PDF. È un'immagine concettuale del workflow, non uno screenshot di una specifica applicazione PDF o un risultato di benchmark.
Fase 2: Estrai il testo localmente, o usa l'OCR solo quando necessario
Opzione A: PyMuPDF per PDF digitali puliti
Se il livello di testo è affidabile, l'estrazione diretta è normalmente la strada più semplice. Evita la latenza dell'OCR ed evita di introdurre errori di carattere OCR in un testo già codificato correttamente. Per documenti lunghi, puoi preservare i separatori di pagina ed elaborare gruppi di pagine o sezioni logiche piuttosto che passare l'intero documento al modello in una volta.
Compromesso: il testo semplice è economico e veloce, ma tabelle, pagine a più colonne, intestazioni, piè di pagina e ordine di lettura potrebbero richiedere una gestione extra. Se queste relazioni sono importanti per i campi di destinazione, passa a una rappresentazione consapevole del layout piuttosto che accumulare istruzioni nel prompt su un testo sorgente povero.
Opzione B: OCRmyPDF più Tesseract per pagine scansionate
Tesseract è un motore OCR open-source. Il suo manuale utente attuale documenta la serie 5.x e il supporto per molte lingue tramite file di dati addestrati separati. OCRmyPDF avvolge l'OCR attorno all'elaborazione specifica per PDF in modo che le pagine scansionate possano acquisire un livello di testo ricercabile.
Per un documento misto dove alcune pagine contengono già testo, le versioni attuali di OCRmyPDF supportano una modalità skip:
ocrmypdf --mode skip input.pdf searchable.pdf
La documentazione avanzata ufficiale di OCRmyPDF spiega che --mode skip lascia invariate le pagine con testo esistente e applica l'OCR alle pagine che ne hanno bisogno. La stessa documentazione descrive redo per sostituire l'OCR precedente rilevato e force per rasterizzare e applicare l'OCR a tutto il contenuto. Usa force con cautela perché la rasterizzazione può scartare i vantaggi vettoriali e appiattire il contenuto interattivo.
Per l'installazione di Tesseract, le lingue e il comportamento della riga di comando, usa il manuale utente ufficiale di Tesseract. La lingua dell'OCR è importante: se le tue fatture contengono inglese e tedesco, ad esempio, installa e configura i dati linguistici appropriati piuttosto che assumere che il modello inglese predefinito gestisca entrambi allo stesso modo.
Opzione C: Docling quando la struttura è importante
Docling è progettato per la conversione di documenti con opzioni di layout, tabella, OCR ed elaborazione locale di visione-linguaggio. La documentazione del progetto elenca la comprensione avanzata dei PDF, la struttura delle tabelle, l'OCR e gli output in stile JSON/Markdown senza perdita di dati, con l'esecuzione locale destinata a workflow sensibili e air-gapped.
Una conversione Python di base può essere piccola come:
Vedi la guida rapida ufficiale di Docling. Docling supporta anche pipeline VLM locali e diversi backend OCR. Le sue opzioni avanzate spiegano che le chiamate ai servizi remoti richiedono un opt-in esplicito, mentre gli artefatti dei modelli possono essere pre-fetchati per l'uso offline.
Migliore adattabilità: tabelle complesse, intestazioni, report a più colonne, scansioni miste o casi in cui si desidera una rappresentazione del documento riutilizzabile invece di un semplice dump di testo.
Compromesso: la pipeline è più pesante di un semplice parser PDF. Usala perché la struttura extra migliora la tua precisione di estrazione, non semplicemente perché ha più componenti.
Azione: scegli il metodo di estrazione più leggero che preserva le informazioni di cui il tuo schema di destinazione ha bisogno. Non fare OCR su testo incorporato pulito e non buttare via il layout quando il layout determina il significato.
Illustrazione generata da AI della scelta dell'OCR per le scansioni e dell'estrazione diretta per i PDF nati digitali. Rappresenta il concetto di decisione piuttosto che l'interfaccia di una vera applicazione OCR.
Fase 3: Mappa il contenuto recuperato in uno schema rigoroso con un modello locale
Una volta ottenuto un contenuto sorgente affidabile, usa il modello locale per ciò che sa fare bene: la mappatura semantica. Invece di chiedere “Estrai tutto da questa fattura”, definisci i campi di cui hai effettivamente bisogno.
Ad esempio:
from pydantic import BaseModel
from typing import Optional
class LineItem(BaseModel):
description: str
quantity: Optional[float]
unit_price: Optional[float]
amount: Optional[float]
class Invoice(BaseModel):
invoice_number: Optional[str]
invoice_date: Optional[str]
vendor_name: Optional[str]
currency: Optional[str]
subtotal: Optional[float]
tax: Optional[float]
total: Optional[float]
items: list[LineItem]
La documentazione attuale sugli output strutturati di Ollama supporta il passaggio di uno JSON Schema tramite il campo format e la validazione della risposta con Pydantic. Una chiamata locale può essere simile a questa:
from ollama import chat
schema = Invoice.model_json_schema()
prompt = f"""
Extract the invoice into the supplied schema.
Rules:
- Use only information present in the source.
- Use null when a field is not found.
- Do not infer missing invoice numbers, dates, tax, or totals.
- Preserve line items individually.
SOURCE:
{text}
"""
response = chat(
model="gpt-oss",
messages=[{"role": "user", "content": prompt}],
format=schema,
options={"temperature": 0},
)
invoice = Invoice.model_validate_json(response.message.content)
Il nome del modello sopra è un esempio dalla documentazione sugli output strutturati di Ollama stessa, non un'affermazione che sia il modello migliore per ogni lavoro di estrazione. Un modello più piccolo potrebbe essere adeguato per fatture ripetitive con etichette chiare; un modello più forte potrebbe aiutare con contratti ambigui o layout incoerenti ma richiederà generalmente più memoria e tempo di elaborazione.
Modello di testo o modello di visione?
Usa un modello di testo quando l'output del parser/OCR preserva già le relazioni dei campi di cui hai bisogno. Usa un modello locale capace di visione quando la posizione visiva è essenziale o la conversione del testo perde costantemente struttura. La documentazione ufficiale sulla Visione di Ollama supporta input di immagini per modelli di visione locali e la sua funzionalità di output strutturato può essere combinata con modelli capaci di visione.
Tuttavia, renderizzare ogni pagina come immagine cambia il compromesso:
devono essere elaborati più pixel;
le pagine ad alta risoluzione consumano più potenza di calcolo e memoria;
il batching delle pagine diventa importante per PDF lunghi;
i modelli visivi possono ancora inventare un campo o leggere male un numero;
hai bisogno di un modo per tracciare i valori estratti fino a una pagina o regione sorgente.
Azione: inizia con il testo del parser/OCR più un LLM locale vincolato dallo schema. Escala solo i tipi di pagina difficili a un VLM locale invece di pagare il costo della visione per ogni pagina.
Illustrazione generata da AI della fase del modello locale. Non raffigura una vera schermata di Ollama né implica che un modello locale possa estrarre ogni campo senza validazione.
Fase 4: Valida prima di scrivere JSON, CSV, Excel o un database
Un JSON valido secondo lo schema non è automaticamente corretto dal punto di vista fattuale. Un modello può produrre campi validi con valori errati. L'ultima fase dovrebbe quindi utilizzare controlli deterministici ove possibile.
Per una fattura, i controlli utili includono:
Campi di identità obbligatori: il numero di fattura o il nome del fornitore devono essere presenti se il tuo workflow ne ha bisogno.
Analisi delle date: analizza le date con una politica fissa piuttosto che fidarti di stringhe ambigue come 03/04/26.
Arithmetic: confronta la somma degli importi delle righe con il subtotale del documento entro una tolleranza definita.
Totali: verifica se subtotale più tasse e altri addebiti è coerente con il totale.
Valuta: non assumere USD perché il documento è in inglese.
Provenienza: memorizza il nome del file sorgente, il numero di pagina, il timestamp dell'estrazione e opzionalmente un hash del PDF originale.
Coda di revisione: instrada i casi mancanti, in conflitto o a bassa confidenza per la revisione umana invece di riempire silenziosamente i valori.
Una struttura batch di base può separare l'estrazione dalla validazione:
from pathlib import Path
import json
for pdf_path in Path("inbox").glob("*.pdf"):
source_text = extract_native_text(str(pdf_path))
# If text is unusable, run your OCR or Docling branch here.
record = extract_with_local_model(source_text)
errors = validate_record(record)
if errors:
save_for_review(pdf_path, record, errors)
else:
output = Path("processed") / f"{pdf_path.stem}.json"
output.write_text(
json.dumps(record, ensure_ascii=False, indent=2),
encoding="utf-8"
)
Le funzioni helper sono intenzionalmente lasciate specifiche per l'applicazione perché le regole di validazione differiscono drasticamente tra fatture, contratti, moduli fiscali, report di laboratorio e ordini di acquisto. Un validatore universale creerebbe una falsa sicurezza.
Se hai bisogno di CSV o Excel, appiattisci solo i campi che appartengono effettivamente a righe e colonne. Per documenti con righe ripetute, è spesso più pulito creare una tabella a livello di documento e una seconda tabella di righe collegate da un ID documento piuttosto che forzare ogni campo in una singola riga di foglio di calcolo larga.
Azione: definisci le regole di validazione prima di elaborare migliaia di file. Testa contro un set di campioni etichettati e registra la precisione a livello di campo, non solo “documenti elaborati con successo”.
Illustrazione generata da AI delle destinazioni di esportazione locali come Excel, CSV e JSON. È un endpoint concettuale, non la prova che ogni PDF possa essere convertito senza revisione.
Un'architettura completamente locale pratica
Per molti lavori di automazione di piccole e medie dimensioni, questa divisione delle responsabilità è più facile da mantenere rispetto a un modello all-in-one:
Questo design ti consente di scambiare i componenti indipendentemente. Se la qualità dell'OCR è debole, migliora il livello OCR senza riaddestrare l'LLM. Se il modello locale è troppo lento, usane uno più piccolo senza cambiare il parser PDF. Se le fatture di un fornitore necessitano di una gestione speciale delle tabelle, instrada solo quei file attraverso Docling o un ramo di visione.
Ollama vs. llama.cpp vs. Docling VLM: quale runtime locale dovresti scegliere?
Opzione
Usala quando
Punto di forza
Compromesso
Ollama
Vuoi l'API del modello locale più semplice e l'output vincolato dallo schema
API localhost semplice, JSON strutturato, supporto visione per modelli compatibili
L'astrazione ti dà meno controllo sul runtime a basso livello rispetto a un motore di inferenza nudo
llama.cpp
Vuoi il controllo diretto GGUF, il deployment a riga di comando o un server locale leggero
CLI/server locale e generazione vincolata da grammatica/schema JSON
Più dettagli sul modello/runtime sono responsabilità tua
Docling VLM
La tua sfida principale è la conversione del layout del documento piuttosto che l'estrazione in stile chat generale
Pipeline VLM locale focalizzata sul documento con output in stile Markdown/HTML/DocTags
Pensala al meglio come un componente di conversione del documento, non come un sostituto per ogni passo di estrazione delle regole di business
Non selezionare un runtime basandoti solo su una classifica dei modelli. Per l'estrazione PDF, le misure pratiche sono la precisione dei campi, la produttività per documento, l'uso della memoria sulla tua macchina, il tasso di fallimento sui tuoi layout, la complessità di avvio e quanto facilmente puoi ispezionare i risultati errati.
Come mantenere la pipeline genuinamente locale
“Nessuna API cloud” dovrebbe essere una proprietà di distribuzione che puoi verificare, non solo un'etichetta di marketing.
Ollama
La FAQ ufficiale di Ollama dice che i prompt e le risposte locali non vengono inviati a Ollama. Documenta anche un'impostazione per disabilitare il cloud:
OLLAMA_NO_CLOUD=1
o l'impostazione del server equivalente disable_ollama_cloud. L'API locale di Ollama gira su http://localhost:11434 e non richiede autenticazione per l'accesso locale, secondo la sua documentazione sull'autenticazione.
Ricorda che un servizio legato a localhost è diverso da uno esposto alla tua LAN. Se cambi il suo indirizzo di bind o lo metti dietro un altro server, sei responsabile del controllo degli accessi.
Docling
Docling mantiene l'uso dei servizi remoti disabilitato per impostazione predefinita. La sua documentazione distingue anche la privacy dell'elaborazione dall'acquisizione dei modelli: i modelli possono essere recuperati al primo utilizzo a meno che non vengano pre-scaricati. Per un sistema air-gapped, usa docling-tools models download su una macchina di staging connessa o pre-posiziona altrimenti gli artefatti dei modelli approvati, quindi punta l'ambiente offline a quella directory di artefatti locale.
Azione: prima di elaborare documenti sensibili, blocca l'accesso di rete in uscita a livello di sistema operativo o di rete ed esegui un test monitorando le connessioni. Le impostazioni dell'applicazione sono utili, ma i controlli di rete ti danno un livello di verifica indipendente.
Cosa l'AI locale non risolve
L'esecuzione locale migliora le opzioni di controllo dei dati, ma non rende automaticamente l'estrazione corretta, conforme o sicura. I file locali possono ancora trapelare attraverso log di debug, directory temporanee, backup, cartelle condivise, servizi troppo permissivi o esportazioni copiate. Un modello locale può anche allucinare valori esattamente come un modello ospitato.
Non usare il modello come unico verificatore per campi ad alto impatto come numeri di conto bancario, istruzioni di pagamento, date contrattuali, valori medici o identificatori regolamentari. Per questi, confronta con il testo sorgente, applica la validazione deterministica e richiedi la revisione umana quando la confidenza è insufficiente.
Come testare prima di automatizzare un'intera cartella
Costruisci un piccolo set di valutazione etichettato contenente i casi che ricevi effettivamente:
PDF digitale pulito;
scansione a bassa risoluzione;
pagina ruotata o storta;
fattura multipagina;
tabella che attraversa le pagine;
campi opzionali mancanti;
diversi formati di data e numero;
almeno un documento deliberatamente difficile.
Per ogni campo di destinazione, confronta il valore estratto con la verità di base. Misura la corrispondenza esatta per gli identificatori, la tolleranza numerica per gli importi e la precisione a livello di riga per le righe. Registra anche il tempo di elaborazione e la percentuale di documenti inviati alla revisione manuale.
Se un percorso più semplice PyMuPDF-plus-LLM raggiunge la precisione richiesta, mantienilo. Se le scansioni sono il fallimento principale, migliora l'OCR. Se le relazioni delle tabelle sono il problema, testa Docling. Se i campi posizionati visivamente rimangono difficili, instrada quel sottoinsieme attraverso un modello di visione locale. Questa escalation graduale di solito ti dà un migliore controllo sulla velocità e sull'uso dell'hardware rispetto all'applicazione del modello più pesante a ogni pagina.
Conclusione
Un buon sistema locale di estrazione PDF separa la lettura del documento dall'estrazione semantica. Usa PyMuPDF quando il PDF contiene già buon testo; OCRmyPDF/Tesseract quando la pagina è scansionata; Docling quando la struttura e le tabelle sono importanti; e un modello locale Ollama o llama.cpp quando hai bisogno di una mappatura flessibile in uno schema di business. Usa la visione locale solo dove il layout visivo aggiunge informazioni che la pipeline di testo non può preservare in modo affidabile.
Il requisito finale è la validazione. Lo JSON Schema può vincolare la forma della risposta di un modello, ma non può provare che l'importo, la data, il nome o il numero di conto corrispondano alla sorgente. Se progetti la pipeline in modo che i documenti incerti siano visibili e revisionabili, puoi automatizzare una grande frazione dell'estrazione dei dati PDF senza consegnare i documenti a un'API cloud, e senza fingere che l'AI locale elimini la necessità di controllo qualità.