LLMの失敗モード抑制戦略

EXCEL

LLMは多様なタスクに適用可能だが、出力の安定性には課題がある。本記事では、失敗モードを抑制するプロンプト設計と評価戦略を詳述する。

LLMの失敗モード抑制戦略

ユースケース定義

ユースケース: 特定の技術文書(例: APIリファレンス)に基づき、JSON形式で主要な機能とパラメータを抽出する。これにより、ドキュメントの構造化と機械処理が可能になる。

入出力契約

  • 入力:
    • 形式: プレーンテキストの技術文書。
    • 内容: 単一の機能に関する説明と関連パラメータ。
    • 制約: 英語または日本語。
  • 出力:
    • 形式: 厳密なJSON形式。ルート要素は {}
    • 必須キー: function_name (string), description (string), parameters (array of objects)。
    • parameters配列の各オブジェクトは name (string), type (string), required (boolean), description (string) を含む。
    • 失敗時の挙動: 無効な入力や情報不足の場合、JSONスキーマに準拠した { "error": "詳細なエラーメッセージ" } を出力。
    • 禁止事項: JSON形式以外の出力、追加の解説文、不正確な情報、幻覚。

制約付き仕様化

  • 抽出対象は主要機能1つとそれに直接関連するパラメータのみ。
  • descriptionは50文字以上200文字以下。
  • parametersは最低1つ、最大5つ。
  • typestring, integer, boolean, array, objectのいずれか。
  • requiredtrueまたはfalse
  • 出力JSONはUTF-8エンコーディング。

失敗モードと抑制手法

LLMの出力品質を確保するため、以下の失敗モードと抑制手法を適用する。

  • 幻覚 (Hallucination): 存在しない情報や誤った情報を生成する。
    • 抑制手法: System指示で「提供された情報のみを使用し、推測や創造は禁止」を明記。Chain-of-Thought (CoT) で情報源の提示を求める。出力検証ステップで外部知識との照合を実施。
  • 様式崩れ (Format Breakage): JSON形式など、指定された出力フォーマットが破綻する。
    • 抑制手法: System指示で「厳密なJSON形式を遵守」を強調。JSONスキーマの提供(例示や制約で)と、出力後のJSONパーサーによる検証。リトライ戦略(パース失敗時に再生成を指示)を実装。
  • 脱線 (Off-topic/Drifting): タスクのスコープから逸脱した情報を生成する。
    • 抑制手法: System指示で「特定のタスクに集中し、不要な情報は含めない」と強調。具体的な例示でタスクの範囲を明確化。
  • 禁止事項違反 (Constraint Violation): 禁止された内容(例: 長すぎる説明、不適切なtype)を出力する。
    • 抑制手法: System指示と少数例で明確な制約条件を提示。出力検証ステップで正規表現や関数による値のチェック。

プロンプト設計

プロンプト1: ゼロショット (Zero-Shot)

あなたは技術文書からAPI機能の情報を抽出し、厳密なJSON形式で出力するエキスパートです。
以下の制約を厳守してください。
1. 提供された文書情報のみを使用し、推測や創造は禁止です。
2. 出力は厳密なJSON形式で、ルート要素は `{}` です。
3. 必須キーは `function_name`, `description`, `parameters` です。
4. `parameters`配列の各オブジェクトは `name`, `type`, `required`, `description` を含みます。
5. `description`は50文字以上200文字以下です。
6. `parameters`は最低1つ、最大5つです。
7. `type`は`string`, `integer`, `boolean`, `array`, `object`のいずれかです。
8. 無効な入力や情報不足の場合、`{ "error": "詳細なエラーメッセージ" }` を出力します。

---
技術文書:
{document}
---
出力:

プロンプト2: 少数例 (Few-Shot)

あなたは技術文書からAPI機能の情報を抽出し、厳密なJSON形式で出力するエキスパートです。
以下の制約を厳守してください。
1. 提供された文書情報のみを使用し、推測や創造は禁止です。
2. 出力は厳密なJSON形式で、ルート要素は `{}` です。
3. 必須キーは `function_name`, `description`, `parameters` です。
4. `parameters`配列の各オブジェクトは `name`, `type`, `required`, `description` を含みます。
5. `description`は50文字以上200文字以下です。
6. `parameters`は最低1つ、最大5つです。
7. `type`は`string`, `integer`, `boolean`, `array`, `object`のいずれかです。
8. 無効な入力や情報不足の場合、`{ "error": "詳細なエラーメッセージ" }` を出力します。

---
技術文書:
Function: createUser
Description: This function creates a new user account in the system. It requires user details such as name, email, and password. The API returns a user ID upon successful creation.
Parameters:
  - name: userName (string, required) - The full name of the user.
  - name: userEmail (string, required) - The user's email address, must be unique.
  - name: password (string, required) - The user's password, must be at least 8 characters.
---
出力:
```json
{
  "function_name": "createUser",
  "description": "システムに新しいユーザーアカウントを作成する機能。ユーザー名、メール、パスワードなどの詳細情報が必要。成功時にはユーザーIDを返す。",
  "parameters": [
    {
      "name": "userName",
      "type": "string",
      "required": true,
      "description": "ユーザーのフルネーム。"
    },
    {
      "name": "userEmail",
      "type": "string",
      "required": true,
      "description": "ユーザーのメールアドレス、一意である必要があります。"
    },
    {
      "name": "password",
      "type": "string",
      "required": true,
      "description": "ユーザーのパスワード、最低8文字である必要があります。"
    }
  ]
}

技術文書:

{document}

出力:

### プロンプト3: Chain-of-Thought制約型 (CoT with Constraints)
```text
あなたは技術文書からAPI機能の情報を抽出し、厳密なJSON形式で出力するエキスパートです。
以下の制約を厳守してください。
1. 提供された文書情報のみを使用し、推測や創造は禁止です。
2. 出力は厳密なJSON形式で、ルート要素は `{}` です。
3. 必須キーは `function_name`, `description`, `parameters` です。
4. `parameters`配列の各オブジェクトは `name`, `type`, `required`, `description` を含みます。
5. `description`は50文字以上200文字以下です。
6. `parameters`は最低1つ、最大5つです。
7. `type`は`string`, `integer`, `boolean`, `array`, `object`のいずれかです。
8. 無効な入力や情報不足の場合、`{ "error": "詳細なエラーメッセージ" }` を出力します。

思考プロセス:
1. 提供された技術文書から、主要な関数名を特定する。
2. その関数の全体的な説明を抽出し、指定された文字数制約(50-200文字)に合うように要約する。この際、文書内のキーワードを保持する。
3. 関数に関連するパラメータを特定する。各パラメータについて、名前、データ型、必須かどうか、説明を正確に抽出する。
4. `type`が指定されたリスト(`string`, `integer`, `boolean`, `array`, `object`)に合致するか確認する。合致しない場合は最も近いものに変換またはエラーとする。
5. `parameters`の数が1から5の範囲内にあるか確認する。範囲外の場合はエラーとする。
6. 全ての情報をJSON形式に整形する。
7. 最後に、生成されたJSONがすべての制約(形式、キー、文字数、パラメータ数、型)を満たしているか自己検証する。もし満たさない箇所があれば、再度修正を試みる。

---
技術文書:
{document}
---
出力:

評価

評価シナリオ

  1. 正例: 全ての情報が明確に記載された標準的なAPIドキュメント。

    • 入力例:
      Function: getItemDetails
      Description: Retrieves detailed information for a specific item using its unique ID.
      Parameters:
      
      name: item_id (integer, required) - The unique identifier of the item.
      name: include_history (boolean, optional) - Whether to include item history. Default is false.
      
  2. 難例: 情報が曖昧、または制約違反の可能性のあるドキュメント。

    • 入力例:

      Function: updateUserProfile
      Description: This updates a user's profile.
      Parameters:
      
      name: user_id (int, required)
      name: new_data (object) - Data to update.
      name: profile_image (url) - URL to a new profile image.
      name: status (string, optional) - User's current status.
      name: last_login (timestamp) - Last login time.
      name: preferences (array) - User preferences.
      

    (この入力は、descriptionが50文字未満、parametersが5つを超える、typeurltimestampといった未定義のものが含まれる点で難易度が高い。)

  3. コーナーケース: 情報が極端に少ない、または存在しないドキュメント。

    • 入力例:

      Function: emptyFunction
      Description: No details provided.
      

      (この入力では、descriptionが50文字未満、parametersが0個となるため、error JSONの出力が期待される。)

自動評価の擬似コード

import json
import re

def evaluate_llm_output(output_text, scenario_type):
    score = 0
    feedback = []
    is_pass = False

    # 1. JSON形式の妥当性チェック
    try:
        output_json = json.loads(output_text)
        score += 10 # JSONとして有効
    except json.JSONDecodeError:
        feedback.append("Format Breakage: 出力が有効なJSONではありません。")
        return {"score": 0, "feedback": feedback, "pass": False}

    # エラー応答の場合の処理
    if "error" in output_json:
        if scenario_type == "corner_case":
            score += 20 # エラーケースで適切にエラー応答
            feedback.append("エラーケースで適切にエラーJSONを生成しました。")
            is_pass = True
        else:
            score -= 10 # 正常系や難例で不適切なエラー応答は減点
            feedback.append("不適切なエラー応答です。")
        return {"score": max(0, score), "feedback": feedback, "pass": is_pass}

    # 必須キーのチェック
    required_keys = ["function_name", "description", "parameters"]
    if all(key in output_json for key in required_keys):
        score += 10
    else:
        feedback.append(f"Missing Keys: 必須キー {required_keys} のいずれかが不足しています。")

    # descriptionの文字数チェック
    description = output_json.get("description", "")
    if 50 <= len(description) <= 200:
        score += 5
    else:
        feedback.append(f"Constraint Violation: descriptionの文字数 ({len(description)}文字) が範囲外 (50-200文字) です。")

    # parameters配列のチェック
    parameters = output_json.get("parameters")
    if isinstance(parameters, list):
        if 1 <= len(parameters) <= 5:
            score += 5
        else:
            feedback.append(f"Constraint Violation: parametersの数 ({len(parameters)}) が範囲外 (1-5個) です。")

        valid_types = {"string", "integer", "boolean", "array", "object"}
        param_required_keys = ["name", "type", "required", "description"]
        for i, param in enumerate(parameters):
            if not isinstance(param, dict) or not all(k in param for k in param_required_keys):
                feedback.append(f"Format Breakage: parameters[{i}]の形式または必須キーが不正です。")
                continue
            if param.get("type") not in valid_types:
                feedback.append(f"Constraint Violation: parameters[{i}]のtype '{param.get('type')}' が無効です。")
            if not isinstance(param.get("required"), bool):
                feedback.append(f"Constraint Violation: parameters[{i}]のrequiredがboolean型ではありません。")
    else:
        feedback.append("Format Breakage: 'parameters'がリストではありません。")

    # 幻覚/脱線 (今回はキーワード一致度や意味的類似度などのより高度な評価が必要。ここでは簡易的に正例での期待スコアで判定)
    # 正例シナリオでの評価基準を厳しくする。
    if scenario_type == "positive_case" and score >= 25 and not feedback:
        is_pass = True
    elif scenario_type == "difficult_case":
        # 難例では部分的な成功も評価するが、エラーでなければ及第点
        is_pass = score >= 15

    return {"score": score, "feedback": feedback, "pass": is_pass}

# 評価実行例は省略。

誤り分析と改良

  • 分析: ゼロショットプロンプトでは、descriptionの文字数制約やtypeの厳密な指定が守られにくい傾向が見られた。特に、難例やコーナーケースではJSON形式が崩壊することもあった。幻覚としては、入力にない説明を補完しようとする挙動が散見された。
  • 改良点:
    1. CoTプロンプトの導入: LLMに思考プロセスを明示的に指示することで、制約遵守の意識を高める。特に自己検証ステップが重要。
    2. 少数例の質向上: 正確かつ多様な制約を網羅した少数例を提供することで、モデルが期待される出力パターンを学習しやすくする。
    3. System指示の強化: 禁止事項や失敗時の挙動をより厳しく明記し、リトライ戦略を組み込む(外部システム連携で)。
    4. 評価の強化: 自動評価だけでなく、人間による出力内容のファクトチェックを組み合わせ、評価ルーブリックを洗練する。

再評価

改良されたプロンプトと評価システムを再適用し、同じ評価シナリオでパフォーマンスを測定する。descriptionの文字数、parametersの型と数、JSONの完全性を中心に評価スコアの改善を確認する。様式崩れや幻覚が抑制され、エラーケースで適切にエラーJSONが出力されるかを確認する。この反復プロセスにより、LLMの出力品質は継続的に向上する。

プロンプト設計・評価ループの可視化

graph TD
    A["プロンプト設計"] --> B(LLM);
    B --> C{"LLM出力"};
    C --> D["自動評価"];
    D -- 失敗 --> E["誤り分析"];
    D -- 成功 --> F["合格/デプロイ"];
    E --> A;
    E -- 抑制手法適用 --> A;

まとめ

LLMの失敗モード抑制には、入出力契約の明確化、制約付きプロンプト設計、厳格な自動評価、そして反復的な誤り分析と改良が不可欠である。特に、Chain-of-ThoughtやFew-Shotの活用、System指示による制約強化、および出力後の検証ステップが、幻覚、様式崩れ、脱線、禁止事項違反といった課題への効果的な対策となる。

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

コメント

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