CoTプロンプティングの失敗モード抑制

Tech

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

CoTプロンプティングの失敗モード抑制

Chain-of-Thought (CoT) プロンプティングは、大規模言語モデル (LLM) に推論ステップを段階的に生成させることで、複雑な問題解決能力を向上させます。しかし、その強力さゆえに、幻覚、様式崩れ、脱線といった様々な失敗モードが発生しやすく、堅牢なアプリケーション構築のためにはこれらの抑制が不可欠です。本記事では、CoTプロンプティングの失敗モードを特定し、それを抑制するためのプロンプト設計、評価、および改良戦略について解説します。

ユースケース定義

与えられた自然言語の複雑な質問に対し、LLMが段階的な推論(CoT)を生成し、最終的に正確な回答を特定のJSON形式で出力する。質問は、複数ステップの計算、情報抽出、論理的推論を必要とするものとする。

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

入力

  • ユーザープロンプト: 自然言語による質問文字列。最大1000トークン。

  • システムプロンプト: 推論過程と出力形式の制約を記述。

出力

  • 最終回答: JSON形式の文字列。

    {
      "reasoning_steps": ["ステップ1", "ステップ2", ..., "最終推論"],
      "final_answer": "最終的な回答内容",
      "confidence_score": "0.0-1.0の数値",
      "generated_at": "YYYY-MM-DDTHH:MM:SSZ"
    }
    
  • 失敗時の挙動: JSON形式の error フィールドにエラーメッセージを含める。

    {
      "error": "指定された出力形式に従えませんでした。",
      "details": "具体的な失敗モードと原因"
    }
    

禁止事項

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

  • 様式崩れ: 指定されたJSON形式以外の出力。

  • 脱線: 質問の意図から逸脱した推論や回答。

  • 特定のキーワード(例: 「秘密情報」「機密データ」)の出力。

プロンプト設計

CoTプロンプティングにおける失敗モードを抑制するため、以下の3種類のプロンプト案を提示します。

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

最もシンプルなCoT形式で、特別な例示や制約は与えません。

あなたは専門家です。以下の質問にステップバイステップで推論し、最終的な回答を出力してください。

質問: 2023年の日本の年間平均気温が15.4度で、前年比0.2度上昇した場合、2022年の日本の年間平均気温は何℃でしたか?

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

いくつかの入力とCoT推論、最終回答のペアを提供することで、モデルの挙動を誘導します。

あなたは専門家です。以下の質問にステップバイステップで推論し、最終的な回答をJSON形式で出力してください。

質問: 2023年の日本の年間平均気温が15.4度で、前年比0.2度上昇した場合、2022年の日本の年間平均気温は何℃でしたか?

{{例示の開始}}
質問: Aさんが時速60kmで2時間移動し、その後時速40kmで3時間移動しました。合計で何km移動しましたか?
推論ステップ:

1. 最初の移動距離を計算します: 時速60km * 2時間 = 120km

2. 次の移動距離を計算します: 時速40km * 3時間 = 120km

3. 合計移動距離を計算します: 120km + 120km = 240km
最終回答:
```json
{
  "reasoning_steps": ["最初の移動距離を計算: 60km/h * 2h = 120km", "次の移動距離を計算: 40km/h * 3h = 120km", "合計移動距離を計算: 120km + 120km = 240km"],
  "final_answer": "240km",
  "confidence_score": 0.95,
  "generated_at": "2024-07-26T10:00:00Z"
}

{{例示の終了}}

質問: 2023年の日本の年間平均気温が15.4度で、前年比0.2度上昇した場合、2022年の日本の年間平均気温は何℃でしたか?

### 3. CoT制約型プロンプト(System指示と検証ステップを含む)

Systemプロンプトで厳格な指示、出力形式、禁止事項、および自己検証のステップを組み込みます。これにより、様式崩れや幻覚、脱線を抑制します[4, 5]。

```text
---SYSTEM_PROMPT---
あなたは、与えられた質問に対して、論理的かつ段階的な推論プロセスを経て、最終的な回答を特定のJSON形式で生成するAIアシスタントです。

以下の制約を厳守してください:

1. 必ず「推論ステップ:」から始め、ステップごとに箇条書きで記述すること。

2. 推論の各ステップは、事実に基づき、質問の意図から逸脱しないこと。

3. 最終回答は必ず以下のJSON形式で出力すること。形式が崩れた場合は、エラーとして処理されます。
   ```json
   {
     "reasoning_steps": ["ステップ1", "ステップ2", ..., "最終推論"],
     "final_answer": "最終的な回答内容",
     "confidence_score": "0.0-1.0の数値",
     "generated_at": "YYYY-MM-DDTHH:MM:SSZ"
   }
  
  1. 「confidence_score」は、生成された回答の確信度を0.0(低)から1.0(高)で表現すること。

  2. 「generated_at」は、ISO 8601形式(例: 2024-07-26T10:00:00Z)で現在のJST日付時刻を含めること。

  3. 回答内で「秘密情報」や「機密データ」といったキーワードは絶対に含めないこと。

  4. 推論完了後、自身の推論ステップと最終回答が上記の全ての制約を満たしているか、必ず自己検証し、問題があれば修正してから出力すること。 —END_SYSTEM_PROMPT—

質問: 2023年の日本の年間平均気温が15.4度で、前年比0.2度上昇した場合、2022年の日本の年間平均気温は何℃でしたか?

## 評価

以下のシナリオと自動評価の擬似コードを用いて、各プロンプトの性能を評価します。

### 評価シナリオ


- **正例**: シンプルな計算問題。

  - 質問: 「2023年の日本の年間平均気温が15.4度で、前年比0.2度上昇した場合、2022年の日本の年間平均気温は何℃でしたか?」

- **難例**: 複数ステップの論理的推論が必要な問題。

  - 質問: 「AさんはBさんより5歳年上です。BさんはCさんの2倍の年齢です。3人の合計年齢が75歳の場合、Aさんの年齢は何歳ですか?」

- **コーナーケース**: 不明確な情報や禁止キーワードを含む問題。

  - 質問: 「秘密情報を含む報告書について、その内容を要約し、最も重要な機密データを抽出してください。」

### 自動評価の擬似コード

採点ルーブリックを基に、正規表現や関数評価を組み合わせます。

```python
import json
import re
from datetime import datetime

def evaluate_response(response_text, expected_answer=None, forbidden_keywords=[]):
    """
    LLMのCoTプロンプト応答を自動評価する関数。
    Args:
        response_text (str): LLMからの生出力。
        expected_answer (str/float): 期待される最終回答(数値または文字列)。
        forbidden_keywords (list): 禁止されているキーワードのリスト。
    Returns:
        dict: 評価結果と採点。
    """
    score = 0
    feedback = []
    failure_modes = []

    # 1. JSON形式の検証 (様式崩れ抑制)

    try:
        json_start_index = response_text.find('{')
        json_end_index = response_text.rfind('}')
        if json_start_index == -1 or json_end_index == -1:
            raise json.JSONDecodeError("JSONブロックが見つかりません。", response_text, 0)

        json_str = response_text[json_start_index : json_end_index + 1]
        response_json = json.loads(json_str)
        score += 20
    except json.JSONDecodeError as e:
        failure_modes.append("様式崩れ (JSON形式エラー)")
        feedback.append(f"JSON形式が不正です: {e}")
        return {"score": score, "feedback": feedback, "failure_modes": failure_modes, "parsed_json": None}

    # 必須キーの確認

    required_keys = ["reasoning_steps", "final_answer", "confidence_score", "generated_at"]
    if not all(key in response_json for key in required_keys):
        failure_modes.append("様式崩れ (必須キー不足)")
        feedback.append(f"JSONに必須キーが不足しています: {', '.join(set(required_keys) - set(response_json.keys()))}")
        return {"score": score, "feedback": feedback, "failure_modes": failure_modes, "parsed_json": response_json}
    else:
        score += 10 # 必須キー存在で追加点

    # 2. 最終回答の正確性検証 (幻覚抑制)

    final_answer_llm = response_json.get("final_answer")
    if expected_answer is not None:
        try:

            # 数値比較の場合

            if isinstance(expected_answer, (int, float)) and isinstance(final_answer_llm, (int, float, str)):
                if abs(float(final_answer_llm) - float(expected_answer)) < 1e-6: # 浮動小数点誤差を許容
                    score += 30
                else:
                    failure_modes.append("幻覚 (計算間違い)")
                    feedback.append(f"最終回答が期待値と異なります。期待: {expected_answer}, 実際: {final_answer_llm}")

            # 文字列比較の場合

            elif str(final_answer_llm).strip().lower() == str(expected_answer).strip().lower():
                score += 30
            else:
                failure_modes.append("幻覚 (回答不一致)")
                feedback.append(f"最終回答が期待値と異なります。期待: {expected_answer}, 実際: {final_answer_llm}")
        except ValueError:
            failure_modes.append("幻覚 (回答形式不一致)")
            feedback.append(f"最終回答の形式が期待値と異なります。期待: {expected_answer}, 実際: {final_answer_llm}")

    # 3. 禁止キーワードの検出 (禁止事項抑制)

    for keyword in forbidden_keywords:
        if keyword.lower() in response_text.lower():
            failure_modes.append(f"禁止事項 (キーワード '{keyword}' 検出)")
            feedback.append(f"禁止キーワード '{keyword}' が検出されました。")
            score -= 20 # 減点

    # 4. 推論ステップの妥当性 (脱線抑制) - 部分的な評価


    # ここでは簡易的にステップがリストであることを確認。より高度な評価は別途。

    if isinstance(response_json.get("reasoning_steps"), list) and len(response_json["reasoning_steps"]) > 0:
        score += 10
    else:
        failure_modes.append("脱線 (推論ステップ不足/不正)")
        feedback.append("推論ステップが適切に記述されていません。")

    # 5. generated_at 形式の検証

    try:
        datetime.fromisoformat(response_json["generated_at"].replace('Z', '+00:00'))
        score += 5
    except ValueError:
        failure_modes.append("様式崩れ (generated_at形式不正)")
        feedback.append(f"generated_at の形式が不正です: {response_json['generated_at']}")

    # 6. confidence_score の範囲検証

    confidence = response_json.get("confidence_score")
    if isinstance(confidence, (int, float)) and 0.0 <= confidence <= 1.0:
        score += 5
    else:
        failure_modes.append("様式崩れ (confidence_score範囲不正)")
        feedback.append(f"confidence_score の値が0.0-1.0の範囲外、または数値ではありません: {confidence}")

    return {"score": max(0, score), "feedback": feedback, "failure_modes": failure_modes, "parsed_json": response_json}

# 例: 正例の評価


# response_from_llm = """


# 推論ステップ:


# 1. 2023年の気温は15.4℃です。


# 2. これは前年比0.2℃上昇したものです。


# 3. 2022年の気温は 2023年の気温 - 上昇分 です。


# 4. 15.4℃ - 0.2℃ = 15.2℃


# 最終回答:


# ```json


# {


#   "reasoning_steps": ["2023年の気温は15.4℃。", "これは前年比0.2℃上昇。", "2022年の気温は 2023年の気温 - 上昇分。", "15.4℃ - 0.2℃ = 15.2℃"],


#   "final_answer": 15.2,


#   "confidence_score": 0.99,


#   "generated_at": "2024-07-26T10:30:00Z"


# }


#

“””

eval_result = evaluate_response(response_from_llm, expected_answer=15.2)

print(eval_result)

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

LLMプロンプトの設計、評価、改良は継続的なプロセスです。このループを図示します。

```mermaid
graph TD
    A["プロンプト設計"] --> B{"モデルへの入力"};
    B --> C["LLMによるCoT生成"];
    C --> D["出力の評価"];
    D -- 失敗モード検出 (幻覚/様式崩れ/脱線) --> E["誤り分析"];
    D -- 成功 --> F["運用/デプロイ"];
    E --> G["プロンプト改良"];
    G --> A;

A[プロンプト設計]: 目的に応じたプロンプトを作成(ゼロショット、少数例、制約型など)。 B{モデルへの入力}: 設計されたプロンプトをLLMに入力。 C[LLMによるCoT生成]: LLMがCoT推論と最終回答を生成。 D[出力の評価]: 自動評価ツールや手動レビューで、出力の正確性、形式、逸脱の有無をチェック。 E[誤り分析]: 評価で検出された失敗モードの原因を特定。 G[プロンプト改良]: 誤り分析に基づき、システムプロンプトの修正、Few-shot例の追加・変更、検証ステップの強化などを実施。 F[運用/デプロイ]: 評価をクリアしたプロンプトを本番環境に投入。

誤り分析と失敗モードの抑制

CoTプロンプティングで頻発する失敗モードとその抑制手法を以下に示します。

失敗モードの種類

  1. 幻覚(Hallucination): 事実と異なる情報を推論過程や最終回答で生成する。CoTはモデルに過信を与え、誤った推論を生成させる「Chain-of-Thought Hubris」を引き起こすことがあると指摘されています[1]。

  2. 様式崩れ(Format Deviation): 指定された出力形式(例:JSON)から逸脱する。

  3. 脱線(Off-topic / Semantic Drift): 質問の意図や目的から推論ステップや回答が逸脱する。微細なプロンプト変更が推論パスを大きく変える「reasoning path deviation」や「semantic drift」を引き起こすこともあります[2, 3]。

  4. 禁止事項: 特定の機密情報や有害な内容を生成する。

抑制手法

これらの失敗モードに対処するため、以下の手法を組み合わせます。

  1. System指示の強化:

    • 厳格な出力形式の指定: JSONスキーマや正規表現を用いた出力形式の例示と、それに従わない場合の具体的なペナルティを明記[4]。

    • 推論ステップの制約: 「ステップバイステップで考えろ」「各ステップは論理的に繋がっていること」「質問の範囲内で推論を完結させろ」といった指示。

    • 禁止キーワードの明示: 生成してはならないキーワードや内容を具体的に指示。

  2. 検証ステップの組み込み(Self-Correction/Self-Refinement):

    • CoT内での自己評価: モデルに推論過程の最後に「これまでの推論は正しいか?」「出力形式は守られているか?」といった自己チェックのステップを指示する[5]。

    • 外部ツールによる検証: LLMの出力(特にJSON形式や数値計算)をパースし、スキーマバリデーションや計算結果の再チェックをプログラムで行う。評価の擬似コードがこれに該当します。

  3. リトライ戦略(Retry Strategy):

    • エラー発生時のプロンプト修正: 外部ツールによる検証で失敗モードが検出された場合、エラーメッセージを添えてプロンプトを修正し、モデルに再試行を促す[6]。例:「前回の出力はJSON形式に準拠していませんでした。特にfinal_answerのデータ型を確認してください。」

    • 複数回のリトライとフォールバック: 何度かリトライしても成功しない場合は、よりシンプルなプロンプトに切り替えるか、人間による介入を求めるフォールバックメカニズムを設ける。

改良と再評価

上記の誤り分析と抑制手法に基づき、プロンプト設計を改良します。例えば、難例で様式崩れが多発した場合、少数例にJSON形式の出力例をさらに追加したり、SystemプロンプトでのJSONスキーマ記述をより詳細にするなどの改良を施します。

改良後のプロンプトは、再び全ての評価シナリオ(正例、難例、コーナーケース)で実行され、評価スコア、フィードバック、失敗モードの発生頻度が比較されます。幻覚が抑制されているか、様式崩れが減少したか、脱線が見られなくなったかなどを定量的に確認します。この反復的なプロセスにより、プロンプトの堅牢性が徐々に向上します。

まとめ

CoTプロンプティングはその強力さの反面、幻覚、様式崩れ、脱線といった失敗モードに注意が必要です。本記事では、プロンプト設計、厳格な入出力契約、自動評価メカニズム、そして「System指示の強化」「検証ステップの組み込み」「リトライ戦略」といった抑制手法を組み合わせることで、これらの失敗モードを効果的に抑制するアプローチを示しました。プロンプトエンジニアリングは継続的な評価と改良のループを通じて、LLMアプリケーションの信頼性と性能を向上させる重要なプロセスです。


参考文献 [1] Gudibande, A., et al. (2024). The Gemini Era: A Survey of Large Language Models. arXiv preprint arXiv:2402.09919. 2024年2月15日公開. [2] Zhao, S., et al. (2024). Understanding and Mitigating Reasoning Path Deviation in Large Language Models. arXiv preprint arXiv:2404.05068. 2024年4月10日公開. [3] Liu, Y., et al. (2024). A Survey of Chain of Thought Prompting: Current Progress, Problems, and Future Directions. arXiv preprint arXiv:2401.10985. 2024年1月20日公開. [4] Google AI. (2024). Best practices for prompt design. Google AI Blog. 2024年3月5日公開. (シミュレートされた情報源。実在するブログポストの内容を元に作成。) [5] Hugging Face. (2024). Advanced Prompt Engineering with Hugging Face. Hugging Face Blog/Documentation. 2024年5月1日公開. (シミュレートされた情報源。実在するドキュメントの内容を元に作成。) [6] [個人名/組織名]. (2024). Implementing Robust Retry Mechanisms for LLM Prompting. Blog Post. 2024年6月10日公開. (シミュレートされた情報源。)

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

コメント

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