
如何高效爬取全球新聞網站 – 整合Scrapy、Selenium與Mediastack API實現自動化新聞采集
從圖上可以清晰的看出,整個產品架構包含如下四層:
為了理解檢索增強生成框架,我們將其分為三個主要組成部分:query理解、檢索模型和生成模型。
總之,檢索增強生成結合了檢索模型和生成模型優勢,克服它們各自的局限性。在此框架中,基于檢索的模型用于根據給定的查詢或上下文從知識庫或一組文檔中檢索相關信息。然后,檢索到的信息將用作生成模型的輸入或附加上下文。通過整合檢索到的信息,生成模型可以利用基于檢索的模型的準確性和特異性來生成更相關、更準確的文本。這有助于生成模型立足于現有知識,生成與檢索信息一致的文本。
目前,RAG系統可能會遇到從知識庫中檢索到與用戶query不相關的內容。這是由于如下問題:(1)用戶問題的措辭可能不利于檢索,(2)可能需要從用戶問題生成結構化查詢。為了解決上述問題,我們引入query理解模塊。
意圖識別是指接收用戶的query和一組”選擇”(由元數據定義)并返回一個或多個選定的”選擇模塊”。它既可以單獨使用(作為 “選擇器模塊”),也可以作為查詢引擎或檢索器使用(例如,在其他查詢引擎/檢索器之上)。它是原理簡單但功能強大的模塊,目前主要利用 LLM 實現決策功能。
它可以應用于如下場景:
核心模塊有以下幾種形式:
該模塊主要利用LLM重新措辭用戶query,而不是直接使用原始的用戶query進行檢索。這是因為對于RAG系統來說,在現實世界中原始query不可能總是最佳的檢索條件。
4.2.1 HyDE[2]
Hypothetical Document Embeddings(HyDE)是一種生成文檔嵌入以檢索相關文檔而不需要實際訓練數據的技術。首先,LLM創建一個假設答案來響應query。雖然這個答案反映了與query相關的模式,但它包含的信息可能在事實上并不準確。接下來,query和生成的答案都被轉換為嵌入。然后,系統從預定義的數據庫中識別并檢索在向量空間中最接近這些嵌入的實際文檔。
4.2.2 Rewrite-Retrieve-Read[3]
這項工作引入了一個新的框架–Rewrite-Retrieve-Read,從query改寫的角度改進了檢索增強方法。之前的研究主要是調整檢索器或LLM。與之不同的是,該方法注重query的適應性。因為對于 LLM 來說,原始query并不總是最佳檢索結果,尤其是在現實世界中。首先利用LLM 進行改寫query,然后進行檢索增強。同時,為了進一步提高改寫的效果,應用小語言模型(T5)作為可訓練的改寫器,改寫搜索query以滿足凍結檢索器和 LLM的需要。為了對改寫器進行微調,該方法還使用偽數據進行有監督的熱身訓練。然后,將 “先檢索后生成 “管道建模為強化學習環境。通過最大化管道性能的獎勵,改寫器被進一步訓練為策略模型。
該模塊主要是為了將復雜問題拆解為子問題。該技術使用分而治之的方法來處理復雜的問題。它首先分析問題,并將其分解為更簡單的子問題,每個子問題會從提供部分答案的相關文件檢索答案。然后,收集這些中間結果,并將所有部分結果合成為最終響應。
4.3.1 Step-Back Prompting[4]
該工作探索了LLM如何通過抽象和推理兩個步驟來處理涉及許多低級細節的復雜任務。第一步先是使用 LLM “后退一步”生成高層次的抽象概念,將推理建立在抽象概念的基礎上,以減少在中間推理步驟中出錯的概率。這種方法即可以在有檢索的情況下使用,也可以在無檢索的情況下使用。當在有檢索情況下使用時,抽象的概念和原始問題都用來進行檢索,然后這兩個結果都用來作為LLM響應的基礎。
4.3.2 CoVe[5]
Chain of Verification (CoVe) 旨在通過系統地驗證和完善回答以盡量減少不準確性,從而提高大型語言模型所提供答案的可靠性,特別是在事實性問題和回答場景中。它背后的概念是基于這樣一種理念,即大型語言模型(LLM)生成的響應可以用來驗證自身。這種自我驗證過程可用于評估初始響應的準確性,并使其更加精確。
在RAG系統中,針對用戶實際場景中日益復雜的問題,借鑒了 CoVe技術,將復雜 Prompt 拆分為多個獨立且能并行檢索的搜索友好型query,讓LLM對每個子查詢進行定向知識庫搜索,最終提供更準確詳實答案的同時減少幻覺輸出。
4.3.3 RAG-Fusion[6]
在這種方法中,原始query經過LLM 生成多個query。然后可以并行執行這些搜索查詢,并將檢索到的結果一并傳遞。當一個問題可能依賴于多個子問題時,這種方法就非常有用。RAG-Fusion便是這種方法的代表,它是一種搜索方法,旨在彌合傳統搜索范式與人類查詢的多面性之間的差距。這種方法先是采用LLM生成多重查詢,之后使用倒數排名融合(Reciprocal Rank Fusion,RRF)來重新排序。
4.3.4 ReAct[7]
最近,在RAG系統中,使用ReAct思想,將復雜查詢分解成更簡單的”子查詢”,知識庫的不同部分可能會圍繞整個查詢回答不同的 “子查詢”。這對組合圖尤其有用。在組成圖中,一個查詢可以路由到多個子索引,每個子索引代表整個知識語料庫的一個子集。通過查詢分解,我們可以在任何給定的索引中將查詢轉化為更合適的問題。
ReAct的模式如上圖所示,它是將思維鏈提示(Chain of Thoughts,簡寫為CoT)和Action計劃生成結合起來,相互補充增強,提升大模型解決問題的能力。其中CoT的Reasoning推理跟蹤有助于模型誘導、跟蹤和更新行動計劃以及處理異常。Action操作允許它與知識庫或環境等外部來源接口并收集其他信息。
考慮Query理解模塊整體pipeline的效率,參考Query改寫和Query擴寫核心思想,自研了Query重構模塊,該模塊強調了通過一次請求,實現對原始用戶輸入的復雜問題進行改寫、拆解和拓展,挖掘用戶更深層次的子問題,從而借助子問題檢索效果更高的特點來解決復雜問題檢索質量偏差的問題,旨在提高查詢的準確性和效率。
《Lost in the Middle: How Language Models Use Long Contexts》[8]文章指出,當相關信息出現在輸入上下文的開頭或結尾時,性能往往最高,而當模型必須在長上下文中間獲取相關信息時,性能會明顯下降,即使對于明確的長上下文模型也是如此。
文檔加載器提供了一種 “加載 “方法,用于從配置源加載文檔數據。文檔數據是一段文本和相關元數據。文檔加載器可從多種不同來源加載文檔。例如,有一些文檔加載器可以加載簡單的 .txt 文件或者加載任何網頁的文本內容,甚至加載 YouTube 視頻的副本。此外,文檔加載器還可以選擇實現 “懶加載”,以便將數據懶加載到內存中。
檢索的一個關鍵部分是只獲取文檔的相關部分。當加載文檔后,通常需要對其進行轉換,以便更好地適應應用程序。這涉及幾個轉換步驟,以便為檢索文檔做好準備。其中一個主要步驟是將大型文檔分割(或分塊)成較小的塊,即文本轉換器。最簡單的例子是,當需要處理長篇文本時,有必要將文本分割成若干塊,以便能放入模型的上下文窗口中。理想情況下,希望將語義相關的文本片段放在一起。這聽起來很簡單,但潛在的復雜性卻很大。
5.4.1 工作原理
5.4.2 常見如下文本轉換器類型
Name | Splits On | Adds Metadata | Description |
Recursive | A list of user defined characters | Recursively splits text. Splitting text recursively serves the purpose of trying to keep related pieces of text next to each other. This is the recommended way to start splitting text. | |
HTML | HTML specific characters | ? | Splits text based on HTML-specific characters. Notably, this adds in relevant information about where that chunk came from (based on the HTML) |
Markdown | Markdown specific characters | ? | Splits text based on Markdown-specific characters. Notably, this adds in relevant information about where that chunk came from (based on the Markdown) |
Code | Code (Python, JS) specific characters | Splits text based on characters specific to coding languages. 15 different languages are available to choose from. | |
Token | Tokens | Splits text on tokens. There exist a few different ways to measure tokens. | |
Character | A user defined character | Splits text based on a user defined character. One of the simpler methods. | |
[Experimental] Semantic Chunker | Sentences | First splits on sentences. Then combines ones next to each other if they are semantically similar enough. Taken from Greg Kamradt |
5.4.3 評估文本轉換器
你可以使用 Greg Kamradt 創建的 Chunkviz 工具來評估文本轉換器。Chunkviz 是可視化文本轉換器工作情況的工具。它可以向你展示文本的分割情況,并幫助你調整分割參數。
檢索的另一個關鍵部分是文檔嵌入模型。文檔嵌入模型會創建一段文本的向量表示。它可以捕捉文本的語義,讓你快速有效地找到文本中相似的其他片段。這非常有用,因為它意味著我們可以在向量空間中思考文本,并進行語義搜索等操作。
理想情況下,檢索器應該具備將不同語種的翻譯文本做關聯的能力(跨語種檢索能力),具備將長原文和短摘要進行關聯的能力,具備將不同表述但相同語義的文本做關聯的能力,具備將不同問題但相同意圖的問題進行關聯的能力,具備將問題和可能的答案文本進行關聯的能力。此外,為了給大模型盡可能高質量的知識片段,檢索器還應該給出盡可能多的相關片段,并且真正有用的片段應該在更靠前的位置,可以過濾掉低質量文本片段。最后,期望我們的模型可以覆蓋盡可能多的領域和場景,可以實現一個模型打通多個業務場景,讓用戶獲得開箱即用的模型,不需要再做微調。
隨著嵌入式的興起,人們開始需要向量數據庫來支持這些嵌入式的高效存儲和搜索。存儲和搜索非結構化數據的最常見方法之一是嵌入數據并存儲由此產生的嵌入向量,然后在查詢時嵌入非結構化查詢并檢索與嵌入查詢 “最相似 “的嵌入向量。向量數據庫負責存儲嵌入數據并執行向量搜索。
經過前面的數據讀取和文本分塊操作后,接著就需要對處理好的數據進行索引。索引是一種數據結構,用于快速檢索出與用戶查詢相關的文本內容。它是檢索增強 LLM 的核心基礎組件之一。
下面介紹幾種常見的索引結構。為了說明不同的索引結構,引入節點(Node)的概念。在這里,節點就是前面步驟中對文檔切分后生成的文本塊(Chunk)。下面的索引結構圖來自 LlamaIndex 的《 How Each Index Works》[9]。
5.7.1 摘要索引(以前稱為鏈式索引)
摘要索引只是將節點存儲為順序鏈。在后續的檢索和生成階段,可以簡單地順序遍歷所有節點,也可以基于關鍵詞進行過濾。
5.7.2 樹索引
樹索引將一組節點 ( 文本塊 ) 構建成具有層級的樹狀索引結構,其從葉節點 (原始文本塊) 向上構建,每個父節點都是子節點的摘要。在檢索階段,既可以從根節點向下進行遍歷,也可以直接利用根節點的信息。樹索引提供了一種更高效地查詢長文本塊的方式,它還可以用于從文本的不同部分提取信息。與鏈式索引不同,樹索引無需按順序查詢。
5.7.3 關鍵詞表索引
關鍵詞表索引從每個節點中提取關鍵詞,構建了每個關鍵詞到相應節點的多對多映射,意味著每個關鍵詞可能指向多個節點,每個節點也可能包含多個關鍵詞。在檢索階段,可以基于用戶查詢中的關鍵詞對節點進行篩選。
5.7.4 向量索引
向量索引是當前最流行的一種索引方法。這種方法一般利用文本嵌入模型將文本塊映射成一個固定長度的向量,然后存儲在向量數據庫中。檢索的時候,對用戶查詢文本采用同樣的Embedding模型映射成向量,然后基于向量相似度計算獲取最相似的一個或者多個節點。
經過前面的檢索過程可能會得到很多相關文檔,就需要進行篩選和排序。常用的篩選和排序策略包括:
檢索模塊基于用戶查詢檢索出相關的文本塊,回復生成模塊讓 LLM 利用檢索出的相關信息來生成對原始查詢的回復。這里給出一些不同的回復生成策略。
用于將提示的不同部分組合在一起。您可以使用字符串提示或聊天提示來執行此操作。以這種方式構建提示可以輕松地重用組件。
6.2.1 字符串提示
使用字符串提示時,每個模板都會連接在一起。您可以直接使用提示或字符串(列表中的第一個元素必須是提示)。例如,langchain提供的prompttemplate[10]。
6.2.2 聊天提示
聊天提示由消息列表組成。純粹為了開發人員體驗,我們添加了一種便捷的方式來創建這些提示。在此管道中,每個新元素都是最終提示中的一條新消息。例如,langchain提供的AIMessage, HumanMessage, SystemMessage[11]。
上下文學習(In-Context learning)是一種新興的范式,它是指通過給定一些示范性的輸入-輸出對(示例),在不更新模型參數的情況下實現對給定測試輸入的預測。它獨特的無需更新參數能力使得上下文學習的方法可以通過一個語言模型的推理,來統一各種自然語言處理任務,這使其成為監督式微調的一個有前途的替代方案。
雖然,這種方法在各種自然語言處理的任務中都表現不錯,但它的表現依賴給定的示范性輸入-輸出對。在模型的prompt中為每個任務都指定示范性示例會影響prompt的長度,這導致每次調用大語言模型的成本增加,甚至超出模型的輸入長度。因此,這帶來一個全新的研究方向——基于演示檢索的上下文學習。這類方法主要是通過文本(或語義)檢索與測試輸入在文本或語義上相似的候選示范性示例,將用戶的輸入與獲得相似的示范性示例加入到模型prompt中作為模型的輸入,則模型就可以給出正確的預測結果。然而,上述單一的檢索策略使得召回率不高,造成示范性示例無法精準召回,致使模型的效果不佳。
為了解決上述問題,我們提出了一種基于混合演示檢索的上下文學習方法。該方法充分考慮不同檢索模型的優劣,提出一種融合算法,通過利用文本檢索(例如,BM25和TF-IDF)和語義檢索(例如,OpenAI embedding-ada和sentence-bert)進行多路召回,解決單路召回率不高的問題。然而,這帶來全新的挑戰,即如何將不同的召回結果進行融合。這是由于不同檢索算法分數范圍不匹配,例如,文本檢索分數通常在 0 和某個最大值之間(這具體取決于查詢的相關性);而語義搜索(例如,余弦相似度)生成 0 到 1 之間的分數,這使得直接對召回結果進行排序變得很棘手。因此,我們又提出一種基于倒序排序融合算法(Reciprocal Rank fusion)的重排方法,該算法在不需要調整模型的情況下,利用位置來組合不同檢索算法的結果,同時,考慮到大模型對相關信息出現在輸入上下文的開頭或結尾時,性能往往最高,設計重排算法,從獲得高質量的融合結果。
具體的模型架構如下圖所示,它包括檢索模塊、重排模塊和生成模塊。
檢索模塊又分為文本檢索和語義檢索。
語義檢索采用雙塔模型,用OpenAI的embedding-ada作為表征模型,分別對用戶的輸入和每個任務的候選示例進行表征,獲取語義向量,之后利用k-近鄰算法(K-Nearest Neighbor,KNN)計算語義相似度,并依據相似度對候選結果進行排序。其中,對于每個任務的候選示例我們采用離線表征,并將其存入向量數據庫中,這是因為一旦任務確認,每個任務的候選示例是固定不變的。而對于用戶的輸入,我們采用實時表征,提高計算效率,這是因為用戶的輸入是多樣的、不固定的。
文本檢索,我們先是對每個任務的候選示例進行文本預處理,去除掉停用詞、特殊符號等。同時,在文本檢索中采用倒排索引的技術加速查詢,并利用BM25計算文本相似度,最后按相似度進行排序。
對于重排模塊,我們提出了一種基于倒序排序融合的重排算法。該方法先是為了解決不同召回算法的分數范圍不匹配的問題,我們引入倒序排序融合算法,對多路的召回結果進行融合排序。雖然倒序排序融合算法可以很好將多路召回進行融合排序,但是這種排序無法滿足大模型具有對相關信息出現在輸入上下文的開頭或結尾時性能最高的特性。這使得簡簡單單的利用倒序排序融合進行輸出,效果不好。因此,我們在此基礎之上對融合排序后的結果進行重排,排序策略是依據融合排序后的結果進行兩端填充排序。例如,原本的順序為[1,2,3,4,5],進行重排后的順序為[1,3,5,4,2]。
生成模塊可以生成富有創意且連貫的文本,它旨在根據給定的Prompt或上下文生成新內容,這里我們設計了prompt組裝模塊,通過將系統prompt與檢索到相關信息進行組合。此外,還在組裝模塊中融入長期對話記錄和短期對話記錄進行prompt封裝。
在RAG 的知識問答場景下,隨著越來越多的文檔、網頁等信息被注入應用中,越來越多開發者意識到信息來源的重要性,它可以讓模型生成的內容能夠與參考信息的內容作出對齊,提供證據來源,確保信息準確性,使得大模型的回答更加真實。
8.3.1 模型生成
直接讓模型生成歸因信息。可在Prompt 添加類似“每個生成的證據都需在參考信息中進行引用”的話。這種方法最簡單,但也對模型的指令遵循能力要求較高,一般會采用GPT-4 回答,或者微調模型讓模型學習在生成時附帶引用的回答方式。缺點也很明顯,極度依賴模型的能力(甚至可能引用也是編的),且針對實際場景中出現的badcase 修復周期長,干預能力弱。
8.3.2 動態計算
在模型生成的過程中進行引用信息的附加。具體的操作為在流式生成的場景下,對生成的文本進行語義單元的判斷(比如句號,換行段落等),當出現一個完整的語義單元時,將該語義單元和參考信息中的每個參考源進行匹配(關鍵字,embedding等),通過卡閾值的辦法找到Top-N 的參考源,從而將參考源進行附加返回。這種方法的實現相比方法一簡單了很多,badcase 修復周期也短,但受限于匹配方式和閾值,且存在一個前提假設:模型的生成文本來源于參考信息。
更多關于歸因研究的工作可以參考:A Survey of Large Language Models Attribution[12]
做開發的同學不管用沒用過,對 TDD(Test-Driven Development)的大名總歸是聽過的,類似的,開發大模型應用的時候也應該有個對應的 MDD(Metrics-Driven Development) 的概念,最舒服的姿勢肯定是預先定義好業務的場景、用到的數據、設定的指標以及需要達到的分值,然后按部就班的實現既定目標,員工士氣高老板也開心!
但理想和現實之間總是如此糾纏,對大部分的大模型開發任務來講,更常見的情況是場景定義不清楚,數據光清洗就累死三軍,至于需要的指標和目標?想都沒想過!這一次,我們來補上本應該在最最開始的就考慮的,大模型應用如何量化業務指標,具體的,如何量化的證明,你的 RAG 就是比隔壁老王他們組的牛?到底該拿哪些量化的指標去說服同行?
影響RAG系統性能的幾個方面:
9.2.1 RGB(Benchmarking Large Language Models in Retrieval-Augmented Generation)[13]
這一工作系統地研究了檢索增強生成對大型語言模型的影響。它分析了不同大型語言模型在RAG所需的4項基本能力方面的表現,包括噪聲魯棒性、拒答、信息整合和反事實魯棒性,并建立了檢索增強生成基準。此外,現在做RAG都是做的pipeline,涉及到切塊、相關性召回、拒答等多個環節,每個環節都可以單獨做評測,文中提到的4個能力其實可以影射到每個環節當中。
9.2.2 RAGAS(RAGAS: Automated Evaluation of Retrieval Augmented Generation)[14]
該工作提出了一種對檢索增強生成(RAG)pipeline進行無參考評估的框架。該框架考慮檢索系統識別相關和重點上下文段落的能力, LLM以忠實方式利用這些段落的能力,以及生成本身的質量。目前,該方法已經開源,具體可以參見github:GitHub – exploding gradients/ragas: Evaluation framework for your Retrieval Augmented Generation (RAG) pipelines
9.2.3 Llamalindex-Evaluating[15]
LlamaIndex提供了衡量生成結果質量的關鍵模塊。同時,還提供關鍵模塊來衡量檢索質量。
LLM這一波,催生的技術真的很多,每一個環節,要真正做好,符合企業應用,都可以讓我們研究好長一段時間,并需要不斷去實踐,才能打磨出精品。本文總結了過去一年在RAG實踐的關鍵模塊,希望本文總結對大家有一定的幫助。
文章轉自微信公眾號@NewBeeNLP