OpenAI の ChatGPT のような生成 AI モデルの急速な進化により、自然言語処理に革命が起こり、これらのシステムが一貫した文脈に関連した応答を生成できるようになりました。ただし、最先端のモデルであっても、ドメイン固有のクエリに取り組んだり、高精度の情報を提供したりする場合には制限に直面します。これは、モデルが不正確または捏造された詳細を生成する場合、幻覚などの課題につながることがよくあります。
検索拡張生成 (RAG) は、このギャップを埋めるために設計された革新的なフレームワークです。 RAG は、外部データ ソースをシームレスに統合することで、生成モデルがリアルタイムのニッチな情報を取得できるようにし、精度と信頼性を大幅に向上させます。
この記事では、RAG の仕組みを深く掘り下げ、そのアーキテクチャを探り、その作成にインスピレーションを与えた従来の生成モデルの制限について説明します。また、実際の実装、高度な技術、評価方法にも焦点を当て、AI が特殊なデータと対話する方法を RAG がどのように変革しているかを紹介します。
取得拡張生成 (RAG) は、外部データのリアルタイム取得を統合することで生成 AI モデルの機能を強化する高度なフレームワークです。生成モデルは、一貫性のある人間のようなテキストを生成することに優れていますが、正確な、最新の、またはドメイン固有の情報の提供を求められると、たじろぐ可能性があります。ここで RAG が介入し、回答が創造的であるだけでなく、信頼できる関連性の高い情報源に基づいていることを保証します。
RAG は、生成モデルを、通常はベクトル データベースや検索システムを利用した検索メカニズムと接続することによって動作します。クエリを受信すると、検索コンポーネントは膨大な外部データセットを検索して関連情報を取得します。次に、生成モデルがこのデータを合成し、正確かつ文脈上の洞察に富んだ出力を生成します。
幻覚や限られた分野の知識などの主要な課題に対処することで、RAG は専門分野で優れた生成モデルの可能性を解き放ちます。そのアプリケーションは、正確な回答による顧客サポートの自動化から、研究者がオンデマンドで精選された知識にアクセスできるようにするなど、さまざまな業界に及びます。 RAG は、AI システムをよりインテリジェントで信頼性が高く、現実世界のシナリオで役立つものにする上での重要な前進を表します。
RAG アーキテクチャの可能性とメリットを最大限に引き出すには、RAG アーキテクチャを明確に理解することが不可欠です。このフレームワークの核心は、Retriever と Generator という 2 つの主要コンポーネントで構築されており、情報処理のシームレスなフローで連携します。
この全体的なプロセスを以下に示します:
出典: https://weaviate.io/blog/introduction-to-rag
RAG プロセス フローのすべての段階と重要なコンポーネントを以下の図に示します。
出典: https://www.griddynamics.com/blog/retrieval-augmented-generation-llm
文書を小さなチャンクに分割することは簡単に思えるかもしれませんが、文を不適切に分割しないようにセマンティクスを慎重に検討する必要があり、質問応答などの後続のステップに影響を与える可能性があります。単純な固定サイズのチャンク化アプローチでは、各チャンク内の情報が不完全になる可能性があります。ほとんどのドキュメント セグメンテーション アルゴリズムは、チャンク サイズとオーバーラップを使用します。チャンク サイズは文字、単語、またはトークンの数によって決まり、オーバーラップは隣接するチャンク間でテキストを共有することで連続性を確保します。この戦略は、チャンク全体で意味論的なコンテキストを保持します。
出典: https://www.griddynamics.com/blog/retrieval-augmented-generation-llm
重要なベクター データベースの一部は次のとおりです。
出典: https://www.griddynamics.com/blog/retrieval-augmented-generation-llm
RAG (検索拡張生成) と微調整は、LLM 機能を拡張するための 2 つの重要な方法であり、それぞれ異なるシナリオに適しています。微調整には、特殊なタスクを実行するためにドメイン固有のデータで LLM を再トレーニングすることが含まれます。これは、特定のトーンやスタイルを必要とするブランディングやクリエイティブ ライティングなどの静的で狭いユースケースに最適です。ただし、コストと時間がかかり、動的で頻繁に更新されるデータには適していません。
一方、RAG はモデルの重みを変更せずに外部データを動的に取得することで LLM を強化し、コスト効率が高く、法律、財務、顧客サービス アプリケーションなどのリアルタイムのデータ駆動型環境に最適です。 RAG を使用すると、LLM は大規模で構造化されていない内部文書コーパスを処理できるようになり、乱雑なデータ リポジトリをナビゲートする従来の方法に比べて大きな利点が得られます。
微調整は微妙な一貫性のある出力の作成に優れていますが、RAG は外部のナレッジ ベースを活用して最新の正確な情報を提供します。実際には、リアルタイムで適応性のある応答を必要とするアプリケーション、特に膨大な非構造化データを管理する企業では、RAG が好まれる選択肢となることがよくあります。
検索拡張生成 (RAG) アプローチにはいくつかの種類があり、それぞれが特定のユースケースと目的に合わせて調整されています。主なタイプは次のとおりです:
出典: https://x.com/weaviate_io/status/1866528335884325070
検索拡張生成 (RAG) フレームワークは、外部の知識を生成言語モデルに動的に統合できるため、さまざまな業界にわたって多様なアプリケーションがあります。以下にいくつかの著名なアプリケーションを示します:
このセクションでは、PDF の内容を理解し、検索拡張生成 (RAG) を使用してその内容に基づいてユーザーのクエリに応答できるストリームリット アプリケーションを開発します。この実装では、LangChain プラットフォームを活用して、LLM およびベクター ストアとの対話を容易にします。 OpenAI の LLM とその埋め込みモデルを利用して、効率的な情報検索のための FAISS ベクトル ストアを構築します。
python -m venv venv source venv/bin/activate #for ubuntu venv/Scripts/activate #for windows
pip install langchain langchain_community openai faiss-cpu PyPDF2 streamlit python-dotenv tiktoken
OPENAI_API_KEY=sk-proj-xcQxBf5LslO62At... OPENAI_MODEL_NAME=gpt-3.5-turbo OPENAI_EMBEDDING_MODEL_NAME=text-embedding-3-small
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
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.')
CSS を使用してユーザーとボットの両方のメッセージ用のカスタム チャット インターフェイスを作成するには、カスタム テンプレートをデザインし、CSS でスタイルを設定します。
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)
ファイルのアップロード、質問の入力、チャット履歴の表示のためのメイン アプリ インターフェイスを設定します。
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 チャット アプリケーションの完全なコード実装です。環境変数の設定、テキスト抽出、ベクトル ストレージ、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
次のような出力が得られます。
この記事をお読みいただきありがとうございます!!
コンテンツをレビューしてくださった Gowri M Bhatt に感謝します。
この記事が気に入ったら、ハート ボタン ♥ をクリックして共有し、他の人が記事を見つけられるようにしてください。
このチュートリアルの完全なソース コードはここにあります
codemaker2015/pdf-chat-using-RAG | github.com
以上が検索拡張生成 (RAG) の究極のガイドの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。