In-context learning e few-shot prompting: il superpotere degli LLM spiegato per integrazioni di produzione

In-context learning e few-shot prompting: il superpotere degli LLM spiegato per integrazioni di produzione

Il 19 marzo 2026 ho dovuto costruire in mezza giornata un estrattore di dati strutturati da PDF di fatture italiane: IVA, codice destinatario, causale, righe di dettaglio. Tempo di progettazione: due ore. Tempo di deploy: quattro ore. Zero fine-tuning, zero infrastruttura di training, solo prompt engineering con in-context learning su Claude Sonnet 4.6. Nel mio laboratorio di red team avevo già testato decine di PDF campione con output variabile; il salto da risposta inconsistente a output JSON validabile è arrivato aggiungendo sei esempi curati dentro il prompt. Questo è il potere dell'in-context learning: riprogrammare il comportamento del modello a runtime senza toccare i pesi. Qui racconto come lo uso in produzione, con sei pattern ripetibili e le trappole che ho incontrato sul campo.

Cosa dice davvero il paper GPT-3 sul few-shot learning?

Il paper fondazionale è Language Models are Few-Shot Learners di Brown et al., OpenAI, maggio 2020, 75 pagine, 175 miliardi di parametri, primo modello a mostrare che la sola scala (non il fine-tuning task-specifico) sblocca capacità emergenti. Il contributo centrale non è "costruiamo un modello grande": è la scoperta che, una volta superata una certa scala, il modello apprende task nuovi dai soli esempi nel prompt, senza nessun aggiornamento dei pesi.

Il meccanismo è costruito sopra l'attention del Transformer: quando metti esempi nel prompt, il modello usa le relazioni tra tokens di input e output degli esempi per condizionare la propria generazione sulla nuova query. Non è magia, è statistica ad alta dimensionalità. Ed è gratis dal punto di vista del training: non ci sono GPU da scaldare, non ci sono dataset da gestire, non ci sono pesi da storare. Il costo, a cambio, è a runtime: ogni chiamata paga il prezzo in token degli esempi.

Tre regimi terminologici da distinguere. Zero-shot: solo istruzione, nessun esempio. One-shot: istruzione più un esempio. Few-shot: istruzione più due o più esempi. N-shot è una generalizzazione operativa.

Step 1: setup di una pipeline di produzione con Claude API

Il pattern base che uso in quasi tutti i progetti PMI è un client Python con Anthropic SDK, templating Jinja per i prompt, e un pool di esempi versionati. Qui la struttura essenziale.

# estrazione_fatture.py
from anthropic import Anthropic
from jinja2 import Template
import json

client = Anthropic()  # legge ANTHROPIC_API_KEY da env

PROMPT_TEMPLATE = Template("""Sei un estrattore di dati da fatture italiane.
Ricevi il testo OCR di una fattura e devi produrre SOLO JSON valido nello schema indicato.
Non aggiungere commenti, non spiegare, non rispondere in linguaggio naturale.

Schema output:
{
  "iva": "string (partita IVA venditore)",
  "codice_destinatario": "string di 7 caratteri",
  "causale": "string",
  "totale": "number (EUR)",
  "righe": [{"descrizione": "string", "quantita": number, "prezzo_unitario": number}]
}

{% for esempio in esempi %}
Esempio {{ loop.index }}:
INPUT:
{{ esempio.input }}

OUTPUT:
{{ esempio.output | tojson }}
{% endfor %}

Ora analizza questo documento:
INPUT:
{{ query }}

OUTPUT:
""")

def estrai(testo_ocr: str, esempi: list) -> dict:
    prompt = PROMPT_TEMPLATE.render(esempi=esempi, query=testo_ocr)
    response = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=2048,
        messages=[{"role": "user", "content": prompt}]
    )
    return json.loads(response.content[0].text)

La chiave del tutorial è in esempi: una lista curata di 4-8 coppie input/output che coprono i casi più frequenti e qualche edge case. Versionate queste coppie con Git come fossero codice, perché sono codice: cambiano il comportamento del modello.

Se vuoi approfondire come costruisco pipeline di in-context learning con governance dei costi e versioning delle prompt library, nel mio hub dedicato allo sviluppo AI trovo articoli tecnici con metodologia applicata e perimetro dichiarato.

Step 2: sei pattern di few-shot che uso ripetutamente in produzione

Pattern 1 - Strutturazione output. Quando devi forzare il modello a produrre JSON, XML, Markdown o qualsiasi formato rigido, gli esempi sono il vettore più affidabile. Prompt testuale tipo "produci JSON" fallisce in edge case; sei esempi con JSON impeccabili riducono gli errori di formato di due ordini di grandezza.

Pattern 2 - Stile e registro. Documenti tecnici italiani con terminologia specialistica richiedono stile. Passare al modello 3-4 esempi di buon testo del tuo dominio (contratti, perizie, relazioni tecniche) lo orienta meglio di qualsiasi system prompt descrittivo.

Pattern 3 - Classificazione multi-label. Tagging di articoli, ticket, email. Gli esempi devono coprire i casi ambigui (un ticket che è sia "fatturazione" sia "tecnico") perché è lì che il modello vacilla.

Pattern 4 - Extraction con validation rules. Oltre all'esempio di input-output, metti nell'esempio output un campo _validazione che elenchi i controlli fatti. Il modello impara a fare il controllo e a metterlo in output.

Pattern 5 - Chain-of-thought implicita. Quando l'output richiede ragionamento (es. "questo contratto è a rischio?"), gli esempi devono esplicitare il ragionamento in un campo intermedio prima della risposta finale. È la via più economica per portare il comportamento di reasoning in un modello base.

Pattern 6 - Rifiuto controllato. Esempi che mostrano come il modello deve rifiutare quando l'input non è nel dominio (es. un PDF che non è una fattura). Senza esempi di rifiuto, il modello prova ad andare avanti anche quando non dovrebbe.

Step 3: come scegliere e ordinare gli esempi (questo è il trucco)

Tre regole operative, non ovvie.

Diversità prima che quantità. Dieci esempi simili peggiorano la generalizzazione del modello perché lo spingono su un sottotipo. Cinque esempi diversi che coprono varianti importanti sono più efficaci.

Edge case in coda. L'ordine degli esempi conta perché la recency pesa nell'attention. Metti gli esempi "tipici" all'inizio e quelli "edge case" alla fine: il modello tratterà l'edge case come segnale più forte sulla sua attesa.

Esempio negativo esplicito. Se il task ha un errore frequente (es. fattura con codice destinatario di 6 caratteri anziché 7), includi un esempio che mostri come gestire l'errore, non come evitarlo.

Un errore comune: mettere un esempio per ogni possibile classe (10 categorie → 10 esempi). Spreco di token e di attention: il modello non ha bisogno di vedere ogni classe, ha bisogno di vedere il confine decisionale. Esempi ben scelti per disambiguare classi vicine battono esempi numerosi.

Step 4: errori che ho fatto e come evitarli

Errore 1: confondere in-context learning con fine-tuning. L'in-context learning non cambia i pesi. Se chiudi la sessione, il modello non ricorda nulla. Mai dire a un cliente "abbiamo allenato il modello sui tuoi esempi" quando hai fatto few-shot prompting. È tecnicamente falso e crea aspettative sbagliate su costi e replicabilità.

Errore 2: esempi nel system prompt o nel user prompt? Nei modelli recenti (Claude 4.x, GPT-5) gli esempi hanno più peso nel user message, perché il system è ottimizzato per istruzioni persistenti, non per exemplars. Mettere cinque esempi nel system prompt degrada spesso le performance.

Errore 3: token sprecati su prompt caching naive. Con Anthropic prompt caching, se metti gli esempi nel system prompt con cache marker puoi riutilizzarli a 10% del costo input. Ma se li metti nel user message, la cache non si attiva. La scelta dipende dal balance tra efficacia didattica e costo ricorrente: per task stabili uso system prompt cached, per task fluidi uso user message. Approfondimento nel mio articolo su prompt caching workspace-level.

Errore 4: non validare il formato dell'output. Anche con dieci esempi di JSON perfetto, un modello produce ogni tanto output malformato. Ogni chiamata deve essere wrappata in un parser che valida lo schema e, se fallisce, riprova con un prompt di correzione esplicito ("il tuo output precedente non era JSON valido per questo motivo, rigeneralo").

Errore 5: overfitting sugli esempi. Se i tuoi esempi sono troppo specifici, il modello imita le peculiarità non significative (es. tutti i tuoi esempi hanno righe di dettaglio con tre voci, e il modello taglia a tre voci fatture che ne hanno dieci). Test sempre con un held-out set di casi reali che gli esempi non coprono.

Step 5: versionare gli esempi come codice

Gli esempi few-shot sono codice nel senso operativo: cambiano il comportamento del sistema. Trattarli come dati usa-e-getta è la ragione principale per cui molte pipeline LLM aziendali degradano nel tempo senza che nessuno capisca perché. Ecco come organizzo la struttura di un repository di prompt engineering.

prompts/
  estrazione_fatture/
    v1/
      system.md          # istruzioni persistenti
      examples.jsonl     # esempi annotati, uno per riga
      schema.json        # schema dell'output atteso
      CHANGELOG.md       # storia delle modifiche
    v2/
      ...
    current -> v2        # symlink alla versione attiva

Ogni esempio in examples.jsonl è tipizzato: input, output, una nota sul perché è presente (es. "edge case: codice destinatario 7 zeri per privato"), un tag sulla fonte ("reale, anonimizzato" o "sintetico"). Quando cambio gli esempi alzo la minor version e registro nel CHANGELOG cosa ho cambiato e cosa mi aspetto cambi nei risultati. Ho un runner che esegue un held-out set fisso contro ciascuna versione e riporta le deviazioni. Senza questo scaffolding, il primo che tocca gli esempi senza misurare cambia silenziosamente il comportamento del sistema.

La stessa logica vale per i prompt caching key: con Anthropic, se cambi anche un carattere nel system prompt cachato, la cache si invalida e paghi pieno fino a quando non si ricostruisce. Versionare gli esempi serve anche a non perdere il vantaggio economico del caching.

Edge case: in-context learning che fallisce nonostante tutto

Tre categorie di task dove l'in-context learning è intrinsecamente debole e vale la pena passare ad altro.

Matematica a più passaggi su numeri grandi. Anche con 20 esempi, il modello sbaglia moltiplicazioni a 8 cifre. Il pattern corretto è tool use con calcolatrice esterna.

Rispetto rigido di grammatiche formali. Un output che deve essere SQL valido per uno schema specifico è meglio ottenuto con constrained decoding o structured output API (Anthropic, OpenAI hanno entrambi feature dedicate), non con in-context learning.

Task con contesto enorme. Se il task richiede tre documenti da 100k token ciascuno, gli esempi few-shot competono con i documenti per lo spazio di contesto. Meglio retrieval mirato + prompt zero-shot.

Decision tree: in-context learning, RAG o fine-tuning?

Quando porto una proposta a un CTO o a un titolare PMI la domanda ricorrente è "ma perché non fine-tuning?". Il decision tree che uso mentalmente è il seguente.

Se il task è ristretto, il volume non estremo e il formato dell'output è il punto critico, in-context learning con 4-8 esempi è la risposta giusta. Tempo di setup: ore. Costo: zero fisso, variabile basso con caching.

Se il modello ha bisogno di conoscere documenti aziendali aggiornati, o leggi, o cataloghi, o manuali interni, allora RAG è la risposta. L'in-context learning resta utile per forzare il formato della risposta sopra il contesto recuperato, ma il cuore è il retrieval. Tempo di setup: giorni. Costo: infrastruttura vector DB più compute di embedding.

Se hai un task iper-ripetitivo ad altissimo volume con latenza critica e hai risorse per mantenere una pipeline MLOps seria, fine-tuning o distillation diventano sostenibili. Tempo di setup: settimane. Costo: training + infrastruttura + retraining periodico.

Nella pratica italiana, nove progetti su dieci che un fornitore propone come "fine-tuning" si risolvono meglio con il primo o il secondo scalino. Il fine-tuning è la scelta naturale solo in frazioni marginali dei casi reali, e il costo di sbagliare è alto perché è irreversibile e crea dipendenze di vendor lock-in.

Costi reali di una pipeline in produzione

Esempio numerico dalla mia sandbox. Estrazione fatture italiane, Claude Sonnet 4.6, 8 esempi nel user message, 1000 chiamate/giorno, ciascuna con prompt medio 4200 token input e 800 token output.

  • Senza prompt caching: circa 4,30 euro al giorno, 130 euro al mese.
  • Con prompt caching su system prompt cached (esempi in user message non cacheable): circa 3,10 euro al giorno.
  • Con riorganizzazione esempi in system prompt cached: circa 0,95 euro al giorno, 28 euro al mese.

Il refactoring del placement degli esempi è stato un'ora di lavoro e ha tagliato il 78% del costo ricorrente. Questo è il tipo di ottimizzazione che un consulente esperto porta in un progetto; è anche il tipo di micro-decisione che un fornitore junior lascia sul tavolo.

L'in-context learning è la tecnica più sottovalutata nel prompt engineering moderno: costa zero in training, è reversibile in un secondo, è interpretabile (leggi gli esempi e sai cosa sta facendo il modello). Ma è anche la tecnica dove la differenza tra un setup amatoriale e uno ingegnerizzato si misura nel fattore dieci sul costo e sulla qualità. Se hai un progetto che richiede output strutturato da LLM e vuoi capire se la pipeline che ti è stata proposta sfrutta davvero questa leva, il modulo di preventivo gratuito ti risponde in due minuti se il caso rientra nel mio ambito. Sei esempi ben scelti valgono più di sei mesi di fine-tuning svogliato; ma metterli al posto giusto, scriverli al livello giusto, validarli con un held-out set e versionarli come codice è ingegneria, non magia, e la qualità della pipeline dipende da questa differenza più di quanto la maggior parte dei fornitori ammetta.

Ultima modifica: