关于 dspy-evaluation-suite
用于评估 DSPy 程序的技能,支持内置或自定义指标及并行执行。它提供平均分和逐样本结果,可用于比较程序版本、建立基准和检查上线准备情况。
主要功能
- 01使用内置及自定义指标
- 02并行评估样本
- 03返回平均分和逐样本结果
- 04支持版本比较与基准测试
适用场景
- 01衡量优化前后的表现
- 02比较不同程序版本
- 03建立评估基准
- 04检查生产就绪情况
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ omidzamani/ dspy-skills --skill dspy-evaluation-suite安装后在 Claude Code 中输入/dspy-evaluation-suite确认已加载。
附带文件example.py
详细介绍
DSPy 评估套件
目标
使用内置和自定义指标,通过并行执行系统地评估 DSPy 程序。
适用场景
- 衡量优化前后程序的性能
- 比较不同的程序变体
- 建立基线
- 验证是否已做好生产部署准备
相关技能
- 与任意优化器配合使用:dspy-bootstrap-fewshot、dspy-miprov2-optimizer、dspy-gepa-reflective
- 评估 RAG 工作流:dspy-rag-pipeline
输入
| 输入 | 类型 | 描述 |
|---|---|---|
program | dspy.Module | 要评估的程序 |
devset | list[dspy.Example] | 评估示例 |
metric | callable | 评分函数 |
num_threads | int | 并行线程数 |
输出
| 输出 | 类型 | 描述 |
|---|---|---|
score | float | 平均指标分数 |
results | list | 每个示例的结果 |
工作流
阶段 1:设置评估器
from dspy.evaluate import Evaluate
evaluator = Evaluate(
devset=devset,
metric=my_metric,
num_threads=8,
display_progress=True
)
阶段 2:运行评估
result = evaluator(my_program)
print(f"Score: {result.score:.2f}%")
# Access individual results: (example, prediction, score) tuples
for example, pred, score in result.results[:3]:
print(f"Example: {example.question[:50]}... Score: {score}")
内置指标
answer_exact_match
import dspy
# Normalized, case-insensitive comparison
metric = dspy.evaluate.answer_exact_match
SemanticF1
基于 LLM 的语义评估:
from dspy.evaluate import SemanticF1
semantic = SemanticF1()
score = semantic(example, prediction)
自定义指标
基本指标
def exact_match(example, pred, trace=None):
"""Returns bool, int, or float."""
return example.answer.lower().strip() == pred.answer.lower().strip()
多因素指标
def quality_metric(example, pred, trace=None):
"""Score based on multiple factors."""
score = 0.0
# Correctness (50%)
if example.answer.lower() in pred.answer.lower():
score += 0.5
# Conciseness (25%)
if len(pred.answer.split()) <= 20:
score += 0.25
# Has reasoning (25%)
if hasattr(pred, 'reasoning') and pred.reasoning:
score += 0.25
return score
与 GEPA 兼容的指标
def feedback_metric(example, pred, trace=None, pred_name=None, pred_trace=None):
"""Return a GEPA-compatible score and textual feedback."""
correct = example.answer.lower() in pred.answer.lower()
if correct:
return dspy.Prediction(score=1.0, feedback="Correct answer provided.")
else:
return dspy.Prediction(
score=0.0,
feedback=f"Expected '{example.answer}', got '{pred.answer}'"
)
生产示例
import dspy
from dspy.evaluate import Evaluate, SemanticF1
import json
import logging
from typing import Optional
from dataclasses import dataclass
logger = logging.getLogger(__name__)
@dataclass
class EvaluationResult:
score: float
num_examples: int
correct: int
incorrect: int
errors: int
def comprehensive_metric(example, pred, trace=None) -> float:
"""Multi-dimensional evaluation metric."""
scores = []
# 1. Correctness
if hasattr(example, 'answer') and hasattr(pred, 'answer'):
correct = example.answer.lower().strip() in pred.answer.lower().strip()
scores.append(1.0 if correct else 0.0)
# 2. Completeness (answer not empty or error)
if hasattr(pred, 'answer'):
complete = len(pred.answer.strip()) > 0 and "error" not in pred.answer.lower()
scores.append(1.0 if complete else 0.0)
# 3. Reasoning quality (if available)
if hasattr(pred, 'reasoning'):
has_reasoning = len(str(pred.reasoning)) > 20
scores.append(1.0 if has_reasoning else 0.5)
return sum(scores) / len(scores) if scores else 0.0
class EvaluationSuite:
def __init__(self, devset, num_threads=8):
self.devset = devset
self.num_threads = num_threads
def evaluate(self, program, metric=None) -> EvaluationResult:
"""Run full evaluation with detailed results."""
metric = metric or comprehensive_metric
evaluator = Evaluate(
devset=self.devset,
metric=metric,
num_threads=self.num_threads,
display_progress=True
)
eval_result = evaluator(program)
# Extract individual scores from results
scores = [score for example, pred, score in eval_result.results]
correct = sum(1 for s in scores if s >= 0.5)
errors = sum(1 for s in scores if s == 0)
return EvaluationResult(
score=eval_result.score,
num_examples=len(self.devset),
correct=correct,
incorrect=len(self.devset) - correct - errors,
errors=errors
)
def compare(self, programs: dict, metric=None) -> dict:
"""Compare multiple programs."""
results = {}
for name, program in programs.items():
logger.info(f"Evaluating: {name}")
results[name] = self.evaluate(program, metric)
# Rank by score
ranked = sorted(results.items(), key=lambda x: x[1].score, reverse=True)
print("\n=== Comparison Results ===")
for rank, (name, result) in enumerate(ranked, 1):
print(f"{rank}. {name}: {result.score:.2%}")
return results
def export_report(self, program, output_path: str, metric=None):
"""Export detailed evaluation report."""
result = self.evaluate(program, metric)
report = {
"summary": {
"score": result.score,
"total": result.num_examples,
"correct": result.correct,
"accuracy": result.correct / result.num_examples
},
"config": {
"num_threads": self.num_threads,
"num_examples": len(self.devset)
}
}
with open(output_path, 'w') as f:
json.dump(report, f, indent=2)
logger.info(f"Report saved to {output_path}")
return report
# Usage
suite = EvaluationSuite(devset, num_threads=8)
# Single evaluation
result = suite.evaluate(my_program)
print(f"Score: {result.score:.2%}")
# Compare variants
results = suite.compare({
"baseline": baseline_program,
"optimized": optimized_program,
"finetuned": finetuned_program
})
最佳实践
- 留出测试数据 — 切勿在评估集上进行优化
- 使用多个指标 — 结合正确性、质量和效率
- 统计显著性 — 使用足够多的示例(100+)
- 持续跟踪 — 对评估结果进行版本控制
局限性
- 指标因任务而异;没有通用的衡量标准
- SemanticF1 需要调用 LLM(有成本)
- 并行评估可能触发速率限制
- 可能无法涵盖边缘情况
官方文档
- DSPy 文档:https://dspy.ai/
- DSPy GitHub:https://github.com/stanfordnlp/dspy
- 评估 API:https://dspy.ai/api/evaluation/
- 指标指南:https://dspy.ai/learn/evaluation/metrics/
评论
支持 Markdown