paint-brush
LangChain を使用した RAG アプリケーションの構築に関する包括的なチュートリアル@bexgboost
1,895 測定値
1,895 測定値

LangChain を使用した RAG アプリケーションの構築に関する包括的なチュートリアル

Bex19m2024/09/03
Read on Terminal Reader

長すぎる; 読むには

RAG システムを構築するための非常に人気のあるフレームワークである LangChain の使い方を学びます。チュートリアルの最後には、プライベート データを RAG して質問に答えるチャットボット (Streamlit インターフェイスなどを含む) が完成します。
featured image - LangChain を使用した RAG アプリケーションの構築に関する包括的なチュートリアル
Bex HackerNoon profile picture

今日の大規模言語モデルは、増え続ける情報にアクセスできます。しかし、これらのモデルが活用していない膨大なプライベートデータがまだ残っています。そのため、企業環境でのLLMの最も人気のあるアプリケーションの1つは、検索拡張生成(略してRAG)です。ヴィズリー、AI を活用したデータ分析プラットフォームを通じて、効果的な RAG システムの構築に関する貴重な洞察を得ました。このチュートリアルでは、私たちが学んだことの一部を共有し、独自の RAG システムを作成する方法を紹介します。


RAG システムを構築するための非常に人気のあるフレームワークである LangChain を使用して、シンプルな RAG システムを構築する方法を学びます。チュートリアルの最後には、プライベート データを RAG して質問に答えるチャットボット (Streamlit インターフェイスなどを含む) が完成します。

RAGとは何ですか?

RAG とは何かを明確にするために、簡単な例を考えてみましょう。


大学 1 年生のチャンドラーは、いくつかの授業を欠席しようと考えていますが、大学の出席規則に違反していないことを確認したいと思っています。最近のあらゆることと同様に、彼はChatGPTに質問します。


もちろん、ChatGPT はそれに答えることができません。チャットボットは愚かではありません。チャンドラーの大学の文書にアクセスできないだけです。そこでチャンドラーは自分でポリシー文書を見つけ、それが長くて技術的な内容で、読みたくないものであることを知りました。代わりに、彼は文書全体を ChatGPT に渡して、もう一度質問しました。今度は、彼は答えを得ました。


これは、検索拡張生成の個別のケースです。言語モデルの回答 (生成) は、元のトレーニングの一部ではないソースから取得されたコンテキストによって拡張 (強化) されます。


RAG システムのスケーラブルなバージョンでは、大学のドキュメント自体を検索し、関連するドキュメントを見つけ、回答が含まれている可能性が最も高いテキストのチャンクを取得することで、学生のあらゆる質問に答えることができます。


一般的に、RAG システムでは、プライベート データ ソースから情報を取得して言語モデルにフィードし、モデルがコンテキストに適した回答を提供できるようにします。

RAG アプリケーションのコンポーネント

このようなシステムは、単純に聞こえるかもしれませんが、多くの可動コンポーネントで構成されます。自分で構築する前に、それらが何であるか、どのように連携するかを確認する必要があります。

文書

最初のコンポーネントは、ドキュメントまたはドキュメントのコレクションです。構築している RAG システムの種類に応じて、ドキュメントはテキスト ファイル、PDF、Web ページ (非構造化データに対する RAG)、またはグラフ、SQL、NoSQL データベース (構造化データに対する RAG) になります。これらは、さまざまな種類のデータをシステムに取り込むために使用されます。

ドキュメントローダー

LangChain は、 PDF、Slack、Notion、Google Drive などのさまざまなドキュメント ソースからデータを読み込むために、ドキュメント ローダーと呼ばれる数百のクラスを実装しています。


各ドキュメント ローダー クラスはそれぞれ異なりますが、すべて同じ.load()メソッドを共有しています。たとえば、LangChain で PDF ドキュメントと Web ページをロードする方法は次のとおりです。

 from langchain_community.document_loaders import PyPDFLoader, WebBaseLoader # pip install langchain-community pdf_loader = PyPDFLoader("framework_docs.pdf") web_loader = WebBaseLoader( "https://python.langchain.com/v0.2/docs/concepts/#document-loaders" ) pdf_docs = pdf_loader.load() web_docs = web_loader.load()


PyPDFLoader クラスは、内部で PyPDF2 パッケージを使用して PDF ファイルを処理し、WebBaseLoader は指定された Web ページのコンテンツを取得します。


pdf_docsには、ページごとに 1 つずつ、合計 4 つのドキュメント オブジェクトが含まれています。


 >>> len(pdf_docs) 4


web_docsは次の 1 つだけが含まれます。

 >>> print(web_docs[0].page_content[125:300].strip()) You can view the v0.1 docs here.IntegrationsAPI referenceLatestLegacyMorePeopleContributingCookbooks3rd party tutorialsYouTubearXivv0.2v0.2v0.1🦜️🔗LangSmithLangSmith DocsLangCh


これらのドキュメント オブジェクトは、後で埋め込みモデルに渡され、テキストの背後にある意味を理解します。


他の種類のドキュメントローダーの詳細については、LangChainが提供しています。専用のハウツーページ

テキスト分割

ドキュメントを読み込んだら、それをより小さく扱いやすいテキストの塊に分割することが重要です。主な理由は次のとおりです。

  1. 多くの埋め込みモデル (後ほど詳しく説明します) には、最大トークン制限があります。
  2. チャンクが小さいほど、検索の精度が高まります。
  3. 言語モデルには正確なコンテキストが供給されます。


LangChain は、langchain_text_splitters パッケージで多くの種類のテキスト スプリッターを提供しており、それらはドキュメントの種類によって異なります。

RecursiveCharacterTextSplitterを使用して、区切り文字とチャンク サイズのリストに基づいてプレーン テキストを分割する方法は次のとおりです。

 !pip install langchain_text_splitters from langchain_text_splitters import RecursiveCharacterTextSplitter # Example text text = """ RAG systems combine the power of large language models with external knowledge sources. This allows them to provide up-to-date and context-specific information. The process involves several steps including document loading, text splitting, and embedding. """ # Create a text splitter text_splitter = RecursiveCharacterTextSplitter( chunk_size=50, chunk_overlap=10, length_function=len, separators=["\n\n", "\n", " ", ""], ) # Split the text chunks = text_splitter.split_text(text) # Print the chunks for i, chunk in enumerate(chunks): print(f"Chunk {i + 1}: {chunk}")

出力:

 Chunk 1: RAG systems combine the power of large language Chunk 2: language models with external knowledge sources. Chunk 3: This allows them to provide up-to-date and Chunk 4: and context-specific information. Chunk 5: The process involves several steps including Chunk 6: including document loading, text splitting, and Chunk 7: and embedding.

このスプリッターは多用途で、多くのユースケースに適しています。可能な限りchunk_sizeに近い文字数で各チャンクを作成します。文字数を維持するために、どのセパレーターで分割するかを再帰的に切り替えることができます。


上記の例では、スプリッターは最初に改行で分割し、次に単一のスペースで分割し、最後に任意の文字間で分割して、目的のチャンク サイズに到達しようとします。


langchain_text_splittersパッケージ内には、他にも多くのスプリッターがあります。以下にいくつか挙げます。

  • HTMLSectionSplitter
  • PythonCodeTexSplitter
  • RecursiveJsonSplitter

などです。一部のスプリッターは、内部でトランスフォーマー モデルを使用して、意味的に意味のあるチャンクを作成します。


適切なテキスト スプリッターは、R​​AG システムのパフォーマンスに大きな影響を与えます。


テキストスプリッターの使用方法の詳細については、関連するハウツーガイドはこちら

埋め込みモデル

ドキュメントがテキストに分割されると、数値表現にエンコードする必要があります。これは、テキスト データで動作するすべての計算モデルの要件です。


RAG のコンテキストでは、このエンコードは埋め込みと呼ばれ、埋め込みモデルによって実行されます。埋め込みモデルは、テキストの意味を捉えたテキストのベクトル表現を作成します。この方法でテキストを提示することで、ドキュメント データベースで意味が最も類似するテキストを検索したり、ユーザー クエリの回答を見つけたりするなど、テキストに対して数学的操作を実行できます。


LangChain は、OpenAI、Cohere、HuggingFace などの主要な埋め込みモデル プロバイダーをすべてサポートしています。これらはEmbeddingクラスとして実装されており、ドキュメントを埋め込むためのメソッドとクエリ (プロンプト) を埋め込むためのメソッドの 2 つを提供します。


以下は、前のセクションで OpenAI を使用して作成したテキストのチャンクを埋め込むコード例です。

 from langchain_openai import OpenAIEmbeddings # Initialize the OpenAI embeddings embeddings = OpenAIEmbeddings() # Embed the chunks embedded_chunks = embeddings.embed_documents(chunks) # Print the first embedded chunk to see its structure print(f"Shape of the first embedded chunk: {len(embedded_chunks[0])}") print(f"First few values of the first embedded chunk: {embedded_chunks[0][:5]}")


出力:

 Shape of the first embedded chunk: 1536 First few values of the first embedded chunk: [-0.020282309502363205, -0.0015041005099192262, 0.004193042870610952, 0.00229285703971982, 0.007068077567964792]

上記の出力は、埋め込みモデルがドキュメント内のすべてのチャンクに対して 1536 次元のベクトルを作成していることを示しています。


単一のクエリを埋め込むには、 embed_query()メソッドを使用します。

 query = "What is RAG?" query_embedding = embeddings.embed_query(query) print(f"Shape of the query embedding: {len(query_embedding)}") print(f"First few values of the query embedding: {query_embedding[:5]}")


出力:

 Shape of the query embedding: 1536 First few values of the query embedding: [-0.012426204979419708, -0.016619959846138954, 0.007880032062530518, -0.0170428603887558, 0.011404196731746197]

ベクターストア

ギガバイト単位のドキュメントを扱う大規模な RAG アプリケーションでは、膨大な数のテキスト チャンクとベクトルが生成されます。これらを確実に保存できなければ、何の役にも立ちません。


これが、ベクター ストアやデータベースが今大流行している理由です。ベクター データベースは、埋め込みを保存するだけでなく、ベクター検索も実行します。これらのデータベースは、クエリ ベクトルが与えられたときに最も類似したベクトルをすばやく見つけられるように最適化されており、これは RAG システムで関連情報を取得するために不可欠です。


以下は、Web ページのコンテンツを埋め込み、そのベクトルを Chroma ベクトル データベース ( Chroma は、完全にマシン上で実行されるオープン ソースのベクトル データベース ソリューションです) に保存するコード スニペットです。

 !pip install chromadb langchain_chroma from langchain_community.document_loaders import WebBaseLoader from langchain_text_splitters import RecursiveCharacterTextSplitter # Load the web page loader = WebBaseLoader("https://python.langchain.com/v0.2/docs/tutorials/rag/") docs = loader.load() # Split the documents into chunks text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200) chunks = text_splitter.split_documents(docs)


まず、 WebBaseLoaderでページをロードし、チャンクを作成します。次に、選択した埋め込みモデルとともに、チャンクをChromafrom_documentsメソッドに直接渡します。

 from langchain_openai import OpenAIEmbeddings from langchain_chroma import Chroma db = Chroma.from_documents(chunks, OpenAIEmbeddings())


LangChain のすべてのベクター データベース オブジェクトは、クエリ文字列を受け入れるsimilarity_searchメソッドを公開します。

 query = "What is indexing in the context of RAG?" docs = db.similarity_search(query) print(docs[1].page_content)


出力:

 If you are interested for RAG over structured data, check out our tutorial on doing question/answering over SQL data.Concepts​A typical RAG application has two main components:Indexing: a pipeline for ingesting data from a source and indexing it. This usually happens offline.Retrieval and generation: the actual RAG chain, which takes the user query at run time and retrieves the relevant data from the index, then passes that to the model.The most common full sequence from raw data to answer looks like:Indexing​Load: First we need to load our data. This is done with Document Loaders.Split: Text splitters break large Documents into smaller chunks. This is useful both for indexing data and for passing it in to a model, since large chunks are harder to search over and won't fit in a model's finite context window.Store: We need somewhere to store and index our splits, so that they can later be searched over. This is often done using a VectorStore and Embeddings model.Retrieval and

similarity_searchの結果は、クエリで要求している情報を含む可能性が最も高いドキュメントのリストです。


ベクトルストアの使用方法の詳細については、関連するハウツーガイドはこちら

レトリーバー

すべてのベクター ストアは類似性検索の形式での検索をサポートしていますが、LangChain は、非構造化クエリが与えられた場合にドキュメントを返す専用のRetrieverインターフェイスを実装しています。リトリーバーはドキュメントを返すか取得するだけでよく、保存する必要はありません。


LangChain で任意のベクター ストアをリトリーバーに変換する方法は次のとおりです。

 # Convert the vector store to a retriever chroma_retriever = db.as_retriever() docs = chroma_retriever.invoke("What is indexing in the context of RAG?") >>> len(docs) 4


search_kwargsを使用すると、関連するドキュメントの数を上位kに制限することができます。

 chroma_retriever = db.as_retriever(search_kwargs={"k": 1}) docs = chroma_retriever.invoke("What is indexing in the context of RAG?") >>> len(docs) 1

search_kwargsには他の検索関連のパラメータを渡すこともできます。リトリーバーの使用の詳細については、 具体的なハウツーガイド

LangChain で RAG アプリを構築するためのステップバイステップのワークフロー

RAG システムの主要コンポーネントについて説明したので、実際にシステムを構築してみましょう。コード ドキュメントとチュートリアル用に特別に設計された RAG チャットボットの実装を、ステップごとに説明します。これは、今日の LLM のナレッジ ベースにまだ含まれていない新しいフレームワークや既存のフレームワークの新機能の AI コーディング支援が必要な場合に特に役立ちます。

0. プロジェクト構造の作成

まず、作業ディレクトリに次のプロジェクト構造を設定します。

 rag-chatbot/ ├── .gitignore ├── requirements.txt ├── README.md ├── app.py ├── src/ │ ├── __init__.py │ ├── document_processor.py │ └── rag_chain.py └── .streamlit/ └── config.toml


コマンドは次のとおりです:

 $ touch .gitignore requirements.txt README.md app.py $ mkdir src .streamlit $ touch src/{.env,__init__.py,document_processor.py,rag_chain.py} $ touch .streamlit/{.env,config.toml}

1. 環境の設定

このステップでは、まず新しい Conda 環境を作成し、それをアクティブ化します。

 $ conda create -n rag_tutorial python=3.9 -y $ conda activate rag_tutorial


次に、 requirements.txtファイルを開き、次の依存関係を貼り付けます。

 langchain==0.2.14 langchain_community==0.2.12 langchain_core==0.2.35 langchain_openai==0.1.22 python-dotenv==1.0.1 streamlit==1.37.1 faiss-cpu pypdf

インストールします:

 $ pip install -r requirements.txt


また、git インデックスからファイルを非表示にするために.gitignoreファイルを作成します。

 # .gitignore venv/ __pycache__/ .env *.pdf *.png *.jpg *.jpeg *.gif *.svg

2. ドキュメントローダーの設定

次に、 src/document_processor.pyファイルを開き、次のコード スニペットを貼り付けます。


必要なインポート:

 import logging from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.text_splitter import Language from langchain_community.document_loaders import PyPDFLoader from langchain_community.document_loaders.parsers.pdf import ( extract_from_images_with_rapidocr, ) from langchain.schema import Document


インポートの説明:

  • RecursiveCharacterTextSplitter : テキストを再帰的に小さなチャンクに分割します。
  • Language : テキスト分割でプログラミング言語を指定するための列挙型。
  • PyPDFLoader : PDF ファイルからテキストを読み込んで抽出します。
  • extract_from_images_with_rapidocr : 画像からテキストを抽出するための OCR 関数。
  • Document : コンテンツとメタデータを含むドキュメントを表します。
  • logging : デバッグと情報のためのロギング機能を提供します。


次に、PDF を処理する関数:

 def process_pdf(source): loader = PyPDFLoader(source) documents = loader.load() # Filter out scanned pages unscanned_documents = [doc for doc in documents if doc.page_content.strip() != ""] scanned_pages = len(documents) - len(unscanned_documents) if scanned_pages > 0: logging.info(f"Omitted {scanned_pages} scanned page(s) from the PDF.") if not unscanned_documents: raise ValueError( "All pages in the PDF appear to be scanned. Please use a PDF with text content." ) return split_documents(unscanned_documents)


仕組みは次のとおりです:

  1. PyPDFLoaderを使用して PDF を読み込みます。
  2. 空のコンテンツを含むドキュメントを削除することで、スキャンされたページをフィルタリングします。
  3. 省略されたスキャンページ数があれば、それをログに記録します。
  4. すべてのページがスキャンされた場合 (つまり、テキスト コンテンツがない場合)、ValueError が発生します。
  5. 最後に、split_documents 関数を使用して、スキャンされていない残りのドキュメントを小さなチャンクに分割します。

この関数は、PDF にテキストとスキャンされたページが混在している場合に、テキストベースのページのみがさらに処理されるように処理します。これは、OCR なしでスキャンされたページが使用できないテキスト分析タスクにとって非常に重要です。split_documents 関数split_documents後で定義します。


次に、画像 (コード スニペットや Web ページのスクリーンショット) から情報を取得するための関数を記述します。


 def process_image(source): # Extract text from image using OCR with open(source, "rb") as image_file: image_bytes = image_file.read() extracted_text = extract_from_images_with_rapidocr([image_bytes]) documents = [Document(page_content=extracted_text, metadata={"source": source})] return split_documents(documents)


この関数は、OCR (光学式文字認識) を使用してテキストを抽出して画像ファイルを処理します。画像ファイルを読み取り、バイトに変換してから、RapidOCR ライブラリを使用して画像からテキストを抽出します。抽出されたテキストは、ソース ファイル パスを含むメタデータとともに Document オブジェクトにラップされます。最後に、関数は、次に定義するsplit_documents関数を使用して、ドキュメントを小さなチャンクに分割します。


 def split_documents(documents): # Split documents into smaller chunks for processing text_splitter = RecursiveCharacterTextSplitter.from_language( language=Language.PYTHON, chunk_size=1000, chunk_overlap=200 ) return text_splitter.split_documents(documents)


この関数は、Python の構文で RecursiveCharacterTextSplitter クラスを使用して、テキストを 1000 文字と 200 文字の重複のチャンクに分割します。


最後の関数は、PDF と画像パーサー関数を 1 つに結合します。


 def process_document(source): # Determine file type and process accordingly if source.lower().endswith(".pdf"): return process_pdf(source) elif source.lower().endswith((".png", ".jpg", ".jpeg")): return process_image(source) else: raise ValueError(f"Unsupported file type: {source}")


この最後の関数は、Streamlit UI によって使用され、提供されたドキュメントからチャンクを作成、埋め込み、保存し、システムの RAG コンポーネントに渡します。

3. RAGの設定

次に、 src/rag_chain.pyファイルを開き、次のコード スニペットを貼り付けます。


まず、必要なモジュールをインポートします。


 import os from dotenv import load_dotenv from langchain.prompts import PromptTemplate from langchain_community.vectorstores import FAISS from langchain_core.output_parsers import StrOutputParser from langchain_core.runnables import RunnablePassthrough from langchain_openai import ChatOpenAI, OpenAIEmbeddings # Load the API key from env variables load_dotenv() api_key = os.getenv("OPENAI_API_KEY")


インポートの説明は次のとおりです。

os : オペレーティングシステムのインタラクション • dotenv : 環境変数の読み込み • langchainコンポーネント:

  • PromptTemplate : カスタムプロンプトの作成
  • FAISS : ドキュメント用の軽量ベクターストア
  • StrOutputParser : LLM メッセージ オブジェクトを文字列出力に変換する
  • RunnablePassthrough : 構成可能なチェーンを作成する
  • ChatOpenAIOpenAIEmbeddings : OpenAIモデルのインタラクション


次に、RAG システムのプロンプトを作成します。


 RAG_PROMPT_TEMPLATE = """ You are a helpful coding assistant that can answer questions about the provided context. The context is usually a PDF document or an image (screenshot) of a code file. Augment your answers with code snippets from the context if necessary. If you don't know the answer, say you don't know. Context: {context} Question: {question} """ PROMPT = PromptTemplate.from_template(RAG_PROMPT_TEMPLATE)


RAG システム プロンプトは、成功の重要な要素の 1 つです。当社のバージョンはシンプルですが、ほとんどの場合は問題なく機能します。実際には、プロンプトを繰り返し改善するのに多くの時間を費やすことになります。


お気づきかもしれませんが、プロンプトの構築にはPromptTemplateクラスを使用しています。この構造により、ドキュメントから取得したコンテキストとユーザーのクエリを最終プロンプトに動的に取り込むことができます。


ドキュメントについて言えば、システム プロンプトにコンテキストとして渡される前に、ドキュメントをフォーマットする関数が必要です。


 def format_docs(docs): return "\n\n".join(doc.page_content for doc in docs)


取得したドキュメントのページコンテンツを連結する単純な関数です。


最後に、RAG チェーンを開発する関数を作成します。


 def create_rag_chain(chunks): embeddings = OpenAIEmbeddings(api_key=api_key) doc_search = FAISS.from_documents(chunks, embeddings) retriever = doc_search.as_retriever( search_type="similarity", search_kwargs={"k": 5} ) llm = ChatOpenAI(model_name="gpt-4o-mini", temperature=0) rag_chain = ( {"context": retriever | format_docs, "question": RunnablePassthrough()} | PROMPT | llm | StrOutputParser() ) return rag_chain


この関数は、 document_processor.pyスクリプト内のprocess_document関数によって提供されるドキュメント チャンクを受け入れます。

この関数は、埋め込みモデルを定義し、ドキュメントを FAISS ベクトル ストアに保存することから始まります。次に、類似性検索を備えたリトリーバー インターフェイスに変換され、ユーザーのクエリに一致する上位 5 つのドキュメントが返されます。


言語モデルにはgpt-4o-miniを使用しますが、予算とニーズに応じて GPT-4o などの他のモデルを使用することもできます。

次に、LangChain Expression Language (LCEL) を使用して、これらすべてのコンポーネントを組み合わせます。チェーンの最初のコンポーネントは、 contextquestionキーとする辞書です。これらのキーの値は、それぞれフォーマット関数とRunnablePassthrough()によってフォーマットされたリトリーバーによって提供されます。後者のクラスは、ユーザーのクエリのプレースホルダーとして機能します。


次に、辞書がシステム プロンプトに渡され、プロンプトが LLM に送られ、出力メッセージ クラスが生成されます。メッセージ クラスは、プレーン テキスト応答を返す文字列出力パーサーに渡されます。

4. Streamlit UI の作成

このセクションでは、アプリ用に以下の UI を構築します。


Streamlit UI のスクリーンショット。

これは、ドキュメント用とドキュメントに関する質問用の 2 つの入力フィールドを備えた、すっきりとした最小限のインターフェースです。左側のサイドバーでは、ユーザーは API キーを入力するよう求められます。


インターフェースを構築するには、作業ディレクトリの最上位レベルにあるapp.pyスクリプトを開き、次のコードを貼り付けます。


 import streamlit as st import os from dotenv import load_dotenv from src.document_processor import process_document from src.rag_chain import create_rag_chain # Load environment variables load_dotenv() st.set_page_config(page_title="RAG Chatbot", page_icon="🤖") st.title("RAG Chatbot") # Initialize session state if "rag_chain" not in st.session_state: st.session_state.rag_chain = None # Sidebar for API key input with st.sidebar: api_key = st.text_input("Enter your OpenAI API Key", type="password") if api_key: os.environ["OPENAI_API_KEY"] = api_key # File uploader uploaded_file = st.file_uploader("Choose a file", type=["pdf", "png", "jpg", "jpeg"]) if uploaded_file is not None: if st.button("Process File"): if api_key: with st.spinner("Processing file..."): # Save the uploaded file temporarily with open(uploaded_file.name, "wb") as f: f.write(uploaded_file.getbuffer()) try: # Process the document chunks = process_document(uploaded_file.name) # Create RAG chain st.session_state.rag_chain = create_rag_chain(chunks) st.success("File processed successfully!") except ValueError as e: st.error(str(e)) finally: # Remove the temporary file os.remove(uploaded_file.name) else: st.error("Please provide your OpenAI API key.") # Query input query = st.text_input("Ask a question about the uploaded document") if st.button("Ask"): if st.session_state.rag_chain and query: with st.spinner("Generating answer..."): result = st.session_state.rag_chain.invoke(query) st.subheader("Answer:") st.write(result) elif not st.session_state.rag_chain: st.error("Please upload and process a file first.") else: st.error("Please enter a question.")


わずか 65 行ですが、次の機能を実装しています。

  1. API キー入力: ユーザーが OpenAI API キーを安全に入力できるようにします。
  2. ファイルのアップロード: PDF、PNG、JPG、JPEG ファイルのアップロードをサポートします。
  3. ドキュメント処理: アップロードされたファイルを処理し、テキスト チャンクを作成します。
  4. RAG チェーンの作成: 処理されたドキュメント チャンクを使用して、検索拡張生成チェーンを構築します。
  5. クエリ処理: アップロードされたドキュメントに関するユーザーの質問を受け入れます。
  6. 回答生成: RAG チェーンを使用して、アップロードされたドキュメントとユーザー クエリに基づいて回答を生成します。
  7. エラー処理: API キーが見つからない場合、ファイルが処理されていない場合、またはクエリが空の場合に適切なエラー メッセージを提供します。
  8. ユーザー フィードバック: 処理中にスピナーを表示し、成功/エラー メッセージを表示してユーザーに情報を提供します。
  9. 状態管理: Streamlit のセッション状態を利用して、インタラクション全体にわたって RAG チェーンを維持します。

5. Streamlitチャットボットとして展開する

残っているのは、Streamlit アプリを展開するステップだけです。ここでは多くのオプションがありますが、最も簡単な方法は、無料で簡単にセットアップできる Streamlit Cloud を使用することです。


まず、 .streamlit/config.tomlスクリプトを開き、次の設定を貼り付けます。


 [theme] primaryColor = "#F63366" backgroundColor = "#FFFFFF" secondaryBackgroundColor = "#F0F2F6" textColor = "#262730" font = "sans serif"


これらは個人的な好みから生まれたテーマの調整です。次に、README.md ファイルを作成します ( GitHub でホストされているこのファイルから内容をコピーできます)。


最後に、 GitHub.comにアクセスして新しいリポジトリを作成します。そのリンクをコピーして、作業ディレクトリに戻ります。


 $ git init $ git add . $ git commit -m "Initial commit" $ git remote add origin https://github.com/YourUsername/YourRepo.git $ git push --set-upstream origin master


上記のコマンドは Git を初期化し、最初のコミットを作成し、すべてをリポジトリにプッシュします (リポジトリ リンクを独自のものに置き換えることを忘れないでください)。


次に、 Streamlit Cloudで無料アカウントにサインアップする必要があります。GitHub アカウントを接続し、アプリが含まれているリポジトリを選択します。


次に、アプリの設定を構成します。

  • Pythonのバージョンを設定します(例:3.9)
  • メインファイルパスをapp.pyに設定する
  • アプリ設定に必要なシークレット( OPENAI_API_KEYなど)を追加します。


最後に、「デプロイ」をクリックします。


アプリは数分以内に動作可能になる必要があります。このチュートリアル用に作成したアプリは、このリンクから入手できます。ぜひお試しください。

RAGシステムの実例

結論

このチュートリアルでは、ドキュメントに基づくインタラクティブな質問応答システムを形成する、検索拡張生成 (RAG) と Streamlit の強力な組み合わせについて説明します。環境の設定、ドキュメントの処理から、RAG チェーンの構築、使いやすい Web アプリの展開まで、プロセス全体を解説します。


重要なポイントは次のとおりです。

  • よりスマートな(外部知識の意味で)言語モデルのためのRAG
  • RAG チェーンは、LangChain、OpenAI のモデル、サードパーティのコミュニティ統合を使用して構築できます。
  • アプリは Streamlit を使用してインタラクティブに作成し、一般公開することができます。


このプロジェクトは、より高度なアプリケーションの基礎となります。複数のドキュメント タイプの組み込み、検索精度の向上、ドキュメントの要約などの機能など、大幅に拡張できます。しかし、このプロジェクトの真の目的は、これらのテクノロジを個別に、または組み合わせて使用​​した場合の潜在的なパワーを実証することです。