asp.net 旅游網(wǎng)站開發(fā)淘寶seo優(yōu)化排名
? ? ? ?想象一下,你是一名偵探,身處龐大的信息世界,試圖在堆積如山的數(shù)據(jù)中找到隱藏的一條重要線索,這就是檢索增強生成(RAG)發(fā)揮作用的地方,它就像你在人工智能和語言模型世界中的可靠助手。但即使是最好的助理也有其局限性,因此,讓我們開始探索RAG的高級方法,重點關注大規(guī)模文檔檢索中的精度和上下文。
一、基本RAG
? ? ? ?想象一下,有一本和地平線一樣寬百科全書?;镜腞AG試圖將這些豐富的知識提煉成一個單一的“嵌入”——本質上是一個數(shù)字。但是,當你在一個特定的主題上尋求智慧時,比如神秘的百慕大三角,基本的RAG的粗筆畫會覆蓋更多細節(jié),給你留下一幅不完整的畫面。這種限制就像試圖用一張只顯示大陸的地圖來尋找隱藏的寶藏,而不是通往標有“X”的地點的復雜路徑。
? ? ? ?另一方面,如果我們只擁有帶有嵌入的單個頁面,我們可能會找出具體的事實,但當它們交織在一起時,我們就會失去它們所講述的故事。如果沒有敘事,大型語言模型(LLM)很難找到一個能抓住我們探究的真正本質的答案。
? ? ? ?基本RAG,雖然是一個值得稱贊的里程碑,但沒有做的更好。基本RAG只是一個基礎,需要跨越通用知識和精確見解之間的距離,我們需要做更細致的優(yōu)化工作。
二、路徑的細化:父子文檔關系
? ? ? ?我們不是對整個百科全書進行單一的總結,而是為每一頁(子文檔)進行簡潔的概述,注意包含的章節(jié)(父文檔)。該方法在我之前的LLM之RAG實戰(zhàn)(五)| 高級RAG 01:使用小塊檢索,小塊所屬的大塊喂給LLM,可以提高RAG性能博客中有所介紹,這里略過。
2.1 步驟1:父子文檔關系
? ? ? ?想象一下,你有一本又大又笨重的書——一本關于所有電器的用戶手冊?,F(xiàn)在,有人問了一個特定的問題:“為什么我的洗衣機顯示錯誤代碼2?”,對于基本的RAG,我們要么得到缺乏上下文的小塊,要么得到搜索不夠準確的大塊。然而,高級RAG采用了更聰明的方法。
? ? ? ?首先,手冊被分解成大塊——這些是我們的“父”文檔。每一節(jié)都涉及更大的信息。在這些部分中,我們拆分了涵蓋特定問題的“子”文檔,如洗衣機的錯誤代碼。
? ? ? ?現(xiàn)在,來看看矢量化的魔力。每個子文檔都通過嵌入模型進行處理,該模型分析文本并將其轉換為向量——一系列表示文本本質的數(shù)字。這就像為每一小段信息創(chuàng)建一個DNA圖譜。
? ? ? ?每個子文檔的文本都被提取到一個向量中,然后將其存儲在向量存儲中,其父文檔也存儲在這個向量存儲中——這也是一個通用數(shù)據(jù)庫。這使我們不僅可以快速檢索最相關的小信息,還可以保留父文檔提供的上下文。
2.2 步驟二:問答
? ? ? ?當關于洗衣機的問題出現(xiàn)時,它就變成了一個“嵌入”——把它想象成一個獨特的數(shù)字簽名。然后使用矢量搜索將這些嵌入與類似的子文檔進行匹配。如果它與“洗衣機”部分的子文檔嵌入緊密對齊,我們就找到了匹配項。
? ? ? ?有了我們的矢量存儲和準備,當出現(xiàn)問題時,我們可以迅速找到最相關的子文檔。但是,我們沒有提供狹義的回應,而是引入了母文檔,它提供了更多的背景和上下文。這個準備好的提示富含特定信息和廣泛的上下文,然后被輸入到大型語言模型(LLM)中,該模型生成精確的上下文感知答案。
? ? ? ?如圖所示,這種先進的RAG過程確保LLM具有生成準確響應所需的所有上下文,就像偵探拼湊線索來解開謎團一樣。借助MongoDB矢量搜索的強大功能,我們可以以超級計算機的速度和精度瀏覽這一過程,確保每個問題都得到盡可能好的答案。
三、MongoDB矢量搜索:高級RAG背后的動力
? ? ? ?從父子關系和矢量化的復雜關系中走出來,我們直接進入了MongoDB的矢量搜索領域,該引擎為我們的高級RAG過程提供了動力。讓我們深入研究一下MongoDB矢量搜索是如何將篩選堆積如山的數(shù)據(jù)這一艱巨任務轉變?yōu)橐粋€精簡高效的過程的。
3.1 矢量搜索:快速尋找答案
? ? ? ?MongoDB中的矢量搜索就像在浩瀚的數(shù)據(jù)海洋中擁有一盞高功率探照燈。當我們的洗衣機愛好者詢問那個令人討厭的錯誤代碼時,矢量搜索不僅僅是梳理數(shù)據(jù),它還可以精確定位信息的確切位置,這要歸功于我們早些時候創(chuàng)建的獨特的“數(shù)字簽名”。最棒的部分?它以驚人的速度做到了這一點,使得搜索答案的速度就像翻閱一個組織良好的文件柜一樣快。
3.2 結構與速度想結合
? ? ? ?MongoDB的矢量搜索將結構和速度和諧地結合在一起。父文檔和子文檔的存儲,以及它們的矢量化本質,使MongoDB能夠快速識別最相關的數(shù)據(jù)片段,而不會被不太相關的信息所困擾。這是一位一絲不茍的圖書管理員和一位偵探大師的完美結合,確保了沒有遺漏任何線索,每個答案都切中要害。
3.3 語境豐富性:增加的層次
? ? ? ?在這里,事情變得更加有趣。一旦矢量搜索精確定位了相關的子文檔,它就不會止步于此。通過檢索父文檔,它確保了上下文的豐富性不會丟失。這意味著我們的LLM不僅了解“什么”,還了解“為什么”和“如何”,提供了超出表面水平的答案。
3.4 MongoDB:不僅僅是一個數(shù)據(jù)庫
? ? ? ?MongoDB不僅僅是一個存儲數(shù)據(jù)的地方;這是一個動態(tài)的生態(tài)系統(tǒng),支持先進的RAG過程的每一步。它可以輕松管理復雜的父文檔和子文檔網(wǎng)絡,并促進快速矢量搜索,使高級RAG功能強大。使用MongoDB,我們不僅僅是在尋找答案;我們正在制定既能提供信息又能與上下文相關的回應。
3.5 結果:知情、準確的回答
? ? ? ?由于高級RAG和MongoDB矢量搜索之間的強大協(xié)作,生成的響應不僅準確,而且信息豐富。當我們的用戶詢問洗衣機上的錯誤代碼時,他們會收到一個既準確又充滿有用上下文的回復,類似于為他們量身定制的全面指南。
? ? ? ?MongoDB矢量搜索是這一高級RAG過程的支柱,提供了在復雜的數(shù)據(jù)檢索環(huán)境中導航所需的速度和精度。在下一節(jié)中,我們將探索這一過程的實際實施,展示如何將先進的RAG系統(tǒng)應用到生活中,為用戶提供人工智能所能提供的最佳答案。請繼續(xù)關注我們將理論轉化為實踐,并充分發(fā)揮先進RAG的潛力。
四、用MongoDB矢量搜索實現(xiàn)高級RAG
? ? ? 將Advanced RAG與MongoDB Vector Search集成到我們的系統(tǒng)中,首先是幾個技術組件的和數(shù)據(jù)處理流程。下面看一下具體步驟:
4.1 步驟1:設置和初始化
? ? ? ?我們通過設置環(huán)境和建立必要的聯(lián)系來啟動工作,這包括加載環(huán)境變量,初始化OpenAI和MongoDB客戶端,以及定義我們的數(shù)據(jù)庫和集合名稱。
import os
from dotenv import load_dotenv
from pymongo import MongoClient
from langchain.embeddings import OpenAIEmbeddings
# Load environment variables from .env file
load_dotenv(override=True)
# Set up MongoDB connection details
OPENAI_API_KEY = os.environ["OPENAI_API_KEY"]
MONGO_URI = os.environ["MONGO_URI"]
DB_NAME = "pdfchatbot"
COLLECTION_NAME = "advancedRAGParentChild"
# Initialize OpenAIEmbeddings with the API key
embeddings = OpenAIEmbeddings(openai_api_key=OPENAI_API_KEY)
# Connect to MongoDB
client = MongoClient(MONGO_URI)
db = client[DB_NAME]
collection = db[COLLECTION_NAME]
4.2 步驟2:數(shù)據(jù)加載和分塊
? ? ? ?接下來,我們將重點處理作為數(shù)據(jù)源的PDF文檔。文檔被加載并拆分為“父”和“子”塊,以準備嵌入和向量化。
from langchain.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
# Initialize the text splitters for parent and child documents
parent_splitter = RecursiveCharacterTextSplitter(chunk_size=2000)
child_splitter = RecursiveCharacterTextSplitter(chunk_size=200)
# Function to process PDF document and split it into chunks
def process_pdf(file):
loader = PyPDFLoader(file.name)
docs = loader.load()
parent_docs = parent_splitter.split_documents(docs)
# Process parent documents
for parent_doc in parent_docs:
parent_doc_content = parent_doc.page_content.replace('\n', ' ')
parent_id = collection.insert_one({
'document_type': 'parent',
'content': parent_doc_content
}).inserted_id
# Process child documents
child_docs = child_splitter.split_documents([parent_doc])
for child_doc in child_docs:
child_doc_content = child_doc.page_content.replace('\n', ' ')
child_embedding = embeddings.embed_documents([child_doc_content])[0]
collection.insert_one({
'document_type': 'child',
'content': child_doc_content,
'embedding': child_embedding,
'parent_ref': parent_id
})
return "PDF processing complete"
4.3 步驟3:查詢嵌入和矢量搜索
? ? ? ?當提交查詢時,我們將其轉換為嵌入,并執(zhí)行向量搜索以找到最相關的子文檔,鏈接回它們的父文檔以獲取上下文。
# Function to embed a query and perform a vector search
def query_and_display(query):
query_embedding = embeddings.embed_documents([query])[0]
# Retrieve relevant child documents based on query
child_docs = collection.aggregate([{
"$vectorSearch": {
"index": "vector_index",
"path": "embedding",
"queryVector": query_embedding,
"numCandidates": 10
}
}])
# Fetch corresponding parent documents for additional context
parent_docs = [collection.find_one({"_id": doc['parent_ref']}) for doc in child_docs]
return parent_docs, child_docs
4.4 步驟4:通過上下文感知生成響應
? ? ? ?在識別出相關文檔后,我們?yōu)長LM創(chuàng)建一個提示,其中包括用戶的查詢和匹配文檔中的內容。這確保了響應具有信息性和上下文相關性。
from langchain.llms import OpenAI
# Initialize the OpenAI client
openai_client = OpenAI(api_key=OPENAI_API_KEY)
# Function to generate a response from the LLM
def generate_response(query, parent_docs, child_docs):
response_content = " ".join([doc['content'] for doc in parent_docs if doc])
chat_completion = openai_client.chat.completions.create(
messages=[{"role": "user", "content": query}],
model="gpt-3.5-turbo"
)
return chat_completion.choices[0].message.content
4.5 第五步:串聯(lián)所有組件
? ? ? ?最后,我們將這些元素組合成一個連貫的界面,用戶可以在其中上傳文檔并提出問題。這是使用Gradio實現(xiàn)的,它提供了一種用戶友好的方式來與我們先進的RAG系統(tǒng)交互。
with gr.Blocks(css=".gradio-container {background-color: AliceBlue}") as demo:
gr.Markdown("Generative AI Chatbot - Upload your file and Ask questions")
?
with gr.Tab("Upload PDF"):
with gr.Row():
pdf_input = gr.File()
pdf_output = gr.Textbox()
pdf_button = gr.Button("Upload PDF")
?
with gr.Tab("Ask question"):
question_input = gr.Textbox(label="Your Question")
answer_output = gr.Textbox(label="LLM Response and Retrieved Documents", interactive=False)
question_button = gr.Button("Ask")
?
?
question_button.click(query_and_display, inputs=[question_input], outputs=answer_output)
pdf_button.click(process_pdf, inputs=pdf_input, outputs=pdf_output)
?
demo.launch()
4.6 步驟6:在MongoDB Atlas上創(chuàng)建索引
{
"fields": [
{
"numDimensions": 1536,
"path": "embedding",
"similarity": "cosine",
"type": "vector"
},
{
"path": "document_type",
"type": "filter"
}
]
}
參考文獻:
[1]?https://ai.gopubby.com/byebye-basic-rag-embracing-advanced-retrieval-with-mongodb-vector-search-47b550be2c59