出力トークン数の最適化戦略

LLM/プロンプトエンジニアリング

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

出力トークン数の最適化戦略

LLMの出力トークン数を最適化することは、APIコスト削減と応答速度向上に直結します。本稿では、プロンプト設計、評価、改良のサイクルを通じた最適化戦略を解説します。

ユースケース定義

特定のビジネス要件として、ニュース記事から要点のみを抽出するタスクを想定します。出力は簡潔で、指定されたトークン数以下に収める必要があります。過剰な情報や冗長な表現は排除し、コアな事実のみを抽出することが求められます。

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

このタスクにおける入出力契約を以下に定義します。

入力契約

  • フォーマット: JSON形式。以下のキーを必須とします。
    • "article_title": 記事のタイトル(文字列)
    • "article_body": 記事本文(文字列)
    • "max_tokens": 出力サマリーの最大トークン数(整数)。この制約はモデルのネイティブトークンカウントに基づきます。
  • データ型: すべての文字列はUTF-8エンコード。

出力契約

  • フォーマット: JSON形式。以下のキーを必須とします。
    • "summary": 記事本文の要約(文字列)。
    • "token_count": 生成されたサマリーの実際のトークン数(整数)。
  • 制約: "summary" のトークン数は、入力の "max_tokens" を超過してはなりません。

失敗時の挙動

  • トークン数超過: "summary" のトークン数が入力の "max_tokens" を超過した場合、モデルは警告をJSON内に含めるか、超過した部分を自動的に切り捨てる試みを行います。理想的には、この場合も完全なJSON形式を維持します。
  • フォーマット崩れ: 出力がJSON形式でない場合、または必須キーが存在しない場合、パースエラーが発生し、クライアント側で処理失敗と判断します。
  • 内容の脱線: 要約が記事内容から逸脱している場合、クライアント側で品質問題と判断されます。

禁止事項

  • 出力に記事タイトルやURLなどのメタ情報を直接含めること。
  • 要約以外の追加情報(例:「以下は記事の要約です:」のような前置き、免責事項)を含めること。
  • Markdown以外の形式や、不要なマークアップ(例:強調、箇条書き)を使用すること。ただし、要約内容が箇条書きとして自然な場合は許容されます。

プロンプト設計

以下に、ニュース記事の要約タスクにおける3種類のプロンプト案を提示します。目標は、指定された最大トークン数内で高品質な要約を生成することです。

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

簡潔な指示で、出力形式とトークン数を指定します。

ニュース記事を読み、主要なポイントのみを抽出し、簡潔な要約を生成してください。
出力はJSON形式で、キーは"summary"と"token_count"としてください。
summaryのトークン数は最大{{max_tokens}}に厳守してください。

記事タイトル: {{article_title}}
記事本文: {{article_body}}

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

具体的な入出力例を提供し、モデルに期待する挙動を学習させます。これにより、出力の安定性と品質が向上する可能性があります。

あなたはニュース記事を簡潔に要約する専門家です。以下の指示に従い、記事の主要なポイントのみを抽出し、指定された最大トークン数以内で要約を生成してください。出力はJSON形式で、キーは"summary"と"token_count"としてください。

---
例1:
記事タイトル: 新技術による省エネエアコン発表
記事本文: XYZ社は、AIを搭載した新しい省エネエアコン「エコクール2.0」を発表しました。このエアコンは、室内の人の動きや外部の気象データをリアルタイムで分析し、最適な温度設定を自動調整します。これにより、従来のモデルと比較して最大30%の電力消費削減が見込まれます。市場への投入は来月からで、初期ロットは限定販売されます。
最大トークン数: 30
出力:
```json
{
  "summary": "XYZ社はAI搭載の省エネエアコン「エコクール2.0」を発表。人や気象データを分析し電力消費を最大30%削減。来月限定販売。",
  "token_count": 29
}

例2: 記事タイトル: 地域コミュニティ支援イベント開催 記事本文: 地元のNPO団体「未来の家」が、地域住民向けの無料相談会と食料支援イベントを今週末に開催します。このイベントでは、生活困窮者への食料配布の他、弁護士や福祉専門家による無料相談も実施されます。参加には事前登録が必要です。多くのボランティアが運営をサポートします。 最大トークン数: 30 出力:

{
  "summary": "NPO「未来の家」が今週末、地域住民向け無料相談会と食料支援イベントを開催。生活困窮者への食料配布や専門家による無料相談を実施。事前登録が必要。",
  "token_count": 30
}

記事タイトル: {{article_title}} 記事本文: {{article_body}} 最大トークン数: {{max_tokens}} 出力:

### 3. Chain-of-Thought制約型プロンプト

モデルに思考プロセスの一部を内部で実行させつつ、最終的な出力には厳格な制約を課します。このアプローチでは、思考ステップ自体は出力に含めず、結果のみを簡潔に示します。

```text
system:
あなたはニュース記事の要点を抽出し、指定されたトークン数内で要約を生成するタスクを専門としています。思考プロセスは内部で完結させ、最終的な要約とトークン数のみをJSON形式で出力してください。要約は記事の主要な情報のみを含み、不要な詳細や個人的な意見は一切含めないでください。

user:
記事タイトル: {{article_title}}
記事本文: {{article_body}}
最大トークン数: {{max_tokens}}

以下に、記事の最も重要なポイントを抽出し、指定された最大トークン数に厳守して要約し、そのトークン数とともにJSON形式で出力してください。

評価

以下のシナリオと自動評価の擬似コードを用いて、プロンプトの有効性を評価します。

評価シナリオ

  1. 正例(標準的な記事):
    • 入力: 一般的な長さのニュース記事。
    • 期待される挙動: 指定された最大トークン数内で、記事の主要な事実を網羅した簡潔な要約が生成される。JSONフォーマットも正しく、token_countも正確。
  2. 難例(情報密度の高い記事):
    • 入力: 専門用語が多く、情報が凝縮された長文記事。
    • 期待される挙動: 限られたトークン数内で、最も重要な情報のみを正確に抽出し、専門用語の意味を損なわずに要約する。トークン数超過のリスクが高い。
  3. コーナーケース(非常に短い記事):
    • 入力: 数行程度の短い記事、または情報量が少ない記事。
    • 期待される挙動: 記事の内容をそのまま、またはわずかに加工して要約する。指定トークン数よりも大幅に少なくなる可能性があるが、不要な加筆はしない。

自動評価の擬似コード

Pythonのtiktokenライブラリを想定したトークンカウントと、正規表現によるフォーマットチェックを行います。

import json
import re
# Assuming tiktoken or equivalent tokenizer is available
# from tiktoken import encoding_for_model 
# enc = encoding_for_model("gpt-4")

def count_tokens(text):
    """
    擬似的なトークンカウント関数。実際にはtiktokenなどを使用。
    """
    return len(text.split()) # 簡易的な単語数カウントとして代用

def evaluate_summary_output(output_json_str, max_tokens, expected_title_keywords, article_body):
    score = 0
    feedback = []

    # 1. JSONフォーマットチェック
    try:
        output_data = json.loads(output_json_str)
        score += 10
    except json.JSONDecodeError:
        feedback.append("JSONフォーマットが不正です。")
        return {"score": score, "feedback": feedback}

    # 2. 必須キーチェック
    if "summary" not in output_data or "token_count" not in output_data:
        feedback.append("必須キー ('summary', 'token_count') が不足しています。")
        return {"score": score, "feedback": feedback}
    score += 10

    summary = output_data["summary"]
    actual_token_count = output_data["token_count"]
    calculated_token_count = count_tokens(summary)

    # 3. トークン数検証 (出力されたトークン数と計算値の一致)
    if actual_token_count == calculated_token_count:
        score += 20
    else:
        feedback.append(f"報告されたトークン数 ({actual_token_count}) が計算値 ({calculated_token_count}) と一致しません。")

    # 4. トークン数制約超過チェック
    if calculated_token_count <= max_tokens:
        score += 30
    else:
        feedback.append(f"トークン数 ({calculated_token_count}) が最大許容数 ({max_tokens}) を超過しています。")

    # 5. 内容の関連性 (簡易的なキーワードマッチング)
    matched_keywords = [kw for kw in expected_title_keywords if kw.lower() in summary.lower()]
    if len(matched_keywords) >= len(expected_title_keywords) / 2: # 半数以上のキーワードが含まれていればOK
        score += 20
    else:
        feedback.append("要約が記事タイトル/内容の主要キーワードを十分に含んでいません。")
        # さらに高度な評価として、RAGや埋め込みベクトルの類似度を使用することも検討

    # 6. 禁止事項チェック (前置き/後書き)
    if re.search(r"^(以下は記事の要約です|この記事は|要約:|)", summary, re.IGNORECASE):
        feedback.append("禁止されている前置き表現が含まれています。")
        score -= 5 # 減点

    # 7. 記事内容からの逸脱がないか (簡易的なネガティブチェック)
    # 例: 記事にない固有名詞が含まれていないかなど、より高度な幻覚検出は別途必要
    # 今回は簡略化のため、この項目はスコアリングしないが、フィードバックとして残す
    if len(summary) > 0 and summary not in article_body and "要約" not in summary:
        pass # 要約なので完全に一致しないのは当然。しかし、無関係な単語の混入は減点対象となりうる。

    return {"score": score, "feedback": feedback, "summary": summary, "token_count": calculated_token_count}

誤り分析と抑制手法

失敗モード

  • 幻覚(Hallucination): 記事に存在しない情報や、推測に基づいた内容を要約に含めてしまう。
  • 様式崩れ(Format Deviation): 出力が指定されたJSON形式に従わない、または必須キーが欠落する。
  • 脱線(Topic Drift): 要約が記事の主要なトピックから外れ、無関係な内容に言及する。
  • 禁止事項違反: 指定された最大トークン数を超過する、または不要な前置き・後書きが出力される。

抑制手法

  • System指示の強化: プロンプトの system ロールで、モデルの役割と制約を明確かつ厳しく定義します。「厳密に指示に従うこと」「推測を避けること」などを明記します。
  • 検証ステップの追加: 出力されたJSONをクライアント側でパースし、キーの存在、データ型、トークン数、禁止ワードなどをプログラム的に検証します。
  • リトライ戦略:
    • 検証ステップでトークン数超過やフォーマット崩れが検出された場合、元のプロンプトに加えてエラー内容をフィードバックし、再生成を促すリトライプロンプトを送信します。
    • 例:「前回の出力はJSONフォーマットが不正でした。または、トークン数が超過していました。以下の記事を再度、厳密にJSON形式で最大{{max_tokens}}トークン以内で要約してください。」
  • Few-shot例の品質向上: 少ないながらも完璧な入出力例を提供し、モデルに期待する挙動を明確に伝えます。特に、トークン数制限を遵守した例を含めます。
  • ネガティブ制約: プロンプト内で「〜を含めないでください」「〜しないでください」といった禁止事項を具体的に指示します。

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

graph TD
    A["プロンプト設計"] --> |プロンプト入力| B("LLMモデル")
    B --> |モデル出力| C["出力評価"]
    C --> |評価結果/フィードバック| D["プロンプト改良"]
    D --> |改良されたプロンプト| A

まとめ

LLMの出力トークン数最適化は、プロンプト設計、厳格な入出力契約、体系的な評価、そして継続的な改良のサイクルを通じて実現されます。ゼロショット、少数例、Chain-of-Thought制約型といった異なるプロンプト戦略を適用し、自動評価と手動分析を組み合わせることで、コストと品質のバランスを最適化できます。失敗モードを特定し、抑制手法を講じることで、信頼性の高いLLMアプリケーションの構築に寄与します。

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

コメント

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