Chain-of-Thoughtプロンプティング活用と効果

Tech

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

Chain-of-Thoughtプロンプティング活用と効果

ユースケース定義

Chain-of-Thought(CoT)プロンプティングは、大規模言語モデル(LLM)が複雑な推論タスクを多段階で思考するプロセスを明示的に促す技術です。これにより、モデルの推論能力と最終回答の正確性が向上し、同時にモデルの思考プロセスを可視化することで説明可能性が高まります[1]。主要なユースケースは以下の通りです。

  • 多段階の複雑な問題解決: 数学的な問題、常識的な推論、論理パズル、コード生成におけるアルゴリズム設計など。

  • 推論パスの透明性確保: 監査可能性やデバッグが必要なシステムにおいて、モデルがどのように結論に至ったかを示す。

  • LLMの性能向上: ゼロショットや少数例プロンプティングでは難しい高度なタスクにおいて、精度とロバスト性を向上させる。

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

LLMとの対話における入出力契約を以下に定義します。

入力契約

  • フォーマット: JSON形式または自然言語テキスト。JSONの場合は{"task": "...", "context": "...", "constraints": [...]}の構造を推奨します。

  • 最大トークン数: 4096トークン(モデルとAPIに依存)。

  • 禁止事項: 個人特定情報(PII)、機密情報、違法行為を促す内容、倫理に反する指示。

  • 必須項目: タスクの目的、入力データ、期待される出力形式。

出力契約

  • フォーマット:

    • 最終回答はJSON形式または特定のMarkdownセクション(例:## 最終回答)に含める。

    • 推論ステップは箇条書きまたは番号付きリストで明示的に出力する。

    • 思考プロセスはThinking Process:または理由:などのプレフィックスで開始する。

  • 失敗時の挙動:

    • 制約違反や不明確な入力の場合、具体的なエラーメッセージと、モデルが理解できなかった部分の指摘を返却する。

    • 推論が中断した場合、「推論プロセスが中断しました。詳細情報を提供してください」といったメッセージを返却。

  • 禁止事項: 入力契約と同様の禁止事項に加え、幻覚、様式崩れ、タスクからの脱線を厳しく禁止します。

プロンプト設計

以下に、同じタスクに対する3種類のプロンプト案を提示します。タスクは「与えられた数字のリストから偶数だけを抽出し、その合計を計算する」とします。

ゼロショットプロンプト

与えられた数字のリストから偶数だけを抽出し、その合計を計算してください。
リスト: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

少数例プロンプト(Few-shot Prompting)

以下の例を参考に、与えられた数字のリストから偶数だけを抽出し、その合計を計算してください。

例1:
リスト: [1, 3, 5, 7, 9]
偶数: []
合計: 0

例2:
リスト: [2, 4, 6]
偶数: [2, 4, 6]
合計: 12

リスト: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Chain-of-Thought制約型プロンプト

あなたは論理的な思考プロセスを順を追って説明し、問題を解決するAIアシスタントです。
与えられた数字のリストから偶数だけを抽出し、その合計を計算してください。

思考プロセスをステップバイステップで明確に記述し、最後に最終回答を提示してください。

リスト: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

---
思考プロセス:

1. まず、与えられたリストの各要素を順番に確認します。

2. 各要素が偶数であるか(2で割り切れるか)を判定します。

3. 偶数である場合、その数字を新しいリストに収集します。

4. 全ての要素を確認した後、収集された偶数のリストを合計します。

5. 最後に、偶数のリストと合計値を提示します。
---
最終回答:

評価

LLMの出力評価は、自動評価と手動評価を組み合わせます。

評価シナリオ

  • 正例: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] → 偶数: [2, 4, 6, 8, 10], 合計: 30

  • 難例: [-2, 0, 1, 3, 4, 7, 100](負の数、ゼロを含む)→ 偶数: [-2, 0, 4, 100], 合計: 102

  • コーナーケース: [](空のリスト)→ 偶数: [], 合計: 0

  • コーナーケース: [abc, 1, 2](不正なデータ型を含む)→ エラーメッセージまたは不正データを無視し、偶数: [2], 合計: 2

自動評価の擬似コード

import re
import json

def evaluate_llm_output(output_text, expected_evens, expected_sum, scenario_type):
    score = 0
    feedback = []

    # 1. 出力フォーマットの確認(CoTプロンプトの場合)

    if "思考プロセス:" in output_text and "最終回答:" in output_text:
        feedback.append("思考プロセスの構造が検出されました。")
        score += 0.5 # 構造点の加点

    # 2. 最終回答の抽出と解析

    final_answer_match = re.search(r"最終回答:\s*```json\n(.*?)\n```", output_text, re.DOTALL)
    if not final_answer_match:
        final_answer_match = re.search(r"最終回答:\s*(.*)", output_text, re.DOTALL) # JSONでない場合のフォールバック

    parsed_output = {}
    if final_answer_match:
        try:

            # 可能な限りJSONとしてパースを試みる

            parsed_output = json.loads(final_answer_match.group(1))
        except json.JSONDecodeError:

            # JSONでない場合は、キーワードで偶数リストと合計を抽出

            evens_match = re.search(r"偶数:\s*\[(.*?)\]", output_text)
            sum_match = re.search(r"合計:\s*(\d+)", output_text)
            if evens_match:
                parsed_output['evens'] = [int(x.strip()) for x in evens_match.group(1).split(',') if x.strip()]
            if sum_match:
                parsed_output['sum'] = int(sum_match.group(1))

    # 3. 内容の正確性評価

    if 'evens' in parsed_output and sorted(parsed_output['evens']) == sorted(expected_evens):
        feedback.append("偶数リストが正確です。")
        score += 1.0
    else:
        feedback.append(f"偶数リストが不正確です。期待値: {expected_evens}, 実際: {parsed_output.get('evens')}")

    if 'sum' in parsed_output and parsed_output['sum'] == expected_sum:
        feedback.append("合計値が正確です。")
        score += 1.0
    else:
        feedback.append(f"合計値が不正確です。期待値: {expected_sum}, 実際: {parsed_output.get('sum')}")

    # 4. 推論ステップの妥当性(CoTプロンプトの場合のみ、簡略化)

    if "思考プロセス:" in output_text:
        if "偶数であるか" in output_text and "合計します" in output_text:
            feedback.append("思考プロセスに主要なステップが含まれています。")
            score += 0.5

    # 5. エラーハンドリング(コーナーケースの場合)

    if scenario_type == "コーナーケース_不正データ" and "不正なデータ" in output_text or "エラー" in output_text:
        feedback.append("不正なデータに対する適切なエラーハンドリングが検出されました。")
        score += 1.0

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

# --- 使用例 ---


# output_cot = """


# 思考プロセス:


# 1. リスト [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] を確認します。


# 2. 各要素が偶数であるかを判定し、偶数のみを抽出します。


#    - 1: 奇数


#    - 2: 偶数


#    ...


#    - 10: 偶数


# 3. 抽出された偶数のリストは [2, 4, 6, 8, 10] です。


# 4. これらの偶数を合計します: 2 + 4 + 6 + 8 + 10 = 30。


# 5. 最終回答として、偶数のリストと合計値を提示します。


# ---


# 最終回答:


# ```json


# {


#   "evens": [2, 4, 6, 8, 10],


#   "sum": 30


# }


#

“””

print(evaluate_llm_output(output_cot, [2, 4, 6, 8, 10], 30, “正例”))

## 誤り分析

CoTプロンプティングにおいても、モデルは様々な失敗モードに陥る可能性があります。

*   **幻覚(Hallucination):** 事実に基づかない推論ステップや誤った事実の生成。例えば、存在しないリスト要素を抽出したり、計算ミスをする。

    *   **抑制手法:** 複数モデルでのクロスチェック、外部ツール(計算機、検索エンジン)との連携、ユーザーへの確認プロンプト。

*   **様式崩れ(Format Deviation):** 定義された出力形式(JSON、Markdownの箇条書きなど)に従わない出力。

    *   **抑制手法:** プロンプトでの明確な形式指定、出力後の正規表現やスキーマバリデーションによる後処理、再試行戦略。

*   **脱線(Topic Drift/Off-topic):** タスクの目的から逸脱し、無関係な情報を生成したり、別の話題に移行してしまう。

    *   **抑制手法:** Systemプロンプトでの厳格なタスク定義と役割指定、思考プロセス中にゴールを再提示するFew-shot CoT、最終回答前のセルフリフレクションステップ。

*   **禁止事項違反(Violation of Prohibitions):** 個人情報や機密情報、不適切なコンテンツの出力。

    *   **抑制手法:** 入力フィルタリング、出力フィルタリング(コンテンツモデレーションAPI)、プロンプトでの明確な禁止事項の明記と罰則(例:「禁止事項を破った場合、出力は破棄されます」)。

## 改良と再評価

プロンプトとモデルの改良は、以下のフィードバックループを通じて継続的に行われます。

```mermaid
graph TD
    A["タスク定義/要件"] --> B("プロンプト設計");
    B --> C("LLMモデル");
    C --> D{"LLM出力"};
    D --> E("評価ツール");
    E --> F{"評価結果"};
    F -- 満足 --> G("デプロイ");
    F -- 不満足 --> H("誤り分析");
    H --> B;
  • A[タスク定義/要件]:LLMに解決させたい問題と期待される挙動を具体的に定義します。

  • B(プロンプト設計):ゼロショット、少数例、Chain-of-Thoughtなどのプロンプトを設計します。

  • C(LLMモデル):設計されたプロンプトをLLMに入力し、出力を生成させます。

  • D{LLM出力}:LLMが生成したテキスト出力です。

  • E(評価ツール):自動評価スクリプトや手動評価でLLM出力を評価します。

  • F{評価結果}:LLM出力のスコア、フィードバック、および成功/失敗の判定結果です。

  • G(デプロイ):評価結果が満足のいくものであれば、プロンプトを本番環境に適用します。

  • H(誤り分析):評価結果が不満足な場合、失敗モードと原因を特定します。

具体的な改良ステップ:

  1. 評価結果の集約: 多数の評価シナリオで得られたスコアとフィードバックを集計します。

  2. 誤りパターンの特定: 特定のプロンプトで繰り返し発生する誤り(例: 計算ミス、特定のフォーマット崩れ)を特定します。

  3. プロンプトの修正: 誤りパターンに基づいて、プロンプトの指示をより明確にする、Few-shot CoTの例を改善する、Systemプロンプトを強化するなどの修正を行います。特に、2024年3月発表の調査論文[2]では、CoTプロンプトの多様性や複雑さが性能に影響することが示されています。

  4. モデルパラメータの調整: temperature, top_pなどのデコーディングパラメータを調整し、出力の多様性や確実性を制御します。

  5. 再評価: 修正されたプロンプトでLLMを再度実行し、同じ評価シナリオで再評価します。このサイクルを繰り返すことで、プロンプトの最適化を図ります。

まとめ

Chain-of-Thoughtプロンプティングは、複雑な推論タスクにおいてLLMの性能と説明可能性を大幅に向上させる強力な技術です。効果的なCoTプロンプトの設計には、厳格な入出力契約の定義、多様な評価シナリオに基づいた評価、そして継続的な誤り分析と改良のフィードバックループが不可欠です。本記事で提示したフレームワークは、{{jst_today}}現在、最先端のプロンプトエンジニアリング実践に基づいており、LLM開発におけるCoTプロンプティングの活用と最適化の一助となるでしょう。Google AIブログが2022年5月に公開した解説[3]以降、この技術の応用範囲は広がり続けています。

参考文献

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

コメント

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