快轉到主要內容

進階 RAG 技巧 - 改變使用者問題 Transform Query

問題會影響「資訊搜尋」,也會影響「答案生成」。

因此,辨認使用者意圖 + 轉化使用者輸入變成更好的問題(甚至進而知道要用什麼方式獲得資訊 / routing)會很有幫助。這跟你的搜尋系統也有關

例如使用者輸入「老婆生日要到了,我該買什麼?」,如果你的搜尋必須仰賴「禮物」這個詞才會準確,這時讓 RAG 改變 query 加上「禮物」 就可能有幫助

Query transformation in perplexity screenshot
Perpexlity AI 搜尋也有做 Query 轉換!

下面是一些 Query 轉換的策略 – 有些可能一起使用變 combo 技 (Note: 本文的「文件」與 chunk 有時意思一樣,或說是一種抽象的概念)


HyDE #

HyDE = 從問題生出「答案」用以檢索 (reference)

HyDE 是 Hypothetical Document Embeddings :把使用者輸入的問題利用 LLM 產生一個「答案」,然後拿這個答案做後續的搜尋與處理(例如正常 RAG 流程,去資料庫搜尋相近的文件後生成答案)

Illustration with and without HyDE
HyDE 把 query 轉成模擬的答案

這個答案可能有幻覺、非事實,也不見得在資料庫內。那為什麼還要這樣做呢?

  • 因為使用者會輸入的「問題」跟資料庫的「文件」,兩者分佈 (distribution) 可能差別很大
    • 例如文字短 vs. 長,問句 vs. 肯定否定句
  • 搜尋「生日禮物買什麼?」,資料庫可能有一模一樣的文件「生日禮物買什麼?」,然而搜尋出這一句對於生成答案不見得有用 – 就像一個只會反問你而不會回答的人。
  • 若想訓練自己的 embedding 模型,因為「問題」跟「答案」分佈不同、性質不同,有可能要蒐集很多「一問一答」配對的 supervised 訓練資料

HyDE 做了強假設:生成出的「假答案」跟資料庫的文件的性質會類似,所以

  • 不用擔心分佈有差異,因為你是用答案去匹配文件
  • 訓練 embedding 模型可以只針對資料庫內的文件,做 unsupervised 或 contrastive 訓練,而不用蒐集一對一對的「問題 + 答案」

其實,一些 embedding model 也有類似的概念:s2p (sentence-to-passage) 還是 p2p (passage-to-passage)

  • sentence 就是一句話
  • passage 是一段話,可以是多個句子

例如 bgestella 模型 都有提到 s2p 陽春的轉換法:在短 query 前面加上類似「为这个句子生成表示以用于检索相关文章:」的文字

Self-querying retrieval #

把講人話的問題,變成資料庫或搜尋引擎的 query 語法 (reference)

當資料庫文件有 metadata 欄位能夠 filter ,例如商品的「價錢」、新聞的「時間」、文章的「作者」等等,這種時候特別有用

例如這個問題「我預算 500 塊,想要給老婆生日禮物」:

  • 「想要給老婆生日禮物」是模糊的問題
  • 「預算 500 塊」是很精確的要求,如果找出 800 元的商品可能會生氣。但無論是用關鍵字或 embedding 都不見得能跟商品的標題或敘述做很精確的匹配

但如果資料庫有「價錢」這個欄位,尋找資料庫的時候就能加上 price < 500 的條件

所以 query 轉換要把精確的要求擷取出來:例如告訴 LLM 資料庫有哪些欄位可篩選,然後去分析使用者的問題,轉換成

  • Query: 我想要給老婆生日禮物
  • Filter: price < 500
Illustration of self-querying retrieval
把精準要求的部分變成精準 query

轉換的時候可能可以分兩階段

  1. 把人話用 LLM 萃取出抽象的條件 (例如 price < 500),這抽象的條件是給電腦看,但跟實際用的資料庫語法無關
  2. 再把抽象條件,根據使用的資料庫 (MySQL, Elasticsearch, Chroma, …) 轉換成該資料庫的語法 query – 這個步驟就不需要 LLM 了

HyDE 跟 self-querying retrieval 都是把問題轉成「好搜尋」的型態。接下來的方法則著重在「拆解或生出不同的問題」,有些甚至不一定要用在搜尋,純 LLM 問答也 ok


Step-back prompting #

Step-back prompting = 從背後的問題出發 (reference)

當問題很複雜,例如「Estella Leopold 在 1954 八月到十一月去了哪間學校?」,這是複合性、複雜的。不過,如果能先知道這個問題的答案:

「Estella Leopold 的學歷與時期是什麼?」

就可能回答原來的問題。也就是用 LLM 去發想原問題背後的「更一般、好回答」的問題,或許也可以說是 “First principle”

實際的 prompt 可以參考論文的 Table 12 跟 Table 14,或是 ragatouille-book

其中論文使用了 few-shot prompt:也就是給 LLM 實際例子到底「找出背後的問題」是什麼例子

Least-to-most prompting #

Least to most prompting = 拆解問題,逐步累積回答 (reference)

跟 step-back 類似,只不過是把問題用 LLM 拆解成多個小問題並依序回答。每一次回答的時候

  1. 都是先累積前幾次的「問 + 答」
  2. 對於當下這一個小問題去資料庫搜尋相關資料
  3. 把 1, 2, 跟當下這小問題,交由 LLM 去生成答案,就回到了 1. 直到所有小問題回答完了,最後再把所有小問答交給 LLM 去生出原問題的答案

注意到,原論文其實並沒有用在 RAG 或搜尋,而是著重在 LLM prompting 的部分。也就是小問題的答案是 LLM 直出而沒有搜尋輔助

論文ragatouille-book 也都有 prompt 範例,也可利用 few-shot prompt


Step-back prompting 跟 Least-to-most prompting

  • 都假設了使用者的問題很複雜、難搞 – 但實際不見得如此
  • 某種角度 Step-back 是 Least-to-most 的特例,頂多分別在把歷次搜尋出來的文件放在 prompt 裡,還是直接放歷次的問答而不記住中介的文件/chunk 作為 context
  • 有股 CoT 或 ReAct 的味道 – 其實根本都是 Google Brain 幾乎同群人

而接下來的 RAG Fusion / Multi-query Retrieval 則是腦洞大開,暴力平行生出很多問題!


RAG Fusion #

RAG Fusion = 發想不同角度的問題 (reference)

最單純的 RAG 是:一個問題,搜出 k 個相關文件,一同交給 LLM 生成答案

RAG Fusion 或 Multi-query retrieval 則是: 一個問題,用 LLM 發想出 n 個問題,每個都找出 k 個相關文件,再一同交給 LLM 生成答案

最單純的就是把 n 乘以 k 個文件全部當 context。不過 RAG Fusion 是更進一步,用 RRF (Reciprocal rank fusion) 把這麼多的文件重新排名

Illustration of RAG Fusion
擴充成多個問題來去搜尋

RRF 會在另外撰文介紹,概念是有 n 個人都說出他們 k 個最喜歡的偶像時,綜合評比哪個偶像最歡迎呢?每個偶像都會獲得「名次倒數」的加分,例如有人說 X 是第三名,他就加 1/3 分

原論文沒有附 prompt, 不過可以參考 ragatouille-book


Disclaimer: 這裡的文獻技巧不一定適合你的應用情境。不如說,那些作者會發明不同的技巧,很可能是他們 debug 他們實務問題的不足之處 – 而不是你的。


若您覺得有趣, 請 追蹤我的Facebook 或  Linkedin, 讓你獲得更多資訊!