Databricks生成AIクックブック - 3.2. 収集、拡張、生成(RAGチェーン)

[3\.2\. Retrieval, augmentation, and generation \(aka RAG Chain\) — Databricks Generative AI Cookbook](https://ai-cookbook.io/nbs/3-deep-dive-chain.html) [2024/6/22時点]の翻訳です。

:::note warn
本書は著者が手動で翻訳したものであり内容の正確性を保証するものではありません。正確な内容に関しては原文を参照ください。
:::

> [Databricks生成AIクックブック](https://qiita.com/taka_yayoi/items/36c51bce8f33a70cf204)のコンテンツです。


# 3.2. 収集、拡張、生成(RAGチェーン)

![](https://ai-cookbook.io/_images/5_img1.png)

RAGチェーンは入力としてユーザーのクエリーを受け取り、与えられたクエリーに適した情報を収集し、収集したデータに基づく適切なレスポンスを生成します。RAGチェーンにおける正確なステップはユースケースや要件によって大きく異なりますが、あなたのRAGチェーンを構築する際に検討すべきキーコンポーネントを以下に示します:

1. **クエリーの理解:** 収集プロセスを改善するために、フィルターやキーワードのように、意図や正確かつ適切な情報をより良く表現するように、ユーザーのクエリーを解析、変換します。
1. **収集:** 与えられた収集クエリーに対して最も適切な情報のチャンクを特定します。非構造化データの場合、大抵セマンティックやキーワードベースの検索の組み合わせが関係します。
1. **プロンプト拡張:** ユーザーのクエリーを収集した情報と、LLMが高品質のレスポンスを生成するようにガイドするための指示と組み合わせます。
1. **LLM:** パフォーマンス、レーテンシー、コストの最適化/バランスを取るために、あなたのアプリケーションに最も適したモデル(とモデルのパラメーター)を選択します。
1. **後処理とガードレイル:** LLMが生成するレスポンスがトピックに沿っており、事実的に一貫性があり、特定のガイドラインや制約に準拠するようにするために、追加の処理ステップや安全性対策を適用します。

[RAGチェーン変更の実装](https://qiita.com/taka_yayoi/items/42de353690e29dbb6efe)セクションでは、チェーンにおけるこれらの様々なコンポーネントに対してどのように試行錯誤するのかをデモンストレーションします。

## 3.2.1. クエリーの理解

収集クエリーとしてユーザーのクエリーを直接用いることは、いくつかのクエリーではうまく動作します。しかし、通常は収集ステップの前にクエリーを再計算することによるメリットがあります。クエリーの理解は、ユーザーのクエリーがより意図を表現し、適切な情報を秀出し、最終的には以降の収集プロセスを支援するように、チェーンの最初にユーザークエリーを解析、変換するステップ(あるいは一連のステップ)となります。収集を改善するためにユーザークエリーを変換するプロセスには以下が含まれます:

1. **クエリーの書き換え:** クエリーの書き換えでは、ユーザーのクエリーをオリジナルの意図をより表現するように1つ以上のクエリーに翻訳します。ここでのゴールは、収集ステップでより適切なドキュメントを発見できる可能性を高められるようにクエリーを再計算することです。これは、収集するドキュメントで使用されている用語に直接マッチしない可能性のある複雑、不明瞭なクエリーを取り扱う際には特に有用です。

    **例:**
    - 会話を複数ターンのチャットに言い換える
    - ユーザークエリーのスペルミスを修正する
    - より広い範囲で適切なドキュメントを捕捉できるように、ユーザークエリーの単語やフレーズを同義語で置き換える

    :::note info
    **注意**
    クエリーの書き換えは、収集コンポーネントの変更と連携して行うべきです。
      :::

1. **フィルターの抽出:** あるケースでは、ユーザークエリーには検索結果を絞り込むための固有のフィルターや評価基準が含まれる場合があります。フィルター抽出では、クエリーでこれらのフィルターを特定、抽出し、収集ステップの追加パラメーターとしてそれらを引き渡します。これによって、利用できるデータの特定のサブセットにフォーカスすることで、収集ドキュメントの適切性を改善する助けとなります。

    **例:**
    - "過去6ヶ月の記事"や"2023年のレポート"のように、クエリーで言及されている特定の期間を抽出する
    - "Databricksプロフェッショナルサービス"や"ラップトップ"のように、クエリー内の特定製品、サービス、カテゴリーを特定する
    - クエリーから都市名、国コードのような地理エンティティを抽出する

    :::note info
    **注意**
    フィルターの抽出は[データパイプライン](https://qiita.com/taka_yayoi/items/c5d63ebe767ec9833464)と[リトリーバーチェーン](#322-収集)の両方のメタデータ抽出処理への変更と連携して行うべきです。メタデータ抽出ステップでは、それぞれのドキュメント/チャンクで適切なメタデータフィールドを利用できるようにし、収集ステップでは、抽出されたフィルターを受け入れ、適用できるように実装すべきです。
      :::

クエリーの書き換えとフィルターの抽出に加え、クエリー理解における別の重要な検討事項は、単体のLLM呼び出しを使うか複数の呼び出しを使うかということです。注意深く作成されたプロンプトを用いた単一の呼び出しは効率的ですが、クエリー理解プロセスを複数のLLM呼び出しにブレークダウンすることで、優れた結果につながることがあります。ちなみに、これは特に多数の複雑な論理ステップを単一のプロンプトで実装しようとしている際には、一般的に適用可能な経験則となります。

例えば、あるLLM呼び出しをクエリーの意図の分類に使用し、別の呼び出しでは適切なエンティティを抽出し、3番目の呼び出しでは、抽出された情報に基づいてクエリーを書き換えることができます。このアプトーリは、全体的なプロセスにある程度のレーテンシーを追加するかもしれませんが、よりきめ細かいコントロールを可能とし、収集されるドキュメントの品質を改善できる可能性があります。

我々のカスタマーサポートbotにおけるマルチステップクエリー理解のコンポーネントは以下のようになります:

1. **意図の分類:** "製品情報"、"トラブルシューティング"、"アカウント管理"のように事前定義されたカテゴリーにユーザークエリーを分類するためにLLMを使用します。
1. **エンティティの抽出:** 特定された意図に基づき、製品名、報告されたエラー、アカウント番号のように適切なエンティティをクエリーから抽出するために別のLLM呼び出しを行います。
1. **クエリーの書き換え:** "私のRAGチェーンのモデルサービングへのデプロイに失敗します。以下のエラーを確認しています..."のように、オリジナルのクエリーをより特定的、ターゲティングされたフォーマットに書き換えるために、抽出した意図とエンティティを活用します。

## 3.2.2. 収集

RAGチェーンの収集コンポーネントは、与えられた収集クエリーに対して最も適切な情報のチャンクを特定することに責任を持ちます。非構造化データの文脈では、通常は収集にセマンティック検索、キーワードベースの検索、メタデータフィルタリングの組み合わせが関係します。収集戦略の選択は、あなたのアプリケーション固有の要件、データの特性、対応するクエリーのタイプに依存します。これらのオプションを比較しましょう:

1. **セマンティック検索:** セマンティック検索では、それぞれのテキストチャンクをその意味をキャプチャするベクトル表現に変換するためにエンべディングモデルを活用します。収集クエリーのベクトル表現とチャンクのベクトル表現を比較することで、セマンティック検索では、クエリーのキーワードを含んでいなかったとしても概念的に類似したドキュメントを収集することができます。
1. **キーワードベースの検索:** キーワードベースの検索は、収集クエリーとインデックスされたドキュメントの間で共有される単語の頻度や分布を分析することでドキュメントの適切性を特定します。クエリーとドキュメントの両方に同じ単語がより頻繁に出現すると、そのドキュメントには高い適切性スコアが割り当てられます。
1. **ハイブリッド検索:** ハイブリッド検索では、2ステップの収集プロセスを用いることで、セマンティック検索とキーワードベース検索両方の強みを組み合わせます。最初に、概念的に適切なドキュメントセットを収集するためにセマンティック検索を実行します。そして、完全キーワードマッチに基づいて結果をさらに改善するために、収集結果にキーワードベース検索を適用します。最後に、ドキュメントをランキングするために両方のステップのスコアを組み合わせます。

以下の表では、これらの収集戦略のそれぞれを比較しています:

|  | セマンティック検索 | キーワード検索 | ハイブリッド検索 |
|:--|:--|:--|:--|
| **簡単な説明**  | クエリーと対象のドキュメントに同じ**概念**が現れているならば、それらは適切なものと言えます。  | クエリーと対象のドキュメントに同じ**単語**が現れているならば、それらは適切なものと言えます。より**多くのクエリーのキーワード**がドキュメントに含まれているほど、そのドキュメントはより適切なものと言えます。  | セマンティック検索とキーワード検索の両方を実行し、結果を組み合わせます。  |
| **ユースケースの例**  |ユーザーのクエリーが製品マニュアルの用語と異なるカスタマーサポートのケース。<br><br>例 *"私の電話をどう起動したらいいの？"* とマニュアルの *"電源のオンオフ"* セクション   | クエリーに特定かつ説明的ではない技術用語が含まれているカスタマーサポートのケース。<br><br>例 *"モデルHD7-8Dは何をする？"*  | 意味的な用語と技術用語の両方を組みわせたカスタマーサポートのクエリー。<br><br>例 *"私のHD7-8Dをどう起動したらいいの？"*  |
| **技術的アプローチ**  | テキストを連続的なベクトル空間で表現するためにエンベディングを用い、セマンティック検索を実現。  | キーワードマッチでは[bag\-of\-words](https://en.wikipedia.org/wiki/Bag-of-words_model)、[TF\-IDF](https://en.wikipedia.org/wiki/Tf%E2%80%93idf)、[BM25](https://en.wikipedia.org/wiki/Okapi_BM25)のような個別のトークンベースの手法を活用。  | 結果を組み合わせるために[reciprocal rank fusion](https://www.elastic.co/guide/en/elasticsearch/reference/current/rrf.html)や[reciprocal rank fusion](https://www.elastic.co/guide/en/elasticsearch/reference/current/rrf.html)のようなリランキングアプローチを活用。  |
| **強み**  | 全く同じ用語が使われていなかったとしても、概念的にクエリーに類似した情報を取得。  | 正確なキーワードマッチを必要とするシナリオ。製品名のように特定の用語にフォーカスしたクエリーでは理想的。  | 両方のアプローチの良いところの組み合わせ。  |

これらのコアの収集戦略に加えて、収集プロセスをさらに強化するために適用できるいくつかのテクニックが存在します:

- **クエリー拡張:** クエリー拡張は、収集クエリーの複数のバリエーションを用いることで、より広範な範囲の適切なドキュメントを細くす助けになります。これは、それぞれの拡張クエリーに対する個々の検索の実行や、単一の収集クエリーで全ての拡張した検索クエリーを結合したものを用いることで達成することができます。

    :::note info
    **注意**
    クエリー拡張は、RAGチェーンのクエリー理解コンポーネントへの変更と合わせて行うべきです。通常、このステップでは複数バージョンの収集クエリーが生成されます。
      :::

- **リランキング:** チャンクの初期セットを収集した後に、追加のランキング指標(時間でのソートなど)や結果を再度並び替えるためのリランカーモデルを適用します。[mxbai\-rerank](https://huggingface.co/mixedbread-ai/mxbai-rerank-large-v1)や[ColBERTv2](https://docs.llamaindex.ai/en/stable/examples/node_postprocessor/ColbertRerank/)のようなクロスエンコーダーモデルによるリランキングは、収集パフォーマンスの改善をもたらすことができます。
- **メタデータフィルタリング:** 特定の評価指標に基づき検索空間を絞り込むために、クエリー理解ステップから抽出したメタデータフィルターを活用します。メタデータフィルターには、ドキュメントタイプ、作成日、作成者、ドメイン固有のタグのような属性が含まれます。メタデータフィルターとセマンティック検索、キーワードベース検索を組み合わせることで、よりターゲティングされ効率的な収集を行うことができます。

    :::note info
    **注意**
    メタデータフィルタリングは、RAGチェーンのクエリー理解コンポーネントへの変更と、データパイプラインのメタデータ抽出コンポーネントへの変更と合わせて行うべきです。
      :::

## 3.2.3. プロンプト拡張

プロンプト拡張は、高品質なレスポンスを生成するように言語モデルをガイドするためのプロンプトテンプレートで、ユーザークエリーと収集情報と指示を組みわせるステップです。モデルが正確で事実に基づき、一貫性のあるレスポンスを生成するようにガイドされることを確実にするために、LLMに提供されるプロンプトを最適化するためにこのテンプレートで試行錯誤することが必要となるでしょう。

全体的な[プロンプトエンジニアリングのガイド](https://www.promptingguide.ai/)が存在しますが、以下にプロンプトエンジニアリングを繰り返す際に念頭に置くべきいくつかの検討事項を示します:

1. 例を示す
    - プロンプトテンプレート自身に、適切に構成されたクエリーと対応する理想的なレスポンスの例を含めます(例 [few\-shot learning](https://arxiv.org/abs/2005.14165))。これによって、モデルは期待されるレスポンスのフォーマット、スタイル、コンテンツを理解する助けになります。
    - 良い例を思いつく有用な手段は、あなたのチェーンが取り組むクエリーのタイプを特定することです。これらのクエリーに対する代表的なレスポンスを作成し、プロンプトに例として含めるようにしましょう。
    - 提供する例は、推論時に期待するユーザークエリーを代表するものであるようにしましょう。モデルの汎用性を高めるために、期待される様々なクエリーをカバーするようにしましょう。
1. プロンプトテンプレートをパラメータ化する
    - 収集データとユーザークエリー以外の追加情報を取り込めるようにパラメータ化することで、プロンプトテンプレートに柔軟性を持たせるように設計しましょう。これは、現在の日付、ユーザーのコンテキスト、そのほかの適切なメタデータのような変数となります。
    - 推論時にこれらの変数をプロンプトに取り込むことで、よりパーソナライズされ、コンテキストを前提とするレスポンスを実現できます。
1. チェインオブソートのプロンプトを検討する
    - 直接的な回答が即座に得られないような複雑なクエリーに対しては、[Chain\-of\-Thought \(CoT\)プロンプティング](https://arxiv.org/abs/2201.11903)を検討しましょう。このプロンプトエンジニアリング戦略は、複雑な質問をよりシンプルで連続するステップにブレークダウンし、LLMを論理的な理由づけプロセスを通じてガイドします。
    - モデルに"ステップバイステップで問題を考えて"とプロンプトを与えることで、複数ステップやオープンエンドのクエリーに対応する際には特に効果的となる、より詳細かつよく理由づけされたレスポンスを提供するように動機づけすることができます。
1. プロンプトを異なるモデルに転用できないことがあります
    - 異なる言語モデルにシームレスにプロンプトを移植できないことが多くあることを認識しましょう。それぞれのモデルには、自身のユニークな特性があり、あるプロンプトはあるモデルでうまく動作しますが、別のモデルでは効果的ではないことがあります。
    - オンラインガイド([OpenAI Cookbook](https://cookbook.openai.com/)、[Anthropic cookbook](https://github.com/anthropics/anthropic-cookbook)など)を参考にさまざまなプロンプトフォーマットや長さで実験を行い、モデルを切り替える際にはあなたのプロンプトを適応、改善するように備えましょう。

## 3.2.4. LLM

RAGチェーンの生成コンポーネントは、前のステップで拡張されたプロンプトテンプレートを受け取り、LLMに引き渡します。RAGチェーンの生成コンポーネントとしてのLLMを選択、最適化する際には、LLM呼び出しを伴う他のステップにも同等に適用できる以下のファクターを検討しましょう:

1. 様々なオフザシェルフモデルで実験する
    - それぞれのモデルには自身の固有の属性、強み、弱みがあります。あるモデルは特定ドメインをより理解し、特定のタスクに対して優れたパフォーマンスを示します。
    - 上述したように、別のモデルは同じプロンプトに対して異なるレスポンスを返すので、モデルの選択はプロンプトエンジニアリングプロセスに影響を与えることを認識してください。
    - LLMを必要とするあなたのチェーンで、生成ステップに加えてクエリー理解のLLM呼び出しを行うように複数のステップがある場合には、ステップごとに異なるモデルを使うことを検討しましょう。より高価で汎用的なモデルは、ユーザークエリーの意図を特定するようなタスクではオーバーキルとなる場合があります。
1. 小さくスタートして必要に応じてスケールさせる
    - 最もパワフルで能力のあるモデル(GPT-4やClaudeなど)に直ぐに飛びつきたくなるかもしれませんが、より小規模で軽量なモデルからスタートすることが効率的であることが多々あります。
    - 多くの場合、 Llama 3やDBRXのような小規模なオープンソースの代替品は、より少ないコスト、高速な推論時間で満足できる結果を提供することできます。これらのモデルは、特に高度に複雑な理由づけや広範囲の世界の知識を必要としないタスクでは効果的です。
    - あなたのRAGチェーンを開発、改善していく際には、選択したモデルのパフォーマンスと制限を継続的に評価しましょう。お使いのモデルが特定のタイプのクエリーで苦戦し、十分に詳細で正確なレスポンスを生成することに失敗する場合には、より能力のあるモデルにスケールアップすることを検討しましょう。
    - あなた固有のユースケースの要件において適切なバランスを取れるように、モデルを変更することでレスポンスの品質、レーテンシー、コストのようなキーメトリクスに与えるインパクトを監視しましょう。 
1. モデルパラメーターを最適化する
    - レスポンスの品質、多様性、一貫性の最適なバランスを特定するために様々なパラメーターで実験しましょう。たておば、温度の調整によって生成テキストのランダム性をコントロールできますが、max_tokensはレスポンスの長さを制限することができます。
    - 特定のタスク、プロンプト、期待する出力のスタイルに応じて、最適なパラメーター設定が変化することがあることに注意してください。生成されたレスポンスの評価に基づき、これらのセッテイングを繰り返しテスト、改善しましょう。
1. タスク固有のファインチューニング
    - パフォーマンスを改善する過程で、あなたのRAGチェーンにおけるクエリー理解のような特定のサブタスクで用いる小規模なモデルのファインチューニングを検討しましょう。
    - RAGチェーンの個々のタスクに特化したモデルをファインチューニングすることで、全てのタスクで単一の大規模なモデルを用いるよりも、全体的なパフォーマンスを改善し、レーテンシーを削減し、推論コストを引き下げる場合があります。
1. 継続事前トレーニング
    - あなたのRAGアプリケーションが特殊なドメインに対応し、事前トレーニングLLMで適切に表現されない知識を必要とする際には、ドメイン固有データに対する継続事前トレーニング(CPT)の実行を検討しましょう。
    - 継続事前トレーニングによって、あなたのドメイン固有の特殊用語や概念に対するモデルの理解を改善することができます。結果として、これによって広範囲なプロンプトエンジニアリングやfew-shotの例の必要性を削減することができます。

## 3.2.5. 後処理とガードレイル

LLMがレスポンスを生成した後は、多くの場合、アウトプットが期待されるフォーマット、スタイル、コンテンツの要件を満たすように、後処理のテクニックを適用する必要があります。チェーンにおけるこの最後のステップ(あるいは複数のステップ)は、生成されたレスポンスにおける一貫性と品質を維持する助けとなります。後処理とガードレイルを実装しているのであれば、以下のいくつかを検討しましょう:

1. アウトプットフォーマットの強制
    - あなたのユースケースに応じて、生成されたレスポンスが構造化されたテンプレートや特定のファイルタイプ(JSON、HTML、マークダウンなど)のような特定のフォーマットに準拠するように要求する必要があるかもしれません。
    - 構造化されたアウトプットが必要な際には、[Instructor](https://github.com/jxnl/instructor)や[Outlines](https://github.com/outlines-dev/outlines)のようなライブラリがこの種の検証ステップの実装の良いスタート地点を提供します。
    - 開発の際には、後処理スタップが生成されたレスポンスのバリエーションに対応するのに十分な柔軟性を持ちつつも、必要なフォーマットを維持するように時間をかけてください。
1. スタイルの一貫性の維持
    - あなたのRAGアプリケーションに特定のスタイルガイドラインや口調の要件(フォーマル vs カジュアル、簡潔 vs 詳細)がある場合には、後処理ステップでは、生成されたレスポンスのこれらのスタイル属性をチェック、強制することができます。
1. コンテンツフィルターと安全ガードレイル
    - あなたのRAGアプリケーションの特性と生成されるコンテンツに関係する潜在的なリスクに応じて、不適切、攻撃的、有害な情報のアウトプットを回避するための[コンテンツフィルターや安全ガードレイルを実装](https://www.databricks.com/jp/blog/implementing-llm-guardrails-safe-and-responsible-generative-ai-deployment-databricks)することが重要になるかもしれません。
    - 安全ガードレイルを実装するには、[OpenAI’s moderation API](https://platform.openai.com/docs/guides/moderation)のような、コンテンツのモデレーション、安全性のために特別に設計されたAPIや[Llama Guard](https://marketplace.databricks.com/details/a4bc6c21-0888-40e1-805e-f4c99dca41e4/Databricks_Llama-Guard-Model)のようなモデルを使用することを検討してください。
1. ハルシネーションへの対応
    - ハルシネーションに対する防御策も後処理ステップで実装することができます。これには、生成されたアウトプットと収集ドキュメントのクロス参照や、レスポンスの事実の正確性を検証するために他のLLMを活用することが含まれます。
    - 生成されたレスポンスが事実的な正確性要件に応えられない場合に対応できるように、代替のレスポンス生成やユーザーへの免責事項を提供するようなフォールバックの機構を開発しましょう。
1. エラーハンドリング
    - 全ての後処理ステップでは、このステップが問題に直面したり、満足できるレスポンスの生成に失敗した場合に適切に対応するための機構を実装しましょう。これには、デフォルトのレスポンスの生成、手動でのレビューのために人間のオペレーターにエスカレーションするといったことが含まれます。

<br>

- [目次](https://qiita.com/taka_yayoi/items/36c51bce8f33a70cf204#%E7%9B%AE%E6%AC%A1)
- 前のセクション: [3.1. データパイプライン](https://qiita.com/taka_yayoi/items/4f21f8905f54bef53f10)
- 次のセクション: [4\. RAGの品質の評価](https://qiita.com/taka_yayoi/items/c7e549323b9fcbb9edec)


### はじめてのDatabricks

[はじめてのDatabricks](https://qiita.com/taka_yayoi/items/8dc72d083edb879a5e5d)

### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)