
Python與Ollama的開發(fā)案例
從技術(shù)本質(zhì)來分析,RAG 架構(gòu)設(shè)計是由兩部分構(gòu)成:數(shù)據(jù)工程和信息抽取。其中數(shù)據(jù)工程是最重要的部分,數(shù)據(jù)工程的最重要的工作之一是對文檔進(jìn)行分塊(Chunking)。
因為要處理的文檔可能會相當(dāng)大,所以第一步還包括“分塊”,就是把一個大文件分成更小的、更容易處理的部分。
這個步驟非常重要,因為它確保文本能夠適應(yīng)嵌入模型的輸入大小。
而且,它還能提高信息抽取步驟的效率和準(zhǔn)確性,這直接影響到生成回答的質(zhì)量。
下文我們詳細(xì)剖析兩大問題:
第一、 RAG 架構(gòu)落地中常用的5種分塊技術(shù);
第二、企業(yè) RAG 架構(gòu)落地分塊技術(shù)如何選型。
企業(yè) RAG 架構(gòu)落地,常常使用5種分塊技術(shù):固定大小分塊、語義分塊、遞歸分塊、基于文檔結(jié)構(gòu)分塊、基于 LLM 分塊。
生成文本塊最直觀和簡單的方法就是根據(jù)預(yù)先設(shè)定的字符數(shù)、單詞數(shù)或 tokens,把文本切成大小一致的小段。
因為直接切分可能會打斷文本的語義流暢性,所以建議在兩個連續(xù)的文本塊之間保留一些重疊部分(就像上面圖中藍(lán)色區(qū)域那樣)。
這個方法很容易實現(xiàn)。而且,因為所有文本塊大小都一樣,所以批量處理起來也更簡單。
但是,這樣做有個大問題。它通常會把句子(或想法)從中間切斷。這樣一來,重要信息就可能會分散到不同的文本塊里。
語義分塊方法很簡單。
就是根據(jù)有意義的單元來切分文檔,比如:句子、段落或者主題部分。
然后,為每個部分創(chuàng)建嵌入向量(一種能表示文本意義的數(shù)字)。
假設(shè)我從第一個部分和它的嵌入向量開始。
輸出的結(jié)果可能如下:
和固定大小的文本塊不同,這種方法保持了語言的自然流暢性,并保留了完整的思想。
因為每個文本塊包含的信息更豐富,它提高了檢索的準(zhǔn)確性,這反過來又使得大語言模型(LLM)生成的回答更加連貫和相關(guān)。
一個小問題是,它依賴于一個閾值來確定余弦相似度是否顯著下降,這個閾值可能因文檔而異。
遞歸分塊方法也很容易理解。
首先,根據(jù)文檔中的自然分隔符來分塊,比如:段落或章節(jié)。
然后,如果某個塊的大小超過了我們預(yù)先設(shè)定的塊大小限制,就把它再分成更小的塊。如果塊的大小已經(jīng)在限制范圍內(nèi),就不用再分了。
可能的輸出結(jié)果是這樣的:
如上所示:
和固定大小的塊相比,這種方法同樣保留了語言的自然流暢性,并且保留了完整的語義。
不過,這種方法在實現(xiàn)和計算復(fù)雜度上會稍微復(fù)雜一些。
基于文檔結(jié)構(gòu)分塊是一種很直觀的方法。
它利用文檔本身的結(jié)構(gòu),比如:標(biāo)題、章節(jié)或段落,來確定分塊的邊界。
這樣做的好處是,它能夠保持文檔結(jié)構(gòu)的完整性,因為它和文檔的邏輯部分是對齊的。
輸出的結(jié)果可能看起來像這樣:
話雖如此,這種方法假設(shè)文檔有一個清晰的結(jié)構(gòu),但有時候可能并非如此。
而且,分出來的塊長度可能會不一樣,有可能超出大模型處理的字?jǐn)?shù)限制。實際落地是會把它和遞歸分塊結(jié)合起來使用。
既然每種分塊方法都有優(yōu)點和缺點,那為什么不讓大語言模型(LLM)來創(chuàng)建文本塊呢?
大語言模型可以被引導(dǎo)生成語義上獨立且有意義的文本塊。
很明顯,這種方法將確保高語義準(zhǔn)確性,因為大語言模型具備世界知識,能理解上下文和含義,這超出了上面四種方法中使用的簡單啟發(fā)式方法。
唯一的問題是,這是這里討論的五種技術(shù)中計算量最大的文本塊劃分技術(shù)。
另外,由于大語言模型通常有一個有限的上下文窗口,這也是需要考慮的一點。
總之,每種技術(shù)都有它自己的優(yōu)勢和權(quán)衡,5種分塊技術(shù)總結(jié)對比如下:
我們實際落地發(fā)現(xiàn),語義分塊在很多情況下都效果很好,你在 RAG 應(yīng)用落地的時候可以首選,但是最好針對你的業(yè)務(wù)場景進(jìn)行測試下。
RAG 架構(gòu)落地過程中最終選擇哪種分塊技術(shù),將很大程度上取決于你的內(nèi)容性質(zhì)、嵌入模型的能力、計算資源等等。