RAG基礎
RAG也在很多行業積極實踐中,在【RAG行業交流中發現的一些問題和改進方法】提到了,RAG應該算是核心底層,適配各行各業,依然需要基礎元件和各行業的適配應用:
如果我們需要傾向於獲取外部知識和重視透明度,RAG是我們的首選。另一方面,如果我們正在使用穩定的標記資料,並旨在使模型更接近特定需求,則微調是更好的選擇。
RAG產品的使用者旅程總結
RAG 適用場景:
- 第一:私有資料存在一定頻率的動態更新的;
- 第二:需要給出引用原文的;
- 第三:硬體資源(GPU)不是太充足的(即使用RAG也需要微調,但一次微調處處可用,遠比每個企業私有庫微調一個模型成本低的多)
RAG任務幾個具體問題場景【RAG行業交流中發現的一些問題和改進方法】:
- 不擅長小範圍的描述性問題回答。例如,哪個主體具有某些特徵?
- 不擅長關係推理,即尋找從實體A到實體B的路徑或識別實體集團。
- 不擅長時間跨度很長的總結。例如,“列出所有哈利波特的戰鬥”或“哈利波特有多少次戰鬥?”
RAG應用程式在這類任務上的表現很差,因為只有少數chunk可以輸入到LLM中,而且這些chunk是分散的。LLM會缺少很多輔助資訊,比如後設資料和世界知識。為RAG尋找最適合的領域,避免強行進入錯誤的地方,比如千萬別讓RAG去寫詩,它的算數能力也很差。
在【瀚海方舟:ChatGPT應用:如何征服市場眼中的“萬能RAG”】一文中提到了非常多針對性的解決方式:
- 內容切片不夠好,容易切碎,於是有了段落智慧劃分;
- 向量生成的質量不可控,於是有了可根據不同QA場景動態生成向量的Instructor;
- 隱式的動態向量不夠過癮,再用HyDE做箇中間層:先生成一些虛擬文件/假設文件再做召回,提升召回率;
- 如果向量這一路召回不夠,再上關鍵詞召回,傳統BM25+向量HNSW融合各召回通路;
- 召回的太多容易干擾答案生成,探究一下Lost in the Middle,搞一搞trick,或者用LLMLingua壓縮;
- 嫌召回太麻煩?直接擴到100k視窗全量懟進大模型,LongLoRA橫空出世;
- 剛才提到的各個環節需要改進的點太多,懶得手工做,直接交給大模型,用Self-RAG替你完成每個步驟
按照上述的內容全部擼一遍,但是仍然有非常多的問題,然後又需要:
- 要建立元資料過濾單元,不是一上來就全文檢索,要有更精細化的索引,根據查詢需求先做一遍過濾,比如時間、內容源等等;
- 要建立全文處理單元,解決由於切割帶來的資訊損耗,需要從離線、線上兩部分同時考慮,離線預計算覆蓋高頻需求,線上覆蓋長尾需求;
- 要建立數值計算單元,彌補大模型在做數學題上的缺陷,並且補充足夠的金融行業計算公式或企業自定義計算公式;
- 要建立資料庫查詢單元,區別於“數值計算”,這裡主要是指NL2Sql,有些資訊查詢需要走資料庫而不僅僅是文章內容;
- 要建立意圖澄清單元,我們允許使用者發起五花八門的查詢請求,但當查詢需求不明確時,系統要有能力幫助使用者改進查詢語言
RAG應用難點
-
資料難點:文件種類多
有doc、ppt、excel、pdf,pdf也有掃描版和文字版,抽取出來的文字資訊,呈現碎片化、不完整的特點。
-
資料難點:不同文件結構影響,需要不同的切片方式
這個可是老大難問題了,不好的切片方式會造成:
- 如果切片太大,查詢精準度會低
- 一段完整的話可能被切成好幾塊,每一段文字包含的語義資訊實際上也是不夠完整的
- 一些雞肋切片,其實可以刪掉
-
資料難點:內部知識專有名詞不好查詢
目前較多的方式是向量查詢,對於專有名詞非常不友好;影響了生成向量的精準度,以及大模型輸出的效果。
-
使用者提問的隨意性 + 大眾對RAG的定位混亂
大部分使用者在提問時,寫下的query是較為模糊籠統的,其實際的意圖埋藏在了心裡,而沒有完整體現在query中。使得檢索出來的文字段落並不能完全命中使用者想要的內容,大模型根據這些文字段落也不能輸出合適的答案。
-
公域與私域知識混淆難定位
提問:乙烯和丙烯的關係是什麼?
大模型應該回答兩者都屬於有機化合物,還是根據近期產業資訊回答,兩者的價格均在上漲?
-
新舊版本文件同時存在
-
多條件約束失效
提問:昨天《獨家新聞》統計的化學制品行業的關注度排名第幾?
加上約束之後,如何讓大模型讀懂什麼叫“昨天”,又有哪段內容屬於《獨家新聞》?
-
全文/多文類意圖失效
提問:近期《獨家新聞》系列文章對哪些行業關注度最高?
受限於文件切割,遇到橫跨多篇文章,或全篇文章的提問,基本上涼涼了 。
-
複雜邏輯推理
提問:近期碳酸鋰和硫酸鎳同時下跌的時候,哪個在上漲?
除非原文中有顯性且密集型相關內容,大模型可能能夠直接回答正確,否則涼涼的機率極高。
而使用者在提問這類問題時,往往是無法在某一段落中直接找到答案的,需要深層次推理。
-
金融行業公式計算
提問:昨天哪些股票發生了漲停?
如何讓大模型理解“漲停”意味著 (收盤價/昨日收盤價-1)≥10%
-
人工搜尋效率低下
人類並不擅長在搜尋系統中輸入他們想要的東西,比如打字錯誤、模糊的查詢或有限的詞彙,這通常會導致錯過明顯的頂級搜尋結果之外的大量資訊。雖然RAG有所幫助,但它並沒有完全解決這個問題。
-
長下文長度
檢索內容過多,超過視窗限制怎麼辦 ?如果 LLMs 的上下文視窗不再受限制,RAG 應該如何改進?
-
向量檢索的弊端
向量檢索是基於詞向量的相似度計算
如果查詢語句太短,比如只有一個ID、一個雜湊碼或者一個產品名稱,那麼它們的詞向量可能無法反映出它們的真實含義,也無法和其他相關的文件進行有效的匹配。這樣就會導致向量檢索的結果不準確,甚至出現一些完全不相關的內容。類似的,如果我們查詢“8XLARGE64”,“99.9%”,這樣的一些關鍵字時,向量搜尋會得出一些毫不相干的內容,以至於讓背後的大模型毫無用武之地,甚至可能被誤導
解決方案
知識庫文件預處理
在載入知識庫檔案的時候,直接上傳文件雖然能實現基礎的問答,但是,其效果並不能發揮到最佳水平。因此,我們建議開發者對知識庫檔案做出以下的預處理。 以下方式的預處理如果執行了,有機率提升模型的召回率。
-
使用
TXT / Markdown
等格式化檔案,並按照要點排版 -
減少檔案中衝突的內容,分門別類存放資料
-
減少具有歧義的句子
-
減少單個檔案的大小,減少檔案中的特殊符號
-
結構複雜的先根據大模型以問答對的形式輸出
-
對文件合理分塊
不合理的分塊會導致很多問題,過小的chunk導致上下文資訊的缺失;連貫文章因為chunk而進行拆分
-
資料清洗
文件智慧分塊與解析
-
文件版面佈局(Layout)分析
-
圖片的資訊抽取
-
PDF 解析
搜尋架構、索引構建、Embedding
檢索的主要方式還是這幾種:
- 相似度檢索:前面我已經寫過那篇文章《大模型應用中大部分人真正需要去關心的核心——Embedding》種有提到六種相似度演算法,包括歐氏距離、曼哈頓距離、餘弦等。
- 關鍵詞檢索:這是很傳統的檢索方式,但是有時候也很重要。剛才我們說的後設資料過濾是一種,還有一種就是先把chunk做摘要,再透過關鍵詞檢索找到可能相關的chunk,增加檢索效率。據說Claude.ai也是這麼做的;
- SQL檢索:這就更加傳統了,但是對於一些本地化的企業應用來說,SQL查詢是必不可少的一步,比如我前面提到的銷售資料,就需要先做SQL檢索。
query改造、轉換、意圖識別
-
Query transformations:Query拆解,如果查詢很複雜,LLM 可以將其分解為多個子查詢。
-
HyDE,生成相似的,或者更標準的prompt模板,然後去檢索文件chunk
-
Query向量化/文件向量化前加特定的Prompt,
-
query邏輯鏈的多跳實現
-
增加追問機制
這裡是透過Prompt就可以實現的功能,只要在Prompt中加入“如果無法從背景知識回答使用者的問題,則根據背景知識內容,對使用者進行追問,問題限制在3個以內”。這個機制並沒有什麼技術含量,主要依靠大模型的能力。不過大大改善了使用者體驗,使用者在多輪引導中逐步明確了自己的問題,從而能夠得到合適的答案。
-
歷史聊天融入成為統一的Prompt
-
意圖識別模組
RAG的路由 + 代理
路由其實有一點意圖識別 + 分發任務的意味,本節參考【RAG 高效應用指南 04:語義路由】,有幾種路由方式:
- 元件路由:路由到不同的元件型別,比如將查詢傳遞給 Agent、Vector Store,或者直接傳遞給 LLM 進行處理
- Prompt 路由:根據 question 的不同路由到不同的 prompt template
RAG路由的實現:
- 基於大語言模型(LLM)識別使用者意圖
- 基於傳統的 NLP 技術,訓練一個分類模型,對使用者的查詢型別進行分類
- 根據使用者查詢與預設話術模板的相似性進行匹配
-
LLM Prompt
基於 LLM Prompt,就是透過 prompt 來判斷使用者的 query 屬於哪個意圖,當然,我們不可能窮舉使用者 query 的所有意圖,所以對於不在預設意圖的使用者 query,我們一般還會進行兜底處理。
響應合成Response synthesiser
這是任何 RAG 管道的最後一步 - 根據我們仔細檢索的所有上下文和初始使用者查詢生成答案。
最簡單的方法是將所有獲取的上下文(高於某個相關閾值)與查詢一起連線並立即提供給 LLM。
但是,一如既往,還有其他更復雜的選項,涉及多個 LLM 呼叫,以細化檢索到的上下文並生成更好的答案。
響應合成的主要方法是:
- 透過將檢索到的上下文逐塊傳送到 LLM 來迭代完善答案
- 將query的上下文一起丟進來以適應提示
- 根據不同的上下文塊生成多個答案,然後連線或總結它們。
query 意圖識別+意圖補充+意圖修復 環節
- 意圖識別方式一:多關鍵詞/主題詞提取與檢索
大致方案羅列:
-
基於傳統 NLP 的成分句法分析,提取名詞短語;再透過短語間的依存關係,生成關鍵詞列表
-
從完整語句的 Embedding,切換為關鍵詞 Embedding:
-
- 知識庫構建時。基於單知識點入庫,入庫時提取關鍵詞列表進行 Embedding,用於檢索。
- 查詢時。對使用者的問題提取關鍵詞列表進行 Embedding 後,從本地知識庫命中多條記錄。
-
將單問句中的多知識點拆解後檢索,將召回的多條記錄交付給 LLM 整合。
該方法的優勢在於:
- 相比傳統 Embedding,大幅提升召回精準度。
- 支援單次互動,對多知識點進行聚合處理。而不必讓使用者,手動分別查詢單個知識點,然後讓 LLM 對會話歷史中的單個知識點進行彙總。
- 使用傳統 NLP 在專項問題處理上,相比 LLM 提供更好的精度和效能。
- 減少了對 LLM 的互動頻次;提升了交付給 LLM 的有效資訊密度;大大提升問答系統的互動速度。
- 意圖識別方式二:中心化大模型做語義識別
透過 System Role 告知LLM 需要提取槽位資訊,讓 LLM透過多輪對話引導使用者給出所有槽位資訊。
-
意圖補充、修復、改寫
-
多輪對話意圖繼承能力
-
過長提問的總結
-
拒絕回覆
面對使用者提問的內容並不是目前我們預期支援的領域,我們就需要進行拒絕,並給使用者一些回覆,讓使用者不至於那麼不舒服。常見的策略一般有這些:
- 一句寫死的回覆:“哎呀,這方面的問題我還不太懂,需要學習下”。
- 用大模型生成,例如藉助prompt引導生成一些安撫性的回覆,“對不起,你問的[]問題,我好像還不太懂。你可以試試問問別的”。
- 使用推薦問或者追問的策略。(你是否在找以下幾個問題XX;你描述的我好像不太懂,能再補充補充嗎)