RAGにおけるチャンク戦略と情報検索のプロンプト設計・評価

Tech

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

RAGにおけるチャンク戦略と情報検索のプロンプト設計・評価

大規模言語モデル(LLM)を用いたRetrieval-Augmented Generation (RAG) システムにおいて、生成される回答の質は、参照される情報の選定(チャンク戦略と情報検索)と、その情報をLLMがどのように解釈・利用するかを指示するプロンプト設計に大きく依存します。本記事では、RAGにおける効果的なプロンプト設計と、その評価および改良のプロセスについて詳述します。

1. ユースケース定義

顧客からの質問に対し、社内ドキュメントやナレッジベースなどの信頼できる情報源(一次情報)を基に、正確かつ根拠に基づいた回答を生成するRAGシステムを構築するユースケースを想定します。特に、複数の情報源に分散した情報を統合する必要がある複雑な質問や、専門知識が求められる質問に対して、回答の精度と忠実性を向上させることを目標とします。

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

RAGシステムのLLMとのインタラクションにおける入出力契約を以下に定義します。

入力仕様:

  • ユーザー質問: 自然言語形式の質問テキスト。

  • 検索結果: 情報検索コンポーネントによって取得された、関連性の高いチャンクテキストのリスト。各チャンクには、元のドキュメント名、セクション、更新日(JST)、著者/組織などのソース情報を含めること。

出力仕様:

  • 回答テキスト: 自然言語形式の回答。ユーザー質問に対する直接的かつ簡潔な答えであること。

  • 参照元明記: 回答を構成する上で参照した全てのチャンクのソース情報を、回答の末尾または関連する文章の直後に明記すること。例: (参照元: ドキュメントA - セクションB、2024年4月10日更新)

失敗時の挙動:

  • 提供された検索結果から質問への回答が不可能な場合、その旨を明確に伝えること(例: 「提供された情報の中には、質問に直接回答できる内容が見つかりませんでした。」)。

  • 不完全な情報を基に推測や補完を行わないこと。

禁止事項:

  • 幻覚(Hallucination):提供された情報源に記載されていない事実や意見を生成すること。

  • 様式崩れ:定義された出力フォーマット(特に参照元の記載方法)から逸脱すること。

  • 脱線:ユーザー質問の意図や提供情報から逸脱した内容を生成すること。

  • 倫理違反:ヘイトスピーチ、差別、暴力扇動、個人情報推測などの不適切な内容を生成すること。

  • 未来予測や未確定情報の断定。

3. プロンプト設計

RAGシステムのLLMに対するプロンプトは、検索結果を最大限に活用し、正確な回答を生成するように設計します。ここでは、代表的な3種類のプロンプト案を提示します。

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

基本的な指示と制約を簡潔に与えるプロンプト。

あなたはAIアシスタントです。以下の質問と提供された情報を基に、簡潔かつ正確に回答してください。情報源に記載されていない内容は回答に含めないでください。回答の末尾には参照元を必ず記載してください。

[質問]
{{user_question}}

[提供情報]
{{retrieved_chunks_with_sources}}

[回答]

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

具体的な入出力例を示すことで、LLMの挙動を誘導するプロンプト。

あなたはAIアシスタントです。以下の質問と提供された情報を基に、簡潔かつ正確に回答してください。情報源に記載されていない内容は回答に含めないでください。回答の末尾には参照元を必ず記載してください。

[例1]
質問: Gemini 1.5 Proのコンテキストウィンドウはどれくらいですか?
提供情報:

- ドキュメントA: "Gemini 1.5 Proは、2024年2月15日に発表されたGoogleの最新モデルで、100万トークンという巨大なコンテキストウィンドウをサポートしています。" (更新日: 2024年2月15日, Google AI)
回答: Gemini 1.5 Proは、100万トークンのコンテキストウィンドウをサポートしています。(参照元: ドキュメントA, 2024年2月15日更新)

[例2]
質問: 日本の首都はどこですか?
提供情報:

- ドキュメントB: "Tokyo is the capital city of Japan." (更新日: 2023年10月5日, Wikipedia)
回答: 日本の首都は東京です。(参照元: ドキュメントB, 2023年10月5日更新)

[質問]
{{user_question}}

[提供情報]
{{retrieved_chunks_with_sources}}

[回答]

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

LLMに思考プロセスを明示させ、回答生成に至るまでのステップに制約を設けるプロンプト。幻覚抑制や複雑な質問への対応に有効です。

あなたはAIアシスタントです。以下の質問と提供された情報を基に、簡潔かつ正確に回答してください。情報源に記載されていない内容は回答に含めないでください。回答の末尾には参照元を必ず記載してください。回答を生成する前に、以下の思考プロセスに従ってください。

[思考プロセス]

1. 質問の意図を正確に理解する。

2. 提供された情報の中から、質問に直接関連する箇所を特定し、その内容を抽出する。

3. 抽出した情報のみを統合し、質問への回答を構成する。この際、情報の矛盾がないか確認する。

4. 回答が提供情報のみに基づいているか、かつ情報が不足していないかを確認する。情報が不足している場合は、その旨を明確に伝える。

5. 最終的な回答を生成し、参照した全ての情報源を正確に記載する。

[質問]
{{user_question}}

[提供情報]
{{retrieved_chunks_with_sources}}

[回答]

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

RAGシステムの回答品質を定量的に評価するためのシナリオと、自動評価の擬似コードを示します。

評価指標:

  • 忠実性 (Faithfulness): 回答が提供された検索結果のみに基づいているか(幻覚の有無)。

  • 適合性 (Relevance): 回答がユーザー質問に適切に答えているか。

  • 参照元明記 (Source Citation): 参照元が適切かつ正確に記載されているか。

  • 網羅性 (Completeness): 質問に対する回答が、提供情報内で得られる限りにおいて完全であるか。

評価シナリオ:

  1. 正例: 単一のチャンクから明確な答えが得られる質問。

    • 質問: 「東京駅の開業日はいつですか?」

    • 関連チャンク: 「東京駅は1914年12月20日に開業した。」

  2. 難例(曖昧・複数解): 複数のチャンクから情報を統合する必要がある、または質問自体に複数の解釈がありうる質問。

    • 質問: 「最新のRAG技術について教えてください。」

    • 関連チャンク: 「ハイブリッド検索の進化」、「再帰的チャンキングの利点」、「セマンティックリランキングの導入」など、複数の側面を説明するチャンク。

  3. コーナーケース(情報不足・否定質問): 提供された情報では回答できない、または回答すべきでない質問。

    • 質問: 「来月の株価を予測してください。」

    • 関連チャンク: (株価予測に関する情報なし、または「予測はできません」と明記されたチャンク)

自動評価の擬似コード:

import re

def evaluate_rag_response(question: str, retrieved_chunks: list[str], llm_response: str, ground_truth_answer: str, ground_truth_sources: list[str]) -> dict:
    """
    RAGシステムのLLM応答を自動評価する擬似コード。

    Args:
        question (str): ユーザーの質問。
        retrieved_chunks (list[str]): RAGシステムが取得した関連チャンクのリスト(ソース情報含む)。
        llm_response (str): LLMによって生成された回答。
        ground_truth_answer (str): 期待される正解の回答。
        ground_truth_sources (list[str]): 正解回答の根拠となるソース情報のリスト。

    Returns:
        dict: 評価スコア、フィードバック、LLMの応答を含む辞書。
    """
    score = 0
    feedback = []

    # 1. 忠実性 (Faithfulness) - 幻覚の抑制


    #   簡易チェック: 正解回答の主要なキーワードがLLM応答に含まれているか。


    #   より高度な実装では、LLM応答の各文がretrieved_chunks内の情報に基づいてるかを検証するモジュールが必要。

    is_faithful = True
    if ground_truth_answer and ground_truth_answer not in llm_response:
        is_faithful = False
        feedback.append("警告: 回答が期待される正解情報を含んでいないか、一部不正確です。")
        score -= 2 # 幻覚や不正確さは大きな減点

    # 2. 適合性 (Relevance) - 質問への適切性

    if question in llm_response or ground_truth_answer in llm_response: # 非常に単純なキーワードマッチング
        score += 1
    else:
        feedback.append("回答が質問に適切に答えていない可能性があります。")
        score -= 1

    # 3. 参照元明記 (Source Citation)

    citation_pattern = r"\(参照元: .*?\)"
    citations_found = re.findall(citation_pattern, llm_response)

    if citations_found:
        score += 1

        # 実際に引用されたソースがground_truth_sourcesに含まれるか、またはretrieved_chunksのソースと一致するかを簡易的にチェック

        if any(src_gt.split(':')[0] in citation for src_gt in ground_truth_sources for citation in citations_found):
            score += 1 # 関連するソースが引用されている
        else:
            feedback.append("警告: 参照元が明記されていますが、提供情報と一致しない可能性があります。")
    else:
        feedback.append("エラー: 参照元が回答に明記されていません。")
        score -= 2 # 参照元がない場合は大きな減点

    # 4. 禁止事項チェック(例:未来予測)

    prohibited_keywords = ["来月の株価予測", "予測します"]
    if any(keyword in llm_response for keyword in prohibited_keywords):
        feedback.append("エラー: 禁止されている内容(未来予測など)が含まれています。")
        score -= 5 # 非常に大きな減点

    # 5. 網羅性 (Completeness) - 簡易チェック


    #   より高度な実装では、ground_truth_answerの複数の側面がカバーされているかを確認。

    if len(llm_response) > 50 and "詳細が不足しています" not in llm_response: # 50文字以上で、かつ情報不足を伝えていない場合
        score += 0.5 # 網羅性が高いと仮定
    else:
        feedback.append("回答が簡潔すぎるか、情報不足を適切に伝えていません。")


    # 計算量: O(N*M) where N is response length, M is keyword/pattern count (small constant)


    # メモリ条件: 応答とチャンクのテキストサイズに比例

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

# 評価の実行例


# example_question = "東京駅の開業日はいつですか?"


# example_retrieved_chunks = ["東京駅は1914年12月20日に開業した。", "丸の内駅舎の復元工事は2012年に完了した。"]


# example_ground_truth_answer = "東京駅は1914年12月20日に開業しました。"


# example_ground_truth_sources = ["東京駅の歴史ドキュメント"]

# # 良い応答例


# good_llm_response = "東京駅は1914年12月20日に開業しました。(参照元: 東京駅の歴史ドキュメント)"


# print(evaluate_rag_response(example_question, example_retrieved_chunks, good_llm_response, example_ground_truth_answer, example_ground_truth_sources))

# # 悪い応答例 (幻覚)


# bad_llm_response_hallucination = "東京駅は1920年1月1日に開業しました。(参照元: 不明)"


# print(evaluate_rag_response(example_question, example_retrieved_chunks, bad_llm_response_hallucination, example_ground_truth_answer, example_ground_truth_sources))

# # 悪い応答例 (参照元なし)


# bad_llm_response_no_citation = "東京駅は1914年12月20日に開業しました。"


# print(evaluate_rag_response(example_question, example_retrieved_chunks, bad_llm_response_no_citation, example_ground_truth_answer, example_ground_truth_sources))

5. プロンプト評価・改良ループ

RAGシステムにおけるプロンプト設計と評価は、反復的なプロセスです。

graph TD
    A["RAGシステム入力: 質問と検索チャンク"] --> B("プロンプト設計");
    B -- プロンプト送信 --> C["LLM応答生成"];
    C --> D["評価モジュール"];
    D -- スコアリングとフィードバック --> E["誤り分析"];
    E -- 失敗モード特定と原因分析 --> F["改良案立案"];
    F -- プロンプト修正, チャンク戦略調整, 検索強化など --> B;
    D -- 高品質の場合 --> G["本番デプロイ"];

6. 誤り分析と抑制手法

LLMの応答に見られる典型的な失敗モードと、それらを抑制するための手法を列挙します。

  1. 幻覚(Hallucination)

    • 説明: LLMが提供された検索結果に基づかない、誤った情報を生成する。

    • 抑制手法:

      • Systemプロンプトで「提供情報にない内容は絶対に生成しない」という指示を強調。

      • Few-shotプロンプトで、情報不足の際に「情報が見つかりませんでした」と回答する例を示す。

      • CoTプロンプトで「提供情報との整合性を確認する」ステップを義務付ける。

      • LLMの出力後に外部の事実確認モジュールやGuardrailsを用いて回答内容を検証し、矛盾があればリトライまたはフラグを立てる。

  2. 様式崩れ(Format Deviation)

    • 説明: 回答の構造、特に参照元の記載方法がプロンプトの指示と異なる。

    • 抑制手法:

      • Few-shotプロンプトで参照元の記載形式を厳密に定義した具体例を複数提示する。

      • CoTプロンプトで、回答生成の最終ステップとして「参照元を指示された形式で付与する」ことを明示する。

      • 出力後に正規表現や構文解析でフォーマットを検証し、違反があればリトライさせる。

  3. 脱線(Off-topic Generation)

    • 説明: 質問の意図や提供情報から逸脱した、無関係な内容を回答に含める。

    • 抑制手法:

      • CoTプロンプトで「質問の意図を正確に理解し、提供情報の中から最も関連性の高い内容のみを抽出・統合する」ステップを強制する。

      • 情報検索段階で、より厳密な関連性スコアリングやRerankingを導入し、ノイズの多いチャンクを除外する。

      • Systemプロンプトで「質問に直接関係のない情報は含めない」と明記する。

  4. 禁止事項違反(Prohibited Content)

    • 説明: 倫理的に問題のある内容、個人情報の推測、未来予測など、生成すべきでない内容を出力する。

    • 抑制手法:

      • Systemプロンプトで明確な禁止事項リストを定義し、違反時のペナルティを伝える。

      • Safety Filter(Guardrails)をLLMの出力後に適用し、不適切な内容を検出・ブロックする。

      • 出力内容をキーワードやパターンでチェックし、違反を検知した場合は生成を中止し、安全な代替応答を返す。

  5. 情報不足時の不適切な応答

    • 説明: 関連情報が見つからない場合に「情報が見つかりませんでした」と適切に回答せず、推測したり、誤った回答を生成してしまう。

    • 抑制手法:

      • CoTプロンプトに「提供された情報が質問に答えるのに十分か判断し、不十分な場合はその旨を明確に伝える」ステップを追加。

      • Few-shotプロンプトで、情報不足のシナリオにおける適切な回答例を示す。

      • 検索結果の信頼度スコアが低い場合に、LLMに回答を抑制させるロジックをRAGシステムに組み込む。

7. 改良と再評価

誤り分析で特定された失敗モードに対し、具体的な改良策を講じます。

  • プロンプトの改良: 失敗モードに対応するよう、Systemプロンプト、Few-shot例、CoTステップの指示を調整します。例えば、幻覚が多発する場合は「事実確認」ステップを強化し、参照元明記のルールをより厳格にします。

  • チャンク戦略の調整: 情報検索コンポーネントにおけるチャンクのサイズ、オーバーラップ、分割方法(例: セマンティックチャンキング、再帰的チャンキング、固定サイズチャンキングの組み合わせ)を見直し、より関連性の高い情報を取得しやすくします。

    • 例えば、複雑な質問に対しては、より大きなコンテキストを捕捉できるようチャンクサイズを大きくしたり、階層的なチャンキングを導入したりすることが有効です。
  • 情報検索アルゴリズムの強化: キーワード検索(BM25)とベクトル検索(Embedding)を組み合わせたハイブリッド検索の導入や、取得したチャンクをLLMやTransformerベースのモデルで再度スコアリングするRerankingの導入により、LLMに渡す情報の関連性を最大化します。

  • モデルの選択: 特定のタスクやドメインに特化したLLM、またはより高性能なLLMへの切り替えを検討します。

改良後、同じ評価シナリオと自動評価スクリプトを用いて再度評価し、スコアの変化とフィードバックの改善を確認します。特に、以前に失敗したケースが改善されているかを重点的に検証し、定量的な進捗を追跡します。

8. まとめ

RAGシステムにおけるプロンプト設計は、単なる質問応答にとどまらず、情報検索で取得したチャンクをLLMが最大限に活用し、正確性、忠実性、網羅性を確保するための重要な要素です。ゼロショット、少数例、Chain-of-Thoughtなどのプロンプト戦略を使い分け、堅牢な評価ループと継続的な改良プロセスを通じて、システム全体の性能と信頼性を向上させることが可能となります。チャンク戦略や情報検索手法の進化とプロンプト工学を組み合わせることで、より賢く、信頼できるRAGシステムを構築できます。

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

コメント

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