AI Prompt Engineering · Lekcja

Ewaluacja potoków DSPy

Metryki, zbiory deweloperskie i funkcja evaluate() do automatycznej oceny.

Lekcja 4 z 413 kroki

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 score

Podział 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 time

Interpretowanie 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 score

Najlepsze 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.

Bezpłatny start

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

  1. Wprowadzenie do frameworka DSPy
  2. Definiowanie sygnatur i modułów
  3. Kompilowanie i optymalizowanie promptów
  4. Ewaluacja potoków DSPy
← Powrót do AI Prompt Engineering