RAG從入門到精通系列:基礎(chǔ)RAG
LLM(Large Language Model,大型語(yǔ)言模型)是一個(gè)功能強(qiáng)大的新平臺(tái),但它們并不總是使用與我們的任務(wù)相關(guān)的數(shù)據(jù)或者是最新的數(shù)據(jù)進(jìn)行訓(xùn)練。
RAG(Retrieval Augmented Generation,檢索增強(qiáng)生成)是一種將 LLM 與外部數(shù)據(jù)源(例如私有數(shù)據(jù)或最新數(shù)據(jù))連接的通用方法。它允許 LLM 使用外部數(shù)據(jù)來(lái)生成其輸出。
要想真正掌握 RAG,我們需要學(xué)習(xí)下圖所示的技術(shù)(技巧):
圖片
這個(gè)圖看起來(lái)很讓人頭大,但是不用擔(dān)心,你來(lái)對(duì)地方了。
本系列教程將從頭開(kāi)始介紹如何建立對(duì) RAG 的理解。
我們先從 Indexing(索引)、Retrieval(檢索)和 Generation(生成)的基礎(chǔ)知識(shí)開(kāi)始。
下面的流程圖說(shuō)明了基礎(chǔ) RAG 的過(guò)程:
- 我們對(duì)外部文檔建立索引(Indexing);
- 根據(jù)用戶的問(wèn)題去檢索(Retrieval)相關(guān)的文檔;
- 將問(wèn)題和相關(guān)的文檔輸入 LLM 生成(Generation)最終答案。
圖片
Indexing
我們從加載文檔開(kāi)始學(xué)習(xí) Indexing。LangChain 有超過(guò) 160 種不同的文檔加載器,我們可以使用它們從許多不同的來(lái)源抓取數(shù)據(jù)進(jìn)行 Indexing。
https://python.langchain.com/docs/integrations/document_loaders/
我們將 Question(問(wèn)題)輸入到 Retriever(檢索器),Retriever 也會(huì)加載外部文檔(知識(shí)),然后篩選出與 Question 相關(guān)的文檔:
我們需要將 Text Representation(文本表示)轉(zhuǎn)成 Numerical Representation(數(shù)值表示)才能更好地實(shí)現(xiàn)相關(guān)性(比如余弦相似度)篩選:
有很多種方法可以將文本轉(zhuǎn)成數(shù)值表示,典型的有:
- Statistical(基于統(tǒng)計(jì)學(xué))
- Machine Learned(基于機(jī)器學(xué)習(xí))
目前最常用的就是使用機(jī)器學(xué)習(xí)方法將文本轉(zhuǎn)成固定長(zhǎng)度的,可捕獲文本語(yǔ)義的 Embedding Vector(嵌入向量)。
有很多開(kāi)源的 Embedding Model(比如 BAAI 系列)可以將文本轉(zhuǎn)成 Embedding Vector。但是這些模型能接受的 Context Window(上下文窗口)有限,一般在 512~8192 個(gè) token(如果你不知道什么是 token 的話,請(qǐng)?zhí)轿哪?/p>
所以正常的流程是我們將外部文檔切分成一個(gè)個(gè) Split,使得這些 Split 的長(zhǎng)度能夠滿足 Embedding Model 的 Context Window:
到現(xiàn)在,我們已經(jīng)掌握了 Indexing 的理論了,現(xiàn)在可以用 Qwen + BAAI + LangChain + Qdrant 實(shí)踐了。
首先配置 LLM 和 Embedding Model:
然后加載外部文檔,這里的文檔是一個(gè)網(wǎng)頁(yè)博客:
正如我之前說(shuō)的, Embedding Model 的 Context Window 有限,我們不能直接把整篇文檔丟進(jìn)去,所以要將原始文檔拆分成一個(gè)個(gè)文檔塊:
接下來(lái)就是配置 Qdrant 向量數(shù)據(jù)庫(kù):
可以閱讀《Qdrant:使用Rust編寫的開(kāi)源向量數(shù)據(jù)庫(kù)&向量搜索引擎》了解一下 Qdrant。
最后一步對(duì)文檔塊建立索引并存到向量數(shù)據(jù)庫(kù)中:
Retrieval
Retrieval 就是根據(jù)我們提出的問(wèn)題的語(yǔ)義向量(也就是 Embedding Vector)去按照某種距離/相似度衡量方法找出與之相似的 k 個(gè) Split 的語(yǔ)義向量。
下圖演示了一個(gè)在一個(gè) 3D 空間的 Embedding Vector Retrieval:
Embedding Vector 通常存儲(chǔ)在 Vector Store(向量數(shù)據(jù)庫(kù))中,Vector Store 實(shí)現(xiàn)了各種比較 Embedding Vector 之間相似度的方法。
接下來(lái)我們用在 Indexing 時(shí)構(gòu)建的 Vector Store 構(gòu)建一個(gè) retriever,然后輸入問(wèn)題并進(jìn)行檢索:
根據(jù)我們?cè)O(shè)定的 k 值,我們檢索出了一個(gè)與問(wèn)題相關(guān)的文檔塊。
Generation
現(xiàn)在我們已經(jīng)能夠根據(jù)用戶的問(wèn)題檢索出與之相關(guān)的知識(shí)片段(Split),那么我們現(xiàn)在需要將這些信息(問(wèn)題 + 知識(shí)片段)輸入 LLM,讓 LLM 幫忙生成一個(gè)有時(shí)事實(shí)依據(jù)(知識(shí)片段)的回答:
我們需要:
- 問(wèn)題和知識(shí)片段放到一個(gè)字典中,問(wèn)題放到 Question 這個(gè) key,知識(shí)片段放到 Context 這個(gè) key;
- 然后通過(guò) PromptTemplate 組成一個(gè) Prompt String;
- 最后將 Prompt String 輸入 LLM,LLM 再產(chǎn)生回答。
看起來(lái)很復(fù)雜,但這就是 LangChain 和 LlamaIndex 這類框架存在的意義:
細(xì)心的你發(fā)現(xiàn)返回的結(jié)果是一個(gè) AIMessage 對(duì)象,我們可能需要一個(gè)純字符串的輸出結(jié)果;而且檢索過(guò)程和生成過(guò)程是分開(kāi)的,這很不方便。
不過(guò)我們可以借助于 LangChain 將上述檢索和生成過(guò)程鏈(Chain)在一起:
LangSmith
如果你還是對(duì)整個(gè) RAG 管道過(guò)程很陌生,那么不妨去 LangSmith 頁(yè)面上看一下整個(gè)過(guò)程是怎么被一步步串到一起的:
LangSmith 是一個(gè)用于構(gòu)建生產(chǎn)級(jí) LLM 應(yīng)用程序的平臺(tái)。它允許我們密切監(jiān)控和評(píng)估我們的應(yīng)用程序,以便我們可以快速、自信地交付。使用 LangSmith,我們可以:
- ?跟蹤 LLM 應(yīng)用程序
- 了解 LLM 調(diào)用和應(yīng)用程序邏輯的其他部分。
什么是 token?
token 是模型用來(lái)表示自然語(yǔ)言文本的基本單位,可以直觀的理解為“字”或“詞”。
對(duì)于英文文本來(lái)說(shuō),1 個(gè) token 通常對(duì)應(yīng) 3 至 4 個(gè)字母:
對(duì)于中文文本來(lái)說(shuō),1 個(gè) token 通常對(duì)應(yīng)一個(gè)漢字:
GitHub 鏈接:
??https://github.com/realyinchen/RAG/blob/main/01_Indexing_Retrieval_Generation.ipynb??
本文轉(zhuǎn)載自 ??PyTorch研習(xí)社??,作者: 南七無(wú)名式
