RAGによるLLMの情報補強のためのプロンプト設計と評価

Tech

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

RAGによるLLMの情報補強のためのプロンプト設計と評価

入出力契約

RAG (Retrieval-Augmented Generation) を用いたLLMの情報補強におけるプロンプト設計と評価のプロセスを定義します。

入力契約

  • ユーザーの質問 (query): ユーザーが知りたい情報を含む自然言語の質問文。

  • 関連情報 (context): RAGシステムによって取得された、質問に関連するテキストスニペットやドキュメント。最大でNトークン(例: 4000トークン)以内。各スニペットには [ソース: ドキュメントID] の形式で情報源を付与。

出力契約

  • フォーマット: 回答はMarkdown形式で生成される。

    • 質問への直接的な回答。

    • 回答内で引用した情報源を [ソース: ドキュメントID] の形式で明記。

    • 複数の情報源から内容を統合する場合は、それらすべての情報源を列挙。

    • 関連情報が見つからない場合は、その旨を明記。

  • 失敗時の挙動:

    • 関連情報が質問に答えるのに不十分な場合、LLMは憶測に基づいた回答を生成せず、「提供された情報だけでは質問に回答できません」といった旨のメッセージを返す。

    • 出力フォーマットが崩れた場合は、後処理で修正を試みるか、エラーとして扱う。

    • 禁止事項に抵触する内容を生成しようとした場合、安全な拒否応答を返す。

  • 禁止事項:

    • 提供された関連情報以外の知識に基づく幻覚(Hallucination)の生成。

    • 不適切、差別的、暴力的、または有害な内容の出力。

    • 機密情報や個人を特定できる情報(PII)の漏洩。

    • 関連情報に記載されていない個人的な意見や推測の表明。

ユースケース定義

企業内ナレッジベースからの質問応答システムを想定します。具体的には、社内規定、製品仕様書、顧客からのFAQドキュメントなどから情報を検索し、ユーザーの質問に対して正確で根拠のある回答を生成します。目的は、従業員が迅速かつ正確に必要な情報にアクセスできるようにすることです。

制約付き仕様化

  1. 根拠明示: 生成されるすべての回答は、提供された context 内の情報に明確に根拠を持つこと。

  2. 情報源引用: 回答内の各事実に付随して、対応する [ソース: ドキュメントID] を必ず含めること。

  3. 簡潔性: 回答は質問に直接的に答え、不必要な冗長性を避けること。

  4. 網羅性: 提供された context 内の関連する情報は、可能な限り回答に統合されること。

  5. 言語: 回答は日本語で行われること。

プロンプト設計

最低3種類のプロンプト案を提示します。

1. ゼロショットプロンプト (Zero-shot Prompt)

最も基本的な形式で、追加の例なしに直接指示を与えます。

あなたは情報検索と要約に特化したアシスタントです。
以下の「関連情報」だけを使用して、「質問」に回答してください。
回答には、必ず情報源を`[ソース: ドキュメントID]`の形式で明記してください。

---
関連情報:
{{context}}
---
質問:
{{query}}
---
回答:

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

いくつかのQ&Aの例を提供することで、望ましい出力形式や回答スタイルをモデルに示します。

あなたは情報検索と要約に特化したアシスタントです。
以下の「関連情報」だけを使用して、「質問」に回答してください。
回答には、必ず情報源を`[ソース: ドキュメントID]`の形式で明記してください。
以下に例を示します。

---
例1 関連情報:
ドキュメントA: 「製品Xのサポートは2025年12月31日に終了します。」
ドキュメントB: 「製品Yのサポート期間は購入から3年間です。」
例1 質問:
製品Xのサポート終了日はいつですか?
例1 回答:
製品Xのサポートは2025年12月31日に終了します。[ソース: ドキュメントA]

---
例2 関連情報:
ドキュメントC: 「当社の返品ポリシーでは、購入後30日以内の未開封品のみ返品可能です。開封済みのソフトウェアは返品できません。」
例2 質問:
開封済みのソフトウェアを返品できますか?
例2 回答:
開封済みのソフトウェアは返品できません。[ソース: ドキュメントC]

---
関連情報:
{{context}}
---
質問:
{{query}}
---
回答:

3. Chain-of-Thought制約型プロンプト (CoT Constraint Prompt)

モデルに思考プロセスを強制し、回答生成の前に情報分析のステップを踏ませることで、より正確な回答を促します。

あなたは情報検索と要約に特化したアシスタントです。
以下の「関連情報」だけを使用して、「質問」に回答してください。
回答には、必ず情報源を`[ソース: ドキュメントID]`の形式で明記してください。

回答の前に、以下の思考プロセスに従ってください。

1. 質問から主要なキーワードと意図を特定する。

2. 関連情報の中から、キーワードと意図に合致する情報を全て抽出する。

3. 抽出した情報に基づいて、質問に対する回答を構成する。

4. 回答の各要素に、対応する情報源を付与する。

5. 提供された情報で回答できない場合は、その旨を明確に述べる。

---
関連情報:
{{context}}
---
質問:
{{query}}
---
思考プロセス:

評価

評価シナリオ

  1. 正例 (Happy Path): 質問に対する明確な答えが単一の関連情報に含まれている。

    • query: 「プロジェクトAの最終締め切りはいつですか?」

    • context: ドキュメント1: 「プロジェクトAの最終締め切りは2023年10月26日です。」

    • 期待される回答: 「プロジェクトAの最終締め切りは2023年10月26日です。[ソース: ドキュメント1]」

  2. 難例 (Complex/Multi-source): 質問に対する答えが複数の関連情報に分散しており、それらを統合する必要がある。

    • query: 「2024年の休暇申請ポリシーにおける承認フローと提出期限を教えてください。」

    • context: ドキュメント2: 「休暇申請はマネージャーの承認が必要です。」 ドキュメント3: 「2024年の休暇申請は、希望日の2週間前までに提出してください。」

    • 期待される回答: 「2024年の休暇申請ポリシーでは、マネージャーの承認が必要です。[ソース: ドキュメント2] 提出期限は希望日の2週間前までです。[ソース: ドキュメント3]」

  3. コーナーケース (No Answer/Contradiction): 関連情報に質問への答えが含まれていない、または矛盾する情報が含まれている。

    • query: 「プロジェクトZの予算はいくらですか?」

    • context: ドキュメント4: 「プロジェクトYは予算500万円で進行中です。」 (プロジェクトZに関する情報なし)

    • 期待される回答: 「提供された情報だけでは、プロジェクトZの予算について回答できません。」

自動評価の擬似コード

def evaluate_rag_response(query, context, generated_response, expected_response, document_ids):
    score = 0
    feedback = []

    # 1. 採点ルーブリック


    # 完全に正確な回答: +30


    # 情報源が正確に引用されている: +20


    # 幻覚がない: +20


    # 適切なフォーマット: +10


    # 適切な回答拒否: +20 (コーナーケースのみ)

    # 2. 正規表現とキーワードマッチング


    # 期待される回答に主要なキーワードが含まれているか

    if contains_keywords(generated_response, expected_response):
        score += 10
        feedback.append("キーワード適合性: 良好")
    else:
        feedback.append("キーワード適合性: 不足")

    # 情報源の引用チェック (例: `[ソース: ドキュメントID]` のパターン)

    if re.search(r'\[ソース: (ドキュメント\d+)\]', generated_response):
        score += 10
        feedback.append("情報源引用形式: 適切")
    else:
        feedback.append("情報源引用形式: 不足")

    # 幻覚チェック(コンテキスト外の情報が含まれていないか)


    # より高度な幻覚チェックは別途LLMやNLIモデルが必要だが、ここでは簡易的にコンテキスト内のキーワード以外がないかを見る

    if not detect_hallucination_keywords(generated_response, context): # 擬似関数
        score += 20
        feedback.append("幻覚検出: なし")
    else:
        feedback.append("幻覚検出: あり")
        score -= 20 # 重いペナルティ

    # 3. 関数評価


    # `check_source_citation(response, document_ids)`: 引用されたソースIDが実際にコンテキストに含まれるか、かつ全ての情報が適切に引用されているか

    if check_source_citation(generated_response, document_ids): # 擬似関数
        score += 20
        feedback.append("引用の正確性: 高")
    else:
        feedback.append("引用の正確性: 低")

    # `compare_semantic_similarity(generated_response, expected_response)`: 回答の意味的類似度

    if compare_semantic_similarity(generated_response, expected_response) > 0.8: # 擬似関数、埋め込みモデル使用
        score += 30
        feedback.append("意味的正確性: 高")
    else:
        feedback.append("意味的正確性: 低")

    # コーナーケースの評価: 「回答できません」の検出

    if "回答できません" in generated_response and expected_response == "No information provided":
        score += 20
        feedback.append("適切な回答拒否: 成功")
    elif "回答できません" in generated_response and expected_response != "No information provided":
        score -= 10 # 誤った拒否
        feedback.append("不適切な回答拒否: 失敗")


    # 最終的なスコアとフィードバックを返す

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

# 擬似関数の定義例 (実際は詳細な実装が必要)

def contains_keywords(response, target):

    # targetから主要キーワードを抽出し、responseに含まれるか確認

    return all(k.lower() in response.lower() for k in extract_keywords(target))

def extract_keywords(text):

    # NLTKやSpaCyなどを用いてキーワードを抽出するロジック

    return text.split()[:5] # 簡易的な例

def detect_hallucination_keywords(response, context):

    # response中のキーワードがcontext内にあるかを確認


    # contextにないキーワードがresponseに複数出現する場合、幻覚とみなす

    return False # 仮に幻覚なし

def check_source_citation(response, document_ids):

    # responseから引用パターンを抽出し、document_idsに存在するか確認


    # また、response内の主要な事実が全て引用されているか(高度なNLIタスク)

    cited_ids = re.findall(r'\[ソース: (ドキュメント\d+)\]', response)
    return all(cid in document_ids for cid in cited_ids) and len(cited_ids) > 0 # 簡易チェック

def compare_semantic_similarity(text1, text2):

    # 埋め込みモデル(例: BERT, Sentence-BERT)を使用して意味的類似度を計算


    # 実際にはSentenceTransformerやOpenAI Embedding APIなどを利用

    return 0.9 # 仮に高い類似度

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

graph TD
    A["要求定義・要件定義"] --> B{"ユースケース・制約付き仕様化"};
    B --> C["プロンプト設計"];
    C --|プロンプト入力| D["LLMモデル"];
    D --|LLM出力| E["評価"];
    E --|評価結果| F{"誤り分析"};
    F --|改善案| G["プロンプト改良"];
    G --> C;
    E --|最終評価結果| H["完了/デプロイ"];

失敗モードと抑制手法

1. 幻覚 (Hallucination)

  • 定義: 提供された context にない情報をあたかも事実であるかのように生成する。

  • 抑制手法:

    • System指示: プロンプトに「提供された関連情報のみを使用し、それ以外の知識は一切利用しないでください。情報がない場合は、その旨を明記してください。」といった厳格な指示を組み込む。

    • 検証ステップ: 生成された回答に含まれる主要な事実を抽出し、RAGシステムが提供した context との突合を自動的に行う。引用されている情報源が実際にその内容を含んでいるかを確認する。

    • リトライ戦略: 幻覚が検出された場合、プロンプトに「前回の回答にはコンテキストにない情報が含まれていました。再度、関連情報のみを使用して回答してください。」といった修正指示を加えて再実行する。

2. 様式崩れ

  • 定義: 出力契約で定められたMarkdown形式や引用形式が守られない。

  • 抑制手法:

    • System指示: プロンプトの冒頭に「出力は以下のMarkdown形式と引用形式を厳守してください。」と具体的な形式例を提示する。少数例プロンプトで具体的な出力例を示す。

    • 検証ステップ: 生成されたテキストを正規表現やカスタムパーサーでチェックし、指定された形式(例: [ソース: ドキュメントID] の存在、箇条書きの構造など)に準拠しているかを確認する。

    • 後処理: 形式が軽微に崩れている場合、自動的に修正するパース処理を導入する。

3. 脱線 (Off-topic)

  • 定義: ユーザーの質問に直接関係のない内容を生成したり、質問意図から逸脱した情報を提供する。

  • 抑制手法:

    • System指示: プロンプトに「質問に直接的かつ簡潔に回答してください。質問と関連性の低い情報は含めないでください。」と指示を明記する。

    • 検証ステップ: 質問のエンベディングと回答のエンベディングのコサイン類似度を計算し、類似度が低い場合は脱線と判断する。回答内の主要なキーワードが質問のキーワードと重なるかを確認する。

    • Chain-of-Thought: モデルに「まず質問の意図を把握し、関連情報から質問に直接答える部分を抽出せよ」といった思考ステップを課す。

4. 禁止事項違反 (Security/Policy Violation)

  • 定義: 不適切コンテンツ、機密情報、個人情報などの出力契約で禁止されている内容を生成する。

  • 抑制手法:

    • System指示: プロンプトの冒頭に「不適切、差別的、暴力的、または有害なコンテンツは生成しないでください。機密情報や個人を特定できる情報(PII)は出力しないでください。」といった明確な禁止事項を提示する。

    • 検証ステップ: 業界標準のコンテンツモデレーションAPIや、キーワードリスト、PII検出ツールを用いて生成されたコンテンツをリアルタイムでスキャンする。

    • フィルターレイヤー: LLMの出力がユーザーに届く前に、専用のセキュリティフィルターを通して不適切コンテンツを検出・ブロックする。検出された場合は、汎用的な安全応答に差し替える。

誤り分析、改良、再評価

誤り分析

評価フェーズで検出された失敗モード(幻覚、様式崩れ、脱線、禁止事項違反)について、詳細な原因分析を行います。

  • 幻覚: context の情報が不十分だったか、プロンプトの指示が不明瞭だったか、モデルが過度に自信を持ったか。

  • 様式崩れ: プロンプトの指示が複雑すぎたか、少数例が不足していたか。

  • 脱線: 質問の解釈が誤っていたか、RAGで取得した context がノイズを含んでいたか。

  • 禁止事項: プロンプトの指示不足か、安全メカニズムの欠陥。

改良

分析結果に基づき、以下の点を改善します。

  • プロンプトの具体化: 指示をより明確にし、曖昧さを排除する。特に、情報源の引用方法や回答拒否の条件を詳細に記述する。

  • 制約の強化: System指示による制約をさらに厳格にする。CoTプロンプトの思考ステップを調整し、モデルの推論パスを制御する。

  • Few-shot例の追加: さまざまなタイプの質問、特に難例やコーナーケースに対応する高品質な少数例を追加する。

  • RAGシステムとの連携改善: 関連情報取得の精度を高め、ノイズを減らす。関連情報が不足している場合に、その旨をLLMに伝えるシグナルを強化する。

  • 失敗モード特化の対策: 各失敗モードに対応する抑制手法をより堅牢に実装する。

再評価

改良されたプロンプトやシステムを用いて、新たな評価セット(未検証のテストデータ)で再評価を実施します。自動評価だけでなく、人間のレビュアーによる品質チェックも組み合わせ、改善の効果を定量・定性的に確認します。特に、前回の評価で失敗したシナリオが改善されているかを重点的に検証します。

まとめ

RAGによるLLMの情報補強は、幻覚抑制と精度向上に不可欠です。本記事では、H1タイトルからユースケース定義、制約付き仕様化、プロンプト設計(ゼロショット、少数例、Chain-of-Thought制約型)、評価シナリオと自動評価の擬似コード、プロンプト→モデル→評価→改良のループの可視化、失敗モードとその抑制手法、そして誤り分析から改良、再評価に至るまでの一連のプロセスを詳細に説明しました。これらのフレームワークは、LLMアプリケーション開発におけるプロンプトエンジニアリングと品質保証の基盤となります。厳格な入出力契約と評価基準を設けることで、信頼性の高いLLMシステムの構築が可能になります。

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

コメント

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