実行例:

Tech

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

プロンプト評価指標と改善サイクル

大規模言語モデル(LLM)の性能を最大限に引き出すためには、プロンプトの設計とその効果的な評価、そして継続的な改善サイクルが不可欠です。本記事では、LLMのプロンプトを評価し、品質を向上させるための具体的な指標、手法、および改善サイクルについて解説します。

1. ユースケース定義

本稿では、特定の記事コンテンツを要約し、読者が興味を持つ可能性のあるキーワードを抽出するユースケースを想定します。具体的には、与えられた入力テキストから、指定された条件に基づいてタイトル、要約、および関連キーワードをJSON形式で出力させることを目的とします。

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

LLMとのやり取りにおける入出力契約を明確に定義し、期待される動作と失敗時の挙動を規定します。

2.1. 入力契約

  • フォーマット: 純粋なテキスト形式。

  • 内容: 要約対象の記事コンテンツ。

  • 文字数: 最大2000文字。

  • 付加情報: 要約の焦点を当てるための「主要テーマ」を最大3つまで指定可能。

2.2. 出力契約

  • フォーマット: 以下の構造を持つJSON形式。

    {
      "title": "記事の主要テーマを反映した簡潔なタイトル",
      "summary": "記事内容を200文字以内で要約したもの",
      "keywords": ["主要キーワード1", "主要キーワード2", "主要キーワード3"]
    }
    
  • 要約文字数: summary フィールドは厳密に200文字以内。

  • キーワード数: keywords フィールドは3つまで。

  • 言語: 日本語。

2.3. 失敗時の挙動

  • 指定されたJSON形式に準拠しない場合、{"error": "INVALID_OUTPUT_FORMAT"}を返す。

  • 要約が200文字を超える場合、{"error": "SUMMARY_TOO_LONG"}を返す。

  • 入力テキストの解析に失敗した場合、{"error": "PROCESSING_FAILED"}を返す。

2.4. 禁止事項

  • 個人情報(氏名、住所、電話番号、メールアドレスなど)の抽出または生成。

  • ヘイトスピーチ、差別的表現、暴力、性的表現を含むコンテンツの生成。

  • 誤報や幻覚(Hallucination)の生成。

3. プロンプト設計

提示されたユースケースに対し、異なるアプローチで3種類のプロンプトを設計します。

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

最も基本的な形式で、モデルに直接タスクを指示します。

あなたはプロのコンテンツライターです。以下の記事コンテンツを読み、タイトル、200文字以内の要約、および主要キーワード3つをJSON形式で出力してください。

記事コンテンツ:
{記事コンテンツ}

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

具体的な入力と出力の例を提示し、モデルの理解を深めます。

あなたはプロのコンテンツライターです。以下の記事コンテンツを読み、タイトル、200文字以内の要約、および主要キーワード3つをJSON形式で出力してください。

---
例1:
入力:
記事コンテンツ:
「2024年7月29日、東京都は新たな交通インフラ計画を発表しました。この計画は、都心部の渋滞緩和と公共交通機関の利便性向上を目的としており、特に自動運転バスの導入が注目されています。初期段階では特定のルートで運行が開始され、将来的には都内全域への拡大が目指されています。市民からのフィードバックを基に、より安全で効率的なシステムが構築される予定です。」

出力:
```json
{
  "title": "東京都、自動運転バス導入を含む新交通計画を発表",
  "summary": "東京都は2024年7月29日、都心部の渋滞緩和と公共交通機関の利便性向上を目指し、新たな交通インフラ計画を発表した。特に自動運転バスの導入が注目され、初期ルートでの運行開始後、都内全域への拡大を計画。市民の意見を反映し、安全かつ効率的なシステム構築を目指す。",
  "keywords": ["東京都", "交通インフラ", "自動運転バス"]
}

以下の記事コンテンツについて、同様にJSON形式で出力してください。

記事コンテンツ: {記事コンテンツ}

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

モデルに思考プロセスを段階的に実行させ、要約の基準やキーワード抽出のルールを明示的に指示します。

```text
あなたはプロのコンテンツライターです。以下の指示に従い、記事コンテンツを分析し、最終的にタイトル、200文字以内の要約、および主要キーワード3つをJSON形式で出力してください。

**思考ステップ:**

1.  記事コンテンツ全体を読み、中心となるテーマを特定します。

2.  中心テーマに基づき、読者の興味を引くようなタイトルを考案します。

3.  記事の主要なポイントを抽出し、200文字以内に収まるように簡潔な要約を作成します。要約には、導入、主要な事実、結論を含めることを意識してください。

4.  記事全体から最も重要だと思われるキーワードを3つ選出します。これらのキーワードは、記事の内容を最もよく表すものであるべきです。

**制約:**

*   出力は必ずJSON形式にしてください。

*   `summary`フィールドは厳密に200文字以内です。

*   `keywords`フィールドは3つの文字列配列です。

記事コンテンツ:
{記事コンテンツ}

4. 評価

プロンプトの性能を客観的に評価するためのシナリオと自動評価の擬似コードを定義します。

4.1. 評価シナリオ

  • 正例: 短く、明確な主題を持つニュース記事(例: 「新製品発表」「イベント開催」)。モデルが指示通りに動作することを確認します。

  • 難例:

    • 長文かつ複数のトピック: 1000文字以上の長い技術記事や、異なる複数の話題を含むコンテンツ。要約の精度と範囲、キーワードの選定能力を評価します。

    • 専門用語が多い: 特定の業界(医療、法律など)の専門用語が多用された記事。用語の理解度と要約への反映、誤った解釈がないかを確認します。

  • コーナーケース:

    • 入力テキストが極端に短い: 50文字程度の短い情報。必要な情報を抽出しつつ、要約が空にならないか、不自然な表現にならないかを確認します。

    • 関連キーワードがない: テキスト内に明確なキーワードが見当たらない、または一般的な単語しかない場合。それでも3つのキーワードを選出できるか(もしくは適切なエラーを返すか)を確認します。

    • 禁止事項関連: センシティブな内容を含む記事を入力した場合、禁止事項に抵触しないかを確認します。

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

import json
import re

def evaluate_prompt_output(output_text, expected_title_keywords, expected_summary_keywords, expected_keywords_list, max_summary_length=200):
    score = 100 # 満点からスタート
    feedback = []

    # 1. JSON形式の検証

    try:
        output_json = json.loads(output_text)
        if not all(k in output_json for k in ["title", "summary", "keywords"]):
            score -= 30
            feedback.append("ERROR: Required keys (title, summary, keywords) are missing.")
    except json.JSONDecodeError:
        score -= 50
        feedback.append("ERROR: Output is not a valid JSON format.")
        return {"score": score, "feedback": feedback, "parsed_output": None}

    # 2. 'title' フィールドの評価

    title = output_json.get("title", "")
    if not title:
        score -= 10
        feedback.append("WARNING: Title field is empty.")
    if any(kw in title for kw in expected_title_keywords):
        feedback.append("INFO: Title contains expected keywords.")
    else:
        score -= 5
        feedback.append("WARNING: Title does not reflect expected themes.")

    # 3. 'summary' フィールドの評価

    summary = output_json.get("summary", "")
    if not summary:
        score -= 15
        feedback.append("WARNING: Summary field is empty.")
    elif len(summary) > max_summary_length:
        score -= 20
        feedback.append(f"ERROR: Summary exceeds {max_summary_length} characters. (Actual: {len(summary)})")

    # 簡易的な要約内容の評価(キーワード含有率など)

    matched_summary_keywords = [kw for kw in expected_summary_keywords if kw in summary]
    if len(matched_summary_keywords) < len(expected_summary_keywords) / 2:
        score -= 10
        feedback.append(f"WARNING: Summary lacks coverage of key themes. Missing: {list(set(expected_summary_keywords) - set(matched_summary_keywords))}")

    # 4. 'keywords' フィールドの評価

    keywords = output_json.get("keywords", [])
    if not isinstance(keywords, list):
        score -= 20
        feedback.append("ERROR: Keywords field is not a list.")
    elif len(keywords) > 3:
        score -= 15
        feedback.append(f"ERROR: Too many keywords. (Actual: {len(keywords)})")

    # 抽出されたキーワードの妥当性評価(例: 期待されるキーワードとの一致度)


    # より高度な評価には、テキスト埋め込みやTF-IDFなどを用いた関連性スコアリングが必要

    matched_keywords = [kw for kw in keywords if kw in expected_keywords_list]
    if len(matched_keywords) < len(expected_keywords_list):
        score -= (len(expected_keywords_list) - len(matched_keywords)) * 5
        feedback.append(f"WARNING: Some extracted keywords do not match expected ones. Expected: {expected_keywords_list}, Actual: {keywords}")

    # 5. 禁止事項の簡易チェック (例: 記事が機密情報を含まないという前提での幻覚チェック)


    # 実際の評価では、外部サービスやより複雑な正規表現、NLG評価モデルが必要

    if "個人情報" in summary or "機密情報" in summary: # これはあくまで例
        score -= 50
        feedback.append("CRITICAL: Potentially generated sensitive/forbidden content.")

    # スコアの最低値を保証

    score = max(0, score)

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

# 実行例:


# input_article = "..."


# llm_output = call_llm(input_article, prompt_type="few_shot")


# eval_result = evaluate_prompt_output(


#     llm_output,


#     expected_title_keywords=["交通", "東京"],


#     expected_summary_keywords=["渋滞", "自動運転", "利便性"],


#     expected_keywords_list=["東京都", "交通インフラ", "自動運転バス"]


# )


# print(eval_result)

5. 誤り分析

評価結果に基づき、以下の失敗モードに分類して根本原因を分析します。

  • 幻覚(Hallucination): 事実に基づかない情報が要約やタイトルに含まれる場合。

    • 原因例: モデルの知識不足、プロンプトの曖昧さ、情報源の欠如。
  • 様式崩れ(Format Deviation): JSON形式が不正、特定のフィールドが欠落、文字数制限を超過する場合。

    • 原因例: プロンプトでの指示の曖昧さ、モデルの出力制御の難しさ、複雑すぎる出力形式。
  • 脱線(Off-topic / Drifting): 要約やキーワードが記事の主要テーマから逸脱している場合。

    • 原因例: プロンプトが要点の特定を十分に指示できていない、長文入力に対する集中力の欠如。
  • 禁止事項違反: 個人情報や不適切なコンテンツの生成があった場合。

    • 原因例: セーフティフィルターの不備、プロンプトに明確な禁止事項が定義されていない。

6. 改良

誤り分析の結果に基づき、プロンプトを改良します。

  • System指示の強化: モデルの役割、制約、出力形式の厳守をより強くSystemプロンプトで指示します。

  • 検証ステップの追加: Chain-of-Thoughtプロンプト内で、「最終出力前にJSON形式と文字数制限を自己チェックせよ」といった内部検証ステップを明示的に要求します。

  • リトライ戦略: 初回出力が形式エラーだった場合、エラー内容をフィードバックし、再度生成を試みる仕組みを導入します。

  • 負例の提示: 少数例プロンプトにおいて、望ましくない出力例とその理由を示すことで、モデルが「何をしてはいけないか」を学習するよう促します。

  • RAGの導入: 専門用語が多い難例に対しては、外部知識源(Wikipedia、社内ドキュメントなど)から情報を取得し、プロンプトに付加するRAG(Retrieval Augmented Generation)を検討します。

7. 再評価

改良されたプロンプトを、同じ評価シナリオと自動評価ルーブリックを用いて再評価します。これにより、プロンプトの変更がどの程度性能改善に寄与したかを定量的に把握し、改善サイクルを継続します。

8. プロンプト改善サイクル

プロンプトの設計から評価、改良、再評価までのループを可視化します。

graph TD
    A["ユースケース定義"] --> B{"プロンプト設計"};
    B -- プロンプト案作成 --> C["モデル実行"];
    C -- 出力生成 --> D["出力検証"];
    D -- 評価対象選定 --> E["評価シナリオ実行"];
    E -- 結果収集 --> F["自動評価"];
    E -- 人間による確認 --> G["手動評価"];
    F -- 指標集計 --> H["評価レポート"];
    G -- 課題特定 --> H;
    H -- 課題分析 --> I["誤り分析"];
    I -- 改善策立案 --> J["プロンプト改良"];
    J -- 新プロンプト設計 --> B;
    J -- 成果物リリース --> K["デプロイ"];

9. まとめ

LLMのプロンプトエンジニアリングは、一度の設計で完結するものではなく、継続的な評価と改善を通じて性能を向上させるプロセスです。明確なユースケース定義、厳密な入出力契約、多様なプロンプト設計、そして体系的な評価と誤り分析が、高品質なLLMアプリケーション開発の鍵となります。この改善サイクルを回し続けることで、モデルの挙動をより精密に制御し、ビジネス要求に応える出力を安定的に得ることが可能になります。 本記事で提示した手法は、2024年7月29日時点の一般的なプロンプトエンジニアリングプラクティスに基づいています。

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

コメント

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