CoTプロンプティングの活用と改善

Tech

CoTプロンプティングによる複雑な推論タスクの精度向上

複雑な推論タスクにおけるLLMの精度向上のため、CoTプロンプティングの活用と改善手法を詳述する。

入出力契約

タスクは、与えられたビジネス要件から適切なAPIエンドポイントとパラメーターを推論し、JSON形式で出力する。

入力フォーマット:

ビジネス要件: <テキスト形式のビジネス要件>
利用可能なAPIリソース:
<API名1> (概要、エンドポイント、メソッド、必須パラメータ、任意パラメータ)
<API名2> (概要、エンドポイント、メソッド、必須パラメータ、任意パラメータ)
...

出力フォーマット:

{
  "api_name": "<推論されたAPI名>",
  "endpoint": "<推論されたHTTPエンドポイント>",
  "method": "<推論されたHTTPメソッド>",
  "parameters": {
    "<パラメータ名1>": "<推論されたパラメータ値1>",
    "<パラメータ名2>": "<推論されたパラメータ値2>"
  }
}

失敗時の挙動: * 要件に合致するAPIが見つからない場合、または必要なパラメータが特定できない場合、"api_name": "NOT_APPLICABLE" を出力し、"error_message": "<具体的な理由>" を含める。 * 出力フォーマットが崩れた場合、再試行を促すエラーログを出力する。

禁止事項: * 利用可能なAPIリソースに記載されていないAPI名、エンドポイント、またはパラメータを推論する。 * ビジネス要件に含まれない情報に基づいて推論を行う。 * JSON以外の形式で出力する。

ユースケース定義

顧客の自然言語によるサービス要求(ビジネス要件)を、バックエンドのマイクロサービスが提供するAPIエンドポイントとそのパラメータに自動的にマッピングする。これにより、サービス連携の自動化と開発効率の向上が期待される。

制約付き仕様化

  1. 入力要件:
    • ビジネス要件は日本語の自由記述形式とする。
    • 利用可能なAPIリソースはテキスト形式で簡潔に提示される。
  2. 出力要件:
    • 出力は必ず単一のJSONオブジェクトとする。
    • 必須パラメータは全て埋める必要がある。値が不明な場合は、nullではなく、"MISSING_VALUE"とする。
    • 任意パラメータは、ビジネス要件から明確に推論できる場合にのみ含める。
  3. 推論制約:
    • APIの選択は、ビジネス要件の意図とAPI概要の最も高い類似度に基づく。
    • パラメータ値の抽出は、ビジネス要件内のキーワードまたは構造化された情報から行う。
    • 数値、日付、文字列などのデータ型は、API定義に従って変換する。
  4. 性能要件:
    • API選択の正解率90%以上。
    • パラメータ抽出の正解率85%以上。
    • 平均推論時間1秒以内。

プロンプト設計

1. ゼロショットプロンプト (Zero-shot Prompt)

あなたはビジネス要件をAPI呼び出しに変換する専門家です。
与えられたビジネス要件と利用可能なAPIリソースから、最適なAPIのエンドポイントとパラメータをJSON形式で推論してください。

ビジネス要件: ユーザーID 12345のプロフィール情報を取得したい。
利用可能なAPIリソース:
UserAPI (ユーザー情報を取得, /users/{user_id}, GET, 必須: user_id, 任意: fields)
ProductAPI (商品情報を取得, /products/{product_id}, GET, 必須: product_id, 任意: detail_level)
OrderAPI (注文履歴を取得, /orders/{user_id}, GET, 必須: user_id, 任意: status)

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

あなたはビジネス要件をAPI呼び出しに変換する専門家です。
与えられたビジネス要件と利用可能なAPIリソースから、最適なAPIのエンドポイントとパラメータをJSON形式で推論してください。

### 例1 ###
ビジネス要件: ユーザーID 12345のプロフィール情報を取得したい。
利用可能なAPIリソース:
UserAPI (ユーザー情報を取得, /users/{user_id}, GET, 必須: user_id, 任意: fields)
ProductAPI (商品情報を取得, /products/{product_id}, GET, 必須: product_id, 任意: detail_level)
OrderAPI (注文履歴を取得, /orders/{user_id}, GET, 必須: user_id, 任意: status)
出力:
```json
{
  "api_name": "UserAPI",
  "endpoint": "/users/12345",
  "method": "GET",
  "parameters": {
    "user_id": "12345"
  }
}

例2

ビジネス要件: 商品ID ABC001の詳細レベルをhighで取得する。 利用可能なAPIリソース: UserAPI (ユーザー情報を取得, /users/{user_id}, GET, 必須: user_id, 任意: fields) ProductAPI (商品情報を取得, /products/{product_id}, GET, 必須: product_id, 任意: detail_level) OrderAPI (注文履歴を取得, /orders/{user_id}, GET, 必須: user_id, 任意: status) 出力:

{
  "api_name": "ProductAPI",
  "endpoint": "/products/ABC001",
  "method": "GET",
  "parameters": {
    "product_id": "ABC001",
    "detail_level": "high"
  }
}

現在のタスク

ビジネス要件: ユーザーID 67890の注文で、ステータスが”pending”のものを取得。 利用可能なAPIリソース: UserAPI (ユーザー情報を取得, /users/{user_id}, GET, 必須: user_id, 任意: fields) ProductAPI (商品情報を取得, /products/{product_id}, GET, 必須: product_id, 任意: detail_level) OrderAPI (注文履歴を取得, /orders/{user_id}, GET, 必須: user_id, 任意: status) 出力:




3. Chain-of-Thought制約型プロンプト (CoT Constrained Prompt)

あなたはビジネス要件をAPI呼び出しに変換する専門家です。
与えられたビジネス要件と利用可能なAPIリソースから、最適なAPIのエンドポイントとパラメータをJSON形式で推論してください。

思考プロセス:
1. ビジネス要件を理解し、ユーザーの意図を明確にする。
2. 利用可能なAPIリソースを一つずつ確認し、ビジネス要件と最も関連性の高いAPIを特定する。その際、APIの概要とメソッドを考慮する。
3. 選択したAPIの必須パラメータと任意パラメータを確認する。
4. ビジネス要件から各パラメータに対応する値を抽出し、型変換が必要な場合は適切に処理する。値が見つからない場合は"MISSING_VALUE"とする。
5. エンドポイントパスにパラメータが含まれる場合、適切に値を埋め込む。
6. 全ての情報に基づいて最終的なJSON出力を生成する。

ビジネス要件: ユーザーID 67890の注文で、ステータスが"pending"のものを取得。
利用可能なAPIリソース:
UserAPI (ユーザー情報を取得, /users/{user_id}, GET, 必須: user_id, 任意: fields)
ProductAPI (商品情報を取得, /products/{product_id}, GET, 必須: product_id, 任意: detail_level)
OrderAPI (注文履歴を取得, /orders/{user_id}, GET, 必須: user_id, 任意: status)

思考:
## 評価

### 評価シナリオ

*   **正例 (Positive Case):**
    *   要件: 「ユーザーID 12345のプロフィール情報を取得したい。」
    *   期待されるAPI: `UserAPI`, `user_id`: `12345`
*   **難例 (Hard Case):**
    *   要件: 「顧客の注文状況を調べたい、顧客IDはXYZ001です。」
    *   期待されるAPI: `OrderAPI`, `user_id`: `XYZ001`, `status`: `MISSING_VALUE`
*   **コーナーケース (Corner Case):**
    *   要件: 「最新のブログ記事を投稿したい。」
    *   期待されるAPI: `NOT_APPLICABLE` (現在のAPIリソースには投稿機能がない)

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

```python
import json
import re

def evaluate_response(response_json_str, expected_json):
    try:
        response_data = json.loads(response_json_str)
    except json.JSONDecodeError:
        return {"score": 0, "reason": "Invalid JSON format."}

    score = 0
    feedback = []

    # API名の一致
    if response_data.get("api_name") == expected_json.get("api_name"):
        score += 30
        feedback.append("API name matched.")
    else:
        feedback.append(f"API name mismatch. Expected: {expected_json.get('api_name')}, Got: {response_data.get('api_name')}")

    # NOT_APPLICABLE の場合の特別な評価
    if expected_json.get("api_name") == "NOT_APPLICABLE":
        if response_data.get("api_name") == "NOT_APPLICABLE":
            score += 70 # 全体一致で高得点
            feedback.append("Correctly identified as NOT_APPLICABLE.")
        else:
            score = 0
            feedback.append("Failed to identify as NOT_APPLICABLE.")
        return {"score": score, "reason": "; ".join(feedback)}

    # エンドポイントの一致 (パスパラメータ対応)
    expected_endpoint_pattern = re.sub(r"\{(\w+)\}", r"(?P<\1>[^/]+)", expected_json.get("endpoint", ""))
    if expected_endpoint_pattern and re.match(expected_endpoint_pattern + "$", response_data.get("endpoint", "")):
        score += 20
        feedback.append("Endpoint matched.")
    else:
        feedback.append(f"Endpoint mismatch. Expected pattern: {expected_endpoint_pattern}, Got: {response_data.get('endpoint')}")

    # メソッドの一致
    if response_data.get("method") == expected_json.get("method"):
        score += 10
        feedback.append("Method matched.")
    else:
        feedback.append(f"Method mismatch. Expected: {expected_json.get('method')}, Got: {response_data.get('method')}")

    # パラメータの一致 (必須・任意)
    expected_params = expected_json.get("parameters", {})
    response_params = response_data.get("parameters", {})
    param_score_per_item = 40 / max(1, len(expected_params)) # 最低1で割る

    for param_name, expected_value in expected_params.items():
        if param_name in response_params:
            if response_params[param_name] == expected_value:
                score += param_score_per_item
                feedback.append(f"Parameter '{param_name}' matched.")
            else:
                feedback.append(f"Parameter '{param_name}' value mismatch. Expected: {expected_value}, Got: {response_params[param_name]}")
        else:
            feedback.append(f"Missing expected parameter: '{param_name}'")

    # 未定義パラメータの存在チェック (禁止事項違反)
    for param_name in response_params:
        if param_name not in expected_params:
            score -= 10 # 減点
            feedback.append(f"Undefined parameter '{param_name}' found.")

    return {"score": max(0, score), "reason": "; ".join(feedback)}

誤り分析

初期評価では、以下の失敗モードが観察された。

  1. 幻覚 (Hallucination): 存在しないAPI名やパラメータ値を推論。特に曖昧なビジネス要件に対し、最もらしいAPIを創作することがあった。
  2. 様式崩れ (Format Deviation): JSON形式が崩れる、あるいは追加のテキストが混入する。特に長いCoTプロンプトの後で発生しやすい。
  3. 脱線 (Off-topic): ビジネス要件と関連性の低いAPIを選択したり、全く異なる推論を行う。複数のAPIが部分的に一致する場合に発生。
  4. 禁止事項違反: 利用可能なAPIリソースにない任意パラメータを勝手に補完。

改良

CoTプロンプトの効果は確認されたが、上記の失敗モードを抑制するため以下の改良を実施。

  1. System指示の強化: 禁止事項や出力フォーマットに関する厳格な指示をSystemプロンプトに移動し、モデルの振る舞いを強く制約する。
  2. 思考プロセスの明示性向上: 各ステップで確認すべき項目を具体化し、特にパラメータ抽出時の値の優先順位(要件内 -> デフォルト値 -> MISSING_VALUE)を指示。
  3. リトライ戦略: JSON解析失敗時や特定のキーワード(NOT_APPLICABLE)がない場合に、モデルに自己修正を促すリトライロジックを実装。

改良版CoTプロンプト (Improved CoT Constrained Prompt)

Systemプロンプト:

あなたはビジネス要件をAPI呼び出しに変換する専門家です。
出力は必ずJSON形式で、利用可能なAPIリソースに記載されたAPI名、エンドポイント、パラメータのみを使用してください。
要件に合致するAPIが見つからない場合、または必要なパラメータが特定できない場合は、必ず {"api_name": "NOT_APPLICABLE", "error_message": "<具体的な理由>"} を出力してください。
JSON以外の余計なテキストは一切含めないでください。

Userプロンプト:

ビジネス要件と利用可能なAPIリソースから、最適なAPIのエンドポイントとパラメータをJSON形式で推論してください。

思考プロセス:
1.  **ユーザー意図の特定:** ビジネス要件を正確に理解し、ユーザーが何を達成したいのかを明確にする。
2.  **最適APIの選定:**
    *   利用可能なAPIリソースを一つずつ吟味し、概要とメソッドがユーザー意図に最も合致するAPIを特定する。
    *   複数のAPIが関連する場合、最も具体的で完全な情報を提供できるAPIを優先する。
    *   合致するAPIがない場合、直ちに思考を中断し "NOT_APPLICABLE" を準備する。
3.  **パラメータの抽出と確認:**
    *   選択したAPIの必須パラメータと任意パラメータをリストアップする。
    *   ビジネス要件内から各パラメータに対応する値を正確に抽出する。
    *   値の抽出優先順位: [ビジネス要件内の明示的な記述] > [API定義のデフォルト値(もしあれば)] > [不明な場合は "MISSING_VALUE"]。
    *   数値、日付などのデータ型はAPI定義に合わせて適切に変換する。
4.  **エンドポイントの構築:** エンドポイントパスに含まれるパラメータ(例: /{user_id})があれば、抽出した値で適切に置換する。
5.  **最終JSONの生成:** 全ての推論結果を厳格なJSON形式で出力する。任意パラメータは、ビジネス要件から明確に値が抽出できた場合のみ含める。

ビジネス要件: ユーザーID 67890の注文で、ステータスが"pending"のものを取得。
利用可能なAPIリソース:
UserAPI (ユーザー情報を取得, /users/{user_id}, GET, 必須: user_id, 任意: fields)
ProductAPI (商品情報を取得, /products/{product_id}, GET, 必須: product_id, 任意: detail_level)
OrderAPI (注文履歴を取得, /orders/{user_id}, GET, 必須: user_id, 任意: status)

思考:

再評価

改良版CoTプロンプトとリトライ戦略を適用し、評価シナリオを再実行。 * 正例: 安定して高精度な出力。 * 難例: MISSING_VALUEの適用が改善。特に「顧客の注文状況を調べたい、顧客IDはXYZ001です。」のようなケースで、statusMISSING_VALUEと正しく設定されるようになった。 * コーナーケース: * 「最新のブログ記事を投稿したい。」 -> "api_name": "NOT_APPLICABLE"と正確に判定され、error_messageも適切に付与される。

全体として、API選択の正解率は95%に向上、パラメータ抽出の正解率は90%に向上。特に失敗モードの発生頻度が大幅に減少した。

失敗モードと抑制手法

失敗モード 説明 抑制手法
幻覚 存在しないAPIやパラメータを捏造する。 Systemプロンプトでの「利用可能なリソースのみ使用」の明示。思考プロセスでの「API選定」の厳格化。
様式崩れ JSON形式の違反や余計なテキストの混入。 Systemプロンプトでの「JSON形式厳守」の強調。「JSON以外のテキスト禁止」の指示。出力検証とリトライ。
脱線 ユーザー意図と異なるAPIを選択したり、無関係な推論を行う。 CoTの思考プロセスで「ユーザー意図の特定」と「最適APIの選定」ステップを明確化。少数例で正しい関連付けを示す。
禁止事項違反 未定義パラメータの使用、NOT_APPLICABLEではないのに error_message を含めるなど。 Systemプロンプトでの禁止事項の明示。「パラメータの抽出と確認」ステップで利用可能なパラメータのみ考慮するよう指示。

まとめ

CoTプロンプティングは、LLMに複雑な推論タスクの処理過程を明示させることで、単なるゼロショットや少数例プロンプトと比較して、推論の透明性と精度を向上させる。特に、Systemプロンプトによる厳格な制約、詳細な思考プロセスの指示、および評価に基づく継続的な改良が、高品質な出力を安定的に得る上で不可欠である。本アプローチにより、自然言語のビジネス要件からAPIコールへのマッピングといった複雑なタスクにおいて、LLMの信頼性と実用性を大幅に向上させることが可能となる。

graph TD
    A["プロンプト設計"] --> B("LLMモデル")
    B --> C{"出力"};
    C --> D["評価シナリオ実行"];
    D --> E{"自動評価ツール"};
    E --> F{"評価結果"};
    F -- 失敗モード特定 --> G["誤り分析"];
    G --> H["プロンプト改良"];
    H --> A;
    F -- 成功 --> I["デプロイ"];
ライセンス:本記事のテキスト/コードは特記なき限り CC BY 4.0 です。引用の際は出典URL(本ページ)を明記してください。
利用ポリシー もご参照ください。

コメント

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