dspy-gepa-optimizer について
DSPy 3.2.x で GEPA を使ってプログラムを最適化するためのガイドです。テキストによる詳細な評価指標と、分離した学習・検証データを用意できる開発者向けに、予算設定やチェックポイント、結果の確認方法を説明します。
主な機能
- 01指示と少数例の反省的最適化
- 02パレート候補選択
- 03自動および明示的な評価予算
- 04チェックポイントと実行再開
- 05候補間の最良出力を追跡
活用シーン
- 01具体的な批評による複数予測器プログラムの改善
- 02軽量予算での最適化テスト
- 03中断した最適化の再開
- 04候補と最良の検証出力の確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ intertwine/ dspy-agent-skills --skill dspy-gepa-optimizerインストール後、Claude Code で/dspy-gepa-optimizerを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
example_bettertogether.pyexample_gepa.pyreference.md詳細
DSPy GEPA オプティマイザー(3.2.x)
GEPA(Genetic-Pareto)は、リフレクティブオプティマイザーです。メトリクスのテキスト形式のフィードバックを読み取り、改善案を提案する LM を使って、プログラムの指示と few-shot 例を変更します。検証タスク全体でパレートフロンティアを維持し、2026 年の複雑な DSPy ワークロードに対するデフォルトの推奨事項です。
一部の AI 生成要約に登場する「Genetic-Evolutionary Prompt Adaptation」という展開形は、LLM が幻覚によって後付けした頭字語です。論文では GEPA を Genetic-Pareto と定義しています。「Pareto」は重要な要素です(GEPA は候補を 1 つに絞り込まず、候補のフロンティアを維持します)。
前提条件 — 先に済ませないと GEPA のロールアウトが無駄になります
- エンドツーエンドで実行できる
dspy.Module(dspy-fundamentalsを参照)。 dspy.Prediction(score=float, feedback=str)を返す、豊富なフィードバックを提供するメトリクス(dspy-evaluation-harnessを参照)。有益なフィードバックはリフレクションに役立ちます。優位性を前提とせず、タスク上でオプティマイザーの効果を評価してください。同じフィールドを持つ dict でも、DSPy 3.2.1 のdspy.Evaluateでは引き続きクラッシュします。dspy.Predictionを使ってください。trainsetと別個のvalset。GEPA ではトレーニング例を最大限に活用し、検証用データは下流の分布を表現できる最小限の規模にしてください。同じ例を両方に再利用しないでください。reflection_lm—temperature=1.0に設定した、強力な LM(多くの場合、タスク用 LM と同等以上の性能を持つもの)です。現在の DSPy ドキュメントでは、出力予算の大きい GPT-5 クラスのリフレクションモデルを使用しています。
標準的な呼び出し
import dspy
dspy.configure(lm=dspy.LM("openai/gpt-5-mini"))
reflection_lm = dspy.LM("openai/gpt-5", temperature=1.0, max_tokens=32000)
optimizer = dspy.GEPA(
metric=rich_metric,
auto="medium", # "light" / "medium" / "heavy"
reflection_lm=reflection_lm,
reflection_minibatch_size=3,
candidate_selection_strategy="pareto", # or "current_best"
skip_perfect_score=True,
use_merge=True,
num_threads=8,
track_stats=True,
track_best_outputs=True, # enables inference-time best-of selection
log_dir="./gepa_logs", # resume/checkpoint
seed=0,
)
optimized = optimizer.compile(
student=program,
trainset=trainset,
valset=valset,
)
# Pareto inspection
pareto = optimized.detailed_results.val_aggregate_scores
print("Pareto frontier:", sorted(pareto, reverse=True)[:5])
optimized.save("optimized_program.json", save_program=False)
インポートパス
どちらでも動作します。新しいコードではトップレベルのものを使ってください。
import dspy
dspy.GEPA(...) # preferred
# equivalently:
from dspy.teleprompt import GEPA
メトリクスの契約(詳細)
import dspy
def rich_metric(gold, pred, trace=None, pred_name=None, pred_trace=None):
score = ... # 0.0..1.0
feedback = ... # detailed natural-language critique
return dspy.Prediction(score=score, feedback=feedback)
dict ではなく dspy.Prediction を返してください。 上流の GEPA の説明の一部では、score と feedback は dict に似た形式として説明されていますが、DSPy 3.2.1 の dspy.Evaluate はリテラルな dict を返すメトリクスで依然としてクラッシュします(TypeError: unsupported operand type(s) for +: 'int' and 'dict')。GEPA は候補のスコアリングに内部で dspy.Evaluate を使うため、明示的な Evaluate(...) の呼び出しだけでなく、GEPA 内部でも dict を返すと失敗する可能性があります。
pred_name/pred_traceは、モジュール内の特定の予測器をリフレクションするときに設定されます。可能な場合は、予測器ごとのフィードバックを記述してください(クレジット割り当て)。フィードバックを特定の箇所に紐づけられない場合は、曖昧なスコアだけの批評ではなく、プログラム全体に対するフィードバックを返してください。- 最も重要なのはフィードバックの質です。なぜ失敗したのか、何が望ましい結果かを具体的に示すことで、リフレクション LM が改善に取り組めます。
予算の調整項目
auto=... または明示的な予算のどちらか一方を使ってください。両方は使わないでください。
| モード | おおよそのロールアウト数 | 用途 |
|---|---|---|
auto="light" | 約 20~40 回の完全評価 | GEPA がメトリクス上で機能することを確認 |
auto="medium" | 約 80~150 回の完全評価 | 通常の最適化 |
auto="heavy" | 約 300~600 回の完全評価 | リリース前の最終実行 |
max_full_evals=N | 明示的 | 決定的な予算設定 |
max_metric_calls=N | 明示的 | メトリクス呼び出し回数の厳密な上限(コストをより予測しやすい) |
「完全評価」1 回あたりのメトリクス呼び出し数は、およそ len(valset) です。コストを考慮して予算を設定してください。
コンストラクターのパラメーター(全項目、DSPy 3.2.x)
dspy.GEPA(
metric, # required
auto=None, # Literal["light","medium","heavy"] | None
max_full_evals=None,
max_metric_calls=None,
reflection_minibatch_size=3,
candidate_selection_strategy="pareto", # or "current_best"
reflection_lm=None, # required in practice
skip_perfect_score=True,
add_format_failure_as_feedback=False,
instruction_proposer=None, # custom ProposalFn
component_selector="round_robin", # or a callable
use_merge=True,
max_merge_invocations=5,
num_threads=None,
failure_score=0.0,
perfect_score=1.0,
log_dir=None,
track_stats=False,
use_wandb=False,
wandb_api_key=None, # overrides WANDB_API_KEY env var
wandb_init_kwargs=None, # dict forwarded to wandb.init(...)
track_best_outputs=False,
warn_on_score_mismatch=True,
use_mlflow=False,
seed=0,
gepa_kwargs=None, # e.g. {"use_cloudpickle": True} for dynamic signatures
)
.compile(student, *, trainset, valset=None, teacher=None) — 現時点で teacher は使われません。
データ分割のガイダンス
DSPy の一般的なプロンプトオプティマイザーのドキュメントでは、トレーニングセットが小さいとプロンプトオプティマイザーが小規模な trainset に過剰適合する可能性があるため、トレーニング 20%/検証 80% のように検証データを多くする分割を推奨する場合がよくあります。GEPA は異なります。トレーニングセットを最大限に活用し、下流の動作を表現するのに十分な分だけ検証例として確保してください。パレートフロンティアを構築するには実際の valset が必要ですが、GEPA はトレーニング例のトレースとテキスト形式のフィードバックから学習するため、trainset が少なすぎると効果が損なわれます。
DSPy 3.2.x の BetterTogether
複数段階のオプティマイザーループを使いたい場合、DSPy 3.2.0 の BetterTogether は、従来の固定された prompt_optimizer/weight_optimizer のペアではなく、任意の名前付きオプティマイザーを受け付けるようになりました。
optimizer = dspy.BetterTogether(
metric=rich_metric,
bootstrap=dspy.BootstrapFewShotWithRandomSearch(metric=rich_metric),
gepa=dspy.GEPA(metric=rich_metric, auto="light", reflection_lm=reflection_lm),
)
optimized = optimizer.compile(
student=program,
trainset=trainset,
valset=valset,
strategy="bootstrap -> gepa",
)
bootstrap=... や gepa=... のような名前付きステージを使う場合は、strategy= を明示的に渡してください。DSPy 3.2.0 のデフォルト戦略は引き続き "p -> w -> p" であり、オプティマイザーのキーが文字どおり p と w の場合にしか機能しません。
最初のパスでは、通常の GEPA をデフォルトとして使ってください。オプティマイザーを連鎖させる具体的な理由があり、valset に最適な中間プログラムを選ばせたい場合に限り、BetterTogether を使いましょう。
GEPA が MIPROv2 より適している場合
- メトリックが具体的で学習に役立つ批評を生成できる場合(これが GEPA の強みです)。
- 対象プログラムに、個別に改善する必要がある複数の予測器がある場合(GEPA は予測器ごとのフィードバックを提供しますが、MIPRO は提供しません)。
- ロールアウトの予算が少ない場合(GEPA は豊富なフィードバックによって、より早く収束します)。
MIPROv2 が GEPA より適している場合
- メトリックがスカラー値のみの場合(内省のためのシグナルがありません)。この場合は
dspy.MIPROv2を使ってください。 - 指示を変更せず、純粋な少数例ブートストラップを行いたい場合。
- 学習セットが非常に大きい場合(500 以上)。デモを対象としたベイズ探索の効果が期待できます。
SIMBA を試す価値がある場合
dspy.SIMBA は、より軽量な内省型オプティマイザーです。GEPA より低コストの内省パスを使いたい場合、プログラムが単純な場合、または本格的な GEPA の実行を始める前に手早く探索したい場合に試してください。予測器ごとのフィードバックとパレート候補の選定が重要な、複数予測器を含むプログラムでは、GEPA をデフォルトとして使いましょう。
再開とチェックポイント
log_dir は、ラウンドごとの候補プログラムとスコアを書き込みます。中断した実行を再開するには、同じディレクトリを log_dir に指定してください。GEPA は最後のチェックポイントから再開します。<log_dir>/candidates/ を確認すると、提案されたすべてのプログラムを確認できます。
track_best_outputs による推論時のベスト・オブ選択
track_best_outputs=True を指定すると、GEPA はタスクごとに、すべての候補の中で最良だった予測を記録します。ホールドアウトデータで推論する際、頑健性を高めるため、上位のパレートプログラムをアンサンブルしたり、その中から選択したりできます。optimized.detailed_results.best_outputs_valset からアクセスできます。
アンチパターン
- フィードバックのない浮動小数点値のみのメトリック(「スコアは 0.7」)を使うと、GEPA はランダム探索に陥ります。
- 学習と検証に同じセットを使うと、パレート選択が過学習します。
reflection_lmに小規模なモデルを使うと、批評ができません。この役割に使える範囲で最も強力な LM を使ってください。- テストしていないメトリックで
auto="heavy"を実行すると、メトリックのバグに気づくために費用を浪費します。まずauto="light"を実行してください。 log_dirを無視すると、接続切断によって 4 時間分の実行結果を失うことになり、とても大きな損失です。
注意点:reflection_lm は compile 時ではなく、インスタンス生成時に必須です
dspy.GEPA(...) は、インスタンス生成時に reflection_lm is not None(またはカスタムの instruction_proposer)であることを確認します。.compile() まで指定を先送りすることはできません。次のエラーが表示された場合:
AssertionError: GEPA requires a reflection language model...
コンストラクターに reflection_lm=dspy.LM("openai/gpt-5", temperature=1.0, max_tokens=32000) を追加するか、プロバイダーで利用可能な、指示追従性能が最も高いモデルに置き換えてください。dspy.LM(...) は実際に呼び出すまでは軽量なスタブなので、インスタンスを生成してもネットワークには接続しません。
次のステップ
- メトリックを作成する →
dspy-evaluation-harness。 - エンドツーエンドのパイプライン →
dspy-advanced-workflow。 - パラメーターリファレンス → reference.md。
- 実行可能な例 → example_gepa.py。
- BetterTogether の連鎖の例 → example_bettertogether.py。