Il caso d’uso prezioso e poco appariscente
Per due decenni, estrarre dati strutturati da documenti non strutturati era un progetto di un intero trimestre: pipeline OCR, regole regex, gestione dei casi limite e template di layout per ogni provider. Con un LLM vincolato a uno schema JSON, bastano 30 righe di codice, una buona accuratezza al primo passaggio e un rilascio in un giorno. Gli esempi seguenti funzionano su Kunavo, un gateway indipendente compatibile con OpenAI, ma il modello è dei modelli e funziona allo stesso modo con qualunque provider.
Ti interessa estrarre dati dalle fatture? Questa pagina offre una panoramica trasversale ai documenti. La guida dedicata all’estrazione dei dati dalle fatture approfondisce quel tipo di documento: il confronto tra i vecchi approcci basati su template e modelli e una chiamata vision-LLM, il tutorial Python completo con schema vincolato, la protezione aritmetica, il routing dei modelli a due livelli e il costo per fattura.
Categorie in cui questo funziona particolarmente bene:
- Fatture, ricevute, ordini di acquisto
- Contratti e accordi legali (estrazione di parti, date e obblighi)
- Curriculum / CV (conversione in una struttura adatta agli ATS)
- Arricchimento dei lead da firme email o pagine web
- Cartelle cliniche e referti di laboratorio (con gestione dei dati personali)
- Annunci immobiliari e cataloghi di prodotti
- Smistamento delle email e acquisizione strutturata
Il modello essenziale in 30 righe
import json
from openai import OpenAI
client = OpenAI(api_key="sk-kn-...", base_url="https://api.kunavo.com/v1")
# The schema is the output contract. Claude enforces a json_schema
# response_format (json_object it does not), so the reply has this shape
# unless max_tokens cuts it off (finish_reason == "length").
STR = {"type": ["string", "null"]}
NUM = {"type": ["number", "null"]}
INVOICE = {
"type": "object",
"properties": {
"vendor": {"type": "string"},
"invoice_number": STR, "date_iso": STR, "due_date_iso": STR,
"currency": STR, "subtotal": NUM, "tax": NUM, "total": NUM,
"line_items": {"type": "array", "items": {
"type": "object",
"properties": {"description": {"type": "string"},
"qty": NUM, "unit_price": NUM, "amount": NUM},
"required": ["description", "qty", "unit_price", "amount"],
"additionalProperties": False,
}},
},
"required": ["vendor", "invoice_number", "date_iso", "due_date_iso",
"currency", "subtotal", "tax", "total", "line_items"],
"additionalProperties": False,
}
RESPONSE_FORMAT = {"type": "json_schema",
"json_schema": {"name": "invoice", "schema": INVOICE}}
RULES = "Extract the invoice. Use null for missing fields. Dates in ISO 8601."
# Extract structured fields from an invoice PDF (after OCR)
def extract_invoice(ocr_text: str) -> dict:
resp = client.chat.completions.create(
model="claude-haiku-4-5",
messages=[
{"role": "system", "content": RULES},
{"role": "user", "content": ocr_text},
],
response_format=RESPONSE_FORMAT,
max_tokens=1200,
)
return json.loads(resp.choices[0].message.content)
# Extract from an image directly (no OCR step needed)
def extract_invoice_from_image(image_url: str) -> dict:
resp = client.chat.completions.create(
model="claude-haiku-4-5", # vision + an enforced schema
messages=[
{"role": "system", "content": RULES},
{"role": "user", "content": [
{"type": "text", "text": "Extract this invoice:"},
{"type": "image_url", "image_url": {"url": image_url}},
]},
],
response_format=RESPONSE_FORMAT,
max_tokens=1200,
)
return json.loads(resp.choices[0].message.content)Due flussi: solo testo (dopo un passaggio OCR separato) e visione diretta (un modello vision legge l’immagine e restituisce JSON in una sola chiamata). Il percorso vision è più rapido da realizzare ma leggermente più costoso per chiamata; il percorso OCR e poi LLM è più economico su larga scala perché l’OCR è un costo una tantum per pagina.
Benchmark di accuratezza
Su un dataset pubblico di fatture (1.000 fatture di 50 fornitori), con modalità JSON e un prompt di sistema di 200 parole:
- Claude Haiku 4.5: accuratezza a livello di campo del 96%
- Claude Sonnet 4.6: accuratezza a livello di campo del 98%
- Template tradizionali: 80-90% sui provider noti, 0% sui nuovi
L’LLM gestisce layout di nuovi provider senza esempi preliminari. Aggiungi 2-3 coppie di esempi nel prompt di sistema (few-shot) e Haiku si avvicina all’accuratezza di Sonnet a una frazione del costo.
Costo per documento
- Fattura (~2K token di input, ~500 di output): Haiku ~$0,003, Sonnet ~$0,02
- Contratto di una pagina (~5K token di input): Haiku ~$0,005, Sonnet ~$0,04
- Contratto di 10 pagine (~50K token di input, riepilogo strutturato in output): Sonnet ~$0,30
- Curriculum (~3K token di input): Haiku ~$0,003
- Immagine di una ricevuta con vision: Haiku, circa quanto una fattura — l’immagine conta come circa 1.5K token di input
Elaborare 10.000 fatture al mese: ~$30 con Haiku. L’alternativa commerciale più vicina (Rossum, AWS Textract + post-processing) costa circa ~$2.000-5.000 al mese per lo stesso volume.
I 5 pattern che mantengono alta l’accuratezza
- Gestione esplicita dei valori null: indica al modello di usare
nullper i campi mancanti, non "N/A" o stringhe vuote. Il codice a valle può distinguere tra "assente" e "intenzionalmente vuoto" - Date ISO 8601: dichiaralo esplicitamente. Altrimenti il modello sceglie formati regionali e il parsing a valle si interrompe
- Valuta come codice ISO: "USD", non "$"; "EUR", non "€". Evita ambiguità ($ può indicare USD, CAD o AUD)
- Convalida il JSON: usa Pydantic / Zod per imporre lo schema. Se non è valido, ripeti la richiesta includendo l’errore
- Controlla manualmente l’1% per una settimana, poi lo 0,1% continuativamente. Monitora l’accuratezza a livello di campo, non solo a livello di record
Quando usare quale modello
| Tipo di documento | Modello consigliato |
|---|---|
| Strutturato semplice (fattura, ricevuta) | Claude Haiku 4.5 |
| Contratti / accordi lunghi | Claude Sonnet 5 (gestisce contesti lunghi) |
| Vision diretta (PDF senza OCR) | Claude Haiku 4.5 oppure Claude Sonnet 5 per pagine di grandi dimensioni |
| Ambiti ad alta criticità (legale, medico) | Claude Sonnet 5 + verifica umana |
| Acquisizione in massa (100K+/giorno) | Haiku 4.5 + esempi few-shot + caching |
Considerazioni sulla conformità
Per i documenti contenenti dati personali (le fatture includono nomi e indirizzi; le cartelle cliniche includono ogni tipo di dato), pseudonimizza i dati prima dell'estrazione oppure usa Zero Data Retention a monte. Consulta la guida alla conformità per i modelli specifici per regione e l'approfondimento sul DSGVO per il playbook tedesco.
Inizia da: /app/signup — il pagamento a consumo a partire da una ricarica di $10 copre circa 3.000 estrazioni di fatture e il saldo non scade mai. Leggi la documentazione della chat su /docs/chat per sapere cosa response_format applica a ogni famiglia di modelli e per i modelli di utilizzo degli strumenti.
FAQ
Quanto costa estrarre dati da un documento con un LLM?
Circa 0,003–0,005 $ per documento con Claude Haiku 4.5 e circa 0,02–0,04 $ con Claude Sonnet 4.6. Elaborare 10.000 fatture al mese costa circa 30 $, contro 2,000–5,000 $ per i servizi commerciali di estrazione.
Quanto è accurata l’estrazione di dati zero-shot con un LLM?
Accuratezza dei campi del 95–98% senza esempi, con circa 30 righe di codice: un livello sufficiente per sostituire una pipeline OCR più regex.
Quale modello dovrei usare per estrarre dati dai documenti?
Per i documenti strutturati semplici, come fatture e ricevute, usa Claude Haiku 4.5. Per i contratti lunghi, usa Claude Sonnet 4.6. Per i documenti letti direttamente come immagini, usa Claude Haiku 4.5 oppure Sonnet 4.6 per le pagine grandi.
Come posso mantenere accurata l’estrazione in produzione?
Cinque accorgimenti: gestione esplicita dei valori null, date ISO 8601, codici valuta ISO, convalida dello schema con un nuovo prompt in caso di output non valido e controllo manuale a campione: l’1% degli output durante la prima settimana e lo 0,1% nel periodo successivo. Monitora l’accuratezza a livello di campo, non di record.