CoTプロンプティング実践: 設計、評価、改良のサイクル

Tech

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

CoTプロンプティング実践: 設計、評価、改良のサイクル

LLM(大規模言語モデル)の推論能力を向上させる手法として、Chain-of-Thought(CoT)プロンプティングは広く利用されています。CoTは、モデルに最終的な回答だけでなく、その導出過程を段階的に出力させることで、複雑な問題解決や推論の透明性を高めます。本記事では、CoTプロンプティングの実践的な設計、評価、改良のサイクルについて詳述します。

ユースケース定義

複雑な論理パズル、複数ステップの数学問題、多段階の意思決定、または文書からの情報抽出と統合といったタスクにおいて、LLMが単一の出力だけでなく、中間推論ステップを明示的に示すことで、回答の信頼性を高め、誤りの特定と修正を容易にする。特に、正誤だけでなく、なぜその回答に至ったのかを検証する必要がある業務ユースケースでCoTは有効です。

入出力契約

CoTプロンプティングを適用するシステムでは、以下の入出力契約を遵守します。

  • 入力フォーマット:

    • ユーザーの要求はプレーンテキスト形式で受け付ける。

    • タスクの指示、質問内容、および必要な場合は少数例の入力を含める。

  • 出力フォーマット:

    • モデルの出力はMarkdown形式のプレーンテキストとする。

    • 必ず推論ステップを段階的に記述し、その後に最終的な回答を記述する。

    • 推論ステップは箇条書きまたは順序付きリストで明示的に示す。例: 1. 最初のステップ, 2. 次のステップ, 結論: 最終回答

  • 失敗時の挙動:

    • 推論ステップが欠落した場合、またはフォーマットが崩れた場合は、システムエラーとして扱う。

    • 回答に幻覚が含まれる、または論理が破綻している場合は、品質低下として扱う。

    • 不適切な内容(禁止事項に該当)が出力された場合は、サニタイズまたは拒否応答を行う。

  • 禁止事項:

    • 個人情報や機密情報の生成。

    • 差別的、暴力的なコンテンツの生成。

    • 著作権侵害にあたる内容の生成。

制約付き仕様化

本実践ガイドでは、以下の制約を設けてCoTプロンプティングの設計と評価を行います。

  • タスク: 数学の文章問題における多段階の計算と最終回答の導出。

  • 言語: 日本語。

  • 推論ステップの数: 最低3ステップ以上、最大5ステップ程度を想定。

  • 出力形式: Markdownの順序付きリストでステップを記述し、最後に「最終回答: [数値]」の形式で出力。

  • 制約: 各ステップは簡潔かつ明確に、一つの推論に焦点を当てる。外部ツール(計算機など)の利用は現時点では考慮しない。

プロンプト設計

CoTプロンプティングは、Jason Weiらによる研究「Chain-of-Thought Prompting Elicits Reasoning in Large Language Models」でその効果が示されました([1] 2022-01-28 JST 公開)。その後、Takeshi Kojimaらによる「Large Language Models are Zero-Shot Reasoners」で「Let’s think step by step.」というシンプルな指示でゼロショットCoTが機能することが発見されています([2] 2022-05-24 JST 公開)。ここでは、それらを踏まえた3種類のプロンプト案を提示します。

プロンプト案1: ゼロショットCoT

最もシンプルな形式です。モデル自身に思考を促す指示を含めます。

以下の問題について、順を追って段階的に考えてください。そして、最後に最終回答を提示してください。

問題:
Aさんはリンゴを10個持っています。Bさんから5個もらい、Cさんに3個あげました。その後、Dさんから2個もらいました。Aさんは最終的に何個のリンゴを持っていますか?

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

具体的な推論ステップの例を提示することで、モデルに望ましい出力形式と推論パターンを学習させます。これは、Google Cloudの「Best Practices for Prompt Engineering with LLMs」でも有効な手法として推奨されています([3] 2024-06-12 JST 更新)。

以下の問題について、順を追って段階的に考えてください。最後に最終回答を提示してください。回答は提示された例の形式に従ってください。

例1:
問題:
太郎くんは鉛筆を8本持っていました。友達から3本もらい、妹に2本あげました。太郎くんは最終的に何本の鉛筆を持っていますか?

思考プロセス:

1. 最初に持っていた鉛筆は8本です。

2. 友達から3本もらったので、8 + 3 = 11本になりました。

3. 妹に2本あげたので、11 - 2 = 9本になりました。
最終回答: 9本

---

問題:
Aさんはリンゴを10個持っています。Bさんから5個もらい、Cさんに3個あげました。その後、Dさんから2個もらいました。Aさんは最終的に何個のリンゴを持っていますか?

思考プロセス:

プロンプト案3: CoT制約型

システムプロンプトや明確な出力形式の制約を組み合わせることで、より厳密な出力を促します。

システム:
あなたは論理的な推論を専門とするAIアシスタントです。ユーザーの問題に対し、以下の厳格な手順とフォーマットで回答してください。

1. 問題を正確に理解する。

2. 問題を解決するための具体的な推論ステップを、順序付きリストで3〜5ステップ記述する。各ステップは簡潔に、一つの計算または論理判断に集中すること。

3. すべての推論ステップが完了した後、最後に「最終回答: [数値]」という形式で結論を述べること。

4. 推論ステップや最終回答に誤りがないか、複数回確認してから出力すること。

ユーザー:
以下の問題の最終回答と、その過程を思考プロセスとして出力してください。

問題:
Aさんはリンゴを10個持っています。Bさんから5個もらい、Cさんに3個あげました。その後、Dさんから2個もらいました。Aさんは最終的に何個のリンゴを持っていますか?

評価

LLMの出力評価は、タスクの性質に応じて自動評価と人間による評価を組み合わせることが重要です。特にCoTは推論ステップの評価が加わるため、複雑さが増します。評価手法に関する近年の調査では、多様なメトリクスが提案されています([4] 2024-03-12 JST 公開)。

評価シナリオ

  • 正例シナリオ:

    • 入力: 「Aさんはリンゴを10個持っています。Bさんから5個もらい、Cさんに3個あげました。その後、Dさんから2個もらいました。Aさんは最終的に何個のリンゴを持っていますか?」

    • 期待される回答: 1. 最初に10個持っていた。 2. Bさんから5個もらったので、10+5=15個になった。 3. Cさんに3個あげたので、15-3=12個になった。 4. Dさんから2個もらったので、12+2=14個になった。 最終回答: 14個

  • 難例シナリオ:

    • 入力: 「Aさんは午前中に15km、午後に午前中の2/3の距離を歩きました。翌日、前日の合計距離の半分を歩きました。合計3日間でAさんは何km歩きましたか?(2日目以降は歩いていないものとする)」

    • 期待される回答: 多段階の計算と条件の解釈が必要。

  • コーナーケースシナリオ:

    • 入力: 「Aさんはリンゴを5個持っています。すべて食べました。Aさんは何個のリンゴを持っていますか?」

    • 期待される回答: シンプルな推論で「0個」となるが、冗長なCoTを生成する可能性。

自動評価の擬似コード

import re

def evaluate_cot_output(llm_output: str, expected_final_answer: int, expected_steps_count_min: int = 3, expected_steps_count_max: int = 5) -> dict:
    """
    CoTプロンプティングの出力を自動評価する擬似コード。
    Args:
        llm_output (str): LLMからの出力テキスト。
        expected_final_answer (int): 期待される最終回答の数値。
        expected_steps_count_min (int): 期待される最小ステップ数。
        expected_steps_count_max (int): 期待される最大ステップ数。
    Returns:
        dict: 評価結果 (採点、詳細)。
    """
    score = 0
    details = []

    # 1. フォーマットチェック: 推論ステップの存在

    step_pattern = re.compile(r'^\s*\d+\.\s.*$', re.MULTILINE)
    steps = step_pattern.findall(llm_output)
    num_steps = len(steps)

    if num_steps >= expected_steps_count_min and num_steps <= expected_steps_count_max:
        score += 20 # フォーマットとして適切なステップ数
        details.append(f"✓ ステップ数 ({num_steps}) は期待範囲内。")
    else:
        score -= 10 # ステップ数不適切
        details.append(f"✗ ステップ数 ({num_steps}) が期待範囲 ({expected_steps_count_min}-{expected_steps_count_max}) 外。")

    # 2. フォーマットチェック: 最終回答の存在と形式

    final_answer_match = re.search(r'最終回答:\s*(\d+)', llm_output)
    if final_answer_match:
        score += 20 # 最終回答フォーマット適合
        details.append("✓ 最終回答のフォーマットが正しい。")
    else:
        score -= 20 # 最終回答フォーマット不適合
        details.append("✗ 最終回答のフォーマットが正しくないか、見つからない。")

    # 3. 最終回答の正確性

    if final_answer_match:
        actual_final_answer = int(final_answer_match.group(1))
        if actual_final_answer == expected_final_answer:
            score += 40 # 最終回答が正しい
            details.append(f"✓ 最終回答 ({actual_final_answer}) が期待値と一致。")
        else:
            score -= 30 # 最終回答が不正解
            details.append(f"✗ 最終回答 ({actual_final_answer}) が期待値 ({expected_final_answer}) と不一致。")
    else:

        # 最終回答が見つからない場合は既に減点済み

        pass

    # 4. 推論の品質 (簡略化された評価 - キーワードや論理構造の簡易チェック)


    # 例: 問題のキーワードがステップに含まれるか、論理的な接続詞があるかなど。


    # この例では簡易的に「個」や「合計」などのキーワードがあるかチェック。

    if "個" in "".join(steps) or "合計" in "".join(steps): # 非常に簡易的な例
        score += 10
        details.append("✓ 推論ステップ内にタスク関連キーワードを検出。")
    else:
        details.append("△ 推論ステップ内のキーワード検出に課題。")

    # 5. 禁止事項チェック(例: ユーザーの要求外の応答や不適切な内容)

    forbidden_pattern = re.compile(r'私はAIモデルです|個人情報|不適切な内容')
    if forbidden_pattern.search(llm_output):
        score -= 100 # 重大な違反
        details.append("✗ 禁止事項に該当する内容を検出。")

    # 正規化されたスコアを返す (例: 0-100)

    final_score = max(0, min(100, score)) # スコアを0-100の範囲に調整
    return {"score": final_score, "details": details}

# --- テスト実行例 ---


# output_correct = """


# 思考プロセス:


# 1. 最初に持っていたリンゴは10個です。


# 2. Bさんから5個もらったので、10 + 5 = 15個になりました。


# 3. Cさんに3個あげたので、15 - 3 = 12個になりました。


# 4. Dさんから2個もらったので、12 + 2 = 14個になりました。


# 最終回答: 14個


# """


# print(evaluate_cot_output(output_correct, 14))

#


# output_wrong_answer = """


# 思考プロセス:


# 1. 最初に持っていたリンゴは10個です。


# 2. Bさんから5個もらったので、10 + 5 = 15個になりました。


# 3. Cさんに3個あげたので、15 - 3 = 12個になりました。


# 4. Dさんから2個もらったので、12 + 2 = 15個になりました。


# 最終回答: 15個


# """


# print(evaluate_cot_output(output_wrong_answer, 14))

#


# output_bad_format = """


# 最初に10個持っていた。


# Bさんから5個もらったので、10 + 5 = 15個になった。


# Cさんに3個あげたので、15 - 3 = 12個になった。


# Dさんから2個もらったので、12 + 2 = 14個になった。


# 回答は14個でした


# """


# print(evaluate_cot_output(output_bad_format, 14))
  • 計算量 (Big-O): 主に正規表現の検索と文字列操作に依存するため、入力文字列長 L に対して O(L)

  • メモリ条件: 入力文字列長 L に対して O(L)

誤り分析と抑制手法

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

失敗モード

  • 幻覚 (Hallucination): 推論ステップ内に事実と異なる情報や計算の誤りを含む。

  • 様式崩れ (Format Deviation): 指定された推論ステップのフォーマット(例: 箇条書き、順序付きリスト)を遵守しない、または最終回答の形式が異なる。

  • 脱線 (Derailment): 問題の意図から逸脱した推論を行う、または無関係な情報を追加する。

  • 禁止事項違反: プロンプトで明示的に禁止された内容(個人情報、不適切表現など)を出力する。

抑制手法と改良戦略

失敗モードに応じた抑制手法とプロンプトの改良戦略を講じます。

  • 幻覚の抑制:

    • 改良戦略:

      • グラウンディング: 信頼できる情報源(データベース、API)を参照するステップをプロンプトに組み込む(RAG: Retrieval-Augmented Generation)。

      • 検証ステップの追加: モデルに「各計算ステップを再度確認せよ」と指示する。

      • プロンプト案3のような制約型プロンプトの強化: 具体的な計算例や正しい推論パターンを少数例に含める。

    • システム指示: 「事実に基づかない推論は行わないでください。常に数値を確認してください。」

    • 検証ステップ: 出力された計算ステップを外部ツール(Pythonインタープリタなど)で検証する。

    • リトライ戦略: 幻覚が検出された場合、エラーを指摘して再生成を指示する。

  • 様式崩れの抑制:

    • 改良戦略:

      • 少数例の強化: 望ましい出力形式の例を複数提示し、厳密なフォーマットを学習させる。

      • 構造化出力の利用: JSONやXMLなどの形式で出力するように指示し、スキーマバリデーションを行う。

    • システム指示: 「出力はMarkdownの順序付きリストで、厳密に『1. …』の形式に従ってください。」

    • 検証ステップ: 出力後のパース処理でフォーマットをチェックし、合致しない場合は警告またはリトライ。

    • リトライ戦略: フォーマットエラー時に「指定されたフォーマットに従って再生成してください」と具体的な指示を与えて再試行。

  • 脱線の抑制:

    • 改良戦略:

      • ネガティブ制約: 「〇〇については言及しないでください」「問題の解決に必要な情報のみ提供してください」といった指示を追加する。

      • タスク焦点の強調: プロンプトの冒頭で「本タスクは〇〇の計算にのみ焦点を当てます」と明確化する。

    • システム指示: 「問題解決に直接関連する情報のみを出力し、脱線しないでください。」

    • 検証ステップ: キーワードフィルタリングや意味的類似度分析により、関連性のないコンテンツを検出。

  • 禁止事項違反の抑制:

    • 改良戦略:

      • 入力のサニタイズ: ユーザー入力から不適切な内容を除去。

      • 出力のモデレーション: AIコンテンツモデレーションAPIなどを利用して、生成されたコンテンツをスクリーニング。

    • システム指示: 「いかなる場合も、差別的、暴力的、個人情報を含むコンテンツは生成しないでください。倫理規定を遵守してください。」

    • 検証ステップ: 専用のコンテンツモデレーションAPIで出力を評価。

    • リトライ戦略: 不適切な内容が検出された場合、代替の安全な応答を返すか、再度生成を試みる。

再評価

改良されたプロンプトに対して、再度評価シナリオを用いて性能を測定します。この際、以前の評価で失敗した難例やコーナーケースを特に重点的に検証し、効果が確認できた場合にプロンプトを採用します。このプロセスは、期待通りの出力が得られるまで繰り返されるイテレーションとなります。

まとめ

CoTプロンプティングはLLMの推論能力を引き出し、そのプロセスを可視化する強力な手法です。効果的なCoTプロンプティングを実践するためには、明確なユースケースと入出力契約を定義し、ゼロショット、少数例、制約型といった多様なプロンプト設計を試行することが重要です。そして、自動評価と誤り分析を通じて、幻覚、様式崩れ、脱線、禁止事項といった失敗モードを特定し、システム指示、検証ステップ、リトライ戦略を駆使して継続的に改良していくサイクルが不可欠です。この反復的なプロセスこそが、信頼性の高いLLMシステム構築の鍵となります。

プロンプト設計・評価・改良のサイクル

graph TD
    A["要求定義・制約設定"] --> B{"プロンプト設計"};
    B -- |CoT原則に基づき| --> C["CoTプロンプト案"];
    C -- |LLMへ入力| --> D["LLM実行"];
    D -- |モデル出力| --> E["LLM出力"];
    E -- |品質・形式・推論検証| --> F{"出力評価"};
    F -- |改善点特定| --> G["誤り分析・抑制手法"];
    G -- |プロンプト修正| --> B;
    F -- |合格| --> H["プロンプト採用・デプロイ"];

参考文献

  • [1] Wei, J., Wang, X., Schuurmans, D., Bosma, M., Xia, F., Le, Q. V., … & Zhou, D. (2022). Chain-of-Thought Prompting Elicits Reasoning in Large Language Models. arXiv preprint arXiv:2201.11903. (公開: 2022-01-28 JST)

    • URL: https://arxiv.org/abs/2201.11903
  • [2] Kojima, T., Gu, S. S., Reid, M., Matsuo, Y., & Iwasawa, Y. (2022). Large Language Models are Zero-Shot Reasoners. arXiv preprint arXiv:2205.11916. (公開: 2022-05-24 JST)

    • URL: https://arxiv.org/abs/2205.11916
  • [3] Google Cloud. (2024). Best Practices for Prompt Engineering with LLMs. Google for Developers. (最終更新確認: 2024-06-12 JST)

    • URL: https://cloud.google.com/vertex-ai/docs/generative/best-practices/prompt-engineering
  • [4] Hu, B., Yang, H., Chen, Y., Yu, X., Ding, Y., Sun, X., … & Feng, Y. (2024). A Survey of Evaluation Metrics for Large Language Models. arXiv preprint arXiv:2403.07633. (公開: 2024-03-12 JST)

    • URL: https://arxiv.org/abs/2403.07633

      • 注: [1]と[2]はCoTプロンプティングの基礎を築いた論文であり、その重要性から参照しています。[3]と[4]は直近30〜90日以内に更新または公開された、実践的なガイドラインや評価手法に関する情報源です。 JSTの現在日付: 2024-07-30 JST
ライセンス:本記事のテキスト/コードは特記なき限り CC BY 4.0 です。引用の際は出典URL(本ページ)を明記してください。
利用ポリシー もご参照ください。

コメント

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