用 DSPy Optimizer 做高级 Prompt 优化
DSPyOptimizer 使用 DSPy 的 MIPROv2 算法,为 Ragas 指标提供最先进的 prompt 优化。它结合 instruction 和 demonstration 优化,找出比简单进化方法更好的 prompts。
概述
DSPyOptimizer 使用 MIPROv2(Multi-prompt Instruction Proposal with Ranked Outcomes)通过以下方式优化指标 prompts:
- Instruction 优化:生成并测试多种 prompt 变体
- Demonstration 优化:自动选择有效的 few-shot 示例
- 组合搜索:同时探索 instruction 和 demonstration 空间
这通常比更简单的 GeneticOptimizer 产生更好的结果,尤其是在你有高质量标注数据时。
安装
DSPy 是可选依赖。用以下方式安装:
# Using uv (recommended)
uv add "ragas[dspy]"
# Using pip
pip install "ragas[dspy]"
基本用法
前置条件
你需要:
- 标注数据集:你的指标的 ground truth 分数
- 带 prompts 的指标:使用 PydanticPrompt 的指标(大多数 Ragas 指标)
- LLM:用于优化的 LLM(推荐 gpt-4o-mini 以控制成本)
快速开始
from openai import OpenAI
from ragas.llms import llm_factory
from ragas.metrics.collections import Faithfulness
from ragas.optimizers import DSPyOptimizer
from ragas.config import InstructionConfig
# Setup LLM for optimization
client = OpenAI()
llm = llm_factory("gpt-4o-mini", client=client)
# Initialize metric
metric = Faithfulness(llm=llm)
# Create annotated dataset (see below for format)
dataset = create_annotated_dataset()
# Configure DSPy optimizer
config = InstructionConfig(
llm=llm,
optimizer=DSPyOptimizer(
num_candidates=10, # Try 10 prompt variations
max_bootstrapped_demos=5, # Generate up to 5 examples
max_labeled_demos=5, # Use up to 5 human annotations
)
)
# Optimize the metric's prompts
metric.optimize_prompts(dataset, config)
# Save optimized prompts for reuse
metric.save_prompts("optimized_faithfulness.json")
标注数据集格式
DSPy optimizer 需要 ground truth 标注:
from ragas.dataset_schema import (
PromptAnnotation,
SampleAnnotation,
SingleMetricAnnotation
)
# Create prompt annotations
prompt_annotation = PromptAnnotation(
prompt_input={"user_input": "...", "response": "..."},
prompt_output={"score": 0.9}, # Actual metric output
edited_output=None, # Or corrected output if needed
)
# Create sample with annotations
sample = SampleAnnotation(
metric_input={"user_input": "...", "response": "..."},
metric_output=0.9, # Ground truth score
prompts={"faithfulness_prompt": prompt_annotation},
is_accepted=True, # Whether to use in optimization
)
# Create dataset
dataset = SingleMetricAnnotation(
name="faithfulness",
samples=[sample, ...] # Need 20-50+ samples for best results
)
高级配置
优化参数
控制 MIPROv2 行为:
optimizer = DSPyOptimizer(
num_candidates=20, # More candidates = better prompts, higher cost
max_bootstrapped_demos=10, # Auto-generated few-shot examples
max_labeled_demos=10, # Human-annotated examples to use
init_temperature=1.0, # Exploration temperature (0.0-2.0)
)
参数指南:
| 参数 | 默认值 | 描述 | 成本影响 |
|---|---|---|---|
num_candidates |
10 | 要尝试的 prompt 变体 | 高 - 线性扩展 |
max_bootstrapped_demos |
5 | 自动生成的示例 | 中 - 增加 LLM 调用 |
max_labeled_demos |
5 | 要使用的人工标注 | 低 - 使用已有数据 |
init_temperature |
1.0 | 探索随机性 | 无 - 仅算法层面 |
成本优化
MIPROv2 优化可能很贵。通过以下方式降低成本:
# Budget-conscious configuration
budget_optimizer = DSPyOptimizer(
num_candidates=5, # Fewer candidates
max_bootstrapped_demos=2, # Fewer generated examples
max_labeled_demos=3, # More reliance on annotations
init_temperature=0.5, # Less exploration
)
# Use cheaper LLM for optimization
cheap_llm = llm_factory("gpt-4o-mini", client=client)
config = InstructionConfig(llm=cheap_llm, optimizer=budget_optimizer)
成本估算:
- 每个 candidate 约 10-50 次 LLM 调用
- 每个 bootstrapped demo 约 5-10 次调用
- 总计:
num_candidates * 30 + max_bootstrapped_demos * 7次调用(近似)
与 GeneticOptimizer 比较
何时使用 DSPyOptimizer
✅ 在以下情况使用 DSPyOptimizer:
- 你有 50+ 条高质量标注示例
- 你需要尽可能好的指标准确率
- 你能承担 100-500 次 LLM 调用用于优化
- 你在优化关键的生产指标
何时使用 GeneticOptimizer
✅ 在以下情况使用 GeneticOptimizer:
- 你的标注数据有限(<20 条示例)
- 你需要更快、更便宜的优化
- 你在做初期原型
- 仅优化 instruction 就足够
并排比较
from ragas.optimizers import GeneticOptimizer, DSPyOptimizer
# Genetic optimizer - simpler, faster, cheaper
genetic_config = InstructionConfig(
llm=llm,
optimizer=GeneticOptimizer(
max_steps=50, # Evolution steps
population_size=10, # Population per generation
)
)
# DSPy optimizer - advanced, better results, more expensive
dspy_config = InstructionConfig(
llm=llm,
optimizer=DSPyOptimizer(
num_candidates=10,
max_bootstrapped_demos=5,
max_labeled_demos=5,
)
)
# Compare results
metric_genetic = Faithfulness(llm=llm)
metric_genetic.optimize_prompts(dataset, genetic_config)
metric_dspy = Faithfulness(llm=llm)
metric_dspy.optimize_prompts(dataset, dspy_config)
# Evaluate on holdout set
test_scores_genetic = metric_genetic.batch_score(test_set)
test_scores_dspy = metric_dspy.batch_score(test_set)
典型结果:
| 指标 | GeneticOptimizer | DSPyOptimizer | 提升 |
|---|---|---|---|
| Faithfulness | 0.82 | 0.89 | +8.5% |
| Answer Relevancy | 0.75 | 0.84 | +12% |
| Context Precision | 0.78 | 0.86 | +10% |
处理多个指标
用同样的方法优化多个指标:
from ragas.metrics.collections import (
Faithfulness,
AnswerRelevancy,
ContextPrecision
)
metrics = {
"faithfulness": Faithfulness(llm=llm),
"answer_relevancy": AnswerRelevancy(llm=llm),
"context_precision": ContextPrecision(llm=llm),
}
# Optimize each metric
for name, metric in metrics.items():
print(f"Optimizing {name}...")
# Load metric-specific dataset
dataset = load_annotated_dataset(name)
# Optimize
metric.optimize_prompts(dataset, dspy_config)
# Save
metric.save_prompts(f"optimized_{name}.json")
故障排查
Import Error
如果你遇到 ImportError: DSPy optimizer requires dspy-ai:
# Install the DSPy extra
uv add "ragas[dspy]"
# or
pip install "ragas[dspy]"
优化耗时过长
减少 LLM 调用次数:
fast_optimizer = DSPyOptimizer(
num_candidates=3, # Minimum viable
max_bootstrapped_demos=1,
max_labeled_demos=3,
)
结果不佳
常见原因:
- 数据不足:需要 20+ 条高质量标注
- 标注质量低:确保 ground truth 分数准确
- LLM 不对:优化请使用 gpt-4o 或更好的模型
- 配置不当:先尝试默认参数
内存问题
MIPROv2 对大型数据集可能占用大量内存:
# Process in smaller batches
from ragas.dataset_schema import SingleMetricAnnotation
def optimize_in_batches(dataset, batch_size=20):
# Split dataset
batches = [
dataset.select(range(i, min(i + batch_size, len(dataset.samples))))
for i in range(0, len(dataset.samples), batch_size)
]
# Optimize on first batch for speed
best_batch = batches[0]
metric.optimize_prompts(best_batch, dspy_config)
最佳实践
数据质量
- 多样化示例:覆盖边界情况和常见场景
- 准确标签:反复检查 ground truth 分数
- 足够数量:生产指标用 50+ 条示例
优化策略
- 从小开始:先用 3-5 个 candidates 测试
- 迭代:按需逐步增加参数
- 验证:始终在 holdout 集上测试
- 缓存:保存优化后的 prompts,避免重复运行
生产部署
# 1. Optimize offline
metric = Faithfulness(llm=optimization_llm)
metric.optimize_prompts(training_dataset, dspy_config)
metric.save_prompts("production_faithfulness.json")
# 2. Load in production
production_metric = Faithfulness(llm=production_llm)
production_metric.load_prompts("production_faithfulness.json")
# 3. Use for evaluation
results = production_metric.batch_score(production_samples)
另见
- Optimizers API Reference - 完整 API 文档
- Metric Customization - 创建自定义指标
- DSPy Documentation - 了解更多关于 DSPy