像 OpenAI 的 ChatGPT 這樣的生成式 AI 模型的快速發展徹底改變了自然語言處理,使這些系統能夠產生連貫且上下文相關的響應。然而,即使是最先進的模型在處理特定領域的查詢或提供高度準確的資訊時也面臨限制。這通常會導致諸如幻覺之類的挑戰——模型產生不準確或捏造的細節的情況。
檢索增強生成(RAG),一個旨在彌合這一差距的創新框架。透過無縫整合外部資料來源,RAG 使生成模型能夠檢索即時、利基訊息,從而顯著提高其準確性和可靠性。
在本文中,我們將深入研究 RAG 的機制,探索其架構,並討論激發其創作靈感的傳統生成模型的限制。我們還將重點介紹實際實現、先進技術和評估方法,展示 RAG 如何改變人工智慧與專業數據互動的方式。
檢索增強生成(RAG)是一種先進的框架,透過整合外部資料的即時檢索來增強生成式人工智慧模型的能力。雖然生成模型擅長產生連貫的、類似人類的文本,但當要求提供準確、最新或特定領域的資訊時,它們可能會猶豫不決。這就是 RAG 介入的地方,確保回覆不僅具有創意,而且基於可靠且相關的來源。
RAG 透過將生成模型與檢索機制連接起來進行操作,通常由向量資料庫或搜尋系統提供支援。當收到查詢時,檢索元件會搜尋大量外部資料集以取得相關資訊。然後,產生模型綜合這些數據,產生既準確又具有上下文洞察力的輸出。
透過解決幻覺和有限領域知識等關鍵挑戰,RAG 釋放了生成模型在專業領域中脫穎而出的潛力。其應用涵蓋各個行業,從提供精確答案的自動化客戶支持,到使研究人員能夠按需獲取精選知識。 RAG 代表著在使 AI 系統在現實場景中更加聰明、值得信賴和有用方面向前邁出了重要一步。
清楚了解 RAG 架構對於釋放其全部潛力和優勢至關重要。這個框架的核心是建立在兩個主要組件之上:檢索器和生成器,它們在無縫的資訊處理流程中協同工作。
整個過程如下圖:
來源: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能力的兩種關鍵方法,每種方法適合不同的場景。微調涉及對特定領域數據的法學碩士進行再培訓,以執行專門的任務,非常適合靜態、狹窄的用例,例如需要特定語氣或風格的品牌或創意寫作。然而,它成本高昂、耗時,且不適合動態、頻繁更新的數據。
另一方面,RAG 透過動態檢索外部資料而不修改模型權重來增強 LLM,使其具有成本效益,非常適合法律、財務或客戶服務應用程式等即時資料驅動環境。 RAG 使法學碩士能夠處理大型、非結構化的內部文件語料庫,與導航混亂的資料儲存庫的傳統方法相比,具有顯著的優勢。
微調擅長創造細緻、一致的輸出,而 RAG 透過利用外部知識庫提供最新、準確的資訊。在實踐中,RAG 通常是需要即時、適應性回應的應用程式的首選,特別是在管理大量非結構化資料的企業中。
檢索增強產生 (RAG) 方法有多種類型,每種方法都針對特定用例和目標量身定制。主要類型包括:
資料來源:https://x.com/weaviate_io/status/1866528335884325070
檢索增強生成(RAG)框架由於其能夠將外部知識動態整合到生成語言模型中,因此在各個行業中具有廣泛的應用。以下是一些突出的應用:
在本節中,我們將開發一個 Streamlit 應用程序,能夠理解 PDF 的內容並使用檢索增強生成 (RAG) 根據該內容響應用戶查詢。該實施利用 LangChain 平台來促進與法學碩士和向量商店的互動。我們將利用 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")
導入用於建立應用程式、處理 PDF 的基本庫,例如 langchain、streamlit、pyPDF。
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中文網其他相關文章!