LLM APIにおけるtemperature/top_pパラメータ調整のプロンプト工学

Tech

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

LLM APIにおけるtemperature/top_pパラメータ調整のプロンプト工学

本稿では、LLM APIのtemperatureおよびtop_pパラメータが生成出力に与える影響を理解し、特定のユースケース要件に合わせてこれらのパラメータを最適に調整するためのプロンプト工学的手法について詳述します。

1. ユースケース定義

特定のトピックに基づいて、読者の注目を引き、かつ内容を正確に伝えるニュース記事の見出しを複数生成するタスクを想定します。このタスクには、以下の二つの異なる生成モードが存在します。

  1. 高創造性モード: ユニークで魅力的な、多様な見出しを生成する。

  2. 高再現性モード: 事実に基づき、標準的なフォーマットで一貫した見出しを生成する。

これらのモードに応じて、temperaturetop_pの調整が重要となります。

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

LLM APIとの入出力について、以下の契約を定義します。

  • 入力形式: JSONオブジェクト

    {
      "topic": "文字列",             // 見出しを生成する対象のトピック
      "creativity_level": "low" | "medium" | "high", // 要求される創造性のレベル
      "num_headlines": 1           // 生成する見出しの数(1~5)
    }
    
  • 出力形式: JSONオブジェクト

    {
      "headlines": ["見出し1", "見出し2", ...], // 生成された見出しの配列
      "model_params": {"temperature": 0.X, "top_p": 0.Y} // 使用されたパラメータ
    }
    
    • 各見出しは最大30文字とします。
  • 失敗時の挙動:

    • APIエラー: HTTPステータスコード 5xx(内部エラー)または 4xx(リクエストエラー)を返す。

    • 形式不一致: {"error": "Output format mismatch", "details": "Expected JSON object with 'headlines' array and 'model_params'."}

    • 内容不適切: {"error": "Content policy violation", "details": "Generated content violates safety guidelines."}

  • 禁止事項:

    • 差別的、暴力的、性的に露骨な内容の生成。

    • 特定の個人や組織を特定できる情報の生成。

    • 著作権を侵害する内容の生成。

3. プロンプト設計とパラメータ調整

temperatureは生成されるトークンのランダム性を制御し、値が高いほど多様で予測不能な出力を生成します。top_pは累積確率が指定値に達するまでのトークン群のみを考慮することで、出力の多様性を制御します。一般的に、両者を同時に大きく変更すると予測が難しくなるため、片方を中心に調整することが推奨されます [1][2][3]。

  • temperature: 通常0.0(決定的)から1.0(高ランダム性)の範囲で調整されますが、OpenAI APIでは2.0まで設定可能です [1]。

  • top_p: 通常0.0(少数の高確率トークンのみ)から1.0(全てのトークンを考慮)の範囲で調整されます [1][2][3]。

以下に、創造性レベルに応じたプロンプト案と推奨パラメータを示します。

3.1. ゼロショットプロンプト(高再現性モード)

厳密な事実に基づき、標準的な見出しを求める場合。temperaturetop_pを低く設定し、出力の再現性と焦点を重視します。

System: あなたはニュース記事の見出し生成AIです。ユーザーの指定したトピックについて、事実に基づき、標準的な表現で最大30文字の見出しを生成してください。出力はJSON形式でお願いします。
User: {"topic": "月面基地建設の最新動向", "creativity_level": "low", "num_headlines": 2}

推奨パラメータ: temperature=0.2, top_p=0.1 (Google Gemini API [2]、Anthropic Claude API [3] の推奨範囲を考慮)

3.2. 少数例プロンプト(中間モード)

特定のスタイルや表現のヒントを与えつつ、ある程度の多様性を許容する場合。temperaturetop_pを中程度に設定します。

System: あなたはニュース記事の見出し生成AIです。以下の例を参考に、ユーザーの指定したトピックについて、創造性と正確性のバランスが取れた最大30文字の見出しを生成してください。出力はJSON形式でお願いします。
Example Input: {"topic": "AI倫理の新たな課題", "creativity_level": "medium", "num_headlines": 2}
Example Output: {"headlines": ["AI倫理の新局面:公正性と透明性の追求", "進化するAI、問われる人間の倫理:課題と展望"], "model_params": {"temperature": 0.7, "top_p": 0.8}}
User: {"topic": "最新の量子コンピュータ開発", "creativity_level": "medium", "num_headlines": 3}

推奨パラメータ: temperature=0.7, top_p=0.8

3.3. Chain-of-Thought制約型プロンプト(高創造性モード)

モデルに思考プロセスを明示させ、自由な発想を促しつつ、最終的な出力形式を厳密に指定する場合。temperaturetop_pを高く設定し、モデルの創造性を最大限に引き出します。

System: あなたは経験豊富なニュースエディターです。ユーザーの指定したトピックと創造性レベルに基づき、魅力的なニュース記事の見出しを複数生成してください。
思考プロセス:

1. まず、提供されたトピックの核となるキーワードと主要な論点を特定します。

2. 次に、指定された創造性レベルに応じた複数の見出しアイデアを自由に発想します。

   - 'low'ならば、事実に基づいた標準的な表現を重視。

   - 'medium'ならば、少しひねりを加えつつも正確さを保持。

   - 'high'ならば、型にとらわれず、読者の好奇心を刺激するようなユニークな表現を追求。

3. 発想したアイデアの中から、出力数と文字数制限(最大30文字)を満たす最適な見出しを選定します。

4. 最終的に、選定した見出しをJSON形式で出力します。

User: {"topic": "深海探査技術の革新", "creativity_level": "high", "num_headlines": 4}

推奨パラメータ: temperature=1.0, top_p=1.0

4. 評価シナリオと自動評価

生成された見出しの品質を評価するために、以下のシナリオと自動評価ルーブリックを定義します。

4.1. 評価シナリオ

  • 正例: {"topic": "月面基地建設の最新動向", "creativity_level": "medium", "num_headlines": 2}

    • 期待される結果: トピックに関連し、多様性があり、かつ適切に創造性のある見出しが2つ生成される。
  • 難例: {"topic": "量子コンピュータの未来:課題と展望", "creativity_level": "high", "num_headlines": 3}

    • 期待される結果: 専門的なトピックに対して、創造的でありながらも意味が通じ、脱線せず、かつ読者の興味を引く見出しが3つ生成される。
  • コーナーケース: {"topic": "昨日の東京の天気", "creativity_level": "low", "num_headlines": 1}

    • 期待される結果: 決定的で事実に基づいた、標準的な見出しが1つ生成される。

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

import json
import re

def evaluate_headline_generation(response_raw: str, input_data: dict) -> dict:
    """
    LLMからの見出し生成出力を自動評価する擬似コード。

    Args:
        response_raw (str): LLMからの生の出力文字列。
        input_data (dict): プロンプトへの入力データ (topic, creativity_level, num_headlines)。

    Returns:
        dict: 評価スコア、フィードバック、エラー情報を含む辞書。
    """
    score = 0.0
    feedback = []
    error = None

    # 1. 出力形式の検証 (JSONパース)

    try:
        response_json = json.loads(response_raw)
    except json.JSONDecodeError:
        error = "JSONDecodeError: Output is not a valid JSON."
        return {"score": score, "feedback": feedback, "error": error}

    if "headlines" not in response_json or not isinstance(response_json["headlines"], list):
        error = "FormatError: 'headlines' key missing or not a list."
        return {"score": score, "feedback": feedback, "error": error}

    if "model_params" not in response_json or not isinstance(response_json["model_params"], dict):
        error = "FormatError: 'model_params' key missing or not a dict."
        return {"score": score, "feedback": feedback, "error": error}

    headlines = response_json["headlines"]
    expected_num = input_data["num_headlines"]
    topic = input_data["topic"]
    creativity_level = input_data["creativity_level"]

    # 2. 生成見出し数の検証 (10%)

    if len(headlines) == expected_num:
        score += 0.1
    else:
        feedback.append(f"Headline count mismatch: Expected {expected_num}, Got {len(headlines)}.")

    # 3. 各見出しの文字数検証 (20%)

    all_lengths_ok = True
    for h in headlines:
        if not isinstance(h, str):
            feedback.append(f"Non-string headline found: {h}.")
            all_lengths_ok = False
            break
        if len(h) > 30:
            feedback.append(f"Headline too long (>{30} chars): '{h}' ({len(h)} chars).")
            all_lengths_ok = False
    if all_lengths_ok:
        score += 0.2

    # 4. トピック関連性の検証 (40%)


    # 簡易的なキーワードマッチング。より高度には埋め込みベクトル類似度を使用。

    topic_keywords = re.findall(r'\b\w+\b', topic.lower()) # トピックからキーワード抽出
    relevant_headlines_count = 0
    for h in headlines:
        if any(keyword in h.lower() for keyword in topic_keywords if len(keyword) > 2): # 短すぎるキーワードは除く
            relevant_headlines_count += 1

    relevance_ratio = relevant_headlines_count / len(headlines) if headlines else 0
    if relevance_ratio >= 0.75: # 75%以上の見出しがトピック関連
        score += 0.4
    else:
        feedback.append(f"Low topic relevance: {relevant_headlines_count}/{len(headlines)} headlines relevant.")

    # 5. 創造性/多様性の検証 (30%)

    unique_headlines = set(h.lower() for h in headlines) # 大文字小文字を無視して重複チェック
    diversity_ratio = len(unique_headlines) / len(headlines) if headlines else 0

    if creativity_level == "low":

        # 低創造性ではある程度の多様性を許容しつつ、標準的な表現が多いことを期待

        if diversity_ratio >= 0.7: score += 0.3 # 0.7以上であればOKとする
        else: feedback.append(f"Diversity too low for 'low' creativity: {diversity_ratio:.2f}.")
    elif creativity_level == "medium":
        if diversity_ratio >= 0.85: score += 0.3
        else: feedback.append(f"Diversity lower than expected for 'medium' creativity: {diversity_ratio:.2f}.")
    elif creativity_level == "high":
        if diversity_ratio >= 0.95: score += 0.3 # 高創造性では高い多様性を期待
        else: feedback.append(f"Diversity too low for 'high' creativity: {diversity_ratio:.2f}.")

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

# 想定される入出力と評価呼び出しの例:


# input_data = {"topic": "月面基地建設の最新動向", "creativity_level": "medium", "num_headlines": 2}


# raw_output = '{"headlines": ["月面基地、建設加速へ:国際協力進む", "宇宙開発の新時代:月面拠点計画の全貌"], "model_params": {"temperature": 0.7, "top_p": 0.8}}'


# result = evaluate_headline_generation(raw_output, input_data)


# print(result)

5. 誤り分析と抑制手法

LLMの生成プロセスで発生しうる主要な失敗モードと、それらを抑制するための手法を以下に示します。

  • 幻覚(Hallucination):

    • 失敗モード: 事実に基づかない情報を生成したり、トピックから逸脱した内容を創出したりする。

    • 抑制手法:

      • System指示: プロンプトのSystemパートで「事実に基づかない情報を生成しない」と明確に指示する。

      • 検証ステップ: 生成後、外部の知識ベースやファクトチェッカーを用いて内容の真偽を確認するステップを導入する。

      • パラメータ調整: temperaturetop_pを低く設定し、モデルの生成の幅を狭める。

  • 様式崩れ:

    • 失敗モード: 要求されたJSON形式や文字数制限などの出力契約に違反する。

    • 抑制手法:

      • System指示: 出力形式の指定(JSONスキーマ、文字数制限)を厳格にプロンプトに含める。

      • 検証ステップ: 生成後、JSONパーサーや正規表現を用いて出力形式を自動検証する。

      • リトライ戦略: 検証失敗時に、エラーメッセージとともに再生成を指示するリトライロジックを実装する。

  • 脱線(Off-topic):

    • 失敗モード: 指定されたトピックから外れた見出しを生成する。

    • 抑制手法:

      • Chain-of-Thought: モデルに思考プロセスを段階的に踏ませ、「まずトピックのキーワードを特定する」などのステップを強制する。

      • 少数例学習: 適切なトピック関連性を持つ見出しの例をいくつか提示し、学習を促す。

      • パラメータ調整: temperaturetop_pを低めに設定し、トピックに集中させる。

  • 禁止事項違反:

    • 失敗モード: 差別的、暴力的、性的な内容など、安全ポリシーに違反する見出しを生成する。

    • 抑制手法:

      • 安全設定の活用: LLM APIが提供する安全設定(コンテンツフィルタリング)を最大限に活用する [2]。

      • System指示: 「不適切な内容や個人を特定する情報は生成しない」と明示的に指示する。

      • 後処理フィルタリング: 生成された見出しを、禁止ワードリストやNLUモデルでフィルタリングする。

6. 改良と再評価のサイクル

プロンプトとパラメータの調整は、一連の継続的なサイクルとして実施されます。

graph TD
    A["ユースケース定義"] --> B["入出力契約"];
    B --> C["プロンプト初期設計"];
    C --> D{"パラメータ選択"};
    D -- 低創造性 --> E["temperature=0.2, top_p=0.1"];
    D -- 中間 --> F["temperature=0.7, top_p=0.8"];
    D -- 高創造性 --> G["temperature=1.0, top_p=1.0"];
    E --> H["LLM API呼び出し"];
    F --> H;
    G --> H;
    H --> I["出力生成"];
    I --> J["自動評価"];
    J -- 評価OK --> K["目的達成/デプロイ"];
    J -- 評価NG --> L["誤り分析"];
    L --> M["改良"];
    M -- パラメータ調整 --> D;
    M -- プロンプト修正 --> C;

このサイクルでは、評価フェーズで発見された課題(例えば、創造性が不足している、脱線が多いなど)に基づいて、プロンプトの記述内容やtemperature/top_pの値を調整します。例えば、見出しが単調すぎる場合はtemperaturetop_pを微増させ、逆に脱線が多い場合は減らすといった具体的な調整を行います。

7. まとめ

LLM APIのtemperaturetop_pパラメータは、生成される出力の多様性と再現性を制御する上で不可欠です。これらのパラメータは、プロンプト設計と密接に連携し、ユースケースに応じて最適化されるべきです。本稿で示したプロンプト設計パターン、自動評価、誤り分析、そして継続的な改良サイクルは、LLMアプリケーション開発において、これらのパラメータを効果的に管理し、期待される出力品質を達成するための堅牢なフレームワークを提供します。

参照情報

  1. OpenAI. “API Reference – Chat.” 最終アクセス日: 2024年7月25日. https://platform.openai.com/docs/api-reference/chat/object

  2. Google AI for Developers. “Safety settings.” 最終アクセス日: 2024年7月25日. https://ai.google.dev/gemini-api/docs/safety_settings

  3. Anthropic. “API Reference – Sampling parameters.” 最終アクセス日: 2024年7月25日. https://docs.anthropic.com/claude/reference/sampling

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

コメント

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