BEACHSIDE BLOG

Azure と GitHub と C# が好きなエンジニアの個人メモ ( ・ㅂ・)و ̑̑

Contextual Retrieval のざっくりノート

結構古い記事ですが、以下のサイトで語られている "Contextual Retrieval" の考え方が好きなのでさっとまとめます。

最近で仕事でのワークショップの裏側で使ってる自作の RAG も(?)、 地味のこのアプローチの一部を簡易に行っていたりで聞かれることも多いので書いておこうかなという感じです。

ざっくりまとめ

最初に Contextual Retrieval のざっくりまとめです。

  • RAG の精度を改善するための手法で、インデックスを作る際の手法のひとつ。
  • RAG のナレッジベースを作成する際、ソースのデータを chunk することで前後のコンテキストが失われ、RAG の検索精度が落ちる課題がある。
  • この課題を解決するために、chunk する際に失われるコンテキストを補完する文章をつけることで、RAG の精度を向上させるアプローチ
    • この記事ではこれプラスαのアプローチで改善したって話になります。

ここからは記事の内容を要約・意訳していきます。

"Contextual Retrieval"

従来の RAG における課題

従来の RAG のアプローチだと、チャンクすることで各コーパスの前後のコンテキストが失われることで RAG の精度が落ちる問題がある。 具体例として...

  • ナレッジベースに"米国証券取引委員会" から出ている財務情報があり、「ACME社の2023年第2四半期の収益成長率は?」という質問に関連する情報を検索する場合。
  • 関連するチャンクに「同社の収益は前四半期比で3%増加しました」という記述が含まれていたとしても、このチャンク単体では「同社」がACME社を指すのか、そしてこの記述が「2023年第2四半期」に関するものなのかを特定するためのコンテキストが欠落している。
  • このようなコンテキストの欠落は、関連性の高いチャンクを正確に検索すること、また検索されたチャンクをモデルが効果的に利用することを困難にし、結果としてRAGシステム全体の性能低下を招く。

このコンテキスト破壊の問題は、従来のRAGが持つ根本的な弱点であり、特に文脈依存性の高い情報を扱う場合に顕著になります

Contextual Retrieval の概要

Contextual Retrieval とは、前述の課題を解決するために以下2つのアプローチを行うこと。

  • Contextual Embeddings
  • Contextual BM25

具体的な例だとこんな感じ。

original_chunk = "同社の収益は前四半期比で3%成長しました。"

contextualized_chunk = "このチャンクは、2023年第2四半期におけるACME社の業績に関するSECファイリングからのものであり、前四半期の収益は3億1400万ドルでした。同社の収益は前四半期比で3%成長しました。"

Contextual Retrieval 以外のアプローチとして Anthropic で以下を実験したが、いい成果を得れなかった。

  • ジェネリックな文書要約をチャンクに追加 →非常に限定的な効果しか見られなかった。
  • HyDE(hypothetical document embedding) → パフォーマンスが低い。
  • Summary-based indexing (要約ベースのインデックス作成) → パフォーマンスが低い。

Contextual Retrieval の実装

Anthropic にて Claude 3 Haiku の model を使い以下のプロンプトで Contextual Retrieval を実現。

<document> 
{{WHOLE_DOCUMENT}} 
</document> 
以下に、全体文書内に位置付けたいチャンクを示します。
<chunk> 
{{CHUNK_CONTENT}} 
</chunk> 
このチャンクの検索精度を向上させる目的で、全体文書内でのこのチャンクの位置付けを示す、短く簡潔な文脈を提供してください。簡潔な文脈のみを回答し、それ以外は何も含めないでください。

結果として得られる文脈テキスト(通常50-100トークン)は、embedding 前および BM25 index作成前に、チャンクの前に付加されます。 以下に、前処理フローが実際にはどのように見えるかを示します。

Contextual Retrieval での考慮事項

  1. チャンクの境界: ドキュメントをどのようにチャンクに分割するかを検討してください。チャンクサイズ、チャンク境界、およびチャンクのオーバーラップの選択は、検索性能に影響を与える可能性があります。
  2. Embedding model: Contextual Retrieval は Anthropic がテストした全ての Embedding model で性能を向上させますが、一部の model は他の model よりも大きな恩恵を受ける可能性があります。我々は Gemini および Voyage の embeddings が特に効果的であることを見出しました。
  3. Custom contextualizer prompt: Anthropic が提供した汎用プロンプトもうまく機能しますが、特定のドメインやユースケースに合わせたプロンプト(例えば、ナレッジベース内の他のドキュメントでのみ定義されている可能性のある主要用語の用語集を含めるなど)を使用すると、さらに良い結果が得られる可能性があります。
  4. チャンク数: より多くのチャンクをコンテキストウィンドウに追加すると、関連情報を含める可能性が高まります。ただし、情報が増えるとモデルにとって混乱を招く可能性があるため、これには限界があります。我々は5、10、20のチャンクを試した結果、20を使用するのがこれらのオプションの中で最も性能が高いことが分かりましたが、ご自身のユースケースで実験する価値があります。

常に評価を実行してください。応答の生成は、文脈化されたチャンクを渡し、何が文脈で何がチャンクであるかを区別することで改善される可能性があります。

Reranking によるさらなる性能向上

最終的に Context retrieval と Reranking を組み合わせることでさらに性能向上をもらたすことができる。具体的なステップは以下。

  1. 初期検索を実行して、潜在的に関連性の高い上位チャンクを取得します(我々は上位150個を使用しました)。
  2. 上位N個のチャンクを、ユーザーのクエリとともにリランキングモデルに渡します。
  3. リランキングモデルを使用して、各チャンクにプロンプトとの関連性と重要度に基づいたスコアを与え、その後上位K個のチャンクを選択します(我々は上位20個を使用しました)。
  4. 最終的な結果を生成するために、上位K個のチャンクを文脈としてモデルに渡します。

Reranking での考慮事項

Reranking における重要な考慮事項の一つは、特に多数のチャンクをリランキングする場合のレイテンシとコストへの影響です。 Reranking は実行時に追加のステップを加えるため、Reranker がすべてのチャンクを並行してスコアリングしても、不可避的にわずかなレイテンシーが加わります。 より良い性能のために多くの chunk を reranking することと、より低いレイテンシーとコストのために少ない chunk を reranking することの間には、固有のトレードオフが存在します。 ご自身の特定のユースケースで様々な設定を実験し、適切なバランスを見つけることを推奨します。

Anthropic 的まとめ

Anthropic は、上述の全ての技術の異なる組み合わせ(embedding model, use of BM25, use of contextual retrieval, use of a reranker, and total # of top-K results retrieved)を、全て様々な異なるデータセットタイプ全体で比較する多数のテストを実行しました。以下に見出したことのまとめを示します。

  1. embeddings 単独よりも、embeddings + BM25 の方が優れています。
  2. テストした中で、VoyageとGeminiが最高の embeddings を備えています。
  3. 上位20の chunk をモデルに渡すことは、上位10または上位5だけを渡すよりも効果的です。
  4. chunk に context を追加すると、検索精度が大幅に向上します。
  5. reranking は reranking なしよりも優れています。
  6. これらの利点は全て積み重なります。性能向上を最大化するには、(Voyage または Gemini での) contextual embeddings と contextual BM25を組み合わせ、さらにreranking のステップを追加し、20個のチャンクをプロンプトに追加することです。

参考