ホームページ > バックエンド開発 > Python チュートリアル > 検索拡張生成 (RAG) の究極のガイド

検索拡張生成 (RAG) の究極のガイド

Barbara Streisand
リリース: 2024-12-21 18:55:10
オリジナル
886 人が閲覧しました

OpenAI の ChatGPT のような生成 AI モデルの急速な進化により、自然言語処理に革命が起こり、これらのシステムが一貫した文脈に関連した応答を生成できるようになりました。ただし、最先端のモデルであっても、ドメイン固有のクエリに取り組んだり、高精度の情報を提供したりする場合には制限に直面します。これは、モデルが不正確または捏造された詳細を生成する場合、幻覚などの課題につながることがよくあります。

検索拡張生成 (RAG) は、このギャップを埋めるために設計された革新的なフレームワークです。 RAG は、外部データ ソースをシームレスに統合することで、生成モデルがリアルタイムのニッチな情報を取得できるようにし、精度と信頼性を大幅に向上させます。

この記事では、RAG の仕組みを深く掘り下げ、そのアーキテクチャを探り、その作成にインスピレーションを与えた従来の生成モデルの制限について説明します。また、実際の実装、高度な技術、評価方法にも焦点を当て、AI が特殊なデータと対話する方法を RAG がどのように変革しているかを紹介します。

はじめる

目次

  • RAG とは
  • RAG のアーキテクチャ
  • RAG プロセスの流れ
  • RAG とファインチューニング
  • RAG の種類
  • RAG のアプリケーション
  • RAG を使用した PDF チャット システムの構築
  • リソース

RAGとは

取得拡張生成 (RAG) は、外部データのリアルタイム取得を統合することで生成 AI モデルの機能を強化する高度なフレームワークです。生成モデルは、一貫性のある人間のようなテキストを生成することに優れていますが、正確な、最新の、またはドメイン固有の情報の提供を求められると、たじろぐ可能性があります。ここで RAG が介入し、回答が創造的であるだけでなく、信頼できる関連性の高い情報源に基づいていることを保証します。

RAG は、生成モデルを、通常はベクトル データベースや検索システムを利用した検索メカニズムと接続することによって動作します。クエリを受信すると、検索コンポーネントは膨大な外部データセットを検索して関連情報を取得します。次に、生成モデルがこのデータを合成し、正確かつ文脈上の洞察に富んだ出力を生成します。

幻覚や限られた分野の知識などの主要な課題に対処することで、RAG は専門分野で優れた生成モデルの可能性を解き放ちます。そのアプリケーションは、正確な回答による顧客サポートの自動化から、研究者がオンデマンドで精選された知識にアクセスできるようにするなど、さまざまな業界に及びます。 RAG は、AI システムをよりインテリジェントで信頼性が高く、現実世界のシナリオで役立つものにする上での重要な前進を表します。

RAGのアーキテクチャ

RAG アーキテクチャの可能性とメリットを最大限に引き出すには、RAG アーキテクチャを明確に理解することが不可欠です。このフレームワークの核心は、Retriever と Generator という 2 つの主要コンポーネントで構築されており、情報処理のシームレスなフローで連携します。

この全体的なプロセスを以下に示します:
The ultimate guide to Retrieval-Augmented Generation (RAG)
出典: https://weaviate.io/blog/introduction-to-rag

  • 取得 — RAG の推論段階は取得から始まり、ユーザー クエリに関連するデータが外部知識ソースから取得されます。基本的な RAG 設定では、類似性検索が一般的に使用され、クエリと外部データを同じベクトル空間に埋め込んで、最も近い一致を特定します。 Retriever は、スパース検索やデンス検索などの方法を使用して、ドキュメントを取得する際に重要な役割を果たします。 TF-IDF や BM25 などの技術を使用するスパース検索は、単語の正確な一致に依存しますが、同義語や言い換えに苦労します。一方、密検索は、BERT や RoBERTa などのトランスフォーマー モデルを利用してセマンティック ベクトル表現を作成し、より正確でニュアンスのある一致を可能にします。
  • 拡張 — 外部ソースから最も関連性の高いデータ ポイントを取得した後、拡張プロセスでは、事前定義されたプロンプト テンプレートにこの情報を埋め込むことで、この情報が組み込まれます。
  • 生成 — 生成フェーズでは、モデルは拡張プロンプトを使用して、内部の言語理解と取得した外部データを組み合わせることにより、一貫性のある文脈的に正確な応答を作成します。拡張によって外部の事実が統合される一方で、生成によってこの充実した情報がユーザーのクエリに合わせた自然で人間のようなテキストに変換されます。

RAGのプロセスフロー

RAG プロセス フローのすべての段階と重要なコンポーネントを以下の図に示します。

The ultimate guide to Retrieval-Augmented Generation (RAG)
出典: https://www.griddynamics.com/blog/retrieval-augmented-generation-llm

  • ドキュメントの読み込み: RAG プロセスの最初のステップにはデータの準備が含まれます。これには、ストレージからのドキュメントのロード、抽出、解析、クリーニング、およびドキュメント分割のためのテキストの書式設定が含まれます。テキスト データには、プレーン テキスト、PDF、Word ドキュメント、CSV、JSON、HTML、Markdown、プログラミング コードなど、さまざまな形式があります。 LLM 用にこれらの多様なソースを準備するには、通常、抽出、解析、クリーニングを通じてソースをプレーン テキストに変換する必要があります。
  • ドキュメントの分割: ドキュメントは、テキストの分割またはチャンクによって、より小さく管理しやすいセグメントに分割されます。これは、大きなドキュメントを処理し、LLM のトークン制限 (GPT-3 の 2048 トークンなど) を遵守するために不可欠です。戦略には固定サイズまたはコンテンツ認識のチャンク化が含まれ、アプローチはデータの構造と要件に応じて異なります。 The ultimate guide to Retrieval-Augmented Generation (RAG)

文書を小さなチャンクに分割することは簡単に思えるかもしれませんが、文を不適切に分割しないようにセマンティクスを慎重に検討する必要があり、質問応答などの後続のステップに影響を与える可能性があります。単純な固定サイズのチャンク化アプローチでは、各チャンク内の情報が不完全になる可能性があります。ほとんどのドキュメント セグメンテーション アルゴリズムは、チャンク サイズとオーバーラップを使用します。チャンク サイズは文字、単語、またはトークンの数によって決まり、オーバーラップは隣接するチャンク間でテキストを共有することで連続性を確保します。この戦略は、チャンク全体で意味論的なコンテキストを保持します。

  • テキスト埋め込み: テキスト チャンクはベクトル埋め込みに変換され、意味上の類似性を簡単に比較できる方法で各チャンクを表します。ベクトル埋め込みは、テキストなどの複雑なデータを、同様のデータ点がクラスター化された数学的空間にマッピングします。このプロセスでは、テキストの意味論的な意味がキャプチャされるため、たとえ言い方が違っていても、同様の意味を持つ文がベクトル空間内で近くにマッピングされます。たとえば、「猫がネズミを追いかける」と「ネコ科の動物がげっ歯類を追いかける」は、表現の違いにもかかわらず、近くのポイントにマッピングされます。

The ultimate guide to Retrieval-Augmented Generation (RAG)
出典: https://www.griddynamics.com/blog/retrieval-augmented-generation-llm

  • ベクター ストア: ドキュメントはセグメント化され、ベクター埋め込みに変換された後、ベクターの保存と管理に特化したデータベースであるベクター ストアに保存されます。ベクター ストアにより、類似したベクターの効率的な検索が可能になります。これは、RAG モデルの実行にとって重要です。ベクター ストアの選択は、データの規模や利用可能な計算リソースなどの要素によって異なります。

重要なベクター データベースの一部は次のとおりです。

  • FAISS: Facebook AI によって開発された FAISS は、高次元ベクトルの大規模なコレクションを効率的に管理し、高次元環境で類似性検索とクラスタリングを実行します。メモリ使用量とクエリ期間が最適化され、数十億のベクトルの処理に適したものになります。
  • Chroma: オープンソースのメモリ内ベクトル データベースである Chroma は、LLM アプリケーション向けに設計されており、ベクトルの保存、検索、取得のためのスケーラブルなプラットフォームを提供します。クラウドとオンプレミスの両方の展開をサポートし、さまざまなデータの種類と形式を多用途に処理できます。
  • Weaviate: 自己ホスト型または完全管理型のオープンソースのベクター データベース。高性能、スケーラビリティ、柔軟性に重点を置き、幅広いデータ型とアプリケーションをサポートします。ベクトルとオブジェクトの両方を保存できるため、ベクトルベースとキーワードベースの検索手法を組み合わせることができます。
  • Pinecone: 大規模な ML アプリケーションの開発と展開を簡素化するように設計された、クラウドベースの管理されたベクトル データベースです。多くのベクトル データベースとは異なり、Pinecone は独自のクローズド ソース コードを使用します。高次元ベクトルの処理に優れており、類似性検索、推奨システム、パーソナライゼーション、セマンティック検索などのアプリケーションに適しています。 Pinecone は 1 段階のフィルタリング機能も備えています。
  • ドキュメント検索: ドキュメント検索や質問応答などの情報検索システムの検索プロセスは、クエリが受信され、ドキュメントのインデックス付けと同じ埋め込みモデルを使用してベクトルに変換されるときに始まります。目標は、クエリ ベクトルとインデックス (ベクトル ストア) に格納されているチャンク ベクトルを比較することによって、関連するドキュメント チャンクを返すことです。取得者の役割は、ドキュメントを保存せずに、関連するドキュメント チャンクの ID を識別して返すことです。類似性検索 (コサイン類似性に基づく) や、特定の類似性スコアを超えるドキュメントのみを返すしきい値ベースの検索など、さまざまな検索方法を使用できます。さらに、LLM を利用した取得は、コンテンツとメタデータのフィルタリングの両方を含むクエリに役立ちます。

The ultimate guide to Retrieval-Augmented Generation (RAG)
出典: https://www.griddynamics.com/blog/retrieval-augmented-generation-llm

  • 回答生成: 取得プロセスでは、関連するドキュメント チャンクがユーザー クエリと結合されて、コンテキストと LLM のプロンプトが生成されます。 LangChain の「Stuff」メソッドと呼ばれる最も単純なアプローチでは、すべてのチャンクを同じコンテキスト ウィンドウに集めて直接的かつ単純な答えを求めます。ただし、この方法は、コンテキスト ウィンドウの制限により、大量のドキュメントや複雑なクエリを処理するのに苦労します。これに対処するために、Map-reduce、Refine、Map-rerank などの代替方法が使用されます。 Map-reduce はドキュメントを個別に LLM に送信し、応答を結合します。 Refine はプロンプトを繰り返し更新して回答を絞り込みますが、Map-rerank は関連性に基づいてドキュメントをランク付けするため、複数の説得力のある回答に最適です。

The ultimate guide to Retrieval-Augmented Generation (RAG)

RAG vs ファインチューニング

RAG (検索拡張生成) と微調整は、LLM 機能を拡張するための 2 つの重要な方法であり、それぞれ異なるシナリオに適しています。微調整には、特殊なタスクを実行するためにドメイン固有のデータで LLM を再トレーニングすることが含まれます。これは、特定のトーンやスタイルを必要とするブランディングやクリエイティブ ライティングなどの静的で狭いユースケースに最適です。ただし、コストと時間がかかり、動的で頻繁に更新されるデータには適していません。

一方、RAG はモデルの重みを変更せずに外部データを動的に取得することで LLM を強化し、コスト効率が高く、法律、財務、顧客サービス アプリケーションなどのリアルタイムのデータ駆動型環境に最適です。 RAG を使用すると、LLM は大規模で構造化されていない内部文書コーパスを処理できるようになり、乱雑なデータ リポジトリをナビゲートする従来の方法に比べて大きな利点が得られます。

微調整は微妙な一貫性のある出力の作成に優れていますが、RAG は外部のナレッジ ベースを活用して最新の正確な情報を提供します。実際には、リアルタイムで適応性のある応答を必要とするアプリケーション、特に膨大な非構造化データを管理する企業では、RAG が好まれる選択肢となることがよくあります。

RAGの種類

検索拡張生成 (RAG) アプローチにはいくつかの種類があり、それぞれが特定のユースケースと目的に合わせて調整されています。主なタイプは次のとおりです:

The ultimate guide to Retrieval-Augmented Generation (RAG)
出典: https://x.com/weaviate_io/status/1866528335884325070

  • ネイティブ RAG: 取得拡張生成システムの取得コンポーネントと生成コンポーネントが同じアーキテクチャ内でシームレスに動作するように設計された、緊密に統合されたアプローチを指します。外部ツールや API に依存する従来の実装とは異なり、ネイティブ RAG は取得メカニズムと生成モデルの間の相互作用を最適化し、より高速な処理とコンテキストの関連性の向上を可能にします。このアプローチでは、多くの場合、インメモリ処理または高度に最適化されたローカル データベースが使用され、レイテンシーとリソースのオーバーヘッドが削減されます。ネイティブ RAG システムは通常、特定のユースケースに合わせて調整されており、サードパーティ サービスへの依存を排除​​することで効率、精度、コスト効率が向上します。
  • RAG の取得と再ランク付け: 精度と関連性を向上させるために、取得プロセスを改良することに重点を置いています。この方法では、ドキュメントまたはチャンクの初期セットがクエリの意味的類似性に基づいて取得されます。通常、埋め込み空間のコサイン類似度によって決定されます。その後、再ランキング モデルにより、クエリに対する文脈上の関連性に基づいて、取得されたドキュメントの順序が変更されます。この再ランキングのステップでは、多くの場合、深層学習モデルまたはトランスフォーマーを活用し、基本的な類似性メトリクスを超えた、より微妙なランキングを可能にします。このアプローチでは、最も関連性の高いドキュメントに優先順位を付けることで、生成モデルがコンテキストに富んだ入力を確実に受け取り、応答品質を大幅に向上させることができます。
  • マルチモーダル RAG: テキスト、画像、オーディオ、ビデオなどの複数のデータ モダリティを検索拡張生成パイプラインに組み込むことで、従来の RAG パラダイムを拡張します。これにより、システムはさまざまな形式のデータを統合した応答を取得および生成できます。たとえば、画像ベースのクエリを含むシナリオでは、システムはテキスト コンテンツとともに関連する画像を取得して、より包括的な回答を作成することがあります。マルチモーダル RAG は、電子商取引、医療画像、マルチメディア コンテンツ分析などの分野で特に役立ちます。これらの分野では、洞察がテキスト情報と視覚情報の組み合わせに依存することがよくあります。
  • Graph RAG: グラフベースのデータ構造を利用して、エンティティ間の関係と接続に基づいて情報をモデル化し、取得します。このアプローチでは、知識はグラフとして編成され、ノードがエンティティ (概念、文書、オブジェクトなど) を表し、エッジがそれらの関係 (意味論的、階層的、時間的など) をキャプチャします。クエリが処理されて、入力に関連するサブグラフまたはパスが特定され、これらのサブグラフが生成モデルに供給されます。この方法は、科学研究、ソーシャル ネットワーク、知識管理など、関係性に関する洞察が重要な分野で特に価値があります。
  • ハイブリッド RAG: 密な検索と疎な検索などの複数の検索手法を組み合わせて、さまざまな種類のクエリのパフォーマンスを向上させます。密検索ではベクトル埋め込みを使用して意味上の類似性を取得しますが、疎検索では正確な一致を得るために BM25 などのキーワードベースの方法に依存します。これらのメソッドを統合することで、Hybrid RAG は精度と再現率のバランスをとり、クエリが非常に具体的または抽象的なシナリオ全体で汎用性を持たせることができます。これは、異種データが含まれる環境で特に効果的であり、取得中に高レベルのセマンティクスと特定のキーワードの両方が確実に考慮されます。
  • エージェント RAG (ルーター): 意思決定レイヤーを使用して、クエリをその特性に基づいて適切な検索および生成モジュールに動的にルーティングします。ルーターは受信クエリを分析して最適な処理パスを決定します。これには、さまざまな取得方法、データ ソース、さらには特殊な生成モデルが含まれる場合があります。このアプローチにより、システムは各クエリの特定のニーズに合わせて操作を調整し、さまざまなアプリケーションの効率と精度を向上させることができます。
  • エージェント RAG (マルチエージェント RAG): マルチエージェント RAG には、複数の専門エージェントが取得および生成プロセスの異なる側面を処理する協調フレームワークが含まれます。各エージェントは、特定のドメインからのデータの取得、結果の再ランク付け、特定のスタイルでの応答の生成など、特定のタスクを担当します。これらのエージェントは通信および協力して、一貫した出力を提供します。 Multi-Agent RAG は、システムがさまざまなエージェントの専門知識を活用して包括的で微妙な応答を提供できるため、複雑なマルチドメイン クエリに対して特に強力です。

RAGの応用例

検索拡張生成 (RAG) フレームワークは、外部の知識を生成言語モデルに動的に統合できるため、さまざまな業界にわたって多様なアプリケーションがあります。以下にいくつかの著名なアプリケーションを示します:

  • カスタマー サポートとサービス: RAG システムは、製品マニュアル、ナレッジ ベース、会社のポリシー文書から関連データを取得することで、複雑なクエリに答えることができるインテリジェントなチャットボットを作成するために、カスタマー サポートで広く使用されています。これにより、顧客は正確で最新の情報を確実に受け取り、エクスペリエンスを向上させることができます。
  • 法的文書分析: 法的分野では、RAG は判例法、契約書、法的文書の膨大なコーパスから要約や回答を解析、取得、生成できます。これは、法的調査の実施、契約書の草案作成、規制順守の確保に特に役立ちます。
  • 財務分析: RAG は、収益レポート、市場動向、規制文書を分析するために金融サービスで使用されています。関連する財務データを取得することで、アナリストが洞察、レポート、さらには市場パフォーマンスに関する質問に対するリアルタイムの回答を生成するのに役立ちます。
  • ヘルスケアと医療診断: ヘルスケアでは、RAG は医学文献、患者記録、治療ガイドラインから情報を取得して統合するために利用されます。診断サポート、創薬、個別の治療推奨を支援し、臨床医が最新かつ最も関連性の高いデータに確実にアクセスできるようにします。
  • 教育と E ラーニング: RAG を利用したツールは、コース教材を取得し、カスタマイズされた回答や学習ガイドを生成することで、個別の教育を支援します。ユーザーのクエリに基づいて状況に応じた説明と動的なコンテンツを提供することで、学習プラットフォームを強化できます。
  • 電子商取引と小売: 電子商取引では、RAG システムはカタログや顧客レビューからデータを取得することにより、製品の検索エンジンと推奨エンジンを改善します。また、ユーザーの好みに基づいてパーソナライズされた製品の提案を提供する会話型ショッピング アシスタントも可能になります。
  • インテリジェント仮想アシスタント: RAG は、特にリアルタイムの天気予報やローカル ビジネス情報など、外部の知識を必要とするクエリに対して、正確で状況に応じた応答を提供することで、Alexa や Siri などの仮想アシスタントを強化します。

RAGを使用したPDFチャットシステムの構築

このセクションでは、PDF の内容を理解し、検索拡張生成 (RAG) を使用してその内容に基づいてユーザーのクエリに応答できるストリームリット アプリケーションを開発します。この実装では、LangChain プラットフォームを活用して、LLM およびベクター ストアとの対話を容易にします。 OpenAI の LLM とその埋め込みモデルを利用して、効率的な情報検索のための FAISS ベクトル ストアを構築します。

依存関係のインストール

  • 次のコマンドを実行して仮想環境を作成し、有効化します。
python -m venv venv
source venv/bin/activate #for ubuntu
venv/Scripts/activate #for windows
ログイン後にコピー
  • pip を使用して、langchain、langchain_community、openai、faiss-cpu、PyPDF2、streamlit、python-dotenv、tiktoken ライブラリをインストールします。
pip install langchain langchain_community openai faiss-cpu PyPDF2 streamlit python-dotenv tiktoken
ログイン後にコピー

環境と資格情報のセットアップ

  • .env という名前のファイルを作成します。このファイルには、OpenAI キー、モデル、埋め込みなどの環境変数が保存されます。
  • .env ファイルを開き、次のコードを追加して OpenAI 認証情報を指定します。
OPENAI_API_KEY=sk-proj-xcQxBf5LslO62At...
OPENAI_MODEL_NAME=gpt-3.5-turbo
OPENAI_EMBEDDING_MODEL_NAME=text-embedding-3-small
ログイン後にコピー

環境変数のインポート

  • app.py という名前のファイルを作成します。
  • OpenAI 認証情報を環境変数に追加します。
from dotenv import load_dotenv
import os
load_dotenv()
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
OPENAI_MODEL_NAME = os.getenv("OPENAI_MODEL_NAME")
OPENAI_EMBEDDING_MODEL_NAME = os.getenv("OPENAI_EMBEDDING_MODEL_NAME")
ログイン後にコピー

必要なライブラリをインポートする

アプリの構築、langchain、streamlit、pyPDF などの PDF の処理に必要なライブラリをインポートします。

import streamlit as st
from PyPDF2 import PdfReader
from langchain.text_splitter import CharacterTextSplitter
from langchain.prompts import PromptTemplate
from langchain_community.embeddings import OpenAIEmbeddings
from langchain_community.vectorstores import FAISS
from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationalRetrievalChain
from langchain_community.chat_models import ChatOpenAI
from htmlTemplates import bot_template, user_template, css
ログイン後にコピー

PDF からテキストを抽出する関数の定義

  • PyPDF2 を使用して、アップロードされた PDF ファイルからテキストを抽出します。
def get_pdf_text(pdf_files):
    text = ""
    for pdf_file in pdf_files:
        reader = PdfReader(pdf_file)
        for page in reader.pages:
            text += page.extract_text()
    return text
ログイン後にコピー

抽出されたテキストをチャンクに分割する

LangChain の CharacterTextSplitter を使用して、大きなテキストを小さくて管理しやすいチャンクに分割します。

def get_chunk_text(text):
    text_splitter = CharacterTextSplitter(
        separator="\n",
        chunk_size=1000,
        chunk_overlap=200,
        length_function=len
    )
    chunks = text_splitter.split_text(text)
    return chunks
ログイン後にコピー

テキスト埋め込み用のベクター ストアの作成

FAISS を使用してテキスト チャンクの埋め込みを生成し、ベクター データベースに保存します。

def get_vector_store(text_chunks):
    embeddings = OpenAIEmbeddings(openai_api_key=OPENAI_API_KEY, model=OPENAI_EMBEDDING_MODEL_NAME)
    vectorstore = FAISS.from_texts(texts=text_chunks, embedding=embeddings)
    return vectorstore
ログイン後にコピー

会話型検索チェーンの構築

ベクター ストアから情報を取得し、LLM 経由でユーザーと対話するチェーンを定義します。

def get_conversation_chain(vector_store):
    llm = ChatOpenAI(openai_api_key=OPENAI_API_KEY, model_name=OPENAI_MODEL_NAME, temperature=0)
    memory = ConversationBufferMemory(memory_key='chat_history', return_messages=True)
    system_template  =  """
    Use  the following pieces of context and chat history to answer the question at the end. 
    If you don't know the answer, just say that you don't know, don't try to make up an answer.

    Context: {context}

    Chat history: {chat_history}

    Question: {question}
    Helpful Answer:
    """
    prompt = PromptTemplate(
        template=system_template,
        input_variables=["context", "question",  "chat_history"],
    )
    conversation_chain = ConversationalRetrievalChain.from_llm(
        verbose = True,
        llm=llm,
        retriever=vector_store.as_retriever(),
        memory=memory,
        combine_docs_chain_kwargs={"prompt": prompt}
    )
    return conversation_chain
ログイン後にコピー

ユーザークエリの処理

ユーザー入力を処理し、会話チェーンに渡し、チャット履歴を更新します。

def handle_user_input(question):
    try:
        response = st.session_state.conversation({'question': question})
        st.session_state.chat_history = response['chat_history']
    except Exception as e:
        st.error('Please select PDF and click on Process.')
ログイン後にコピー

ストリームリット チャット用のカスタム HTML テンプレートの作成

CSS を使用してユーザーとボットの両方のメッセージ用のカスタム チャット インターフェイスを作成するには、カスタム テンプレートをデザインし、CSS でスタイルを設定します。

  • htmlTemplates.py という名前のファイルを作成し、次のコードをそれに追加します。
css = '''
<style>
.chat-message {
    padding: 1rem; border-radius: 0.5rem; margin-bottom: 1rem; display: flex
}
.chat-message.user {
    background-color: #2b313e
}
.chat-message.bot {
    background-color: #475063
}
.chat-message .avatar {
  width: 10%;
}
.chat-message .avatar img {
  max-width: 30px;
  max-height: 30px;
  border-radius: 50%;
  object-fit: cover;
}
.chat-message .message {
  width: 90%;
  padding: 0 1rem;
  color: #fff;
}
'''

bot_template = '''
<div>



<h3>
  
  
  Displaying chat history
</h3>

<p>Show the user and AI conversation history in a reverse order with HTML templates for formatting.<br>
</p>

<pre class="brush:php;toolbar:false">def display_chat_history():
    if st.session_state.chat_history:
        reversed_history = st.session_state.chat_history[::-1]

        formatted_history = []
        for i in range(0, len(reversed_history), 2):
            chat_pair = {
                "AIMessage": reversed_history[i].content,
                "HumanMessage": reversed_history[i + 1].content
            }
            formatted_history.append(chat_pair)

        for i, message in enumerate(formatted_history):
            st.write(user_template.replace("{{MSG}}", message['HumanMessage']), unsafe_allow_html=True)
            st.write(bot_template.replace("{{MSG}}", message['AIMessage']), unsafe_allow_html=True)
ログイン後にコピー

Streamlit アプリインターフェイスの構築

ファイルのアップロード、質問の入力、チャット履歴の表示のためのメイン アプリ インターフェイスを設定します。

def main():
    st.set_page_config(page_title='Chat with PDFs', page_icon=':books:')
    st.write(css, unsafe_allow_html=True)

    if "conversation" not in st.session_state:
        st.session_state.conversation = None
    if "chat_history" not in st.session_state:
        st.session_state.chat_history = None

    st.header('Chat with PDFs :books:')

    question = st.text_input("Ask anything to your PDF:")
    if question:
        handle_user_input(question)

    if st.session_state.chat_history is not None:
        display_chat_history()

    with st.sidebar:
        st.subheader("Upload your Documents Here: ")
        pdf_files = st.file_uploader("Choose your PDF Files and Press Process button", type=['pdf'], accept_multiple_files=True)

        if pdf_files and st.button("Process"):
            with st.spinner("Processing your PDFs..."):
                try:
                    # Get PDF Text
                    raw_text = get_pdf_text(pdf_files)
                    # Get Text Chunks
                    text_chunks = get_chunk_text(raw_text)
                    # Create Vector Store
                    vector_store = get_vector_store(text_chunks)
                    st.success("Your PDFs have been processed successfully. You can ask questions now.")
                    # Create conversation chain
                    st.session_state.conversation = get_conversation_chain(vector_store)
                except Exception as e:
                    st.error(f"An error occurred: {e}")

if __name__ == '__main__':
    main()
ログイン後にコピー

PDF チャット アプリケーションの完全なコード

以下は、PDF チャット アプリケーションの完全なコード実装です。環境変数の設定、テキスト抽出、ベクトル ストレージ、RAG 機能を合理化されたソリューションに統合します。

from dotenv import load_dotenv
import os
load_dotenv()
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
OPENAI_MODEL_NAME = os.getenv("OPENAI_MODEL_NAME")
OPENAI_EMBEDDING_MODEL_NAME = os.getenv("OPENAI_EMBEDDING_MODEL_NAME")

import streamlit as st
from PyPDF2 import PdfReader
from langchain.text_splitter import CharacterTextSplitter
from langchain.prompts import PromptTemplate
from langchain_community.embeddings import OpenAIEmbeddings
from langchain_community.vectorstores import FAISS
from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationalRetrievalChain
from langchain_community.chat_models import ChatOpenAI
from htmlTemplates import bot_template, user_template, css

def get_pdf_text(pdf_files):
    text = ""
    for pdf_file in pdf_files:
        reader = PdfReader(pdf_file)
        for page in reader.pages:
            text += page.extract_text()
    return text

def get_chunk_text(text):
    text_splitter = CharacterTextSplitter(
        separator="\n",
        chunk_size=1000,
        chunk_overlap=200,
        length_function=len
    )
    chunks = text_splitter.split_text(text)
    return chunks

def get_vector_store(text_chunks):
    embeddings = OpenAIEmbeddings(openai_api_key=OPENAI_API_KEY, model=OPENAI_EMBEDDING_MODEL_NAME)
    vectorstore = FAISS.from_texts(texts=text_chunks, embedding=embeddings)
    return vectorstore

def get_conversation_chain(vector_store):
    llm = ChatOpenAI(openai_api_key=OPENAI_API_KEY, model_name=OPENAI_MODEL_NAME, temperature=0)
    memory = ConversationBufferMemory(memory_key='chat_history', return_messages=True)
    system_template  =  """
    Use  the following pieces of context and chat history to answer the question at the end. 
    If you don't know the answer, just say that you don't know, don't try to make up an answer.

    Context: {context}

    Chat history: {chat_history}

    Question: {question}
    Helpful Answer:
    """
    prompt = PromptTemplate(
        template=system_template,
        input_variables=["context", "question",  "chat_history"],
    )
    conversation_chain = ConversationalRetrievalChain.from_llm(
        verbose = True,
        llm=llm,
        retriever=vector_store.as_retriever(),
        memory=memory,
        combine_docs_chain_kwargs={"prompt": prompt}
    )
    return conversation_chain

def handle_user_input(question):
    try: 
        response = st.session_state.conversation({'question': question})
        st.session_state.chat_history = response['chat_history']
    except Exception as e:
        st.error('Please select PDF and click on OK.')

def display_chat_history():
    if st.session_state.chat_history:
        reversed_history = st.session_state.chat_history[::-1]

        formatted_history = []
        for i in range(0, len(reversed_history), 2):
            chat_pair = {
                "AIMessage": reversed_history[i].content,
                "HumanMessage": reversed_history[i + 1].content
            }
            formatted_history.append(chat_pair)

        for i, message in enumerate(formatted_history):
            st.write(user_template.replace("{{MSG}}", message['HumanMessage']), unsafe_allow_html=True)
            st.write(bot_template.replace("{{MSG}}", message['AIMessage']), unsafe_allow_html=True)

def main():
    st.set_page_config(page_title='Chat with PDFs', page_icon=':books:')
    st.write(css, unsafe_allow_html=True)

    if "conversation" not in st.session_state:
        st.session_state.conversation = None
    if "chat_history" not in st.session_state:
        st.session_state.chat_history = None

    st.header('Chat with PDFs :books:')

    question = st.text_input("Ask anything to your PDF:")
    if question:
        handle_user_input(question)

    if st.session_state.chat_history is not None:
        display_chat_history()

    with st.sidebar:
        st.subheader("Upload your Documents Here: ")
        pdf_files = st.file_uploader("Choose your PDF Files and Press Process button", type=['pdf'], accept_multiple_files=True)

        if pdf_files and st.button("Process"):
            with st.spinner("Processing your PDFs..."):
                try:
                    # Get PDF Text
                    raw_text = get_pdf_text(pdf_files)
                    # Get Text Chunks
                    text_chunks = get_chunk_text(raw_text)
                    # Create Vector Store
                    vector_store = get_vector_store(text_chunks)
                    st.success("Your PDFs have been processed successfully. You can ask questions now.")
                    # Create conversation chain
                    st.session_state.conversation = get_conversation_chain(vector_store)
                except Exception as e:
                    st.error(f"An error occurred: {e}")

if __name__ == '__main__':
    main()

ログイン後にコピー

アプリケーションを実行する

次のコマンドを使用して、Streamlit でアプリを実行します。

streamlit run app.py
ログイン後にコピー

次のような出力が得られます。
The ultimate guide to Retrieval-Augmented Generation (RAG)

この記事をお読みいただきありがとうございます!!

コンテンツをレビューしてくださった Gowri M Bhatt に感謝します。

この記事が気に入ったら、ハート ボタン ♥ をクリックして共有し、他の人が記事を見つけられるようにしてください。

このチュートリアルの完全なソース コードはここにあります

codemaker2015/pdf-chat-using-RAG | github.com

リソース

  • RAG および LLM ビジネス プロセスの自動化: 技術戦略 - Grid Dynamics | www.gridynamics.com
  • 検索拡張生成 (RAG) の概要 |回避
  • 拡張言語モデルの技術、課題、将来 - グラデーション フロー
  • 地球規模での検索拡張生成 |アークス

以上が検索拡張生成 (RAG) の究極のガイドの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート