Ewaluacja potoków DSPy
Metryki, zbiory deweloperskie i funkcja evaluate() do automatycznej oceny.
Ewaluacja potoków DSPy to bezpłatna lekcja AI Prompt Engineering na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej AI Prompt Engineering, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs AI Prompt Engineering zawiera 4 lekcji w sumie.
Dlaczego ewaluacja ma znaczenie w DSPy
Skuteczność optymalizacji DSPy zależy od jakości ewaluacji. Słaba metryka prowadzi do utworzenia skompilowanego programu, który uzyskuje dobre wyniki według tej metryki, ale zawodzi w środowisku produkcyjnym. Właściwy mechanizm ewaluacji pozwala porównywać programy zoptymalizowane i niezoptymalizowane oraz wykrywać regresje po aktualizacji potoku.
Klasa dspy.Evaluate
dspy.Evaluate uruchamia program na zbiorze danych, stosuje metrykę i raportuje zagregowane wyniki. Obsługuje przetwarzanie równoległe za pomocą num_threads, co przyspiesza ewaluację dużych zbiorów danych.
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%}')Pisanie funkcji metryk
Funkcje metryk mają sygnaturę (example, prediction, trace=None) -> float. Porównują predykcję programu z wartością referencyjną zawartą w przykładzie.
Parametr trace ma wartość inną niż None podczas optymalizacji, ale nie podczas ewaluacji — można go użyć do zastosowania innej logiki podczas kompilacji i ewaluacji.
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)Schematy progów zaliczenia i niezaliczenia
W przypadku metryk binarnych można zdefiniować próg: predykcja jest „zaliczona”, jeśli spełnia minimalny wymagany poziom jakości. Jest to przydatne podczas filtrowania demonstracji few-shot w ramach optymalizacji 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 scorePodział danych: train, dev i test
W DSPy należy stosować standardowe praktyki dzielenia danych ML:
- Trainset: używany przez optymalizator do tworzenia demonstracji bootstrap (20–200 przykładów)
- Devset: używany przez optymalizator do walidacji podczas wyszukiwania
- Testset: całkowicie odłożony — używany wyłącznie do końcowej ewaluacji
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)}')Porównywanie programów zoptymalizowanych i niezoptymalizowanych
Zawsze porównuj swój skompilowany program z programem bazowym (nieskompilowanym) na tym samym zbiorze testowym. Dzięki temu można potwierdzić, że optymalizacja rzeczywiście pomogła, oraz określić skalę poprawy.
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%}')Przetwarzanie równoległe za pomocą num_threads
Ewaluacja dużych zbiorów danych wykonywana sekwencyjnie mogłaby trwać wiele godzin. Parametr num_threads w dspy.Evaluate uruchamia predykcje równolegle, proporcjonalnie skracając czas rzeczywisty.
Dopasuj wartość num_threads do limitów szybkości interfejsu API — zbyt wiele wątków powoduje błędy przekroczenia limitu.
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 timeInterpretowanie wyników ewaluacji
Gdy ustawisz display_table=True, DSPy wyświetli szczegółową tabelę zawierającą każdy przykład, predykcję oraz informację, czy predykcja spełniła metrykę. Jest to nieoceniona pomoc w diagnozowaniu wzorców błędów.
Zwróć uwagę na: systematyczne błędy dla określonego typu pytań, przypadki brzegowe metryki oraz przykłady, których nie obejmuje zbiór treningowy.
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}')Używanie metryk ocenianych przez LLM
W przypadku otwartych odpowiedzi, dla których dokładne dopasowanie się nie sprawdza, użyj LLM do oceny jakości. DSPy znacznie to ułatwia — sama funkcja metryki może wywoływać predyktor 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)Testy regresji za pomocą ewaluacji
Traktuj zestaw ewaluacyjny DSPy jak zestaw testów. Za każdym razem, gdy aktualizujesz sygnaturę, architekturę modułów lub dane treningowe, uruchom ponownie ewaluację i porównaj wyniki, aby wykrywać regresje.
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 scoreNajlepsze praktyki ewaluacji
Najważniejsze zasady ewaluacji potoków DSPy:
- Trzymaj testset całkowicie odłożony — nigdy nie optymalizuj na jego podstawie
- Używaj co najmniej 50–100 przykładów testowych, aby uzyskać wiarygodne wyniki
- Dopasuj metrykę do rzeczywistego celu produkcyjnego
- Porównuj wiele optymalizatorów — wyniki zależą od zadania
- Śledź wyniki w czasie, aby wykrywać regresje
- Ręcznie analizuj błędy, aby ulepszać dane treningowe
Sprawdź wiedzę: parametr trace w funkcji metryki
Co w funkcji metryki DSPy oznacza parametr trace o wartości innej niż None?
Podsumowanie: ewaluacja potoków DSPy
dspy.Evaluate uruchamia program na oznaczonym devset, stosuje funkcję metryki i raportuje zagregowane wyniki. Funkcje metryk mają postać (example, prediction, trace=None) -> float. Używaj num_threads do ewaluacji równoległej, a display_table=True do diagnozowania błędów. Zawsze porównuj programy zoptymalizowane i niezoptymalizowane na odłożonym testsecie. W przypadku otwartych odpowiedzi metryki oceniane przez LLM dają lepsze wyniki niż dokładne dopasowanie ciągów znaków.
Ucz się AI Prompt Engineering dzięki korepetycjom AI — za darmo
Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.
- Kursy
- 53
- Lekcje
- 199
Często zadawane pytania
Czy lekcja „Ewaluacja potoków DSPy” jest bezpłatna?
Tak — pełny tekst „Ewaluacja potoków DSPy” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu AI Prompt Engineering, przejdź na CoddyKit PRO. Kurs AI Prompt Engineering zawiera 4 lekcji w sumie.
Co nauczysz się w „Ewaluacja potoków DSPy”?
Metryki, zbiory deweloperskie i funkcja evaluate() do automatycznej oceny. Ćwiczysz AI Prompt Engineering z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć AI Prompt Engineering?
Nie wymagamy żadnego doświadczenia. AI Prompt Engineering w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.
Ile czasu zajmuje lekcja „Ewaluacja potoków DSPy”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji AI Prompt Engineering?
Tak. Każda lekcja AI Prompt Engineering zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Wprowadzenie do frameworka DSPy
- Definiowanie sygnatur i modułów
- Kompilowanie i optymalizowanie promptów
- Ewaluacja potoków DSPy