Оценка конвейеров DSPy
Метрики, наборы для разработки и функция evaluate() для автоматической оценки.
«Оценка конвейеров DSPy» — бесплатный урок AI Prompt Engineering на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения AI Prompt Engineering, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс AI Prompt Engineering содержит 4 уроков всего.
Почему важна оценка в DSPy
Качество оптимизации DSPy не может быть выше качества вашей оценки. Слабая метрика создаёт скомпилированную программу, которая хорошо оценивается по этой метрике, но не работает в рабочей среде. Правильно организованный набор средств оценки позволяет сравнивать неоптимизированные и оптимизированные программы и выявлять регрессии при обновлении конвейера.
Класс dspy.Evaluate
dspy.Evaluate запускает вашу программу на наборе данных, применяет метрику и сообщает сводные оценки. Для быстрой оценки больших наборов данных поддерживается параллельное выполнение с помощью num_threads.
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%}')Написание функций метрик
Функции метрик имеют сигнатуру (example, prediction, trace=None) -> float. Они сравнивают прогноз программы с эталонным ответом в примере.
Параметр trace имеет значение, отличное от None, во время оптимизации, но не во время оценки — его можно использовать для применения разной логики при компиляции и оценке.
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)Шаблоны с порогом прохождения
Для двоичных метрик можно определить порог: прогноз считается прошедшим проверку, если он достигает минимально приемлемого уровня качества. Это полезно для фильтрации демонстрационных примеров при начальной оптимизации.
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Разделение данных: обучение, разработка, тестирование
Следуйте стандартным правилам разделения данных машинного обучения в DSPy:
- Обучающий набор: используется оптимизатором для начального создания демонстрационных примеров (20–200 примеров)
- Набор разработки: используется оптимизатором для проверки во время поиска
- Тестовый набор: полностью отложен и используется только для итоговой оценки
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)}')Сравнение оптимизированной и неоптимизированной программ
Всегда сравнивайте производительность скомпилированной программы с базовой, то есть нескомпилированной, программой на одном и том же тестовом наборе. Это подтверждает, что оптимизация действительно помогла, и позволяет количественно оценить улучшение.
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%}')Параллельное выполнение с num_threads
Оценка больших наборов данных при последовательном выполнении могла бы занять несколько часов. Параметр num_threads в dspy.Evaluate запускает прогнозирование параллельно, пропорционально сокращая фактическое время выполнения.
Согласуйте значение num_threads с ограничениями частоты запросов вашего программного интерфейса — слишком большое число потоков вызывает ошибки ограничения частоты запросов.
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Интерпретация результатов оценки
Если установлено значение display_table=True, DSPy показывает подробную таблицу с каждым примером, прогнозом и указанием, прошёл ли он проверку метрикой. Это незаменимо для диагностики закономерностей сбоев.
Ищите систематические сбои для определённого типа вопросов, пограничные случаи метрики и примеры, которые не представлены в вашем обучающем наборе.
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}')Использование метрик, оцениваемых LLM
Для открытых ответов, при оценке которых точное совпадение не работает, используйте LLM для оценки качества. DSPy упрощает эту задачу: ваша функция метрики сама может вызывать предиктор 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)Регрессионное тестирование с помощью оценки
Рассматривайте набор средств оценки DSPy как набор тестов. Каждый раз при обновлении сигнатуры, архитектуры модуля или обучающих данных повторно запускайте оценку и сравнивайте оценки, чтобы выявлять регрессии.
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Рекомендации по оценке
Основные принципы оценки конвейеров DSPy:
- Строго отделяйте тестовый набор — никогда не оптимизируйте на нём
- Используйте не менее 50–100 тестовых примеров для получения надёжных оценок
- Согласуйте метрику с вашей реальной целью в рабочей среде
- Сравнивайте несколько оптимизаторов — результаты зависят от задачи
- Отслеживайте оценки во времени, чтобы обнаруживать регрессии
- Вручную изучайте сбои, чтобы улучшать обучающие данные
Проверка знаний: параметр trace функции метрики
Что означает параметр trace со значением, отличным от None, в функции метрики DSPy?
Итоги: оценка конвейеров DSPy
dspy.Evaluate запускает вашу программу на размеченном наборе разработки, применяет функцию метрики и сообщает сводные оценки. Функции метрик следуют шаблону (example, prediction, trace=None) -> float. Используйте num_threads для параллельной оценки, а display_table=True — для диагностики сбоев. Всегда сравнивайте оптимизированные и неоптимизированные программы на отложенном тестовом наборе. Для открытых ответов метрики, оцениваемые LLM, превосходят сопоставление точных строк.
Изучай AI Prompt Engineering с ИИ-репетитором — бесплатно
Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.
- Курсы
- 53
- Уроки
- 199
Часто задаваемые вопросы
Урок «Оценка конвейеров DSPy» бесплатный?
Да — полный текст урока «Оценка конвейеров DSPy» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс AI Prompt Engineering, подпишись на CoddyKit PRO. Курс AI Prompt Engineering содержит 4 уроков всего.
Чему я научусь в уроке «Оценка конвейеров DSPy»?
Метрики, наборы для разработки и функция evaluate() для автоматической оценки. Ты практикуешь AI Prompt Engineering с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать AI Prompt Engineering?
Предыдущий опыт не требуется. AI Prompt Engineering на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Оценка конвейеров DSPy»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке AI Prompt Engineering?
Да. Каждый урок AI Prompt Engineering включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Введение в фреймворк DSPy
- Определение сигнатур и модулей
- Компиляция и оптимизация запросов
- Оценка конвейеров DSPy