Valutazione delle pipeline DSPy
Metriche, dev set e funzione evaluate() per la valutazione automatizzata
Valutazione delle pipeline DSPy è una lezione AI Prompt Engineering gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento AI Prompt Engineering, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso AI Prompt Engineering include 4 lezioni in totale.
Perché la valutazione è importante in DSPy
L'ottimizzazione di DSPy è efficace solo quanto lo è la valutazione. Una metrica debole produce un programma compilato che ottiene buoni risultati secondo quella metrica, ma non funziona in produzione. Un'infrastruttura di valutazione adeguata consente di confrontare i programmi non ottimizzati con quelli ottimizzati e di individuare le regressioni quando si aggiorna la pipeline.
La classe dspy.Evaluate
dspy.Evaluate esegue il programma su un dataset, applica una metrica e restituisce i punteggi aggregati. Supporta l'esecuzione parallela tramite num_threads, per valutare rapidamente dataset di grandi dimensioni.
import dspy
# Build a devset of labeled examples
devset = [
dspy.Example(question='What is 7 * 8?', answer='56').with_inputs('question'),
dspy.Example(question='Name the largest planet.', answer='Jupiter').with_inputs('question'),
# ... more examples
]
# Create evaluator
evaluate = dspy.Evaluate(
devset=devset,
metric=exact_match_metric, # Your metric function
num_threads=4, # Parallel evaluation
display_progress=True, # Show progress bar
display_table=True, # Show per-example results
)
# Run
score = evaluate(my_program)
print(f'Overall score: {score:.1%}')Scrivere funzioni metrica
Le funzioni metrica hanno la firma (example, prediction, trace=None) -> float. Confrontano la previsione del programma con il valore corretto contenuto nell'esempio.
Il parametro trace è diverso da None durante l'ottimizzazione, ma non durante la valutazione: può essere utilizzato per applicare una logica diversa in fase di compilazione e in fase di valutazione.
import dspy
def exact_match_metric(example, prediction, trace=None):
return float(
example.answer.strip().lower() == prediction.answer.strip().lower()
)
def contains_metric(example, prediction, trace=None):
"""Check if expected answer appears anywhere in prediction."""
return float(example.answer.lower() in prediction.answer.lower())
def length_penalized_metric(example, prediction, trace=None):
"""Reward correct answers, penalize overly long ones."""
correct = float(example.answer.lower() in prediction.answer.lower())
length_ok = float(len(prediction.answer.split()) <= 20)
return correct * (0.8 + 0.2 * length_ok)
# Use any of these as the metric parameter
evaluate = dspy.Evaluate(devset=devset, metric=contains_metric)Schemi di soglia superato/non superato
Per le metriche binarie, è possibile definire una soglia: una previsione è «superata» se raggiunge un livello minimo di qualità. Questo è utile per filtrare gli esempi dimostrativi few-shot durante l'ottimizzazione bootstrap.
import dspy
def quality_metric(example, prediction, trace=None):
"""
Multi-factor metric with pass/fail threshold.
Returns float 0.0 to 1.0.
During compilation (trace is not None), DSPy uses this to decide
which traces to bootstrap as demos.
"""
score = 0.0
# Factor 1: Factual correctness (0.6 weight)
if example.answer.lower() in prediction.answer.lower():
score += 0.6
# Factor 2: Conciseness (0.4 weight)
word_count = len(prediction.answer.split())
if word_count <= 15:
score += 0.4
elif word_count <= 30:
score += 0.2
# During optimization: only use examples scoring >= 0.6
if trace is not None:
return score >= 0.6
return scoreSuddividere i dati: train, dev e test
Segua le pratiche standard di suddivisione dei dati ML in DSPy:
- Trainset: utilizzato dall'ottimizzatore per creare gli esempi dimostrativi bootstrap (20-200 esempi)
- Devset: utilizzato dall'ottimizzatore per la validazione durante la ricerca
- Testset: tenuto completamente da parte e utilizzato solo per la valutazione finale
import random
# All labeled examples
all_examples = load_examples() # Returns list of dspy.Example
random.shuffle(all_examples)
total = len(all_examples)
train_end = int(total * 0.6)
dev_end = int(total * 0.8)
trainset = all_examples[:train_end] # 60% for optimization
devset = all_examples[train_end:dev_end] # 20% for validation
testset = all_examples[dev_end:] # 20% held out
print(f'Train: {len(trainset)}, Dev: {len(devset)}, Test: {len(testset)}')Confrontare programmi ottimizzati e non ottimizzati
Esegua sempre il benchmarking del programma compilato rispetto al programma di base, cioè non compilato, sullo stesso testset. In questo modo dimostra che l'ottimizzazione ha effettivamente migliorato il programma e può quantificare il miglioramento.
import dspy
evaluate = dspy.Evaluate(
devset=testset,
metric=exact_match_metric,
num_threads=4,
display_progress=True,
)
# Baseline: unoptimized program
baseline_score = evaluate(unoptimized_program)
print(f'Baseline (no optimization): {baseline_score:.1%}')
# BootstrapFewShot compiled
bs_score = evaluate(bootstrap_compiled_program)
print(f'BootstrapFewShot compiled: {bs_score:.1%}')
# MIPRO compiled
mipro_score = evaluate(mipro_compiled_program)
print(f'MIPRO compiled: {mipro_score:.1%}')
# Pick the winner
print(f'Best improvement: +{max(bs_score, mipro_score) - baseline_score:.1%}')Esecuzione parallela con num_threads
La valutazione di dataset di grandi dimensioni richiederebbe ore se eseguita in sequenza. num_threads in dspy.Evaluate esegue le previsioni in parallelo, riducendo proporzionalmente il tempo reale trascorso.
Imposti num_threads in base ai limiti di frequenza della propria API: un numero eccessivo di thread provoca errori dovuti al superamento del limite.
import dspy
import time
devset = [...] # 200 examples
# Sequential evaluation
start = time.time()
evaluate_seq = dspy.Evaluate(devset=devset, metric=metric, num_threads=1)
score_seq = evaluate_seq(program)
print(f'Sequential: {time.time()-start:.0f}s')
# Parallel evaluation (4 threads)
start = time.time()
evaluate_par = dspy.Evaluate(devset=devset, metric=metric, num_threads=4)
score_par = evaluate_par(program)
print(f'Parallel (4 threads): {time.time()-start:.0f}s')
# Typically ~4x faster — same score, less wait timeInterpretare l'output della valutazione
Quando display_table=True, DSPy mostra una tabella dettagliata con ogni esempio, la previsione e l'indicazione del superamento o meno della metrica. È uno strumento prezioso per diagnosticare gli schemi ricorrenti degli errori.
Cerchi: errori sistematici in un tipo di domanda, casi limite della metrica o esempi non coperti dal set di addestramento.
import dspy
evaluate = dspy.Evaluate(
devset=devset,
metric=exact_match_metric,
num_threads=2,
display_progress=True,
display_table=10, # Show first 10 rows of results table
return_outputs=True, # Return (score, outputs) tuple
)
score, outputs = evaluate(program, return_all_scores=True)
# Find failing examples
failures = [
(ex, pred, s)
for ex, pred, s in outputs
if s == 0.0
]
print(f'Failures: {len(failures)}/{len(devset)}')
for ex, pred, _ in failures[:3]:
print(f'Q: {ex.question}')
print(f'Expected: {ex.answer}')
print(f'Got: {pred.answer}')Utilizzare metriche valutate da un LLM
Per gli output a risposta aperta, nei quali la corrispondenza esatta non è sufficiente, utilizzi un LLM per valutarne la qualità. DSPy rende questa operazione semplice: la funzione metrica può a sua volta chiamare un predittore DSPy.
import dspy
class GradeAnswer(dspy.Signature):
"""Grade whether the predicted answer is correct given the reference."""
question: str = dspy.InputField()
reference_answer: str = dspy.InputField()
predicted_answer: str = dspy.InputField()
is_correct: bool = dspy.OutputField(
desc='True if the predicted answer is semantically correct'
)
grader = dspy.Predict(GradeAnswer)
def llm_graded_metric(example, prediction, trace=None):
result = grader(
question=example.question,
reference_answer=example.answer,
predicted_answer=prediction.answer,
)
return float(result.is_correct)
# Use this metric when answers can vary in phrasing
evaluate = dspy.Evaluate(devset=devset, metric=llm_graded_metric)Test di regressione con la valutazione
Consideri la suite di valutazione di DSPy alla stregua di una suite di test. Ogni volta che aggiorna la signature, l'architettura dei moduli o i dati di addestramento, esegua nuovamente la valutazione e confronti i punteggi per individuare le regressioni.
import json
import dspy
def run_and_save_evaluation(program, program_name, testset, metric):
evaluate = dspy.Evaluate(
devset=testset,
metric=metric,
num_threads=4,
)
score = evaluate(program)
# Save score to history file
history_file = 'eval_history.json'
try:
with open(history_file) as f:
history = json.load(f)
except FileNotFoundError:
history = []
history.append({'program': program_name, 'score': score})
with open(history_file, 'w') as f:
json.dump(history, f, indent=2)
print(f'{program_name}: {score:.1%}')
return scoreBuone pratiche di valutazione
Principi fondamentali per la valutazione delle pipeline DSPy:
- Mantenga il testset rigorosamente separato e non lo utilizzi mai per l'ottimizzazione
- Utilizzi almeno 50-100 esempi di test per ottenere punteggi affidabili
- Scelga una metrica coerente con l'obiettivo effettivo in produzione
- Confronti più ottimizzatori: i risultati variano in base all'attività
- Monitori i punteggi nel tempo per rilevare le regressioni
- Esamini manualmente gli errori per migliorare i dati di addestramento
Verifica delle conoscenze: parametro trace della funzione metrica
In una funzione metrica DSPy, che cosa indica un parametro trace diverso da None?
Riepilogo: valutare le pipeline DSPy
dspy.Evaluate esegue il programma su un devset con etichette, applica una funzione metrica e restituisce i punteggi aggregati. Le funzioni metrica seguono lo schema (example, prediction, trace=None) -> float. Utilizzi num_threads per la valutazione parallela e display_table=True per diagnosticare gli errori. Confronti sempre i programmi ottimizzati con quelli non ottimizzati su un testset tenuto da parte. Per gli output a risposta aperta, le metriche valutate da un LLM sono più efficaci della semplice corrispondenza esatta delle stringhe.
Domande Frequenti
La lezione «Valutazione delle pipeline DSPy» è gratuita?
Sì — il testo completo di «Valutazione delle pipeline DSPy» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso AI Prompt Engineering, passa a CoddyKit PRO. Il corso AI Prompt Engineering include 4 lezioni in totale.
Cosa imparerò in «Valutazione delle pipeline DSPy»?
Metriche, dev set e funzione evaluate() per la valutazione automatizzata Eserciti AI Prompt Engineering con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare AI Prompt Engineering?
Non è richiesta alcuna esperienza precedente. AI Prompt Engineering su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.
Quanto tempo richiede la lezione «Valutazione delle pipeline DSPy»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione AI Prompt Engineering?
Sì. Ogni lezione AI Prompt Engineering include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Introduzione al framework DSPy
- Definizione di signature e moduli
- Compilazione e ottimizzazione dei prompt
- Valutazione delle pipeline DSPy