Chain-of-Thoughtプロンプティング実践

Tech

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

Chain-of-Thoughtプロンプティング実践

Chain-of-Thought (CoT) プロンプティングは、大規模言語モデル (LLM) に複雑な推論タスクを段階的に解決させるための強力な手法です。本記事では、CoTプロンプティングの設計、評価、改良に至る実践的なアプローチを解説します。

1. ユースケース定義

CoTプロンプティングは、以下のような多段階の思考や情報統合が必要なタスクで特に有効です。

  • 複雑なデータ分析: 複数データソースからの情報抽出、条件に基づいたフィルタリング、比較分析。

  • 問題解決: 数学的な問題、論理パズル、コードスニペットのデバッグ。

  • 意思決定支援: 複数の選択肢とそれぞれのメリット・デメリットを評価し、最適な結論を導出。

  • 要約と統合: 複数の文書から主要な情報を抽出し、一貫性のある要約を生成。

これらのユースケースにおいて、LLMが最終結果だけでなく、その導出過程を明示することで、結果の信頼性と説明可能性が向上します[1][2]。

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

LLMとのやり取りにおいて、入出力のフォーマットと挙動を明確に定義することは、プロンプトの品質と安定性を保つ上で不可欠です。

入力契約

  • フォーマット: JSON形式。タスクの目的と関連するコンテキストデータを明示的に含めます。

    {
      "task": "ある文書から特定の日付範囲のイベントを抽出し、その影響を分析する",
      "context_document": "イベント情報を含む長いテキスト",
      "date_range": "2024-01-01 to 2024-03-31",
      "output_format_instruction": "イベントごとに分析を記述し、最終的な総合影響をまとめる"
    }
    
  • 前提条件: 入力データはUTF-8エンコーディングであること。コンテキストの最大トークン数はモデルの制限を超えないこと。

  • 失敗時の挙動: 入力JSONが不正な場合、モデルはエラーメッセージを返却し処理を中断。

出力契約

  • フォーマット: JSON形式。思考プロセス (Chain-of-Thought) と最終結果を含みます。

    {
      "thought_process": [
        "1. 文書を読み込み、指定された日付範囲内のイベントを識別する。",
        "2. 各イベントについて、関連する情報を抽出し、その性質を分析する。",
        "3. 各イベントがもたらす影響(ポジティブ/ネガティブ/中立)を評価する。",
        "4. 評価された影響を統合し、総合的な分析結果をまとめる。"
      ],
      "analysis_results": [
        {
          "event_name": "イベントA",
          "date": "2024-01-15",
          "summary": "概要",
          "impact_assessment": "詳細な影響分析"
        },
        // ... 他のイベント
      ],
      "overall_impact_summary": "総合的な影響の要約"
    }
    
  • 失敗時の挙動:

    • 解析エラー: 指定されたJSON形式に従わない場合、{"error": "Output format deviation. Please try again with strict JSON format.", "retry_instruction": "Ensure all keys and values are properly quoted and structure matches schema."}

    • 推論不足: 推論ステップが明らかに不足している場合、{"error": "Incomplete thought process. More detailed steps are required.", "retry_instruction": "Provide more granular thinking steps."}

  • 禁止事項:

    • 個人を特定できる情報、機密情報の出力。

    • 有害、差別的、違法なコンテンツの生成。

    • 事実と異なる虚偽情報の生成(幻覚)。

3. プロンプト設計

CoTプロンプティングにはいくつかのバリアントがありますが、ここでは代表的な3種類を提示します。

3.1. ゼロショットCoT

プロンプトに「段階的に考えてみましょう(Let’s think step by step.)」のようなシンプルな指示を追加するだけで、モデルが推論ステップを生成するように誘導します[3]。

あなたは高度な分析を行うAIアシスタントです。
以下の質問に対し、段階的に思考プロセスを記述し、最終的な結論をJSON形式で出力してください。

質問:
企業Xは2023年に売上が前年比10%増加し、コストが5%増加しました。2022年の売上は100億円、コストは60億円でした。2023年の利益は前年と比較してどのように変化しましたか?

出力形式:
{
  "thought_process": [
    "思考ステップ1",
    "思考ステップ2",
    ...
  ],
  "final_answer": "最終的な利益変化の説明"
}

3.2. 少数例CoT (Few-shot CoT)

複数の入力とそれに対応する推論ステップ、最終出力を例として提示することで、モデルに推論パターンを学習させます[1]。

あなたは財務分析を行うAIアシスタントです。以下の例を参考に、質問に対して段階的に思考プロセスを記述し、最終的な結論をJSON形式で出力してください。

---
例1:
質問: 企業Aは2022年に売上500億円、コスト300億円でした。2023年に売上が20%増加し、コストが10%増加しました。2023年の利益は前年と比較してどう変化しましたか?
{
  "thought_process": [
    "1. 2022年の利益を計算: 売上500億円 - コスト300億円 = 200億円。",
    "2. 2023年の売上を計算: 500億円 * (1 + 0.20) = 600億円。",
    "3. 2023年のコストを計算: 300億円 * (1 + 0.10) = 330億円。",
    "4. 2023年の利益を計算: 600億円 - 330億円 = 270億円。",
    "5. 利益の変化を計算: 270億円 - 200億円 = 70億円増加。"
  ],
  "final_answer": "企業Aの2023年の利益は前年と比較して70億円増加しました。"
}

---
質問:
企業Bは2023年に売上が前年比10%増加し、コストが5%増加しました。2022年の売上は100億円、コストは60億円でした。2023年の利益は前年と比較してどのように変化しましたか?

出力形式:
{
  "thought_process": [
    "思考ステップ1",
    "思考ステップ2",
    ...
  ],
  "final_answer": "最終的な利益変化の説明"
}

3.3. CoT制約型

Systemプロンプトで、思考プロセスを特定の構造(例:箇条書き、特定のセクション見出し)で記述するよう厳しく制約します。これにより、評価とデバッグが容易になります[6]。

SYSTEM:
あなたはビジネスアナリストです。
ユーザーからの財務分析リクエストに対し、必ず以下の手順とJSONフォーマットで回答してください。
思考プロセスは必ず「## 思考ステップ」セクションに箇条書きで記述し、その後に「## 結論」を記述してください。
出力は厳格なJSON形式で、`thought_process` は文字列の配列、`final_answer` は文字列としてください。

USER:
企業Cは2023年に売上が前年比15%減少、コストが5%増加しました。2022年の売上は200億円、コストは120億円でした。2023年の利益は前年と比較してどう変化しましたか?

4. 評価

プロンプトの有効性を確認するためには、体系的な評価が必要です。

4.1. 評価シナリオ

  • 正例: 明確な指示とデータを持つ、期待通りの結果を導く簡単な問題。

    • 例: 「X + Y = ?」のような単純な計算問題。
  • 難例: 複数の条件分岐、曖昧な指示、または意図的に誤った情報を含む複雑な問題。

    • 例: 「AかBどちらかを選ぶが、もしCであればAは無効」のような多段階の論理推論。
  • コーナーケース: 入力データが不足している、矛盾している、またはタスクの範囲外である問題。

    • 例: 「未発表のデータに基づいて将来の株価を予測しろ」のような不可能なタスク。

4.2. 自動評価の擬似コード

Pythonを用いた自動評価の擬似コードを以下に示します。

import json
import re

def evaluate_cot_output(llm_output: str, expected_result: str, expected_steps: list = None) -> dict:
    """
    Chain-of-Thoughtプロンプトの出力を自動評価する。
    """
    try:
        output_data = json.loads(llm_output)
    except json.JSONDecodeError:
        return {"score": 0, "reason": "JSON形式の崩壊"}

    thought_process = output_data.get("thought_process")
    final_answer = output_data.get("final_answer")

    if not isinstance(thought_process, list) or not thought_process:
        return {"score": 0, "reason": "思考プロセスが配列形式でないか、空である"}
    if not isinstance(final_answer, str) or not final_answer:
        return {"score": 0, "reason": "最終回答がないか、文字列でない"}

    score = 0
    reasons = []

    # 1. 最終回答の正確性 (キーワードマッチング、正規表現、または関数評価)

    if expected_result in final_answer: # 単純なキーワードマッチ
        score += 50
        reasons.append("最終回答が期待値に一致")
    else:

        # より高度な評価ロジック (例: 数値比較、意味的類似度)

        if re.search(r"(\d+億円増加)", final_answer) and "70億円増加" in final_answer: # 特定のパターン
             score += 50
             reasons.append("最終回答が期待値のパターンに一致")
        else:
             reasons.append(f"最終回答が期待値 '{expected_result}' と異なる")

    # 2. 思考プロセスの品質 (ルーブリック、ステップ数、キーワード)

    if expected_steps:
        matched_steps = 0
        for step in expected_steps:
            if any(step in t_step for t_step in thought_process):
                matched_steps += 1

        if matched_steps >= len(expected_steps) * 0.8: # 80%以上のステップがカバーされているか
            score += 30
            reasons.append("思考プロセスが十分に詳細")
        else:
            reasons.append(f"思考プロセスが期待ステップを十分にカバーしていない ({matched_steps}/{len(expected_steps)})")
    else: # 思考プロセス自体の存在と形式を評価
        if len(thought_process) >= 3: # 最低3ステップ以上を評価基準とする
            score += 30
            reasons.append("思考プロセスが適切に記述されている")
        else:
            reasons.append("思考プロセスが短すぎる")

    # 3. JSON形式の遵守

    score += 20 # JSONDecodeErrorで既に0点になっているため、ここまで到達すれば20点加算

    return {"score": min(score, 100), "reason": ", ".join(reasons)}

# 擬似的な使用例


# output_ok = '{"thought_process": ["step1", "step2", "step3"], "final_answer": "70億円増加"}'


# output_fail_format = '{"thought_process": ["step1", "step2"], "final_answer": "70億円増加'


# output_fail_content = '{"thought_process": ["wrong step"], "final_answer": "0億円変化"}'


# 


# print(evaluate_cot_output(output_ok, "70億円増加", ["1. 2022年の利益を計算", "5. 利益の変化を計算"]))


# print(evaluate_cot_output(output_fail_format, "70億円増加"))


# print(evaluate_cot_output(output_fail_content, "70億円増加", ["1. 2022年の利益を計算"]))

5. プロンプト設計と評価のループ

CoTプロンプティングの性能向上には、反復的な設計・評価・改良サイクルが不可欠です。

flowchart TD
    A["要件定義: 目的, 入出力契約"] --> B{"プロンプト設計: CoT種類, 指示"};
    B -- プロンプト案1~N --> C["LLM実行: 多様なシナリオでテスト"];
    C -- 出力ログ --> D["評価シナリオ実行: 自動評価/手動レビュー"];
    D -- 採点結果とレポート --> E{"誤り分析: 失敗モード特定"};
    E -- 失敗モードの洞察 --> F["改良方針策定: 指示強化, 例示追加など"];
    F -- 新しいプロンプト戦略 --> B;
    D -- 最終的な評価レポート --> G["プロンプト採用/デプロイ"];

6. 誤り分析と抑制手法

LLMは多様な失敗モードを持ちます。これらを理解し、適切な抑制策を講じることが重要です[7]。

6.1. 幻覚 (Hallucination)

  • 内容: 事実に基づかない、あるいは存在しない情報を生成する。

  • 抑制手法:

    • 参照情報の提供: モデルが依拠すべき正確な情報源をプロンプトで明示的に与える。

    • Systemプロンプトでの制約: 「提供された情報のみに基づき回答せよ」「事実と異なる情報を生成するな」といった指示を厳格に与える。

    • 検証ステップ: モデルの出力に対し、外部ツールやデータベースでファクトチェックを行うステップを導入する。

6.2. 様式崩れ (Format Deviations)

  • 内容: 指定されたJSONなどの出力形式に従わない。

  • 抑制手法:

    • 厳格なSystemプロンプト: 出力フォーマットのスキーマ定義をプロンプトに含め、厳密な遵守を指示する。

    • 出力解析とリトライ: モデルの出力をパースし、失敗した場合はフォーマットエラーをフィードバックとしてモデルに渡し、再試行させる。

    • スキーマ検証ライブラリ: Pydanticなどのライブラリで出力されたJSONを自動検証する。

6.3. 脱線 (Off-topic/Rambling)

  • 内容: 本来のタスクから逸脱した情報や不必要な詳細を生成する。

  • 抑制手法:

    • 明確なタスク定義: プロンプトの冒頭でタスクの目的と範囲を明確に定義する。

    • 思考ステップの制約: CoTで生成される思考ステップの数を制限したり、特定のキーワードを含めるよう指示したりする。

    • 最大トークン数の設定: モデルの出力トークン数を制限し、冗長な生成を防ぐ。

6.4. 禁止事項 (Prohibited Content)

  • 内容: 有害、差別的、違法、または倫理的に問題のあるコンテンツを生成する。

  • 抑制手法:

    • 強力なSystemプロンプト: 「常に倫理的で中立的な立場を保て」「有害なコンテンツは生成するな」といった安全に関する指示を最上位に配置する。

    • コンテンツフィルタリングAPI: LLMの出力後に、GoogleのSafety APIのようなサービスを用いてコンテンツを自動フィルタリングする。

7. 改良と再評価

評価結果と誤り分析に基づき、プロンプトを改良します。

  • CoTの粒度調整: 推論ステップが粗すぎる場合はより細分化を促し、細かすぎる場合は統合を指示する。

  • 具体例の追加: 少数例CoTの例示を増やし、多様なパターンに対応させる。

  • Systemプロンプトの強化: 抑制したい失敗モードに対する指示をより具体的かつ強制的に記述する。

改良後、再度上記評価シナリオでプロンプトを再評価し、性能改善度合いを定量的に測定します。この反復サイクルを通じて、プロンプトは洗練されていきます。

8. まとめ

Chain-of-Thoughtプロンプティングは、LLMの推論能力を最大限に引き出し、複雑なタスクを解決するための強力な手法です。効果的なCoTプロンプトを開発するには、明確なユースケース定義、厳格な入出力契約、複数バリアントのプロンプト設計、そして反復的な評価と誤り分析に基づく改良プロセスが不可欠です。本記事で解説したアプローチを実践することで、LLMをより信頼性高く、説明可能な形で活用できるでしょう。


参考情報: [1] Wei, J. et al. (2022). “Chain-of-Thought Prompting Elicits Reasoning in Large Language Models.” Google AI Blog. 公開日: 2022年1月28日. [2] Google Cloud Blog. “Vertex AI PaLM API のプロンプトエンジニアリングのベストプラクティス.” 公開日: 2023年4月25日. [3] Kojima, T. et al. (2022). “Zero-shot-CoT: Leveraging Large Language Models as Zero-Shot Reasoners.” arXiv. 公開日: 2022年5月24日. [4] Google Developers. “Prompt engineering best practices with Gemini.” 最終確認日: {{jst_today}} (JST). (継続的に更新されるドキュメントのため、最終確認日を記載). [5] Google Developers. “Gemini API Overview.” 最終確認日: {{jst_today}} (JST). (継続的に更新されるドキュメントのため、最終確認日を記載). [6] Google Cloud documentation, “Prompt engineering best practices with Gemini”. 最終確認日: {{jst_today}} (JST). [7] OpenAI “Prompt engineering” guide. 最終確認日: {{jst_today}} (JST). (継続的に更新されるドキュメントのため、最終確認日を記載).

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

コメント

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