LLM失敗モード抑制の技術

LLM/プロンプトエンジニアリング

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

LLM失敗モード抑制のためのプロンプト設計と評価技術

LLMの失敗モード抑制には、プロンプト設計と評価の体系化が不可欠であり、本記事では具体的な手法について詳述します。

ユースケース定義

企業のプレスリリースから、製品名、発表日、主要な変更点、影響範囲の4項目を正確に抽出し、構造化されたJSON形式で出力するタスクを対象とします。このタスクは情報の正確性と出力フォーマットの厳守が求められます。

制約付き仕様化

本タスクにおける入出力契約、失敗時の挙動、および禁止事項は以下の通りです。

  • 入力契約:
    • 形式: 自然言語テキスト(企業のプレスリリースまたはそれに準ずる情報公開文)。
    • 内容: 製品に関する発表情報が含まれること。
  • 出力契約:
    • 形式: 厳密なJSON形式。
    • スキーマ: 以下のキーとデータ型を持つこと。
      • product_name: 文字列 (string)
      • release_date: YYYY-MM-DD形式の文字列 (string)
      • key_changes: 箇条書き形式(各項目がハイフンで始まる)の文字列 (string)
      • impact_scope: 以下のいずれかの文字列 (“全顧客”, “一部顧客”, “社内のみ”)
    • 例: {"product_name": "新製品X", "release_date": "2023-10-26", "key_changes": "- 性能向上\n- 新機能追加", "impact_scope": "全顧客"}
  • 失敗時の挙動:
    • 必要な情報が抽出できなかった場合やJSONパースエラーが発生した場合は、以下のJSON形式でエラー情報を出力します。 {"error_code": "EXTRACTION_FAILURE", "message": "Required information not found or invalid format."}
  • 禁止事項:
    • 元のプレスリリースにない情報の幻覚(捏造)。
    • JSON形式以外の出力、または指定スキーマからの逸脱。
    • impact_scopeにおいて、定義された3つの選択肢以外の値の生成。
    • タスクとは無関係な会話や説明の付加。

プロンプト設計

要求される精度と柔軟性に応じて、以下の3種類のプロンプトを検討します。

1. ゼロショットプロンプト

あなたはプレスリリースから情報を抽出するAIアシスタントです。
以下のプレスリリースから、製品名、発表日(YYYY-MM-DD形式)、主要な変更点(箇条書き)、影響範囲("全顧客", "一部顧客", "社内のみ"のいずれか)を抽出し、JSON形式で出力してください。

プレスリリース:
{{PRESS_RELEASE_TEXT}}

2. 少数例プロンプト (Few-shot Prompt)

あなたはプレスリリースから情報を抽出し、JSON形式で出力するAIアシスタントです。
以下に例を示します。

---
入力:
株式会社ABCは、2023年10月15日に「次世代クラウドサービスα」を発表しました。このサービスは既存のクラウドサービスの性能を20%向上させ、セキュリティ機能も強化します。対象は全顧客です。
出力:
{"product_name": "次世代クラウドサービスα", "release_date": "2023-10-15", "key_changes": "- 性能20%向上\n- セキュリティ機能強化", "impact_scope": "全顧客"}
---
入力:
XYZ社は、2024年1月10日に「開発ツールPro」のアップデートをリリースしました。主な変更点は新しいUIデザインとバグ修正です。この変更は一部顧客のみに影響します。
出力:
{"product_name": "開発ツールPro", "release_date": "2024-01-10", "key_changes": "- 新しいUIデザイン\n- バグ修正", "impact_scope": "一部顧客"}
---

上記例を参考に、以下のプレスリリースから情報を抽出し、JSON形式で出力してください。

プレスリリース:
{{PRESS_RELEASE_TEXT}}

3. Chain-of-Thought (CoT) 制約型プロンプト

System:
あなたはプレスリリースから情報を抽出し、JSON形式で出力するAIアシスタントです。
以下の手順を厳守し、出力形式に厳格に従ってください。
1. まず、プレスリリースから「製品名」を正確に特定します。
2. 次に、「発表日」を特定し、必ず「YYYY-MM-DD」形式に変換します。
3. 続けて、「主要な変更点」を特定し、簡潔な箇条書き(各項目をハイフンで始める)として整理します。
4. 最後に、「影響範囲」を特定し、厳密に「全顧客」「一部顧客」「社内のみ」のいずれかを選択します。
5. これらの情報を集約し、指定されたJSONスキーマに沿って出力します。元の情報にない内容を推測したり、余計な説明を追加したりしないでください。

User:
以下のプレスリリースから情報を抽出し、JSON形式で出力してください。

プレスリリース:
{{PRESS_RELEASE_TEXT}}

評価

LLMの出力を評価するためのシナリオと自動評価の擬似コードを示します。

評価シナリオ

  • 正例: 明確な製品名、日付、変更点、影響範囲が全て明記された標準的なプレスリリース。
  • 難例:
    • 発表日がテキスト中に複数箇所にある、または曖昧な表現(例: 「来月発表」)。
    • 複数の製品情報が混在している。
    • 影響範囲が直接的に書かれておらず、文脈から推測する必要がある。
    • 変更点が箇条書きではないテキストで記述されている。
  • コーナーケース:
    • 入力がプレスリリースではない、無関係なテキスト。
    • 情報が完全に欠落しており、抽出不可能なテキスト。
    • JSON形式が不正な出力(パースエラー)。

自動評価の擬似コード

Pythonを想定した自動評価関数の擬似コードです。

import json
import re

def evaluate_llm_output(llm_output: str, expected_product_name: str = None) -> dict:
    score = 0
    feedback = []

    # 1. JSONパースチェック (10点)
    try:
        data = json.loads(llm_output)
        score += 10
        feedback.append("JSON形式は正しいです。")
    except json.JSONDecodeError:
        feedback.append("エラー: JSON形式が不正です。")
        # 失敗時の挙動チェック
        if '"error_code": "EXTRACTION_FAILURE"' in llm_output:
            score += 5 # エラー報告が正しい形式なら加点
            feedback.append("エラーコードの報告形式は正しいです。")
        return {"score": score, "feedback": feedback, "parsed_output": None}

    # 2. 必須キーの存在チェック (各5点)
    required_keys = ["product_name", "release_date", "key_changes", "impact_scope"]
    missing_keys = [key for key in required_keys if key not in data]
    if not missing_keys:
        score += 20
        feedback.append("全ての必須キーが存在します。")
    else:
        feedback.append(f"エラー: 以下の必須キーが不足しています: {', '.join(missing_keys)}")

    # 3. release_dateフォーマットチェック (10点)
    release_date_pattern = r"^\d{4}-\d{2}-\d{2}$"
    if "release_date" in data and re.match(release_date_pattern, data["release_date"]):
        score += 10
        feedback.append("release_dateのフォーマットは正しいです。")
    else:
        feedback.append("エラー: release_dateのフォーマットが不正です。")

    # 4. impact_scope値チェック (10点)
    valid_impact_scopes = ["全顧客", "一部顧客", "社内のみ"]
    if "impact_scope" in data and data["impact_scope"] in valid_impact_scopes:
        score += 10
        feedback.append("impact_scopeの値は正しいです。")
    else:
        feedback.append(f"エラー: impact_scopeの値が不正です。許容値: {valid_impact_scopes}")

    # 5. key_changes形式チェック (5点, 簡易)
    if "key_changes" in data and isinstance(data["key_changes"], str) and data["key_changes"].startswith("-"):
        score += 5
        feedback.append("key_changesは箇条書き形式のようです。")
    elif "key_changes" in data and not isinstance(data["key_changes"], str):
        feedback.append("エラー: key_changesは文字列ではありません。")
    else:
        feedback.append("注意: key_changesが期待される箇条書き形式ではない可能性があります。")

    # 6. 正確性チェック(簡易、期待値がある場合) (30点)
    if expected_product_name and "product_name" in data and data["product_name"] == expected_product_name:
        score += 30
        feedback.append("product_nameは期待値と一致します。")
    elif expected_product_name:
        feedback.append(f"エラー: product_nameが期待値と異なります。期待: '{expected_product_name}', 実際: '{data.get('product_name')}'")
    else:
        feedback.append("注意: product_nameの正確性チェックはスキップされました(期待値未指定)。")

    return {"score": score, "feedback": feedback, "parsed_output": data}

# 採点ルーブリック例:
# 1. JSONパース: 10点 (エラーコード報告で+5点)
# 2. 必須キー: 20点 (各5点)
# 3. release_dateフォーマット: 10点
# 4. impact_scope値: 10点
# 5. key_changes形式: 5点 (簡易)
# 6. product_name正確性: 30点 (期待値との比較)
# 合計: 85点 (+5点で最大90点、さらに他のキーの正確性も加味すれば100点に調整可能)

誤り分析と抑制手法

LLMで発生しうる主要な失敗モードと、その抑制手法を以下に列挙します。

  • 幻覚(Halucination):
    • 失敗モード: 元のテキストに存在しない情報を生成する。
    • 抑制手法: system指示で「提示された情報のみを使用し、推測や想像を加えないこと」を明記。CoTプロンプトで情報源を特定するステップを設ける。評価段階で抽出情報と原文との整合性検証を導入。
  • 様式崩れ(Format Deviation):
    • 失敗モード: JSON形式が不正、release_dateのフォーマットが不一致、impact_scopeが指定外の値になる。
    • 抑制手法: system指示で「出力は厳密にJSON形式であり、各キーのフォーマット(特に日付と選択肢)を厳守すること」を明記。Few-shotプロンプトで正しい形式の例を複数提示。評価段階でJSONパース、正規表現、セット包含チェックを徹底。不正な形式の場合、エラーメッセージを付与してリトライを促す戦略を適用。
  • 脱線(Task Off-topic):
    • 失敗モード: タスクと無関係な説明や追加のコメントを付加する。
    • 抑制手法: system指示で「タスクに厳密に従い、JSON形式以外の情報は一切含めないこと」を強調。出力検証ステップで余分なテキストを除去または検出。
  • 情報抽出漏れ(Information Omission):
    • 失敗モード: プレスリリース内の必須情報を抽出できない。
    • 抑制手法: CoTプロンプトで各情報の抽出ステップを明確に指示。評価段階で必須キーの存在チェックを厳格に行い、抽出漏れを特定。

改良

誤り分析の結果に基づき、以下のサイクルでプロンプトと評価基準を改良します。

  1. プロンプト調整: 特定の失敗モードが多く発生した場合、その失敗モードを抑制するための指示を追加・修正します。例えば、幻覚が多い場合は制約を強化し、様式崩れが多い場合はFew-shot例を増やしたり、フォーマット定義をより厳格に記述します。CoTステップの具体性を高めることも有効です。
  2. 評価基準の精緻化: 評価シナリオに難例やコーナーケースを追加し、自動評価のルーブリックを細分化します。特に正確性の評価において、キーごとの期待値を定義し、より詳細な採点を行うことで、改良の方向性を明確にします。
  3. データセット拡充: 多様なプレスリリース(正例、難例、コーナーケース)を含む評価データセットを継続的に拡充し、プロンプトのロバスト性を検証します。

再評価

改良されたプロンプトと評価基準を用いて、新たな評価データセットに対して再評価を実施します。これにより、改良の効果を定量的に測定し、さらなる改善点を発見します。このプロセスを繰り返すことで、LLMの出力品質を段階的に向上させます。

まとめ

LLMの失敗モード抑制には、明確な入出力契約の定義、多様なプロンプト設計、厳格な自動評価、そして継続的な誤り分析と改良のループが不可欠です。これらのプロセスを体系的に実行することで、LLMの信頼性と実用性を高めることが可能です。

graph TD
    A["要求定義"] --> B{"ユースケース定義"};
    B --> C["制約付き仕様化"];
    C --> D["プロンプト設計"];
    D --> E["プロンプト案生成"];
    E --> F["モデル推論"];
    F --> G["出力取得"];
    G --> H["評価シナリオ準備"];
    H --> I["自動評価実行"];
    I --> J{"評価結果分析"};
    J -- |成功| K["デプロイ"];
    J -- |失敗モード特定| L["誤り分析"];
    L --> M["改良計画"];
    M --> D;
    I -- |評価データ不足| H;
    F -- |リトライ| E;
ライセンス:本記事のテキスト/コードは特記なき限り CC BY 4.0 です。引用の際は出典URL(本ページ)を明記してください。
利用ポリシー もご参照ください。

コメント

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