Chain-of-Thoughtプロンプティング応用

Tech

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

Chain-of-Thoughtプロンプティング応用

Chain-of-Thought (CoT) プロンプティングは、大規模言語モデル(LLM)が複雑な推論タスクを多段階の思考プロセスに分解し、より正確な結果を導き出すための強力な手法です。本記事では、CoTプロンプティングの具体的な応用例、プロンプト設計、評価、誤り分析、そして改良手法について詳述します。

ユースケース定義

「顧客からの問い合わせ内容(自由記述)に基づいて、関連するFAQ項目を複数抽出し、その根拠となった問い合わせ文中のキーワードを特定する」という多段階推論タスクをユースケースとして採用します。このタスクは、自然言語理解、情報検索、理由付けという複数のステップを要するため、CoTプロンプティングの恩恵を受けやすい典型例です。

入出力契約

入力契約

  • フォーマット: プレーンテキスト。顧客からの問い合わせ内容。

  • 必須情報: 顧客からの具体的な質問や要望。

  • 失敗時の挙動: 問い合わせ内容が不明瞭な場合、関連するFAQ項目を特定できない場合がある。その際は「関連FAQなし」と出力する。

  • 禁止事項: 個人を特定できる情報(PII)を含まない。公序良俗に反する内容ではないこと。

出力契約

  • フォーマット: JSON形式。

    {
      "reasoning_steps": ["ステップ1の思考", "ステップ2の思考", ...],
      "extracted_faq_items": [
        {"id": "FAQ-001", "title": "配送状況の確認について", "keywords": ["配送", "状況", "確認"]},
        {"id": "FAQ-003", "title": "返品・交換の手順", "keywords": ["返品", "交換", "手順"]}
      ],
      "summary_of_inquiry": "問い合わせ内容の要約",
      "no_related_faq": false // 関連FAQがない場合はtrue
    }
    
  • 失敗時の挙動: JSON形式の崩れ、必要なキーの欠落、または不正確な情報が含まれる場合がある。

  • 禁止事項: 入力内容にない情報を生成(幻覚)、誤ったFAQ IDの生成、思考プロセスが省略されること。

制約付き仕様化

以下の制約のもとでタスクを実行します。

  • ペルソナ: 顧客サポートAIアシスタント

  • 知識源: 事前学習済みの知識に加え、モデルに与えられる仮想FAQデータベース(例として3件程度)

  • 制約:

    • 出力は必ず上記のJSONフォーマットに従う。

    • reasoning_stepsには、問い合わせ内容の分析、キーワード抽出、FAQマッチングの思考プロセスを具体的に記述する。

    • extracted_faq_itemsは最大3件まで。関連度が高い順に並べる。

    • keywordsは、顧客の問い合わせ文中に明示的に出現し、かつFAQ項目と関連性が高い単語のみを抽出する。

    • no_related_faqは、関連するFAQが1件も特定できなかった場合にのみtrueとする。

プロンプト設計

以下に、同タスクに対するプロンプトの異なるアプローチを示します。

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

基本的な指示のみで、推論プロセスはモデルに委ねます。

あなたは顧客サポートAIアシスタントです。
以下の顧客からの問い合わせ内容に基づいて、関連するFAQ項目を抽出し、その根拠となった問い合わせ文中のキーワードを特定してください。
出力はJSON形式で、`extracted_faq_items`にはFAQのID、タイトル、キーワードを含めてください。
関連FAQがない場合は、`no_related_faq`を`true`に設定してください。

[仮想FAQデータベース]

- FAQ-001: 配送状況の確認について(キーワード:配送、状況、確認、配達)

- FAQ-002: 支払い方法の変更(キーワード:支払い、方法、変更、決済)

- FAQ-003: 返品・交換の手順(キーワード:返品、交換、手順、不良品)

[顧客からの問い合わせ]
先週注文した商品の状況を知りたいです。まだ届いていないのですが、いつ頃配達されますか?

2. 少数例プロンプト

入出力例を示すことで、期待されるフォーマットと挙動を具体的に伝えます。思考プロセスは明示しません。

あなたは顧客サポートAIアシスタントです。
以下の顧客からの問い合わせ内容に基づいて、関連するFAQ項目を抽出し、その根拠となった問い合わせ文中のキーワードを特定してください。
出力はJSON形式で、`extracted_faq_items`にはFAQのID、タイトル、キーワードを含めてください。
関連FAQがない場合は、`no_related_faq`を`true`に設定してください。

[仮想FAQデータベース]

- FAQ-001: 配送状況の確認について(キーワード:配送、状況、確認、配達)

- FAQ-002: 支払い方法の変更(キーワード:支払い、方法、変更、決済)

- FAQ-003: 返品・交換の手順(キーワード:返品、交換、手順、不良品)

[例1]
問い合わせ: 注文した商品の支払い方法をクレジットカードから銀行振込に変更したいのですが。
出力:
```json
{
  "extracted_faq_items": [
    {"id": "FAQ-002", "title": "支払い方法の変更", "keywords": ["支払い", "方法", "変更"]}
  ],
  "summary_of_inquiry": "支払い方法の変更を希望",
  "no_related_faq": false
}

[例2] 問い合わせ: 先週注文した商品の状況を知りたいです。まだ届いていないのですが、いつ頃配達されますか? 出力:

{
  "extracted_faq_items": [
    {"id": "FAQ-001", "title": "配送状況の確認について", "keywords": ["配送", "状況", "配達"]}
  ],
  "summary_of_inquiry": "商品の配送状況と配達予定について確認を希望",
  "no_related_faq": false
}
### 3. Chain-of-Thoughtプロンプト(ゼロショットCoT)

「ステップバイステップで考えよう」という指示を加え、思考プロセスを明示的に引き出します。

```text
あなたは顧客サポートAIアシスタントです。
以下の顧客からの問い合わせ内容に基づいて、関連するFAQ項目を抽出し、その根拠となった問い合わせ文中のキーワードを特定してください。
出力はJSON形式で、`reasoning_steps`には思考プロセスを記述し、`extracted_faq_items`にはFAQのID、タイトル、キーワードを含めてください。
関連FAQがない場合は、`no_related_faq`を`true`に設定してください。

[仮想FAQデータベース]

- FAQ-001: 配送状況の確認について(キーワード:配送、状況、確認、配達)

- FAQ-002: 支払い方法の変更(キーワード:支払い、方法、変更、決済)

- FAQ-003: 返品・交換の手順(キーワード:返品、交換、手順、不良品)

[顧客からの問い合わせ]
先週注文した商品の状況を知りたいです。まだ届いていないのですが、いつ頃配達されますか?

ステップバイステップで考えましょう。

4. Chain-of-Thoughtプロンプト(制約型)

CoTを促しつつ、思考プロセスや出力内容に対して具体的な制約を加えます。これは上記の「制約付き仕様化」をプロンプトに落とし込んだものです。

あなたは顧客サポートAIアシスタントです。
以下の顧客からの問い合わせ内容に基づいて、関連するFAQ項目を複数抽出し、その根拠となった問い合わせ文中のキーワードを特定してください。
思考プロセスと最終出力のJSON形式を厳守してください。

[仮想FAQデータベース]

- FAQ-001: 配送状況の確認について(キーワード:配送、状況、確認、配達)

- FAQ-002: 支払い方法の変更(キーワード:支払い、方法、変更、決済)

- FAQ-003: 返品・交換の手順(キーワード:返品、交換、手順、不良品)

[顧客からの問い合わせ]
先週注文した商品の状況を知りたいです。まだ届いていないのですが、いつ頃配達されますか?

### 思考プロセス


1.  **問い合わせ内容の分析**: 顧客の要望を正確に理解します。

2.  **キーワード抽出**: 問い合わせ文から、主要なキーワードを特定します。

3.  **FAQデータベースとの照合**: 抽出したキーワードとFAQデータベースのキーワードを比較し、関連性の高いFAQ項目を特定します。

4.  **根拠キーワードの特定**: 特定したFAQ項目に関連する、問い合わせ文中の具体的な単語を抽出します。

5.  **出力生成**: 上記の思考に基づき、指定されたJSONフォーマットで結果を生成します。関連FAQは最大3件とし、関連度順に並べます。

### 出力フォーマット

```json
{
  "reasoning_steps": ["1. ...", "2. ...", "3. ...", "4. ...", "5. ..."],
  "extracted_faq_items": [
    {"id": "FAQ-XXX", "title": "...", "keywords": ["...", "..."]}
  ],
  "summary_of_inquiry": "...",
  "no_related_faq": false
}

上記の思考プロセスと出力フォーマットに従って、結果を生成してください。

## 評価シナリオ

### 1. 正例 (Standard Case)


*   **問い合わせ**: 「購入した商品の返品方法について教えてください。不良品だったので交換も検討しています。」

*   **期待**: FAQ-003が抽出され、「返品」「交換」「不良品」がキーワードとして特定される。

### 2. 難例 (Challenging Case)


*   **問い合わせ**: 「先日頼んだものが全然来ないのですが、どうなっていますか?」

*   **期待**: FAQ-001が抽出され、「頼んだもの」「来ない」「どうなっていますか」などの意図から「配送」「状況」がキーワードとして特定される。表現の曖昧さを解釈する能力が問われる。

### 3. コーナーケース (Edge Case)


*   **問い合わせ**: 「特に質問はないのですが、サイトのデザインが素敵ですね。」

*   **期待**: 関連FAQなし(`no_related_faq: true`)と判断される。

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

Pythonを想定した擬似コードです。出力のJSON形式、思考プロセスの品質、抽出されたFAQとキーワードの正確性を評価します。

```python
import json
import re

def evaluate_response(response_text: str, expected_faq_id: str = None, expected_keywords: list = None, expect_no_faq: bool = False) -> dict:
    score = 0
    feedback = []

    # 1. JSONフォーマットの検証 (20点)

    try:
        response_json = json.loads(response_text)
        score += 20
    except json.JSONDecodeError:
        feedback.append("JSONフォーマットが不正です。")
        return {"score": score, "feedback": feedback}

    # 2. 必須キーの存在確認 (10点)

    required_keys = ["reasoning_steps", "extracted_faq_items", "summary_of_inquiry", "no_related_faq"]
    if all(key in response_json for key in required_keys):
        score += 10
    else:
        feedback.append("必須キーの一部が欠落しています。")

    # 3. no_related_faqの正確性 (10点)

    if response_json.get("no_related_faq") == expect_no_faq:
        score += 10
    else:
        feedback.append(f"no_related_faqの期待値と異なります。期待: {expect_no_faq}, 実際: {response_json.get('no_related_faq')}")

    # 4. extracted_faq_itemsの評価 (30点) - expected_faq_idが指定されている場合

    if not expect_no_faq and expected_faq_id:
        found_faq_item = next((item for item in response_json.get("extracted_faq_items", []) if item.get("id") == expected_faq_id), None)
        if found_faq_item:
            score += 10
            feedback.append(f"期待FAQ ID '{expected_faq_id}'が見つかりました。")

            # キーワードの評価 (20点)

            if expected_keywords:
                matched_keywords = set(expected_keywords) & set(found_faq_item.get("keywords", []))
                if len(matched_keywords) == len(expected_keywords): # すべての期待キーワードが含まれるか
                    score += 20
                    feedback.append(f"期待キーワードが全て含まれています: {', '.join(expected_keywords)}")
                elif len(matched_keywords) > 0:
                    score += 10
                    feedback.append(f"一部の期待キーワードが含まれています: {', '.join(matched_keywords)}")
                else:
                    feedback.append("期待キーワードが一つも含まれていません。")
        else:
            feedback.append(f"期待FAQ ID '{expected_faq_id}'が見つかりませんでした。")
    elif expect_no_faq and not response_json.get("extracted_faq_items"):
        score += 30 # 関連FAQなしが正しく、かつFAQリストが空であれば満点
        feedback.append("関連FAQが正しく抽出されませんでした(期待通り)。")
    elif expect_no_faq and response_json.get("extracted_faq_items"):
        score -= 15 # 関連FAQなしを期待したが抽出された場合
        feedback.append("関連FAQなしを期待しましたが、FAQが抽出されました。")


    # 5. reasoning_stepsの品質評価 (30点) - CoTプロンプトの場合のみ


    #   - ステップ数が適切か(例: 3-5ステップ)


    #   - 各ステップが具体的な思考を含んでいるか(キーワードで判断)

    if "reasoning_steps" in response_json and isinstance(response_json["reasoning_steps"], list):
        if 3 <= len(response_json["reasoning_steps"]) <= 5: # 妥当なステップ数
            score += 10

        # 各ステップに具体的な動詞やキーワードが含まれているか(簡易チェック)

        step_quality_score = 0
        for step in response_json["reasoning_steps"]:
            if re.search(r"(分析|抽出|照合|比較|特定|生成|理解)", step):
                step_quality_score += 5
        score += min(step_quality_score, 20) # 最大20点
        feedback.append("reasoning_stepsの品質評価を実施しました。")
    else:
        feedback.append("reasoning_stepsが存在しないか、リスト形式ではありません。")

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

# --- 評価例 ---


# response_from_llm = """...LLMの出力JSON..."""


# # 正例の評価


# # result = evaluate_response(response_from_llm, expected_faq_id="FAQ-003", expected_keywords=["返品", "交換", "不良品"])


# # 難例の評価


# # result = evaluate_response(response_from_llm, expected_faq_id="FAQ-001", expected_keywords=["配送", "状況", "配達"])


# # コーナーケースの評価


# # result = evaluate_response(response_from_llm, expect_no_faq=True)

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

LLMのプロンプト設計は、以下の継続的なフィードバックループを通じて最適化されます。

graph TD
    A["プロンプト設計"] --> B{"モデル実行"};
    B --|LLMの出力| C["評価"];
    C --|評価結果| D{"誤り分析"};
    D --|課題/改善点| E["改良プロンプト"];
    E --> A;
  • プロンプト設計 (A): 目標とするタスクと制約に基づいてプロンプトを作成します。

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

  • 評価 (C): 自動評価スクリプトや手動評価を通じて、LLMの出力品質を定量・定性的に評価します。

  • 誤り分析 (D): 評価結果に基づき、モデルが期待通りの出力を生成できなかった原因を詳細に分析します。

  • 改良プロンプト (E): 分析結果を反映し、プロンプトの指示、例、CoTの形式などを修正・強化します。

誤り分析と失敗モード

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

  1. 幻覚(Hallucination):

    • 説明: 事実に基づかない情報、特に存在しないFAQ IDやキーワードを生成する。

    • : 「FAQ-999: 未登録の問い合わせ」という架空のFAQを生成。

  2. 様式崩れ(Format Deviation):

    • 説明: 指定されたJSONフォーマットに従わない、またはJSONが破損している。

    • : キーの欠落、配列ではなく単一文字列、閉じ括弧の不足。

  3. 脱線(Task Deviation):

    • 説明: 顧客の問い合わせと無関係な情報を提供したり、指定されたタスク目的から逸脱する。

    • : FAQ抽出ではなく、一般的な挨拶や商品説明に終始する。

  4. 禁止事項違反(Violation of Prohibitions):

    • 説明: 入力契約で禁じられたPIIの出力、公序良俗に反する内容の生成など。

    • : 問い合わせ文に含まれていない個人情報を推測して出力。

  5. 不適切な推論(Flawed Reasoning):

    • 説明: reasoning_steps内の思考プロセスが論理的に破綻している、または間違った前提に基づいている。

    • : 誤ったキーワードから関連性の低いFAQを導き出す。

抑制手法

これらの失敗モードを抑制するための手法は以下の通りです。

  1. System指示の強化:

    • 内容: システムプロンプトでモデルの役割、遵守すべきルール(特にセキュリティや倫理面)、出力形式を厳しく定義します。

    • 適用: 幻覚、禁止事項違反、様式崩れへの対策。例:「厳密にJSON形式に従い、存在しないFAQ IDは生成しないでください。

  2. 検証ステップの導入:

    • 内容: CoTの思考プロセスにおいて、事実確認や論理的な一貫性をモデル自身に確認させるステップを追加します。

    • 適用: 幻覚、不適切な推論への対策。例:「ステップXで特定したFAQ IDが、実際に提供されたデータベースに存在するかを確認しなさい。

  3. 出力フォーマットの厳格化とパース:

    • 内容: JSON Schemaを用いた出力形式のバリデーションを導入し、モデルの出力が規定外であればリトライさせる。

    • 適用: 様式崩れへの対策。Pythonのjson.loads()やPydanticモデルで出力を検証。

  4. リトライ戦略:

    • 内容: モデルの出力が検証ステップで失敗した場合、元のプロンプトにエラーフィードバックを加えて再度実行する。

    • 適用: 様式崩れ、不適切な推論、幻覚への対策。例:「エラー: JSON形式が不正です。修正して再出力してください。

  5. 少数例の厳選:

    • 内容: CoTプロンプトに含める少数例を、多様なケース(正例、難例、コーナーケース)をカバーするように慎重に選定します。

    • 適用: 脱線、不適切な推論への対策。

改良と再評価

CoTプロンプティングの改良は、誤り分析で得られた知見に基づいて行われます。

  1. 思考プロセスの明示性の向上: モデルが生成するreasoning_stepsが曖昧な場合、各ステップで具体的にどのような情報を考慮すべきか、より詳細な指示をプロンプトに加えます。例えば、「顧客の意図を汲み取るためのキーワード分析」や「関連度スコアの算出方法」などを具体化します。

  2. 自己修正機能の導入: モデルの初期出力が不正確だった場合、その出力を別のプロンプトで自己評価・自己修正させる多段階プロンプティングを導入します。これは、モデルに「上記の回答について、以下の観点から自己批判し、改善点を挙げてください。その後、改善点を踏まえて再度回答を生成してください。」といった指示を与えることで実現できます。

  3. 知識源の充実: FAQデータベースが不足している場合、LLMの推論能力向上と並行して、提供するFAQデータベース自体を拡張・整備します。これにより、幻覚の発生確率を低減し、より正確なマッチングを可能にします。

これらの改良を施した後、再び評価シナリオを用いて再評価を実施し、精度、堅牢性、効率性の改善度を測定します。この繰り返しにより、CoTプロンプティングの応用は実用レベルに達します。

まとめ

Chain-of-Thoughtプロンプティングは、複雑な推論タスクにおいてLLMの性能を飛躍的に向上させる強力な手法です。本記事では、顧客問い合わせに対するFAQ抽出を例に、具体的なプロンプト設計、厳格な入出力契約、自動評価の擬似コード、そしてプロンプト設計の改善サイクルを解説しました。幻覚、様式崩れ、脱線といった一般的な失敗モードに対する抑制手法を適用し、継続的な評価と改良を行うことで、CoTプロンプティングはLLMの実用的な応用範囲を大きく広げることが可能です。今後もこの手法は、より高度なAIシステム構築の鍵となるでしょう。

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

コメント

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