LLM を組み込んだプロダクトを開発・運用する現場において、プロンプトチューニングはエンジニアにとって大きな工数負担となっています。指示文の調整は属人化しやすく、あるエッジケースを修正するためにプロンプトを変更すると別のケースで精度が低下する「リグレッション(いたちごっこ)」が発生し、調整作業に数日〜数週間の試行錯誤を要することも珍しくありません。

こうした課題に対し、プロンプトを手動で書き直すのではなく、プログラムとして体系的に自動最適化するアプローチが注目されています。なかでも GEPA(Genetic-Pareto Prompt Evolution) とは、LLM による推論トレースの言語的反省(Reflective Prompt Mutation)とパレート最適化を組み合わせ、プロンプトの指示文を自動的に進化・最適化するアルゴリズムです。

本記事では、DSPy と GEPA によるプロンプト自動最適化の仕組み、多観点スコアと自然言語フィードバックを組み合わせた評価関数設計の急所、そして LLM-as-a-Judge の一貫性限界やプロンプト肥大化といった実務上のトレードオフを解説します。

調査範囲と一次資料

本記事は、LINEヤフー株式会社による技術カンファレンス Tech-Verse 2026 の実践記事1、ICLR 2026 Oral に採択された GEPA の原著論文2、DSPy の原著論文3、および公式リポジトリの実装仕様4を一次資料として整理した技術調査記事です。

実務におけるプロンプト自動最適化の挙動、工数削減効果、評価関数の設計指針、および直面した課題と制約について、一次資料の客観的な記述と検証データに基づいて解説します。

DSPyのプログラミングモデルとプロンプト最適化の全体像

スタンフォード大学を中心に開発されている DSPy(Declarative Self-improving Python) は、LLM アプリケーションを「手動のプロンプトエンジニアリング」ではなく「宣言的なプログラミング」として構築するためのフレームワークです3

DSPy は、LLM アプリケーションを以下の 3 つの階層に分離して設計します。

  1. Signature(入出力仕様の宣言): 入力フィールドと出力フィールドの型や意図をクラスとして定義します。プロンプトの具体的な言い回しはここには記述せず、入出力のインターフェースのみを固定します。
  2. Module(処理ロジックの組み立て): Signature を受け取り、推論を実行する構成要素です。単純な呼び出しを行う dspy.Predict や、思考ステップを出力させる dspy.ChainOfThought、ツール呼び出しを伴う dspy.ReAct などを組み合わせてパイプラインを構築します。
  3. Optimizer(自動最適化エンジン): データセットと評価関数(Metric)に基づき、各 Module 内のプロンプト指示文(Instructions)、Few-Shot 事例、またはモデルの重みを自動探索・最適化します。

このプログラミングモデルにより、開発者は「プロンプトの文言を直接修正する作業」から「入出力インターフェースと評価基準(ポリシー)を定義し、プロンプト調整を AI に委譲するアプローチ」へとシフトできます。

GEPAの進化ループと自然言語リフレクションの仕組み

DSPy に公式オプティマイザーとして統合されている GEPA(Genetic-Pareto Prompt Evolution) は、遺伝的アルゴリズム(Genetic Algorithm)の枠組みで候補プロンプトを進化させる最適化手法です2

GEPA の最適化サイクルは、以下の 4 つのステップで構成されます。

  1. 候補プロンプトの初期生成(Proposal): ベースとなる初期プロンプトから、複数の候補プロンプト(集団: Population)を生成します。
  2. 評価とパレート選択(Pareto-based Selection): 評価データセットに対して各候補プロンプトを実行し、スコアを算出します。単一のスカラー値のみで一列に順位付けするのではなく、評価データ点ごとに最高スコアを記録した候補を集合として保持することで、単一の「勝者」に絞り込まず、局所解(局所最適)への収束を防止します。
  3. 言語的反省(Reflective Prompt Mutation): ここが GEPA の最大の核心です。Reflection LM(反省用の LLM)が各候補の実行トレース、エラー内容、および評価関数から渡された「自然言語フィードバック」を読み込み、「なぜ失敗したのか」「どの制約を満たせなかったのか」を言語的に分析し、次世代に向けた具体的な改善指示文を変異(Mutation)として生成します。
  4. 世代交代の反復: この評価・選択・反省・変異のループを数世代から数十世代繰り返すことで、プロンプトを進化させます。

従来の強化学習(RL)ベースの最適化手法(GRPO 等)では、スカラー報酬のみを手がかりに探索するため数万ステップのロールアウトが必要でした。これに対し GEPA は、エラーの言語的な意味を理解してピンポイントに修正するため、わずか数百ロールアウト(数世代)で最高性能に到達する高いサンプル効率を実証しています2

DSPyの主要Optimizer比較:BootstrapFewShot・MIPROv2・GEPA

DSPy には目的に応じて複数の Optimizer が用意されています。タスクの性質や利用可能なフィードバックの種類に応じて、適切なアルゴリズムを選択する必要があります。

Optimizer主な最適化対象探索メカニズムフィードバック形式サンプル効率・計算コスト最適なユースケース
BootstrapFewShotFew-Shot デモ事例成功した推論トレースの抽出と登録スカラー値(0 または 1)最も軽量・高速少量のデータで手軽にベースラインを構築したい場合
MIPROv2指示文 + Few-Shot デモベイズ最適化(Optuna)による同時探索スカラー値(精度・スループット)中程度(評価回数に依存)指示文とデモ事例の最適な組み合わせを探索したい場合
GEPA指示文(Instructions)パレート選択 + 言語的反省変異多観点スコア + 自然言語フィードバック高いサンプル効率(数百試行)複雑な推論・ポリシー準拠・Agentic タスクで深い改善を狙う場合

MIPROv2 が指示文と Few-Shot 事例の組み合わせをベイズ最適化で探索するのに対し、GEPA は自然言語によるリフレクションを活用して指示文そのものを論理的に洗練させます。そのため、詳細な判定理由や改善指示を言語化できるタスクにおいて、GEPA は特に強力な効果を発揮します。

PythonによるDSPy + GEPAの実践実装

ここでは、医療相談の一次受け付け(診断行為を避けつつ適切な受診案内を行うタスク)を題材に、DSPy と GEPA を用いたプロンプト自動最適化の最小実装コードを示します4

実装コード

以下のコードでは、入出力の Signature 定義、多観点スコアと自然言語フィードバックを返す評価関数(Metric)の構築、および dspy.GEPA オプティマイザーによる最適化の実行手順を記載しています。

# ファイル: optimize_gepa.py
import os
import dspy

# 1. 言語モデルの設定 (Task LM と Reflection LM)
# 推論を実行するモデルと、失敗を分析してプロンプトを進化させる Reflection モデルを指定します
task_lm = dspy.LM("openai/gpt-4o-mini", api_key=os.environ.get("OPENAI_API_KEY"))
reflection_lm = dspy.LM("openai/gpt-4o", api_key=os.environ.get("OPENAI_API_KEY"))
dspy.configure(lm=task_lm)

# 2. Signature と Module の定義
class MedicalQASignature(dspy.Signature):
    """ユーザーの医療相談に対し、診断行為を避けつつ正確で分かりやすい助言を提供します。"""
    query: str = dspy.InputField(desc="患者・ユーザーからの症状相談")
    response: str = dspy.OutputField(desc="医療ポリシーを遵守した助言文")

class MedicalQAModule(dspy.Module):
    def __init__(self):
        super().__init__()
        self.prog = dspy.ChainOfThought(MedicalQASignature)

    def forward(self, query: str):
        return self.prog(query=query)

# 3. 多観点スコアと自然言語フィードバックを返す評価関数の定義
def medical_metric(example, pred, trace=None):
    # 観点1: 診断行為の排除 (ルールベース判定)
    has_diagnosis = any(word in pred.response for word in ["〜と断定します", "〜病です", "間違いなく"])
    safety_score = 0.0 if has_diagnosis else 1.0
    
    # 観点2: 適切な文字量と具体性
    clarity_score = 1.0 if len(pred.response) >= 60 else 0.5
    
    # 総合スコア(スカラー値)の算出
    total_score = (safety_score * 0.7) + (clarity_score * 0.3)
    
    # 自然言語フィードバックの生成 (GEPA の Reflection LM に渡す文章)
    feedback_msgs = []
    if safety_score < 1.0:
        feedback_msgs.append("診断と受け取れる断定表現が含まれています。病名を断定せず、可能性の示唆と専門医の受診推奨に留めてください。")
    if clarity_score < 1.0:
        feedback_msgs.append("助言内容が短く具体性に欠けます。受診時の持ち物や緊急性の目安など、具体的な次の行動指針を追加してください。")
        
    feedback_text = " ".join(feedback_msgs) if feedback_msgs else "医療ポリシーを満たした良好な出力です。"
    
    # スカラー値とテキストフィードバックの両方を Prediction オブジェクトで返却
    return dspy.Prediction(score=total_score, feedback=feedback_text)

# 4. GEPA Optimizer によるコンパイルと最適化実行
if __name__ == "__main__":
    # 訓練用データセットの準備
    trainset = [
        dspy.Example(query="急に激しい頭痛と吐き気がします。何の病気でしょうか?").with_inputs("query"),
        dspy.Example(query="子どもが38度の熱を出していますが、お風呂に入れても大丈夫ですか?").with_inputs("query"),
    ]
    
    program = MedicalQAModule()
    
    # GEPA オプティマイザーの初期化
    gepa_optimizer = dspy.GEPA(
        metric=medical_metric,
        reflection_lm=reflection_lm,
        max_metric_calls=30
    )
    
    # 最小構成のため trainset をそのまま評価用にも流用しています。
    # 実務では GEPA のパレート選択が過学習しないよう、trainset とは別に valset を用意して渡すのが望ましい構成です。
    print("=== GEPA 最適化を開始します ===")
    optimized_program = gepa_optimizer.compile(student=program, trainset=trainset)
    print("=== 最適化完了 ===")
    
    # 最適化済みプログラムによる推論テスト
    test_query = "頭の片側がズキズキ痛みます。"
    result = optimized_program(query=test_query)
    print(f"\n質問: {test_query}")
    print(f"回答:\n{result.response}")

想定される挙動の解説

上記スクリプトは、GEPA の最適化サイクル(前節参照)をそのままコードに落とした構成になっています。実行すると、GEPA は初期プロンプトで訓練データを実行し、medical_metric から返された feedback(例: 「病名を断定せず、専門医の受診推奨に留めてください」)を reflection_lm に渡す、という流れになります。

reflection_lm は指摘された問題点を分析し、プロンプトの指示文を修正する変異候補を生成します。LINEヤフーの実務検証記事1では、この過程を経て最適化後のプロンプトに「役割定義」「出力禁止表現」「推奨する回答ステップ」といった章構造が自動的に追加されたことが報告されており、本コード例でも同様の傾向が期待できます。ただし実際の収束挙動(何世代で章構造化に至るか等)は trainset の件数や max_metric_calls の設定に依存するため、一律の結果を保証するものではありません。

評価関数設計の急所と実務運用のトレードオフ

自動プロンプト最適化を導入すると、プロンプトチューニングの作業から解放される一方で、成否のボトルネックは 評価関数(Metric)の設計品質 へと移行します。

1. 評価関数設計こそが開発者の注力すべき判断業務

GEPA に渡す評価関数では、複数の評価観点を 1 つのスカラー値にまとめる必要がありますが、単に平均値を取ると個別の重大な失敗(例: 安全性違反)がスコアの陰に埋もれてしまいます。

これを防ぐためには、dspy.Prediction(score=..., feedback=...) を通じて、問題のあった観点を具体的な自然言語テキストとして feedback に残す設計が不可欠です。どの観点を優先し、どのような振る舞いを違反とするかというポリシーの言語化こそが、開発者が本来注力すべき判断業務となります。

2. LLM-as-a-Judge の一貫性限界と対処法

評価関数内で複雑な品質評価を行う場合、LLM を評価者として用いる「LLM-as-a-Judge」が広く用いられますが、LLM-as-a-Judge には一貫性の課題が存在します5

先行研究や実務事例では、同一の入力や基準であっても、前後の文脈や表現の微妙な差異によって LLM-as-a-Judge の判定が揺れる現象が報告されています51。たとえば、「髄膜炎による頭痛は…ほぼ必ず同時に現れ」という文言について、初期プロンプトの出力では診断行為と判定された一方、最適化後の類似文脈では非診断行為と判定されたといったスコアの揺らぎが発生します。

この一貫性の限界に対処するためには、完全自動化に過度の信頼を置かず、「自動最適化 → 人手によるサンプリング確認 → 評価プロンプト自体の修正」 という多段階の検証サイクルを運用に組み込むことが重要です。

3. 実務導入におけるトレードオフ:文字数の肥大化

LINEヤフーの実務検証記事では、手動で数日〜数週間かかっていたプロンプト調整作業が約 1 時間に短縮され、指示文が体系的な章立て構造へと自動整理される大きな成果が得られました1

一方で、最適化によってプロンプトの文字数が 5,521文字から8,561文字(約55%増)へと大幅に肥大化 したことが報告されています。プロンプトが長文化すると、API のトークン消費コストが増加し、推論レイテンシが延びるトレードオフが生じます。実務プロダクトへ投入する際は、精度向上と推論コストのバランスを評価する必要があります。

また今後の展望として、直前と現在のプロンプト・推論結果の差分(Diff)を分析して無駄な長文化を抑えつつ改善箇所を特定する最新手法の研究も進められています1

よくある質問(FAQ)

Q: GEPAを利用するには大量の教師データが必要ですか?

A: 大量のデータは不要です。 GEPA は失敗理由を自然言語で振り返る Reflective Prompt Mutation を採用しているため、従来の強化学習が数万ステップのロールアウトを要するのに対し、GEPA はわずか数百ロールアウトで最高性能に到達する高いサンプル効率を実証しています2

Q: MIPROv2とGEPAはどのように使い分けるべきですか?

A: デモ事例を含めた網羅探索には MIPROv2、指示文の深い言語的洗練には GEPA が適しています。 Few-Shot のデモ選定と指示文を Optuna で同時に組み合わせ探索したい場合は MIPROv2 を、エラーログや自然言語フィードバックを与えて指示文を論理的に進化させたい場合は GEPA を選択してください。

まとめ

本記事で解説した DSPy + GEPA によるプロンプト自動最適化の要点は以下の通りです。

  • プロンプトチューニングの自動化: 手動調整に数日〜数週間かかっていたプロンプト改善を約 1 時間で完了し、属人化を解消できる。
  • 言語的反省による高いサンプル効率: GEPA はパレート選択と自然言語リフレクションにより、少ない試行回数で指示文を進化させる。
  • 評価関数設計の重要性: 多観点スコアの集約だけでなく、dspy.Prediction(feedback=...) による具体的な言語フィードバックの提供が最適化の成否を分ける。
  • 実務上の制約と検証サイクル: LLM-as-a-Judge の判定揺らぎやプロンプト文字数肥大化(推論コスト増)を前提とし、人手チェックと評価プロンプト改善のループを設計する必要がある。

自社プロダクトへの LLM 導入における評価設計や、AI Operations の仕組み化・標準化についてのご相談は、ぜひ コンタクトフォーム よりお気軽にお問い合わせください。

Footnotes

  1. プロンプトは人手チューニングからAIチューニングへ:遺伝的アルゴリズムで回す自動最適化と高速化 中野 佑哉(LINEヤフー株式会社), Tech-Verse 2026 公式技術ブログ, 2026年。工数約1時間への短縮、文字数55%肥大化(5,521→8,561文字)、評価関数の feedback 設計、LLM-as-a-Judge の判定揺らぎ実例、差分活用(古賀ら, 2026)への言及。 2 3 4 5

  2. GEPA: Reflective Prompt Evolution Can Outperform Reinforcement Learning Agrawal, L. A. et al., ICLR 2026 Oral, arXiv:2507.19457, 2026年。パレート選択・進化的アルゴリズム理論、Reflective Prompt Mutation のメカニズム、RL比較で最大20%性能向上・サンプル効率の証明。 2 3 4

  3. DSPy: Compiling Declarative Language Model Calls into Self-Improving Pipelines Khattab, O. et al., arXiv:2310.03714, 2023年。DSPy の Signatures, Modules (Predict/ChainOfThought), Teleprompters/Optimizers の3層アーキテクチャ定義。 2

  4. gepa-ai/gepa README GEPA Team, 公式 GitHub リポジトリ README, 2026年。dspy.GEPA の API 仕様、dspy.Prediction(feedback=...) の受け渡し構文。 2

  5. A Survey on LLM-as-a-Judge Gu, J. et al., arXiv:2411.15594, 2024年。LLM-as-a-Judge における一貫性の欠如、位置バイアス・冗長性バイアス・自己好感バイアスの体系的指摘。 2