DSPy e prompt-as-code: ottimizzare automaticamente i prompt di produzione contro benchmark interni

DSPy e prompt-as-code: ottimizzare automaticamente i prompt di produzione contro benchmark interni

Il 12 maggio 2026 ho riscritto nella mia pipeline personale di automazione AI un estrattore di entità da documenti tecnici italiani da prompt manuale a DSPy. Prompt manuale ottimizzato in due iterazioni: accuracy 79% sul held-out di 200 esempi. Stesso task in DSPy con bootstrap su 40 esempi di training: accuracy 87% al primo compile. Otto punti percentuali senza un giorno di prompt engineering manuale. DSPy non è l'ultima buzzword, è l'applicazione rigorosa del pattern "prompt-as-code" al problema dell'ottimizzazione automatica. Questo articolo è il confronto fra prompt engineering manuale (anche CO-STAR disciplinato) e DSPy, con template riutilizzabile e decisione tree di quando uno batte l'altro.

Cosa è DSPy e perché è rilevante nel 2026?

DSPy (Declarative Self-improving Python) è il framework rilasciato da Stanford NLP nel paper DSPy: Compiling Declarative Language Model Calls into Self-Improving Pipelines di Khattab et al., presentato a ICLR 2024. La tesi: i prompt template scritti a mano sono "lunghe stringhe di istruzioni e demo fatte a trial-and-error", fragili e non scalabili, non generalizzano fra pipeline, modelli, domini.

DSPy sostituisce la scrittura manuale del prompt con una dichiarazione del task tramite signature (tipo "query -> answer" o "document -> summary"). Il framework genera il prompt concreto bootstrappando da esempi di training, misurando accuracy contro un validation set e iterando per convergere su una versione ottimizzata.

Il claim sperimentale del paper è forte: "succinct DSPy programs can express and optimize sophisticated LM pipelines... Within minutes of compiling, a few lines of DSPy allow GPT-3.5 and llama2-13b-chat to self-bootstrap pipelines that outperform standard few-shot prompting (generally by over 25% and 65%, respectively) and pipelines with expert-created demonstrations (by up to 5-46% and 16-40%, respectively)".

Tradotto: DSPy batte sia il prompting zero-shot che il prompt engineering manuale fatto da esperti, sullo stesso modello, per larghi margini. Il paper è stato validato da decine di progetti open source nel 2024-2026.

DSPy vs prompt manuale CO-STAR: tabella comparativa

DimensionePrompt manuale CO-STARDSPy
Tempo setup iniziale2-4 ore/prompt30 min dichiarazione + 30 min tuning
Tempo iterazioneManuale, 1-2 ore per varianteAutomatico, 10 min per ricompile
Richiede training setNo (opzionale)Sì (40-200 esempi curati)
Richiede metricNo (valutazione qualitativa)Sì (metrica numerica validabile)
Interpretabilità prompt finaleAlta (leggi il testo)Media (prompt generato)
Portabilità fra modelliBassa (cambio modello = rewrite)Alta (ricompile su nuovo modello)
Curva di apprendimentoBassaMedia (concetti DSPy da apprendere)
ROI su task ripetutoMedioAlto su volume
ROI su task one-shotAltoBasso (overhead del framework)

La scelta dipende dal contesto: per task one-shot (query ad-hoc, analisi puntuale), prompt manuale CO-STAR vince per semplicità. Per pipeline di produzione con volume significativo, DSPy batte il manuale quasi sempre perché l'ottimizzazione automatica scopre pattern che l'occhio umano non vede.

Esempio operativo: estrazione entità con DSPy

Un caso concreto dalla mia sandbox. Estrazione di tre campi strutturati da descrizioni testuali di prodotto in italiano.

import dspy

lm = dspy.LM("anthropic/claude-sonnet-4-6", api_key="...")
dspy.configure(lm=lm)

class EstrazioneProdotto(dspy.Signature):
    """Estrai da una descrizione prodotto: codice SKU, categoria, prezzo IVA inclusa."""
    descrizione: str = dspy.InputField()
    sku: str = dspy.OutputField(desc="codice alfanumerico SKU")
    categoria: str = dspy.OutputField(desc="categoria merceologica")
    prezzo_ivato: float = dspy.OutputField(desc="prezzo in EUR con IVA 22%")

extractor = dspy.Predict(EstrazioneProdotto)

Questa signature è dichiarativa: descrive cosa estrarre, non come formulare il prompt. DSPy genera automaticamente il prompt concreto per Claude.

Per ottimizzare, servono esempi di training e una metrica.

# 40 esempi annotati dal corpus reale
trainset = [
    dspy.Example(descrizione="Camera B&B matrimoniale COD-H123 a 89 euro + IVA...",
                 sku="COD-H123", categoria="camera_matrimoniale", prezzo_ivato=108.58).with_inputs("descrizione"),
    # ... altri 39 esempi
]

def accuracy_metric(gold, pred, trace=None):
    return (gold.sku == pred.sku and
            gold.categoria == pred.categoria and
            abs(gold.prezzo_ivato - pred.prezzo_ivato) < 0.01)

optimizer = dspy.BootstrapFewShot(metric=accuracy_metric, max_bootstrapped_demos=4)
optimized_extractor = optimizer.compile(extractor, trainset=trainset)

Dopo il compile, optimized_extractor è una versione ottimizzata del predictor originale: DSPy ha selezionato i migliori 4 esempi da mettere few-shot nel prompt e ha raffinato le istruzioni. Costo del compile: 40 chiamate API di training (pochi euro), 10 minuti di runtime.

Se vuoi approfondire come integro DSPy in pipeline AI di produzione con governance dei costi e versioning dei compile artifact, nel mio hub dedicato allo sviluppo AI trovo articoli tecnici con metodologia applicata, in connessione con l'articolo su in-context learning.

Confronto quantitativo su dataset di matematica

Esempio dal mio laboratorio che replica parte dei risultati del paper Stanford.

Task: risolvere problemi di matematica elementare italiana (200 problemi di testo, tipo GSM8K ma in italiano). Modello: Claude Sonnet 4.6.

  • Zero-shot baseline. Prompt generico "risolvi il problema, dammi solo il numero finale". Accuracy: 58%.
  • Prompt manuale esperto. CO-STAR applicato, 3 esempi few-shot scelti a mano, chain-of-thought implicito. Accuracy: 82%. Tempo di scrittura: 3 ore.
  • DSPy zero-effort. Signature problema -> risposta numerica, nessun training. Accuracy: 76% (sopra zero-shot per via del reasoning strutturato generato).
  • DSPy ottimizzato. Training set di 50 esempi con risposta corretta, BootstrapFewShot. Accuracy: 91%. Tempo: 1 ora di annotazione + 15 minuti di compile.

DSPy ottimizzato batte il prompt esperto di 9 punti percentuali a costo di tempo inferiore. Il paradosso è che DSPy sembra "pigro" (dichiari, non scrivi) ma i risultati empirici superano il prompt engineering manuale sistematicamente nei task con metrica oggettiva.

Auto-DSPy e reinforcement learning: l'evoluzione 2025-2026

Il progetto Stanford è evoluto con varianti. Auto-DSPy aggiunge reinforcement learning sopra il bootstrap: dopo aver generato un prompt iniziale ottimizzato, una seconda fase di RL affina il prompt contro il reward signal della metrica.

In pratica: il prompt genera 10 output per ogni input di training, ciascuno valutato dalla metrica, i migliori vengono usati come nuovi "gold demonstrations" per il prossimo iterato. Il processo converge a un prompt che massimizza la metrica.

Gain tipico su task complessi: ulteriori 3-8 punti percentuali sopra BootstrapFewShot. Costo: 3-5x i token del bootstrap semplice. Vale la pena per task high-volume o high-stakes dove il 3% di accuracy extra paga per il compute.

Quando DSPy è la scelta giusta e quando no

Decisione tree operativo per il mio lavoro.

DSPy se:

  • Il task ha una metrica numerica verificabile (accuracy, F1, recall, BLEU).
  • Hai almeno 40-200 esempi di training con risposta corretta.
  • Il task è a volume (centinaia-migliaia di chiamate al giorno in produzione).
  • Devi cambiare modello frequentemente (DSPy ricompila per ogni modello).
  • L'interpretabilità del prompt finale non è vincolo critico.

Prompt manuale (CO-STAR) se:

  • Il task è one-shot o bassa frequenza.
  • Non hai training data strutturato.
  • La metrica è soggettiva (stile, tono, creatività).
  • L'interpretabilità del prompt è critica (compliance, audit, spiegazione al cliente).
  • Il team ha già expertise prompt engineering forte.

Ibrido (DSPy + human review) se:

  • Il task è ad alto volume ma con vincoli qualitativi.
  • Serve versioning auditabile con human-in-the-loop.
  • Pattern: DSPy fa il compile, esperto human review del prompt risultante, deploy solo dopo approval.

Pattern operativi di integrazione DSPy in produzione

Cinque pratiche che adotto nei progetti che usano DSPy.

Versioning dei compile artifact. Ogni compile DSPy produce un prompt concreto + lista di few-shot scelti. Versiona questo artifact in Git come codice. Non ricompilare in produzione senza approval.

Held-out separato dal training. Il training set di 40-200 esempi NON deve includere casi del held-out di validazione. Separazione rigorosa per evitare inflazione dell'accuracy.

Metric designer come consulente. La metrica è il cuore di DSPy. Va progettata con chi conosce il dominio (esperto fiscale per fatture, commercialista per calcoli IVA, legal per contrattualistica). Se la metrica è sbagliata, DSPy ottimizza verso il male sbagliato.

Shadow deploy. Compile un nuovo prompt, lancialo in shadow (chiamate parallele al prompt vecchio) per 7-14 giorni, confronta metriche business reali, promuovi solo se il nuovo vince significativamente.

Budget di ricompile. Stabilisci un budget massimo di ricompile al trimestre (es. 4 volte l'anno). Evita il ricompilare ad ogni feedback random del team.

Gli optimizer di DSPy: quale scegliere quando

DSPy offre un ecosistema di optimizer (teleprompter nella nomenclatura originale), ciascuno con caratteristiche diverse. Ecco quando usare cosa.

BootstrapFewShot. Optimizer base, genera esempi few-shot dal training set e seleziona i migliori. Rapido (minuti), economico in token, buon baseline. Scelta default per il primo compile di un progetto nuovo.

BootstrapFewShotWithRandomSearch. Estensione che prova configurazioni diverse in parallelo. Tempo 5-10x il base, gain tipico 1-3 punti percentuali sul held-out. Vale la pena quando il task è ad alto volume e il delta di accuracy conta economicamente.

MIPROv2 e MIPRO. Ottimizzatori più sofisticati che usano Bayesian optimization sulle istruzioni del prompt. Più costosi (30-60 minuti di compile + decine di euro di spend API), ma raggiungono gain maggiori su task complessi con logica multi-step. Scelta per pipeline mature che hanno già sfruttato BootstrapFewShot al massimo.

KNN Few-Shot. Retrieval-based: per ogni input in produzione, recupera i K esempi più simili dal training set come few-shot dinamico. Costo di runtime maggiore, accuracy più alta quando il training set copre domini eterogenei difficili da coprire con pochi esempi fissi.

Ensembled optimizer. Compile più volte con seed diversi, maggioranza sulle predizioni in produzione. Accuracy migliore al costo di più chiamate per query in runtime. Riservato a task dove il 2% extra di accuracy conta economicamente.

La scelta dell'optimizer è parte della progettazione, non un dettaglio. Il pattern sano: iniziare con BootstrapFewShot, misurare il gain sul held-out, passare a optimizer più sofisticati solo se il gain potenziale è misurato e giustificato dal volume di produzione.

Pipeline DSPy: scaffolding riutilizzabile

Uno scaffolding di codice che uso come baseline per ogni nuovo progetto DSPy.

# dspy_pipeline.py
import dspy
import json

def load_dataset(path, input_fields):
    examples = []
    with open(path) as f:
        for line in f:
            row = json.loads(line)
            ex = dspy.Example(**row).with_inputs(*input_fields)
            examples.append(ex)
    return examples

def setup_lm(provider, model, api_key):
    lm = dspy.LM(f"{provider}/{model}", api_key=api_key)
    dspy.configure(lm=lm)

def compile_and_evaluate(predictor, trainset, valset, metric, output_path):
    optimizer = dspy.BootstrapFewShot(metric=metric, max_bootstrapped_demos=4)
    compiled = optimizer.compile(predictor, trainset=trainset)
    compiled.save(output_path)
    correct = sum(1 for ex in valset if metric(ex, compiled(**ex.inputs()), None))
    print(f"Held-out accuracy: {correct/len(valset):.1%}")
    return compiled

Lo scaffolding versionato in Git diventa la base riutilizzabile per ogni task DSPy successivo, riducendo il tempo di setup di nuovi compile a meno di un'ora di scrittura del codice custom del task (signature + metric + loading del dataset specifico).

Edge case: DSPy non è una pallottola d'argento

Tre limitazioni da conoscere.

Limite 1: metrica sbagliata = ottimizzazione verso il male. DSPy massimizza la metrica che gli dai. Se la metrica premia risposte corte ma sbagliate su casi borderline, otterrai un modello che taglia sul bordo. La qualità della metrica > la qualità del framework.

Limite 2: compile instability. Due compile con stessa configurazione e stesso training set possono produrre prompt leggermente diversi (stochasticity del bootstrap). Accuracy stabile, ma il testo del prompt varia. Può confondere team che si aspettano deterministic artifact.

Limite 3: costo di training su modelli premium. Se compile DSPy lanciato su GPT-5 a $30/$180 (input/output), il training da 40 esempi può costare 10-30 euro per ricompile. Su Claude Sonnet più economico, ma comunque da budgetare.

Limite 4: stabilità fra versioni di modello. Un compile fatto su Claude Sonnet 4.6 non produce il miglior prompt per Sonnet 5.0. Ogni upgrade di modello richiede ricompile e re-evaluation. Budgetare il tempo di migration quando il vendor rilascia nuove versioni è prassi che va nel piano operativo, non lasciata all'ultimo minuto.

Limite 5: debugging complicato. Quando il prompt compilato produce risposte sbagliate, la causa può essere nella signature, nella metrica, negli esempi di training, nell'optimizer scelto. Il debugging richiede metodo, non intuizione. Logging strutturato di prompt compilati + predizioni + feedback metric è obbligatorio in produzione seria.

DSPy non rende superflui gli ingegneri prompt esperti; li libera dal lavoro manuale ripetitivo per farli concentrare sulla progettazione del task (signature, metrica, training set curato). Il risultato in produzione è prompt più robusti, misurabili e ottimizzabili sistematicamente. Se hai una pipeline LLM in produzione con volume significativo e vuoi valutare se DSPy può batter il tuo prompt engineering manuale su un held-out oggettivo, il modulo di preventivo gratuito ti risponde in due minuti se il caso rientra nel mio ambito. Il prompt-as-code non è un trend di moda: è la direzione strutturale del prompt engineering 2026, e chi la adotta prima estrae vantaggio competitivo sulla concorrenza italiana che ancora scrive prompt manuali in Google Docs condivisi. Il passaggio da "prompt creativo" a "prompt compilato" è lo stesso salto che il software engineering ha vissuto dal copia-incolla di script al build system disciplinato; chi capisce il parallelo capisce anche perché DSPy rappresenta la prossima convergenza degli standard di ingegneria AI applicata al business reale, ben oltre la fase di sperimentazione in cui molte PMI italiane sono ancora ferme a metà 2026.

Ultima modifica: