Ragas Ragas
stable · 中文译文
中文译文 · 原文:https://docs.ragas.io/en/stable/howtos/customizations/optimizers/ · 许可证 Apache-2.0

用 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]"

基本用法

前置条件

你需要:

  1. 标注数据集:你的指标的 ground truth 分数
  2. 带 prompts 的指标:使用 PydanticPrompt 的指标(大多数 Ragas 指标)
  3. 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,
)

结果不佳

常见原因:

  1. 数据不足:需要 20+ 条高质量标注
  2. 标注质量低:确保 ground truth 分数准确
  3. LLM 不对:优化请使用 gpt-4o 或更好的模型
  4. 配置不当:先尝试默认参数

内存问题

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)

最佳实践

数据质量

  1. 多样化示例:覆盖边界情况和常见场景
  2. 准确标签:反复检查 ground truth 分数
  3. 足够数量:生产指标用 50+ 条示例

优化策略

  1. 从小开始:先用 3-5 个 candidates 测试
  2. 迭代:按需逐步增加参数
  3. 验证:始终在 holdout 集上测试
  4. 缓存:保存优化后的 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)

另见