プロンプトエンジニアリングにおける入出力契約の設計

Tech

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

プロンプトエンジニアリングにおける入出力契約の設計

大規模言語モデル(LLM)を用いたアプリケーション開発において、モデルの振る舞いを予測可能かつ信頼性の高いものにするためには、入出力契約の厳密な設計と適用が不可欠です。これにより、モデルの出力品質を向上させ、後続のシステム連携やユーザー体験を安定させることが可能になります。

1. ユースケース定義

本稿では、カスタマーサポートの問い合わせを分類し、適切な対応方法を提案するシステムを想定します。 入力: 顧客からのテキスト形式の問い合わせ内容 出力: 問い合わせの分類(カテゴリ)、緊急度、推奨される対応(回答テンプレートIDまたはアクションコード)

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

LLMとの入出力契約は、システムの堅牢性を保証する上で極めて重要です。ここでは、データ形式、失敗時の挙動、禁止事項を明確に定義します。

2.1. 入力契約

  • 形式: プレーンテキスト文字列。

  • 長さ: 最低10文字、最大1000文字。

  • 内容: 顧客の問い合わせ本文。個人特定情報(PII)はモデルへの入力前に匿名化することを前提とします。

2.2. 出力契約

  • 形式: 厳格なJSON形式。キーは以下の通り。

    • category: 文字列(例: “製品に関する質問”, “技術サポート”, “料金プラン”, “アカウント管理”, “その他”)

    • urgency: 文字列(例: “低”, “中”, “高”, “緊急”)

    • recommended_action: 文字列(例: “FAQ_001”, “TECH_SUPPORT_ROUTE”, “BILLING_SPECIALIST”, “PASSWORD_RESET_GUIDE”, “GENERAL_INFO_EMAIL”)

    • confidence_score: 浮動小数点数(0.0~1.0)

  • 必須要素: 上記すべてのキーが必須。いずれか一つでも欠損している場合はエラーとします。

  • 失敗時の挙動:

    • JSON形式の不正、必須キーの欠損、categoryが定義済みリストにない場合: {"error": "Invalid output format or content", "details": "..."} の形式でエラー詳細を返す。

    • 処理不能な問い合わせ(内容が不明瞭すぎる、言語が特定できないなど): {"category": "その他", "urgency": "低", "recommended_action": "GENERAL_INFO_EMAIL", "confidence_score": 0.1} のように、最低信頼度で汎用的な対応を提案し、confidence_scoreを低く設定する。

  • 禁止事項:

    • モデルは顧客への直接的な応答文を生成しないこと。

    • モデルは顧客の個人情報を出力に含めないこと。

    • モデルは有害または差別的な内容を生成しないこと。

3. プロンプト設計

入出力契約に基づき、3種類のプロンプトを設計します。

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

モデルにタスクの定義と出力形式のみを指示します。

あなたはカスタマーサポートのアシスタントです。
顧客からの問い合わせ内容を分析し、以下の形式でJSONオブジェクトを生成してください。

- category: 問い合わせの分類("製品に関する質問", "技術サポート", "料金プラン", "アカウント管理", "その他"のいずれか)

- urgency: 問い合わせの緊急度("低", "中", "高", "緊急"のいずれか)

- recommended_action: 推奨される対応(定義済みのコード。例: "FAQ_001", "TECH_SUPPORT_ROUTE", "BILLING_SPECIALIST", "PASSWORD_RESET_GUIDE", "GENERAL_INFO_EMAIL")

- confidence_score: この分類と推奨への自信度(0.0~1.0の浮動小数点数)

顧客の問い合わせ:
「新しいプランにアップグレードしたいのですが、どのように手続きすれば良いですか?」

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

いくつかの正解例を示すことで、モデルの理解を深め、出力の質を向上させます。

あなたはカスタマーサポートのアシスタントです。
顧客からの問い合わせ内容を分析し、以下の形式でJSONオブジェクトを生成してください。

- category: 問い合わせの分類("製品に関する質問", "技術サポート", "料金プラン", "アカウント管理", "その他"のいずれか)

- urgency: 問い合わせの緊急度("低", "中", "高", "緊急"のいずれか)

- recommended_action: 推奨される対応(定義済みのコード。例: "FAQ_001", "TECH_SUPPORT_ROUTE", "BILLING_SPECIALIST", "PASSWORD_RESET_GUIDE", "GENERAL_INFO_EMAIL")

- confidence_score: この分類と推奨への自信度(0.0~1.0の浮動小数点数)

例1:
顧客の問い合わせ: 「パスワードを忘れてしまい、ログインできません。」
{"category": "アカウント管理", "urgency": "高", "recommended_action": "PASSWORD_RESET_GUIDE", "confidence_score": 0.95}

例2:
顧客の問い合わせ: 「先月の請求額について質問があります。明細が見たいです。」
{"category": "料金プラン", "urgency": "中", "recommended_action": "BILLING_SPECIALIST", "confidence_score": 0.88}

顧客の問い合わせ:
「新しいプランにアップグレードしたいのですが、どのように手続きすれば良いですか?」

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

モデルに推論ステップを段階的に思考させ、その上で最終的な出力を生成させることで、より複雑なタスクや曖昧な入力に対するロバスト性を高めます。

あなたはカスタマーサポートのアシスタントです。
顧客からの問い合わせ内容を分析し、思考ステップを経てから、以下の形式でJSONオブジェクトを生成してください。

思考ステップ:

1. 問い合わせの主旨を特定する。

2. 主旨から最も適切なカテゴリを決定する("製品に関する質問", "技術サポート", "料金プラン", "アカウント管理", "その他")。

3. 問い合わせ内容から緊急度を判断する("低", "中", "高", "緊急")。

4. カテゴリと緊急度に基づき、最適な推奨対応コード(例: "FAQ_001", "TECH_SUPPORT_ROUTE", "BILLING_SPECIALIST", "PASSWORD_RESET_GUIDE", "GENERAL_INFO_EMAIL")を決定する。

5. 最終的な判断に自信度(0.0~1.0)を設定する。

出力形式: JSONオブジェクト(上記2.2の出力契約を参照)。

顧客の問い合わせ:
「新しいプランにアップグレードしたいのですが、どのように手続きすれば良いですか?」

4. 評価

設計したプロンプトと入出力契約の有効性を検証するため、自動評価シナリオと擬似コードを定義します。

4.1. 評価シナリオ

  • 正例: 「インターネットに接続できません。」 → {"category": "技術サポート", "urgency": "高", "recommended_action": "TECH_SUPPORT_ROUTE", "confidence_score": 0.9}

  • 難例: 「最近、アプリの調子が悪いです。特にエラーは出ないのですが、以前より遅い気がします。」 → {"category": "製品に関する質問", "urgency": "中", "recommended_action": "FAQ_001", "confidence_score": 0.7} (具体的な情報不足)

  • コーナーケース: 「隣の家の猫が可愛いです。うちの犬は散歩に行きたがっています。」 → {"category": "その他", "urgency": "低", "recommended_action": "GENERAL_INFO_EMAIL", "confidence_score": 0.1} (タスク逸脱)

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

import json
import re

def evaluate_output(llm_output: str, expected_category: str, expected_urgency: str) -> dict:
    """
    LLMの出力を評価する関数。
    出力契約(JSON形式、カテゴリ、緊急度など)に準拠しているか、
    期待される値と一致しているかを検証する。
    """
    score = 0
    feedback = []

    # 1. JSON形式のバリデーション

    try:
        parsed_output = json.loads(llm_output)
        feedback.append("JSON_FORMAT_OK")
        score += 0.2
    except json.JSONDecodeError:
        feedback.append("JSON_FORMAT_ERROR: 出力が有効なJSONではありません。")
        return {"score": 0, "feedback": feedback}

    # 2. 必須キーの存在チェック

    required_keys = ["category", "urgency", "recommended_action", "confidence_score"]
    if all(key in parsed_output for key in required_keys):
        feedback.append("REQUIRED_KEYS_OK")
        score += 0.2
    else:
        feedback.append(f"REQUIRED_KEYS_ERROR: 必須キーが不足しています。不足: {set(required_keys) - set(parsed_output.keys())}")
        return {"score": score, "feedback": feedback} # JSONパースはできたが、キー不足で失敗

    # 3. categoryの検証(定義済みリスト)

    valid_categories = ["製品に関する質問", "技術サポート", "料金プラン", "アカウント管理", "その他"]
    if parsed_output["category"] in valid_categories:
        feedback.append("CATEGORY_VALID")
        score += 0.1
        if parsed_output["category"] == expected_category:
            feedback.append("CATEGORY_MATCH_EXPECTED")
            score += 0.2
    else:
        feedback.append(f"CATEGORY_INVALID: 未定義のカテゴリ '{parsed_output['category']}'")

    # 4. urgencyの検証(定義済みリスト)

    valid_urgencies = ["低", "中", "高", "緊急"]
    if parsed_output["urgency"] in valid_urgencies:
        feedback.append("URGENCY_VALID")
        score += 0.1
        if parsed_output["urgency"] == expected_urgency:
            feedback.append("URGENCY_MATCH_EXPECTED")
            score += 0.1
    else:
        feedback.append(f"URGENCY_INVALID: 未定義の緊急度 '{parsed_output['urgency']}'")

    # 5. confidence_scoreの範囲検証

    if 0.0 <= parsed_output["confidence_score"] <= 1.0:
        feedback.append("CONFIDENCE_SCORE_RANGE_OK")
        score += 0.1
    else:
        feedback.append(f"CONFIDENCE_SCORE_ERROR: 範囲外の値 '{parsed_output['confidence_score']}'")

    return {"score": round(score, 2), "feedback": feedback}

# 例として、正例シナリオを評価


# llm_output_sample = '{"category": "技術サポート", "urgency": "高", "recommended_action": "TECH_SUPPORT_ROUTE", "confidence_score": 0.9}'


# result = evaluate_output(llm_output_sample, "技術サポート", "高")


# print(result)

5. 誤り分析と改良

モデルの出力が契約に違反した場合、その失敗モードを特定し、適切な抑制手法を講じることで改良を行います。

5.1. 失敗モード

  1. 幻覚(Hallucination): 事実に基づかない、または存在しない recommended_action コードを生成する。

  2. 様式崩れ(Format Deviation): JSON形式が不正、必須キーの欠損、または指定されたカテゴリ/緊急度以外の値を生成する。

  3. 脱線(Off-topic Generation): 問い合わせとは無関係な情報や、顧客への直接的な応答文を生成してしまう。

  4. 禁止事項違反(Prohibited Content): 匿名化されるべき個人情報を含んだり、有害な内容を生成したりする。

5.2. 抑制手法

  1. System指示の強化: プロンプトの先頭でモデルの役割、厳格な出力形式、禁止事項を再強調します。特に、JSONスキーマの厳守を明記します。

  2. 出力パーサー/バリデーター: モデルの出力後、指定されたJSONスキーマや正規表現を用いて自動的に検証し、エラーがあればパース失敗として処理します。

  3. リトライ戦略: 不正なJSON形式や必須キー欠損が発生した場合、自動評価が失敗モードを検出した際に、モデルに「指示された形式で再生成してください」とフィードバックを与えて再実行させる。

  4. Few-shot例の拡充: 特に難例やコーナーケースに対して、期待される入出力例を追加し、モデルの学習を助けます。

  5. ガードレール/コンテンツフィルタ: モデルの出力が外部システムに渡される前に、追加のコンテンツフィルタリング層(例: PII検出、有害コンテンツ検出)を設けることで、最終的な安全性を確保します。

6. 改良と再評価のループ

プロンプトエンジニアリングは一度で完結するものではなく、継続的な評価と改良のループを通じて進化します。

graph TD
    A["プロンプト設計"] --> B{"LLM推論"};
    B --> C["出力"];
    C --> D{"評価ツール"};
    D -- 契約違反検出 --> E["誤り分析"];
    E --> F["プロンプト改良"];
    F --> A;
    D -- 契約遵守 & 高スコア --> G["デプロイ/本番"];

    subgraph 継続的改善
        A -- 新ユースケース/データ --> A;
        D -- 定期的評価 --> D;
    end

図1: プロンプト設計と改良の継続的ループ

このループを回すことで、定義された入出力契約の遵守率とタスクパフォーマンスを段階的に向上させることができます。特に、2023年10月17日にLangChainが公開したブログ記事[1]や、同月24日にarXivで公開された大規模言語モデルの評価に関する論文[2]で強調されているように、自動評価の導入は開発サイクルを加速させる鍵となります。

7. まとめ

プロンプトエンジニアリングにおける入出力契約の設計は、LLMアプリケーションの信頼性と保守性を高める上で不可欠なプロセスです。明確な契約定義、多角的なプロンプト設計、厳密な自動評価、そして継続的な誤り分析と改良のサイクルを通じて、モデルの出力品質を最大化し、ビジネス要件を満たす堅牢なシステムを構築することができます。

参考文献

[1] LangChain. (2023年10月17日). _Evaluating LLM applications_. https://www.langchain.com/blog/llm-application-evaluation/ [2] Chang, Y., et al. (2023年10月24日). _Evaluating Large Language Models: A Comprehensive Survey_. arXiv. https://arxiv.org/abs/2310.15783 [3] OpenAI. (日付不明). _Prompt Engineering Guide_. https://platform.openai.com/docs/guides/prompt-engineering [4] Google Cloud. (日付不明). _Prompt Engineering Best Practices_. https://cloud.google.com/vertex-ai/docs/generative-ai/learn/overview [5] Weng, L. (2023年3月15日). _Prompt Engineering_. Lil’Log. https://lilianweng.github.io/posts/2023-03-15-prompt-engineering/

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

コメント

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