Avaliando pipelines do DSPy
Métricas, conjuntos de desenvolvimento e a função evaluate() para avaliação automatizada.
Avaliando pipelines do DSPy é uma aula grátis de AI Prompt Engineering no CoddyKit. Esta é a aula 4 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de AI Prompt Engineering, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de AI Prompt Engineering inclui 4 aulas no total.
Por que a avaliação é importante no DSPy
A otimização do DSPy só é tão boa quanto a sua avaliação. Uma métrica fraca produz um programa compilado que obtém uma boa pontuação nessa métrica, mas falha em produção. Uma estrutura de avaliação adequada permite comparar programas não otimizados e otimizados e detectar regressões quando você atualiza seu fluxo de processamento.
A classe dspy.Evaluate
dspy.Evaluate executa seu programa em um conjunto de dados, aplica uma métrica e informa as pontuações agregadas. Ela oferece paralelismo por meio de num_threads para realizar avaliações rapidamente em conjuntos de dados grandes.
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%}')Escrevendo funções de métrica
As funções de métrica têm a assinatura (example, prediction, trace=None) -> float. Elas comparam a previsão do programa com a resposta correta de referência presente no exemplo.
O parâmetro trace é diferente de None durante a otimização, mas não durante a avaliação — você pode usá-lo para aplicar lógicas diferentes na compilação e na avaliação.
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)Padrões de limiar de aprovação e reprovação
Para métricas binárias, você pode definir um limiar: uma previsão é considerada aprovada se atingir um nível mínimo de qualidade. Isso é útil para filtrar demonstrações com poucos exemplos durante a otimização por inicialização.
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 scoreDivisão de dados: treino, desenvolvimento e teste
Siga as práticas padrão de divisão de dados de aprendizado de máquina no DSPy:
- Conjunto de treino: usado pelo otimizador para inicializar demonstrações (20–200 exemplos)
- Conjunto de desenvolvimento: usado pelo otimizador para validação durante a busca
- Conjunto de teste: mantido totalmente separado — usado apenas para a avaliação final
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)}')Comparando programas otimizados e não otimizados
Sempre compare o desempenho do seu programa compilado com o do programa de referência, não compilado, no mesmo conjunto de teste. Isso comprova que a otimização realmente ajudou e quantifica a melhoria.
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%}')Paralelismo com num_threads
Conjuntos de avaliação grandes levariam horas para ser processados sequencialmente. num_threads em dspy.Evaluate executa as previsões em paralelo, reduzindo proporcionalmente o tempo real decorrido.
Ajuste num_threads aos limites de taxa da sua API — o excesso de threads provoca erros de limite de taxa.
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 timeInterpretando a saída da avaliação
Quando display_table=True, o DSPy exibe uma tabela detalhada com cada exemplo, a previsão e a indicação de aprovação ou reprovação na métrica. Isso é extremamente útil para diagnosticar padrões de falha.
Procure por: falhas sistemáticas em um tipo de pergunta, casos extremos da métrica ou exemplos que não são contemplados pelo seu conjunto de treinamento.
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}')Usando métricas avaliadas por LLM
Para saídas abertas nas quais a correspondência exata falha, use um LLM para avaliar a qualidade. O DSPy facilita esse processo — sua função de métrica pode chamar um preditor do 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)Testes de regressão com avaliação
Trate seu conjunto de avaliação do DSPy como um conjunto de testes. Sempre que atualizar sua assinatura, a arquitetura do módulo ou os dados de treinamento, execute novamente a avaliação e compare as pontuações para detectar regressões.
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 scoreBoas práticas de avaliação
Princípios fundamentais de avaliação para fluxos de processamento do DSPy:
- Mantenha seu conjunto de teste rigorosamente separado — nunca o use para otimização
- Use pelo menos 50–100 exemplos de teste para obter pontuações confiáveis
- Alinhe sua métrica ao seu objetivo real em produção
- Compare vários otimizadores — os resultados variam conforme a tarefa
- Acompanhe as pontuações ao longo do tempo para detectar regressões
- Inspecione as falhas manualmente para melhorar seus dados de treinamento
Verificação de conhecimento: parâmetro trace da função de métrica
Em uma função de métrica do DSPy, o que indica um parâmetro trace diferente de None?
Recapitulação: avaliando fluxos de processamento do DSPy
dspy.Evaluate executa seu programa em um conjunto de desenvolvimento rotulado, aplica uma função de métrica e informa as pontuações agregadas. As funções de métrica seguem o padrão (example, prediction, trace=None) -> float. Use num_threads para avaliação paralela e display_table=True para diagnosticar falhas. Sempre compare programas otimizados e não otimizados em um conjunto de teste separado. Para saídas abertas, as métricas avaliadas por LLM superam a correspondência exata de cadeias de texto.
Aprenda AI Prompt Engineering com um tutor de IA — grátis
Escreva e execute código real no seu navegador, obtenha ajuda instantânea de um tutor de IA 24/7 e continue de onde parou na web ou no app.
- Cursos
- 53
- Aulas
- 199
Perguntas Frequentes
A aula “Avaliando pipelines do DSPy” é grátis?
Sim — o texto completo de “Avaliando pipelines do DSPy” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de AI Prompt Engineering, atualize para CoddyKit PRO. O curso de AI Prompt Engineering inclui 4 aulas no total.
O que vou aprender em “Avaliando pipelines do DSPy”?
Métricas, conjuntos de desenvolvimento e a função evaluate() para avaliação automatizada. Você pratica AI Prompt Engineering com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar AI Prompt Engineering?
Nenhuma experiência prévia é necessária. AI Prompt Engineering no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 4 de 4.
Quanto tempo leva a aula “Avaliando pipelines do DSPy”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de AI Prompt Engineering?
Sim. Cada aula de AI Prompt Engineering inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Introdução ao framework DSPy
- Definindo assinaturas e módulos
- Compilando e otimizando prompts
- Avaliando pipelines do DSPy