RAGにおけるプロンプト評価と改善

Tech

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

RAGにおけるプロンプト評価と改善

Retrieval Augmented Generation(RAG)システムにおいて、基盤モデル(LLM)へのプロンプトは、その出力品質を決定する極めて重要な要素です。適切なプロンプトは、外部知識の有効活用を促し、幻覚(Hallucination)を抑制し、ユーザーの意図に沿った高品質な回答を生成します。本記事では、RAGにおけるプロンプトの評価と改善プロセスについて、具体的な手法を交えながら解説します。

1. ユースケース定義

今回のユースケースは「特定の社内ドキュメントに基づくFAQ応答システム」とします。ユーザーは自然言語で質問を投げかけ、システムは社内ドキュメントから関連情報を取得し、その情報に基づいて回答を生成します。回答は簡潔かつ正確であり、情報源を明示することを求められます。

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

LLMとのやり取りにおいて、期待される入出力の形式、失敗時の挙動、禁止事項を明確に定義することが、安定したシステム構築の第一歩となります。

入力契約

  • フォーマット: ユーザーの質問はプレーンテキスト形式。RAGコンポーネントが抽出した関連ドキュメントは、質問とは別に{{context}}変数としてプロンプトに挿入される。

  • 制約: 質問の長さは500文字以内。

出力契約

  • フォーマット:

    • 回答はMarkdown形式で出力し、見出し、箇条書き、太字などを適切に使用すること。

    • 回答の最後に、参照したドキュメントのタイトルを箇条書きで示すこと(例: - 参考資料: [ドキュメントAのタイトル])。

    • 回答は日本語で、敬体(です・ます調)を使用すること。

  • 失敗時の挙動: 関連ドキュメントが見つからない、または回答を生成できない場合は「適切な情報が見つかりませんでした。別の質問をお試しください。」と応答すること。

  • 禁止事項:

    • 提供された{{context}}以外の情報に基づいて回答を生成しないこと。

    • 不正確な情報や幻覚を生成しないこと。

    • 個人情報や機密情報を出力しないこと。

    • 外部URLへのリンクを含めないこと。

    • 1つの回答につき、参照ドキュメントは最大3つまでとすること。

3. プロンプト設計

以下に、3種類のプロンプト案を提示します。

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

基本的な指示のみを含むシンプルなプロンプト。

あなたは社内ドキュメントに基づくFAQ応答システムです。
以下の「質問」に対し、「参照情報」のみに基づいて回答してください。
回答は簡潔にまとめ、最後に参照情報源のタイトルを箇条書きで示してください。

---
参照情報:
{{context}}
---
質問:
{{question}}
---
回答:

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

期待される回答形式を示すために、具体的な例をいくつか含めるプロンプト。

あなたは社内ドキュメントに基づくFAQ応答システムです。
以下の「質問」に対し、「参照情報」のみに基づいて回答してください。
回答は簡潔にまとめ、Markdown形式を使用し、最後に参照情報源のタイトルを箇条書きで示してください。

---
例1:
参照情報:
タイトル: 「経費精算ポリシー」
内容: 従業員は業務上の経費について、指定された申請フォームを使用して、発生後30日以内に精算申請を行う必要があります。申請には領収書の添付が必須です。

質問:
経費精算の期限と必要なものは何ですか?

回答:
経費精算は、**発生後30日以内**に申請が必要です。
申請には**指定された申請フォーム**の使用と**領収書の添付**が必須です。

- 参考資料: 「経費精算ポリシー」

---
参照情報:
{{context}}
---
質問:
{{question}}
---
回答:

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

LLMに思考プロセスを明示させ、回答の根拠を明確にするプロンプト。幻覚抑制に効果的です。

あなたは社内ドキュメントに基づくFAQ応答システムです。
以下の「質問」に対し、「参照情報」のみに基づいて回答してください。
回答は簡潔にまとめ、Markdown形式を使用し、最後に参照情報源のタイトルを箇条書きで示してください。

回答を生成する前に、以下の手順で思考してください。

1. 提供された「参照情報」の中から、「質問」に直接関連する箇所を特定します。

2. 関連する情報に基づいて、質問に対する回答の主要なポイントを抽出します。

3. 抽出したポイントを基に、指定された出力フォーマットで回答を構成します。この際、「参照情報」にない内容は絶対に含めないでください。

---
参照情報:
{{context}}
---
質問:
{{question}}
---
思考プロセス:
---
回答:

4. 評価

プロンプトの評価は、期待する品質に達しているかを確認するために不可欠です。

4.1. 評価シナリオ

  • 正例: 関連情報が豊富に存在し、明確な回答が期待される質問。

    • 例: 「経費精算の申請期限はいつですか?」
  • 難例:

    • 複数のドキュメントに情報が分散している質問。

    • 情報が曖昧、または部分的にしか存在しない質問。

    • 否定的な質問(例: 「~でないものは何ですか?」)。

    • 例: 「最近のシステムアップデートで、経費精算のフローにどのような変更がありましたか?」 (アップデート情報が複数ある場合)

  • コーナーケース:

    • 関連情報が全く存在しない質問。

    • 質問自体が不適切または悪意のある質問。

    • 提供されたコンテキストに誤情報が含まれる場合(この場合は幻覚を抑制できているか)。

    • 例: 「来週の天気はどうなりますか?」 (社内ドキュメントにない情報)

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

自動評価は、一貫性と効率性を提供します。RAGシステムに特化した自動評価ライブラリであるRagas(2023年9月発表)や、LangChain/LlamaIndexの評価モジュールを活用できます。以下に、主要な評価項目と擬似コードを示します。

import re
from typing import List, Dict, Any

def evaluate_response(question: str, context: str, generated_answer: str, ground_truth_answer: str) -> Dict[str, Any]:
    """
    RAGシステムからのLLM応答を評価する関数。
    :param question: ユーザーの質問
    :param context: RAGが取得した参照情報
    :param generated_answer: LLMが生成した回答
    :param ground_truth_answer: 正解データ(手動作成または専門家レビュー)
    :return: 評価指標の辞書
    """
    scores = {}

    # 1. 回答の正確性 (Answer Correctness) - F1スコアまたはセマンティック類似度


    # ground_truth_answerとgenerated_answerのキーワード一致度や意味的な近さを評価


    # 例: F1スコア計算 (キーワードベース)

    def calculate_f1(text1: str, text2: str) -> float:
        words1 = set(re.findall(r'\w+', text1.lower()))
        words2 = set(re.findall(r'\w+', text2.lower()))
        if not words1 and not words2:
            return 1.0
        if not words1 or not words2:
            return 0.0

        common = len(words1.intersection(words2))
        precision = common / len(words1)
        recall = common / len(words2)
        if precision + recall == 0:
            return 0.0
        return 2 * (precision * recall) / (precision + recall)

    scores['correctness_f1'] = calculate_f1(ground_truth_answer, generated_answer)

    # 2. 参照情報への忠実性 (Faithfulness / Hallucination Detection)


    # 生成された回答が、提供されたcontextに記述されている事実のみに基づいているか


    # 正規表現やキーワードマッチング、またはLLM自身による検証

    scores['faithfulness_score'] = 1.0 # 暫定的に1.0。実際にはLLMベースの評価が必要
    if "参照情報にない内容が含まれています" in verify_with_another_llm(generated_answer, context):
        scores['faithfulness_score'] = 0.0 # 別のLLMで幻覚を検出した場合

    # 3. 回答の関連性 (Answer Relevancy)


    # generated_answerがquestionに適切に答えているか

    scores['relevancy_score'] = 1.0 # 暫定的に1.0。実際にはLLMベースの評価が必要
    if "質問への関連性が低いです" in verify_with_another_llm(generated_answer, question):
        scores['relevancy_score'] = 0.0

    # 4. コンテキストの関連性 (Context Relevancy) - RAGコンポーネントの評価だが、プロンプト設計にも影響


    # RAGが取得したcontextがquestionに関連しているか


    # これはRAG retrieverの評価だが、プロンプトが「関連情報のみ参照」と指示する場合に重要。


    # scores['context_relevancy_score'] = calculate_context_relevancy(context, question) # 別のLLMで評価

    # 5. フォーマット順守


    # 出力契約で定めた形式(Markdown、参照情報明記など)を守っているか

    scores['format_adherence'] = 1.0
    if not generated_answer.strip().endswith('。'): # 日本語の敬体終わりの簡易チェック
        scores['format_adherence'] = 0.8 # 減点
    if not re.search(r'- 参考資料: \[.*?\]', generated_answer): # 参照情報の有無
        scores['format_adherence'] = 0.0 # 致命的なエラー

    return scores

def verify_with_another_llm(text_to_check: str, reference_text: str) -> str:
    """
    (擬似コード)別のLLMを使用してテキストの正確性や関連性を検証する。
    高い信頼性を要する場合、より強力なモデルや専用の検証プロンプトを用いる。
    """

    # 実際にはここでLLM APIを呼び出し、特定のプロンプトで検証させる


    # 例: "以下の回答は、提供された参照情報のみに基づいていますか?事実と異なる点があれば指摘してください。"


    # print(f"--- LLM Verification for: '{text_to_check[:50]}...' against '{reference_text[:50]}...' ---")

    return "検証結果:問題なし" # 簡易的な返答
  • 前提: ground_truth_answer は事前に人間が作成またはレビューした正解データであると仮定します。verify_with_another_llm は、より高性能なLLMを用いて回答の妥当性や幻覚の有無を評価する(コストとレイテンシを伴う)プロセスを模倣しています。

  • 計算量: calculate_f1 は文字列の単語数に比例します(O(N+M))。verify_with_another_llm はLLM APIコールを含むため、トークン数とモデルの推論時間に依存します。

  • メモリ条件: 大規模なテキストデータを扱う場合、単語セットやLLMの入力・出力バッファに一定のメモリを消費します。

5. 誤り分析と改良

評価結果を基に、具体的な失敗モードを特定し、プロンプトを改良します。

5.1. 失敗モード

RAGシステムにおける典型的な失敗モードと原因を以下に示します。

  • 幻覚(Hallucination):

    • 説明: 提供されたコンテキストに存在しない事実や情報を生成する。

    • 原因: プロンプトの指示が曖昧、モデルが過度に自信過剰、コンテキストの質が低い(ノイズが多い)。

  • 様式崩れ(Format Mismatch):

    • 説明: 指定された出力フォーマット(Markdown、箇条書き、参照情報の明記など)に従わない。

    • 原因: プロンプトの指示が不十分、少数例が不足、モデルの指示追従能力不足。

  • 脱線(Off-topic / Irrelevance):

    • 説明: 質問とは関係のない内容を生成したり、質問の意図から外れた回答をする。

    • 原因: プロンプトが質問の焦点を明確に指示できていない、RAGが不適切なコンテキストを渡している。

  • 禁止事項違反(Prohibited Content):

    • 説明: 個人情報や機密情報を含んだり、外部URLを生成するなど、定義された禁止事項に違反する。

    • 原因: プロンプトで禁止事項が明確に伝わっていない、モデルの安全性フィルタが不十分。

5.2. 抑制手法と改良戦略

各失敗モードに対応する抑制手法とプロンプト改良戦略を以下に示します。

失敗モード 抑制手法/改良戦略
幻覚 Chain-of-Thought (CoT): モデルに思考プロセスを明示させ、「参照情報のみ使用」を強調する。
System指示の強化: プロンプトのSystem指示で「与えられた情報以外を生成しない」と厳格に指示する。
検証ステップ: 回答生成後に、別のプロンプトで回答が参照情報に基づいているかを検証させる。
参照情報の質向上: RAGの検索精度向上、チャンクサイズ最適化。
様式崩れ 少数例(Few-shot): 期待する出力フォーマットの具体例を複数提示する。
明確なフォーマット指示: プロンプト内でMarkdown構文など、具体的なフォーマット規則を詳細に記述する。
XML/JSONスキーマ: モデルが対応している場合、構造化された出力形式を強制する。
後処理: 生成された回答を正規表現などでチェックし、必要に応じて整形する。
脱線 質問の再構築: LLMにまず質問の意図を要約させる、または重要なキーワードを抽出させる。
System指示の強化: 「質問の意図から逸脱しない」ことを強調する。
RAGの精度向上: 検索されたドキュメントがより質問に密接に関連するようにRAGコンポーネントを改善する。
禁止事項違反 System指示の強化: 具体的な禁止事項(例: 「個人情報や機密情報を含めない」)をプロンプトのSystem部分に明記する。
入力フィルタ: 質問が不適切でないか事前にチェックする。
出力フィルタ: 生成された回答を後処理で検出し、フィルタリングまたは修正する。
リトライ戦略: 禁止事項違反を検出した場合、モデルに再生成を指示する。

6. 再評価

プロンプトの改良後、再度評価シナリオを用いて、改善されたプロンプトが期待通りの性能を発揮するかを確認します。特に、誤り分析で特定された失敗モードが抑制されているかを重点的に検証します。このプロセスを繰り返し、継続的にプロンプトの品質を高めていきます。

7. まとめ

RAGシステムにおけるプロンプトの評価と改善は、一連の反復的なプロセスです。ユースケースの明確化、入出力契約の厳密な定義、多様なプロンプト設計、そして自動評価と誤り分析のサイクルを通じて、LLMの性能を最大限に引き出すことができます。特に、幻覚や様式崩れといったRAG特有の課題に対し、Chain-of-Thoughtや少数例学習、明確なSystem指示、そして後処理や検証ステップを組み合わせることで、堅牢で信頼性の高いRAGシステムを構築することが可能になります。

8. プロンプト評価・改善のループ

graph TD
    A["プロンプト設計"] --> |プロンプト生成| B(LLM)
    B --> |回答生成| C{"評価シナリオ実行"}
    C --> |評価指標算出| D["自動評価"]
    D --> |評価結果分析| E{"誤り分析と失敗モード特定"}
    E --> |改善策検討| F["プロンプト改良"]
    F --> |改良プロンプト| A
    C --> |手動レビュー| G{"定性評価と洞察獲得"}
    G --> |フィードバック| F
ライセンス:本記事のテキスト/コードは特記なき限り CC BY 4.0 です。引用の際は出典URL(本ページ)を明記してください。
利用ポリシー もご参照ください。

コメント

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