iT邦幫忙

2026 iThome 鐵人賽

DAY 7
0
AI Engineering

現代化的 AI 系統設計系列 第 7

[Day7] - 找到相似內容還不夠:RAG 如何找回真正能回答問題的證據

  • 分享至 

  • xImage
  •  

明明資料裡有答案,為什麼 RAG 還是會找錯?

昨天談完文件匯入與索引流程,我們已經把 PDF、PowerPoint、表格與其他原始資料,轉換成可以被搜尋的 Chunk,也建立了關鍵字、向量或 Graph Index。

接下來看起來很簡單:把使用者的問題轉成 Embedding,從 Vector Database 找出最相似的幾個 Chunk,再交給 LLM 回答,不就完成了嗎?

但假設使用者問的是:

「升級到 3.2.1 之後出現 ORA-12541,要怎麼恢復?」

Vector Search 可能找到幾篇都在討論「資料庫連線異常」的文件,語意非常相似,卻沒有一篇包含 3.2.1 的已知問題與實際復原步驟;另一份標題看起來不太相似的 Release Note,反而同時記載了版本、錯誤碼與修正方式。

如果系統只取回前五個語意最相似的 Chunk,它找到的可能都是「相關內容」,卻沒有一份是「能回答問題的證據」。

這就是今天真正要處理的問題:

Retrieval 的目標不是找出最像問題的文字,而是以可接受的成本,找回足以支持答案的證據。

https://ithelp.ithome.com.tw/upload/images/20260821/20183613ekRROz3oU4.png


Retrieval 不是一次搜尋,而是逐步縮小不確定性

一條比較完整的 Retrieval Pipeline,可以拆成以下幾個責任不同的階段:

理解 Query → 套用 Metadata Filter → 多路召回 → 融合排序 → Reranking → Context Selection

第一階段的 Retriever,要在大量資料中快速找出候選,重點是不要漏掉答案,也就是提高 Recall。這一層可以同時使用 BM25、Dense Retrieval,甚至針對特定資料使用其他 Retriever。

候選集合產生之後,Fusion 負責把不同搜尋方式的結果合併;Reranker 再使用成本較高、但判斷更細緻的模型,重新評估每個候選與問題之間的關係,提升 Precision。最後的 Context Selection 還要排除重複內容、補回必要上下文,並在 Token Budget 內組成真正要交給 LLM 的證據。

因此,文章裡常看到的 Top-K,其實至少包含三個不同的 K:

  1. Retriever 從每條搜尋路徑取回多少候選
  2. Reranker 要重新判斷多少候選
  3. 最後送進 Prompt 的 Context 有多少

把三者混成同一個數字,很容易造成錯誤調校。第一階段的 K 太小,正確證據可能根本進不了候選集;最後的 K 太大,又可能讓大量相似、過期或互相矛盾的內容一起進入 Prompt。

所以 Retrieval 並不是「找越多越好」,而是在 Recall、Precision、Latency、Cost 與 Context Quality 之間做取捨。


Vector Search 只是其中一條搜尋路徑

Dense Retrieval 會把 Query 與 Chunk 分別轉成向量,再尋找距離較近的內容。它最大的價值,是能跨越字面差異理解語意。例如使用者問「商品壞掉可以換新嗎?」,即使文件寫的是「瑕疵品更換政策」,仍有機會被找出來。

但一個向量必須把整段內容壓縮成固定維度。當 Chunk 同時包含多個主題,或問題依賴否定詞、版本、日期與精確編號時,重要細節可能被整體語意稀釋。Vector Search 找到的,是向量空間中的鄰近內容;鄰近不代表它包含答案,更不代表它是目前有效的答案。

傳統的關鍵字搜尋則有完全不同的優勢。BM25 不真正理解語意,但特別擅長辨識罕見且不能被模糊處理的字串,例如:

  • 錯誤碼、CVE 編號與 API 名稱
  • 商品料號、版本號與法條編號
  • 人名、產品名稱與領域縮寫
  • 使用者直接貼上的系統訊息

它的弱點也很明顯:使用者若採用同義詞、口語描述或不同語言,文件中又沒有出現相同詞彙,就可能完全找不到。

這兩種搜尋方式不是誰取代誰,而是觀察同一份資料的兩種視角:

搜尋方式 擅長的訊號 常見失敗
BM25/Sparse Retrieval 精確詞彙、稀有字串、代碼與名稱 不理解同義改寫與跨語言語意
Dense Retrieval 概念、語意、自然語言改寫 找到主題相似但不能回答的內容,精確細節可能被稀釋
Metadata Filter 權限、時間、版本、產品與資料範圍 Metadata 錯誤或條件過窄會直接漏掉答案

https://ithelp.ithome.com.tw/upload/images/20260821/20183613MXXpmjEwB5.png


Hybrid Search 的重點,不只是同時搜尋兩次

當 BM25 與 Dense Retrieval 的錯誤具有互補性,最直覺的做法就是讓兩條路同時召回候選,這也是 Hybrid Search 的基本概念。現在許多搜尋服務都已提供不同形式的混合搜尋。

不過,「兩邊都查」只完成了一半。接下來還要回答:BM25 的分數與 Cosine Similarity 根本不在同一個尺度上,兩份結果到底如何合併?

一種常見做法是 Reciprocal Rank Fusion,簡稱 RRF。它不直接比較兩套系統的原始分數,而是根據文件在每份結果中的名次計分。某份文件如果在關鍵字與向量搜尋都名列前茅,融合後自然會得到較高順位。

RRF 的好處是簡單、容易解釋,也不需要先校準不同模型的分數,因此適合作為沒有大量標註資料時的 Baseline。Azure AI SearchElasticsearch 都把它放在 Hybrid Search 的核心設計中。

但 RRF 也不是魔法:

  • 如果所有 Retriever 都沒有找到正確文件,Fusion 不會憑空創造答案
  • 它重視名次,卻可能忽略第一名與第二名原始分數差距有多大
  • 品質較差的 Retriever 仍可能把噪音帶進候選集合
  • 重疊 Chunk 可能讓排行榜被同一文件佔滿

例如 Weaviate 提供保留分數差距的 Relative Score Fusion;Pinecone 則能調整 Dense 與 Sparse 的權重。這些差異說明:融合策略本身就是 Retrieval Design 的一部分。 有了自己的 Relevance Dataset,才有條件比較不同方法。

在中文開源生態中,BGE-M3 讓同一個模型產生 Dense、Sparse 與 Token 級 Multi-vector 表示。值得借鏡的不是又多了一個模型名稱,而是背後的共同觀念:

不要要求單一相似度分數,同時理解語意、精確詞彙、文件範圍與答案相關性。


Metadata Filter 決定了「應該在哪裡找」

如果使用者問「目前台灣地區的企業方案價格」,只靠語意相似度,可能同時找回個人方案、其他國家、舊版本與已失效的促銷內容。這時候問題不是排序模型不夠強,而是搜尋範圍一開始就沒有被正確限制。

Metadata 可以包含產品、地區、語言、生效日期、文件版本、部門、Tenant 與 ACL。Filter 的角色不只是改善相關性,也關係到資料隔離與權限:某個 Chunk 即使和問題非常相關,只要使用者沒有權限,它就不應進入候選集合。

這些安全條件必須由可信任的 Application State 注入,不能請 LLM 自己判斷使用者有哪些權限。Query 中的「我是管理員」只是一段不可信的輸入,不是授權證明。

Filter 在什麼時候執行也會影響結果。以 Vector Search 為例:

  • Pre-filter 先限制符合條件的資料,再從中搜尋鄰近向量
  • Post-filter 先做 Vector Search,再把不符合條件的結果移除

Post-filter 如果只從很小的候選集合開始,可能把多數結果移除,最後甚至回傳零筆;Pre-filter 比較能維持條件內的 Recall,但條件高度選擇性時,也可能增加索引遍歷與延遲。Azure 的 Vector Filter 文件 就明確揭露了這項取捨。

因此,看到零結果時不應立刻把 Top-K 加大。也可能是 Metadata 不完整、版本標記錯誤,或 Filter 執行方式造成了 False Negative。


Reranking:把「找得廣」與「排得準」拆開

第一階段 Retriever 必須在大量資料中快速搜尋,因此通常使用 BM25、Bi-encoder 或其他可以預先建立索引的模型。它適合粗篩,卻無法花很多計算逐一細讀 Query 與每個 Chunk。

Cross-encoder Reranker 的做法不同。它把 Query 與候選文件一起交給模型,直接觀察兩者的 Token-level Interaction,再判斷這段內容是否真的回答問題。代價是每個候選都要重新推論,因此通常只用在第一階段找回的數十筆候選,而不是掃描整個 Corpus。

這形成一個常見的兩階段設計:

Retriever 先從數十萬筆資料找出數十筆候選,Reranker 再從候選中選出少量高品質證據。

https://ithelp.ithome.com.tw/upload/images/20260821/20183613aExa8P313s.png

但 Reranker 有一條不能被忽略的邊界:它只能重新排序已經收到的內容。如果第一階段 Candidate Recall 是零,再強的 Reranker 也無法找回答案。

另一個問題是 Domain Shift。在 BRIGHT 這個需要推理的 Retrieval Benchmark 中,研究者發現某些在一般 Web Search 資料上訓練的 Cross-encoder,重新排序後反而讓結果變差。這提醒我們,公開排行榜上的強模型,不一定理解企業內部的繁中術語、規格格式與「什麼才算回答這一題」。

Reranking 還可能遇到:

  • 文件過長而被截斷,答案剛好位於模型沒看見的位置
  • 前幾名全是同一文件的重疊 Chunk
  • 不同 Query 的分數沒有一致含義,無法直接套用同一 Threshold
  • 候選數過多造成延遲與費用上升

所以正確做法不是「打開 Reranker 就會更準」,而是分別量測 Rerank 前後的 Recall、MRR 或 nDCG、延遲,以及最後 Context 的有效比例。


最後一步不是取前幾名,而是組成一組證據

即使 Reranker 已經把最相關的內容排到前面,直接拿前五名仍可能有問題。因為前五名也許都是同一段政策的重複 Chunk,卻漏掉例外條款與最新修訂公告。

Context Selection 應該組成一個 Evidence Portfolio,而不是相似 Chunk 清單。例如退貨問題可能需要:

  • 一份直接說明退貨資格的主要規則
  • 一份清潔或使用後商品的例外條款
  • 一份較新的政策變更文件
  • 對應的商品類別與地區限制

這一層可以依 Parent Document 去重、限制同一來源數量、優先保留最新有效版本,並在 Token Budget 內維持證據多樣性。Google Vector Search 的 Crowding,就是限制同一類結果不要佔滿排行榜的一種產品化設計。

另一個方式是把 Retrieval Unit 與 Context Unit 解耦。小 Chunk 容易精準命中,卻可能缺少前後條件;大 Chunk 脈絡完整,卻會稀釋搜尋訊號。Parent-child Retrieval 用 Child Chunk 搜尋,命中後再取回較大的 Parent 交給 LLM。Dify Parent-child Retrieval

最適合被搜尋的單位,不一定等於最適合被模型閱讀的單位。


有時候,需要先把問題變得可以搜尋

使用者輸入不一定是一個完整、乾淨的 Search Query。在多輪對話中,他可能只問「那第二個方案呢?」;比較題可能同時要求成本、權限與災難復原;同一個產品也可能有正式名稱、舊名稱與社群慣用縮寫。

因此,Retrieval 前也可能需要 Query Transformation:

Query Rewrite

補回對話中的指代、正規化名稱與錯字,讓 Query 更接近文件的語言。但原始 Query 必須保留,錯誤碼、版本、日期與專有名詞也不應被改寫掉。

Multi-query

從不同角度產生數個查詢,各自搜尋後再透過 RRF 等方法融合。它可以提高 Recall,也會讓搜尋與 Reranking 成本隨查詢數增加;生成的 Query 若偏離原意,還可能把整個候選集合帶往錯誤方向。

Query Decomposition

把「比較 A 與 B 的成本、權限和備援能力」拆成多個子問題。這對 Multi-facet 與 Multi-hop 問題很有用,但每個子查詢都拿一批 Top-K,也很容易讓 Context 爆量,因此最後仍需融合、去重與控制總 Budget。

HyDE:先想像答案文件會怎麼寫

HyDE 不只改寫問句,而是請 LLM 生成一份 Hypothetical Document,再把它轉成 Embedding,尋找真實 Corpus 中與它相近的文件。

它的洞見是:短問句與答案文件往往使用不同的表達方式。系統不是把假想內容當成事實,而是先猜「答案文件可能會出現哪些概念與詞彙」,再回到真正的資料來源尋找證據。

但生成內容也可能帶入錯誤假設。HyDE 比較適合短、模糊、缺少領域詞彙的問題;面對精確 ID、日期、版本或法條時,原始查詢與關鍵字路徑仍必須保留。

這些技術的共同風險是 Query Drift。因此系統應保留原始問題、改寫結果、子查詢與各自候選,不能只留下最後答案。


不是每個問題都值得跑完最昂貴的流程

一個產品編號查詢,可能只需要 BM25、Filter 與一次 Reranking;一個跨三份政策的比較題,才需要拆解與多輪搜尋。如果所有 Query 都固定執行 Rewrite、五路搜尋、Graph Traversal 與 LLM Reranking,系統雖然看起來很完整,Latency、Cost 與除錯難度也會一起上升。

Adaptive-RAG 的核心觀念,是先依問題複雜度選擇不檢索、單次檢索或多輪檢索;CRAG 則不假設第一次 Retrieval 一定正確,而是評估候選品質,再決定是否改寫、切換資料來源或採取其他修正。較新的 FrugalRAG 又把另一個常被忽略的問題帶進來:系統除了知道怎麼繼續找,也要知道何時停止。

這些研究不代表 Production 系統一定要完整重現論文架構,但可以萃取成 Retrieval Router:

問題型態 優先路徑 不急著加入
錯誤碼、料號、法條 BM25+Metadata Filter 多輪 LLM Rewrite
自然語言與同義改寫 Dense+BM25+Fusion Graph Retrieval
比較題與多條件問題 Query Decomposition+多路融合 固定單次 Top-K
跨文件實體關係 Iterative/Graph Retrieval 只依 Chunk 相似度

https://ithelp.ithome.com.tw/upload/images/20260821/20183613AfxIxz6x9F.png

系統也需要 Fallback:候選分數過低、證據不足或彼此矛盾時,可以擴大搜尋、換一條 Retriever、要求使用者澄清,或直接說資料不足。最危險的設計,是無論 Retrieval 品質如何,都強迫 LLM 根據手上的內容產生一個肯定答案。


特殊問題,才需要更特殊的 Retrieval Structure

標準的 Hybrid Search 加 Reranking,應該先成為可觀測、可評估的 Baseline。只有當錯誤分析顯示平面 Chunk 搜尋無法處理特定問題,才值得增加其他結構。

Late Interaction:保留比單一向量更多的細節

ColBERT 不把整段文件壓縮成一個向量,而是保留 Token-level Embeddings,查詢時再用 Late Interaction 進行細緻匹配。它位於單一向量與昂貴 Cross-encoder 之間:比 Dense Retrieval 保留更多細節,又能預先建立文件索引,但需要更大的儲存空間與更複雜的 Serving。ColBERTv2

Hierarchical Retrieval:讓問題選擇資訊尺度

RAPTOR 把原始 Chunk 聚類並逐層摘要,建立不同抽象層級的樹。查參數值時可以命中葉節點,詢問整份政策的主要變化時則可以先找到上層摘要。代價是摘要可能遺漏例外,文件更新時也要維護上層結構,因此摘要適合作為導航,不應取代原始證據。

Graph Retrieval:當關係本身就是搜尋訊號

Day 6 已經提過 GraphRAG。到了 Query 階段,更重要的判斷仍然是:問題是否需要跨文件串聯 Entity、Relation 與 Multi-hop Evidence。LightRAG 的雙層 Retrieval 與 HippoRAG 2 的 Knowledge Graph 路徑,都是在處理平面 Chunk 排行榜難以表達的關聯。

它們不是 Dense Retrieval 的進階模式,也不是所有 RAG 的終點。如果問題大多只是查一段規格,建立 Graph、處理 Entity Resolution 與更新關係,只會增加成本。只有當自己的測試題持續敗在跨文件關係與整體脈絡,才有導入價值。


沒有 Evaluation,Retrieval 調校就只是印象

很多團隊會直接比較「換模型後,回答看起來有沒有比較好」。但 Generation 可能掩蓋 Retrieval 問題:LLM 有時可以靠既有知識答對,也可能在拿錯 Context 時仍生成一段流暢答案。

所以 Retrieval 與 Generation 應該分開評估:

指標 想回答的問題
Recall@K/Hit Rate 正確證據有沒有進入第一階段候選?
MRR/nDCG@K 正確或較重要的證據排得夠不夠前面?
Context Precision 最後送給 LLM 的內容,有多少真的有用?
Duplicate Rate/Source Coverage 結果是否被同一來源佔滿?是否涵蓋必要證據?
Citation Correctness 回答引用的來源,是否真的支持該項主張?
Abstention Accuracy 沒有答案時,系統能不能停止而不是硬答?
p50/p95 Latency 與 Cost 品質提升付出了多少時間與費用?

測試資料也不能只有一般問答,至少要分開觀察:精確錯誤碼、中文口語、跨語言、最新文件、比較題、多跳問題、權限限制,以及「資料裡根本沒有答案」的題目。平均分數很容易掩蓋某一類 Query 已經完全失效。

Google Cloud 的 Retrieval 優化建議也強調,應建立真實問題與 Golden Reference、一次只修改一個主要變數,並分開診斷 Nearest-neighbor Retrieval 與最後提供給 LLM 的 Context。Google Cloud:Optimizing RAG Retrieval

最小可行做法,是先收集 50~200 個來自真實使用情境的問題,標註哪些文件段落可以成為可接受證據。接著依序比較:

  1. BM25-only 與 Dense-only Baseline
  2. Hybrid Search 是否真的補足兩邊的漏召回
  3. Reranking 是否改善前段排序
  4. Context Selection 是否降低重複與無關內容
  5. 每一層改善換來多少 Latency 與 Cost

一次打開所有 Retrieval 功能,最後即使回答變好,也不知道是哪一層生效;回答變差時,更不知道該從哪裡修。


真正成熟的 Retrieval,是知道去哪裡找、怎麼排,也知道何時停止

把今天的流程重新整理一次:

先理解資訊需求,利用 Metadata 限定正確範圍,再以多種互補訊號擴大召回;接著融合與 Reranking,最後組成少量、互補且可引用的證據。

BM25 與 Dense Retrieval 解決不同的語言落差;Hybrid Search 讓兩者互補;Metadata Filter 限定正確的資料與權限範圍;Reranker 判斷候選是否真的能回答問題;Context Selection 則決定 LLM 最後看見的是重複片段,還是一組完整證據。

Query Rewrite、Adaptive Retrieval、Hierarchy 與 Graph 都有價值,但它們不是應該一次開啟的功能清單。每增加一層,都應先回答三個問題:

  1. 它要修復哪一種已被觀察到的 Retrieval Failure?
  2. 它會增加多少索引、推論、延遲與維運成本?
  3. 我們要用什麼資料與指標,證明它真的改善了結果?

Retrieval 的品質,不是由用了多少最新技術決定,而是由系統能否穩定地把問題轉成一組足以支持答案的證據決定。

下一步,即使資料已經找對,系統仍然要決定證據如何排序與組裝、遇到衝突版本怎麼處理、哪些內容可以被信任,以及如何避免取回的文件反過來操控模型。這會進一步把問題帶向 Context Engineering 與 RAG 的安全邊界。

AI 你怎麼看?

https://ithelp.ithome.com.tw/upload/images/20260821/20183613H7XhrvE7Cp.png


上一篇
[Day 6] - 從原始文件到可檢索知識:RAG 文件匯入與索引流程
下一篇
[Day8] - Context 不是塞滿就好:證據編排、Attention、Cache 與推論成本
系列文
現代化的 AI 系統設計8
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言