LLMの自己修正プロンプト設計と評価

Tech

本記事はGeminiの出力をプロンプト工学で整理した業務ドラフト(未検証)です。

LLMの自己修正プロンプト設計と評価

大規模言語モデル(LLM)は多様なタスクで高い性能を発揮しますが、複雑な推論や厳密な出力フォーマットが求められる場面では、不正確な情報(幻覚)や一貫性の欠如、様式崩れなどの課題を抱えることがあります。LLMの自己修正プロンプトは、モデルが自身の出力を評価し、修正する能力を引き出すことで、これらの課題を克服し、信頼性と堅牢性を向上させる手法です。本記事では、LLMの自己修正プロンプトの設計、評価、改良プロセスについて詳細に解説します。

ユースケース定義

自己修正プロンプトは、特に以下のユースケースで効果を発揮します。

  • 複雑な多段階推論タスク: 長文要約、複雑なコード生成、多ステップの意思決定支援など、複数の推論ステップを要するタスク。

  • 事実誤認、一貫性欠如のリスクが高いタスク: 法律文書の分析、医療情報の生成、データに基づくレポート作成など、正確性と一貫性が極めて重要なタスク。

  • 特定の出力フォーマット厳守が必要なタスク: JSON/XML形式のデータ抽出、特定のスキーマに基づくAPIリクエスト生成、Markdown形式のドキュメント生成など。

制約付き仕様化(入出力契約)

自己修正プロンプトを効果的に適用するためには、LLMとの入出力契約を明確に定義することが不可欠です。

  • 入力:

    • 形式: JSON または text 形式のユーザープロンプトと関連データ。

    • 内容: 実行したいタスク、目的、出力形式の要件、参照データを含める。

  • 出力:

    • 形式: JSON または text 形式の最終回答。特定のスキーマやフォーマットを厳守。

    • 内容: ユーザーの要求に対する正確かつ一貫性のある回答。修正プロセスを経た最終結果。

  • 失敗時の挙動:

    • 最大 N 回(例: 3回)の修正試行後も要件を満たさない場合、エラーメッセージと、可能であれば部分的な結果を返します。

    • エラーメッセージには、どの制約を満たせなかったかを示す情報を含めるべきです。

  • 禁止事項:

    • 幻覚(Halucination): 事実に基づかない情報の生成。

    • 不適切な内容: 倫理的に問題のある内容や、ハルシネーション。

    • 様式崩れ: 指定された出力フォーマット(例: JSONスキーマ)からの逸脱。

    • 脱線: 指示されたタスクスコープからの逸脱。

プロンプト設計

自己修正を促すためのプロンプトは、その設計によってモデルのパフォーマンスが大きく変動します。ここでは、代表的な3種類のプロンプト設計を紹介します。

1. ゼロショット自己修正

モデルに初回出力後、追加の指示で自身の出力を批評させ、修正を促す手法です。

あなたは専門家です。以下のタスクを実行してください。

---
タスク: ユーザーが提供した情報を元に、特定のイベントに関するニュース記事の見出しと要約を生成してください。見出しは20文字以内、要約は100文字以内とし、簡潔かつ魅力的に記述してください。

入力情報:
イベント名: AI技術の進化と未来
日付: 2024年7月25日
場所: 東京ビッグサイト
主要トピック: 最新LLMモデルの発表、倫理的AIの議論、ロボティクスの未来
参加者: 5000人

---
あなたの最初の出力:

[LLMの初回出力]

---
上記の出力について、以下の基準で自己評価し、改善点があれば修正してください。

1. 見出しは20文字以内か?

2. 要約は100文字以内か?

3. 内容は入力情報に基づいているか?(幻覚は無いか?)

4. 簡潔かつ魅力的か?

自己評価と修正案:

2. 少数例(Few-shot)自己修正

正しい自己修正の例を複数提示し、モデルに自己批評と修正のパターンを学ばせる手法です。

あなたは専門家です。以下のタスクを実行してください。

---
タスク: ユーザーが提供した顧客レビューに基づき、製品のポジティブな点とネガティブな点をJSON形式で抽出してください。

JSONスキーマ:
{
  "product_name": "string",
  "positive_aspects": ["string"],
  "negative_aspects": ["string"]
}

---
例1:
入力レビュー: 「このスピーカーは音質が素晴らしいが、バッテリーの持ちが悪い。」
初回出力:
```json
{
  "product_name": "スピーカー",
  "positive_aspects": ["音質が良い"],
  "negative_aspects": ["バッテリー"]
}

自己評価と修正案: バッテリーの「持ちが悪い」という具体的な表現を「バッテリーの持ちが悪い」に修正し、より詳細にしました。 修正後の出力:

{
  "product_name": "スピーカー",
  "positive_aspects": ["音質が素晴らしい"],
  "negative_aspects": ["バッテリーの持ちが悪い"]
}

例2: 入力レビュー: 「このコーヒーメーカーは使いやすいけど、少し高いね。」 初回出力:

{
  "product_name": "コーヒーメーカー",
  "positive_aspects": ["使いやすい"],
  "negative_aspects": ["価格が高い"]
}

自己評価と修正案: 特になし。スキーマと内容に問題ありません。 修正後の出力:

{
  "product_name": "コーヒーメーカー",
  "positive_aspects": ["使いやすい"],
  "negative_aspects": ["価格が高い"]
}

あなたのタスク: 入力レビュー: 「このマウスは軽くて操作しやすいけど、クリック音が大きすぎる。」 初回出力:

[LLMの初回出力]


上記の出力について、上記の例を参考に自己評価し、改善点があれば修正してください。 自己評価と修正案:

### 3. Chain-of-Thought(CoT)制約型自己修正

推論プロセスと自己評価ステップを明確に構造化し、詳細なフィードバックを与えることで、モデルが論理的に修正を行うように促します。これは、モデルが自身の思考過程を外部化し、ステップバイステップで検証する「Self-Refine」のようなフレームワークに類似しています \[2]。

```text
あなたはステップバイステップで問題を解決し、自身の解答を厳密に検証する論理的な推論エンジンです。以下のタスクを実行してください。

---
タスク: 与えられた数値を昇順にソートし、結果をカンマ区切りの文字列で出力してください。

---

1. 最初の回答を生成してください。

2. 生成された回答の各要素を分析し、タスクの制約(昇順、カンマ区切り)を満たしているか詳細に検証してください。具体的には、以下の点を確認してください。
    a. 数値が本当に昇順になっているか?
    b. 出力形式がカンマ区切りの文字列になっているか?
    c. 元の数値がすべて含まれているか?(欠落や追加がないか?)

3. 検証結果に基づき、問題があればその理由を説明し、修正案を提示してください。

4. 修正案に基づいて最終的な回答を生成してください。

入力数値: [5, 2, 8, 1, 9, 3]

---
ステップ1: 最初の回答を生成します。
[LLMの初回出力]

ステップ2: 生成された回答を検証します。
    a. 昇順チェック: ... (検証結果)
    b. 形式チェック: ... (検証結果)
    c. 欠落/追加チェック: ... (検証結果)

ステップ3: 検証結果に基づく修正案を提示します。
[LLMの自己評価と修正案]

ステップ4: 最終的な回答を生成します。

評価

自己修正プロンプトの効果を測定するためには、体系的な評価プロセスが必要です。

評価シナリオ

  • 正例: 明確な指示に従い、期待される出力が得られるケース。

    • 例: 「日本の首都はどこですか? JSON形式で出力してください。」
  • 難例: 曖昧な指示、複数の解釈が可能なケース、大量のデータ処理、複雑な推論を要するケース。

    • 例: 「このビジネスメールのトーンをもっとプロフェッショナルに修正してください。ただし、顧客への共感は維持してください。」
  • コーナーケース: 境界値、無効な入力、予期せぬエッジケース。

    • 例: 「空のリストをソートしてください。」「不正なJSONスキーマでデータを抽出してください。」

自動評価の擬似コード

自動評価は、一貫性と効率性を提供し、プロンプトの変更による影響を定量的に把握する上で不可欠です。

# python

def evaluate_self_correction_output(llm_output: str, expected_output: str, task_type: str) -> dict:
    """
    LLMの自己修正後の出力を自動評価する擬似コード。

    Args:
        llm_output (str): LLMから得られた最終出力。
        expected_output (str): 期待される正解出力。
        task_type (str): タスクの種類 ('json_extraction', 'text_summary', 'sorting'など)。

    Returns:
        dict: 評価結果(スコア、詳細)。

    前提条件:

        - `expected_output` は評価基準を満たす形式で事前に準備されている。

        - 評価関数はタスクタイプに応じて適切なバリデーションロジックを持つ。
    入出力:

        - 入力: LLMの出力文字列、期待される出力文字列、タスクタイプ文字列

        - 出力: 評価スコアと詳細を含む辞書
    計算量:

        - JSONパース: O(L) (Lは出力文字列長)

        - 正規表現: O(L)

        - 文字列比較: O(L)
    メモリ条件:

        - 主に文字列と辞書オブジェクトのため、出力長に比例。
    """
    score = 0
    details = []

    # 1. 採点ルーブリックに基づく評価

    if task_type == 'json_extraction':
        try:
            import json
            parsed_output = json.loads(llm_output)
            parsed_expected = json.loads(expected_output)

            # スキーマの検証

            if isinstance(parsed_output, dict) and all(k in parsed_output for k in parsed_expected):
                score += 30 # スキーマ準拠
                details.append("JSONスキーマに準拠しています。")
            else:
                details.append("JSONスキーマに準拠していません。")

            # 内容の正確性(簡易チェック)

            if parsed_output == parsed_expected: # 厳密な比較
                score += 50
                details.append("内容が期待値と完全に一致します。")
            else:

                # 詳細な比較ロジックを追加可能

                details.append("内容が期待値と一部異なります。")

        except json.JSONDecodeError:
            details.append("JSON形式が無効です。")

    elif task_type == 'text_summary':

        # 2. 正規表現とキーワードに基づく評価

        if len(llm_output) <= 100: # 文字数制限チェック
            score += 20
            details.append("文字数制限を満たしています。")
        else:
            details.append(f"文字数制限を超過しています ({len(llm_output)}文字)。")

        if any(keyword in llm_output for keyword in ["AI", "LLM", "未来"]): # キーワード含有チェック
            score += 30
            details.append("主要キーワードが含まれています。")
        else:
            details.append("主要キーワードが不足しています。")

        # 3. 関数評価(例: 外部APIで事実確認を行うなど)


        # 例えば、外部のNLPサービスを使って要約の質を評価する


        # from external_nlp_service import evaluate_summary_quality


        # quality_score = evaluate_summary_quality(llm_output, expected_output)


        # score += quality_score * 0.5 # 50点満点

        # 簡易的な内容一致度

        if expected_output in llm_output: # 非常に簡易的な確認
             score += 50
             details.append("期待される要点が要約に含まれています。")
        else:
            details.append("期待される要点が不足しています。")

    elif task_type == 'sorting':
        try:
            llm_list = list(map(int, llm_output.split(',')))
            expected_list = list(map(int, expected_output.split(',')))

            if llm_list == expected_list:
                score += 100
                details.append("ソート結果が期待値と完全に一致します。")
            else:
                details.append("ソート結果が期待値と異なります。")
                if not all(llm_list[i] <= llm_list[i+1] for i in range(len(llm_list)-1)):
                    details.append("結果が昇順ではありません。")

        except ValueError:
            details.append("出力が数値のカンマ区切り形式ではありません。")

    # その他の共通評価項目

    if "幻覚" not in llm_output and "不適切" not in llm_output: # 簡易的なネガティブチェック
        score += 10 # 禁止事項に抵触しないことのボーナス
        details.append("禁止事項に抵触していません。")

    return {"total_score": min(score, 100), "details": details}

# 使用例


# output_json = '{"product_name": "スピーカー", "positive_aspects": ["音質が素晴らしい"], "negative_aspects": ["バッテリーの持ちが悪い"]}'


# expected_json = '{"product_name": "スピーカー", "positive_aspects": ["音質が素晴らしい"], "negative_aspects": ["バッテリーの持ちが悪い"]}'


# print(evaluate_self_correction_output(output_json, expected_json, 'json_extraction'))

# output_summary = 'AI技術の進化と未来に関する発表。最新LLMモデル、倫理的AI、ロボティクスが焦点。'


# expected_summary = 'AIの進化と未来に焦点を当てたイベント。最新LLM、倫理的AI、ロボティクスの未来が議論された。'


# print(evaluate_self_correction_output(output_summary, expected_summary, 'text_summary'))

# output_sorted = '1,2,3,5,8,9'


# expected_sorted = '1,2,3,5,8,9'


# print(evaluate_self_correction_output(output_sorted, expected_sorted, 'sorting'))

プロンプト→モデル→評価→改良のループ

自己修正プロンプトの設計と評価は、継続的なフィードバックループを通じて行われます。

graph TD
    subgraph プロンプト開発ループ
        Prompt["プロンプト生成"] --> LLM["LLM実行"]
        LLM --> Output["初回出力"]
        Output --> Feedback["自己修正フィードバック生成"]
        Feedback --> RefinedPrompt["修正プロンプト"]
        RefinedPrompt --> RefinedLLM["LLM再実行"]
        RefinedLLM --> FinalOutput["最終出力"]
    end

    FinalOutput --> Evaluator["評価モジュール"]
    Evaluator --> Analysis["誤り分析"]
    Analysis --> Improvement["プロンプト改良"]
    Improvement --> Prompt

誤り分析と抑制手法

失敗モードを理解し、適切な抑制手法を講じることで、自己修正プロンプトのロバスト性を高めます。

  • 幻覚(Halucination):

    • 分析: モデルが事実に基づかない情報を生成する。

    • 抑制手法:

      • System指示: 事実に基づいた情報のみを生成するよう厳しく指示する。

      • 検証ステップ: 外部ツール(検索API、データベース)で生成内容を検証するステップをプロンプトに組み込む。

      • リトライ戦略: 検証で事実誤認が検出された場合、情報源を再確認し、再生成を促す。

  • 様式崩れ(Format Deviation):

    • 分析: 指定されたJSONやMarkdownなどの出力フォーマットから逸脱する。

    • 抑制手法:

      • System指示: フォーマットの厳守を強調し、具体的なスキーマや例を提示する。

      • 検証ステップ: 出力後に正規表現やJSONスキーマバリデーターで自動検証を行う。

      • リトライ戦略: バリデーションエラーが発生した場合、エラー内容を具体的に伝え、フォーマットを修正して再生成させる。

  • 脱線(Topic Drift):

    • 分析: 指示されたタスクスコープ外の情報を生成する、あるいは本来の目的から逸脱する。

    • 抑制手法:

      • System指示: タスクの目的と範囲を明確に定義し、不要な情報の生成を禁止する。

      • 検証ステップ: 生成内容がタスクの主要キーワードや目的に合致するかをチェックする。

      • プロンプト改良: 具体的な禁止事項(例: 「個人的な意見を含めない」)を明記する。

  • 禁止事項違反(Policy Violation):

    • 分析: 不適切、有害、倫理的に問題のあるコンテンツを生成する。

    • 抑制手法:

      • System指示: 安全性ポリシーや倫理ガイドラインを冒頭で明示し、違反しないよう指示する。

      • 検証ステップ: 外部の安全性フィルタリングAPIやキーワードフィルタリングを適用する。

      • リトライ戦略: 違反が検出された場合、内容を修正または生成を中止し、安全な代替案を提示する。

改良

誤り分析の結果に基づき、プロンプト、モデル、または評価プロセスを改良します。

  • プロンプト改良:

    • 指示の具体性向上: 曖昧な表現を避け、より明確で具体的な指示に修正します。

    • 制約の強化: 出力フォーマットや内容に関する制約をさらに厳密にします。

    • Few-shot例の追加・修正: より多様なケースや、自己修正の具体的な手順を示す高品質な例を追加します。

  • モデル選択:

    • 特定のタスクにより適したLLMモデル(例: コード生成に特化したモデル)の検討。
  • チューニング:

    • ドメイン固有のデータや自己修正の成功例を用いたファインチューニング。

再評価

改良されたプロンプトやモデルを用いて、再度評価シナリオを実行します。初期の評価結果と比較し、改善度合いを定量的に測定します。特に、難例やコーナーケースにおけるエラー率の低下、特定のメトリクス(例: JSONのパース成功率、要約のROUGEスコア)の向上を指標とします。この反復プロセスにより、自己修正プロンプトの性能は継続的に向上します。

まとめ

LLMの自己修正プロンプトは、モデルの信頼性と出力品質を向上させるための強力な手法です。ゼロショット、Few-shot、Chain-of-Thought制約型といった多様なプロンプト設計を通じて、モデルが自身の出力を批評し、修正する能力を最大限に引き出すことができます。入出力契約の明確化、体系的な評価、そして継続的な誤り分析と改良のループを回すことで、より堅牢で実用的なLLMアプリケーションを構築することが可能となります。2024年1月1日に発表された「Self-Correction in Large Language Models: A Survey」[1] でも様々な自己修正技術が包括的に紹介されており、この分野の重要性が増していることが示唆されています。

ライセンス:本記事のテキスト/コードは特記なき限り CC BY 4.0 です。引用の際は出典URL(本ページ)を明記してください。
利用ポリシー もご参照ください。

コメント

タイトルとURLをコピーしました