Teverant AI · AI 應用趨勢

2026-07-27

RAG 最佳化實踐:影響召回準確率的 6 個關鍵環節

本文系統拆解 RAG 最佳化實踐中影響召回準確率的 6 個關鍵環節:文件解析、分塊策略、向量模型選型、混合檢索、Rerank 重排序與上下文組裝。每個環節提供可直接落地的參數組合與工程實現方案,並附排查 SOP 與迭代優先順序路徑,幫助工程師快速定位召回瓶頸、系統性提升 RAG 管道效果。

環節一:文件解析——召回失敗的隱形元兇

多數團隊在 RAG 效果不達標時,第一反應是換向量模型或調檢索參數。但如果你做過系統性的 bad case 歸因,會發現一個不那麼直覺的事實:大量召回失敗的根因發生在入庫階段,而非檢索階段。典型的失敗模式包括——PDF 表格被解析成亂序文本、掃描件 OCR 輸出夾雜亂碼、Markdown 標題層級在轉換中丟失導致上下文斷裂。這些問題無論後續檢索鏈路多精巧,都無法補救:候選池裡根本不存在品質合格的片段。

一個實用的排查原則是:當 Top-50 粗召回結果中找不到正確答案時,不要急著加 Rerank 或調向量模型,先回頭檢查文件解析和分塊是否把關鍵資訊破壞了。Rerank 只能對已經進入候選池的片段重新排序,它救不了一個從源頭就丟失的答案。

三類文件的解析策略

不同文件型別需要不同的處理管線,盲目用同一套流程處理所有格式是常見的工程失誤:

文件型別核心風險推薦處理方式品質門控
純文本 / 結構良好的 Markdown風險低,標題層級偶爾丟失直接入庫,保留標題層級作為後設資料抽檢標題樹完整性
含表格、列表、程式碼塊的 PDF/Word表格行列錯亂、列表項合併為單段結構化解析器提取邊界,輸出帶型別標註的 JSON人工抽檢表格還原度
掃描件 / 圖片型 PDFOCR 識別錯誤、公式/特殊符號亂碼OCR 引擎處理後按字元置信度過濾置信度低於閾值的段落標記為「待人工校驗」,不直接入庫

工程實現要點

結構化解析的目標不是「把 PDF 轉成文本」,而是「把文件轉成帶邊界標註的結構化資料」。具體來說:

  • 表格獨立成塊:將表格作為獨立片段保留,附帶表頭資訊作為後設資料。表格一旦被拆散混入正文,語義完整性不可恢復。
  • 列表保持原子性:有序列表的每個條目如果包含獨立條件或結論,應保持在同一個 chunk 內,避免條件與結論被切分到不同片段。
  • 程式碼塊標記型別:程式碼段應標註語言型別並作為完整單元入庫,不參與後續的文本分塊邏輯。
  • 後設資料隨片段走:每個輸出片段攜帶來原始檔名、頁碼/章節路徑、文件型別、解析置信度等欄位,供後續檢索時做過濾和溯源。

開源工具鏈中,Unstructured 和 MinerU 都能輸出帶元素型別標註的結構化結果。選型時關注兩點:一是對你業務中高頻文件格式的表格還原準確率,二是是否支援自定義後處理管線(比如把低置信度段落路由到人工審核佇列)。

落地建議

在專案初期投入一到兩天做「入庫品質審計」——隨機抽取 50 個文件片段,人工比對原文與入庫後的文本,統計資訊丟失率。這個動作的 ROI 遠高於在檢索層反覆調參。如果資訊丟失率超過 10%,後續所有最佳化都建立在一個有缺陷的地基上。先把地基修好,再談上層建築。

環節二:分塊策略——可直接抄的參數組合

分塊是 RAG 管線裡最容易被低估的環節。很多團隊把文件丟進去,用預設的固定長度切一刀,chunk_size 設 1000、overlap 設 0,然後花大量時間調 prompt——方向搞反了。切片品質直接決定了檢索精度的上限,後面的向量模型和 Rerank 只能在這個上限內做最佳化。

固定切分為什麼不夠用

固定長度切分的核心問題是它對文本結構完全無感知。一段完整的操作步驟可能被從中間劈開,一個程式碼塊的前半段和後半段落入不同 chunk,使用者提問時只能召回殘缺片段。行業評測普遍顯示,這種樸素方案的檢索準確率大致在六成左右,將近一半的查詢拿不到有效答案。而切片粒度不當(過碎或過大)造成的精度損失,幅度可以達到三到五成——這不是微調能補回來的。

語義感知切分:按結構邊界下刀

改進思路很直接:讓切分點落在文本的自然邊界上——段落結束、標題切換、程式碼塊閉合。這種語義感知策略不需要複雜模型,用規則就能實現大部分收益。多個開源評測的復現結果表明,僅這一步調整就能將召回率提升約 15%–20%。

更進一步,可以引入句子級 Embedding 相似度來判斷主題是否發生了切換:

  • 對相鄰句子計算餘弦相似度
  • 相似度 < 0.5 → 判定為主題轉折,在此處切斷
  • 相似度 ≥ 0.5 → 判定為同一話題,繼續合併

這個 0.5 閾值是中文場景下的經驗起點。英文文本由於句間語義連續性更強,閾值可酌情上浮。實際部署時建議拿標註好的 bad case 做一輪閾值掃描,步長 0.05,通常兩三輪就能收斂。

推薦參數組合:Parent-Child 雙層結構

單層 chunk 始終面臨一個矛盾:粒度細了檢索準,但送進 LLM 的上下文碎片化;粒度粗了上下文完整,但檢索噪聲大。Parent-Child 策略把這個矛盾解耦:

層級Token 長度Overlap用途
子 Chunk(檢索用)300–400 Token50–100 字元做向量化和相似度匹配
父 Chunk(上下文用)1200–2000 Token約 200 字元命中子塊後,把父塊送入 LLM

工程實現上,每個子 chunk 儲存時記錄其父 chunk ID。檢索階段用子 chunk 做 top-K 召回,去重父 chunk 後將完整父段落拼入 prompt。這樣既保證了檢索階段的精度(小粒度匹配),又保證了生成階段的上下文完整性(大粒度輸入)。

Overlap 的作用是避免切分邊界處的資訊丟失。50–100 字元的重疊視窗足以覆蓋一個完整短句,防止關鍵資訊被劈裂到兩個 chunk 的邊緣而兩邊都召不回來。

後設資料增強:給每個 chunk 加一層「檢索外衣」

原始文本切好之後,還有一步低成本高回報的操作:為每個 chunk 生成一段精簡的概括標題(控制在 50 字以內)加上關鍵詞,拼接到檢索文本中一起做向量化。

為什麼有效?因為使用者的提問通常是高度概括性的(比如「怎麼配置 SSL 證書」),而原始 chunk 裡可能通篇都是具體操作步驟,沒有出現「配置 SSL 證書」這幾個字。概括標題相當於在檢索空間裡給 chunk 多建了一個語義入口。行業實測普遍顯示,這種增強手段能在語義切分的基礎上再帶來顯著的準確率提升。

實現建議:用輕量模型(或規則提取 TF-IDF 前 10 個多字詞)生成關鍵詞,用 LLM 一次性批次生成標題。標題和關鍵詞拼在 chunk 正文前面,中間用換行分隔,整體作為 embedding 輸入。注意這段增強文本只用於向量化,不用於最終送入 LLM 的上下文——避免引入噪聲。

決策路徑總結

  • 第一步:把固定切分換成按段落/標題/程式碼塊邊界的規則切分,零成本拿到基礎收益
  • 第二步:引入句子 Embedding 相似度做主題邊界檢測,閾值從 0.5 開始調
  • 第三步:上 Parent-Child 雙層結構,子塊 300–400 Token 檢索、父塊 1200–2000 Token 送生成
  • 第四步:為每個 chunk 追加概括標題和關鍵詞,增強檢索召回面

這四步是遞進關係,每一步都能獨立驗證效果。建議每做一步就跑一輪 evaluation set,確認召回率確實在漲再往下走——避免過度工程化。

環節三:向量模型選型——決策樹與參數速查

向量模型是檢索鏈路中替換成本最高的元件——換一次模型意味著全量文件重新向量化,索引重建,線上灰度切流。相比之下,調整分塊參數只需重跑 pipeline 的後半段。所以選型決策要在專案初期做對,而不是靠後期「試試換個模型」來兜底。

選型決策樹

把場景收斂到三條路徑,逐條判斷即可:

場景特徵推薦模型輸出維度最大輸入 Token核心取捨
中文為主,文件塊控制在 512 Token 以內中文專用嵌入模型——本地部署成本低,中文語義表徵成熟
中英混合語料,或存在超長段落需要大視窗多語言嵌入模型——同時產出稠密與稀疏表徵,天然適配混合檢索
精度優先,可接受 API 呼叫延遲與成本商業高維嵌入模型——高維空間區分度強,支援按需降維壓縮儲存

判斷順序:先確認語言分佈和文件長度,再看部署約束(能否調外部 API、有無 GPU 資源)。多數企業內部知識庫以中文為主且分塊後不超過 512 Token,第一條路徑就能覆蓋。

關鍵參數速查

  • 維度:768 / 1024 / 3072 三檔。維度越高,細粒度語義區分能力越強,但索引體積和檢索延遲線性增長。實際專案中 1024 維是價效比拐點——再往上提升的邊際收益需要用你自己的評估集驗證。
  • 最大輸入長度:512 Token 的模型要求上游分塊嚴格控制長度,超出部分會被截斷而非報錯,這是隱性召回損失。如果分塊策略偏長(800+ Token),必須選 8192 視窗的模型。
  • 歸一化方式:多數模型預設輸出 L2 歸一化向量,此時餘弦相似度等價於內積,檢索時用 Inner Product 即可。注意部分模型(如早期 M3E)需要手動加歸一化步驟,否則相似度分數不可比。
  • 量化:FP16 是部署基線。進一步壓縮到 INT8,索引體積減半,業界實測精度損失通常在可忽略的範圍內。但量化收益取決於資料分佈,建議在自己的評估集上對比 Recall 再決定是否上線。

選型原則:評估先行,換模型是最後手段

正確的工作流是:

  1. 先用當前模型 + 當前分塊跑一輪 Recall@50(取 Top-50 候選看目標文件是否在列),建立基線。
  2. 如果 Recall@50 已經足夠高但最終回答不準,瓶頸大機率在 Rerank 或上下文組裝,而非向量模型。
  3. 只有當 Recall@50 明顯不足,且調整分塊策略、增加後設資料過濾後仍無改善,再考慮換模型。

換模型的隱性成本容易被低估:全量文件重新 Embedding 的計算開銷、新舊索引並存期間的儲存翻倍、上下游 pipeline 的維度參數聯動修改。對於百萬級文件庫,一次模型切換的工程週期通常以周計。把這個成本和「多試幾組 chunk 參數」的成本對比,優先順序就很清晰了。

一條實用經驗:如果你的評估集還沒建好,先別糾結模型選型。用 BGE-large-zh 或 BGE-M3 起步,把精力花在構建 50–100 條標註好的 Query-Document 對上。有了評估集,所有決策都能用資料說話;沒有評估集,換什麼模型都是盲調。

環節四:混合檢索——向量 + BM25 雙路召回工程實現

純向量檢索有一個結構性盲區:它依賴語義相似度打分,但對錯誤碼(如 ERR_0x80070005)、SKU 編號、軟體版本號這類精確識別符號,embedding 模型往往把它們對映到相近的向量空間區域,導致召回結果張冠李戴。工程上的應對不是換更大的模型,而是補一路 BM25 關鍵詞檢索做精確匹配兜底。

標準雙路召回流程

工程實現的骨架很直觀:

  • 向量檢索取 Top-50 候選
  • BM25 關鍵詞檢索取 Top-50 候選
  • 兩路結果合併去重,候選池上限約 100 條
  • 用 RRF(Reciprocal Rank Fusion)對合並結果做融合排序
  • 融合後的有序列表交給下游 Rerank 模組做精排

RRF 的計算邏輯簡單:對每條文件,在每路結果中取其排名 rank,按 1/(k + rank) 求和作為最終分數。參數 k 控制排名衰減的平滑程度,實踐中多數團隊從一箇中間值開始調,這個值在多個主流框架中也是預設項。k 值在一定範圍內對最終排序的影響不算劇烈,初期不必花太多精力調它,把重心放在兩路召回各自的品質上收益更大。

Query Rewrite:必須保留原始查詢

Query Rewrite 是改善使用者模糊提問的常見手段,但它引入了一個容易被忽視的風險:改寫模型本身可能誤解使用者意圖。一旦改寫偏了,後續整條鏈路——檢索、排序、生成——全部跟著偏移,而且這種偏移很隱蔽,因為系統「看起來正常執行」只是答非所問。

工程上的防禦策略很簡單:永遠用原始查詢和改寫查詢同時做召回,兩路結果再融合。這樣即使改寫出錯,原始查詢的召回結果仍然在候選池裡兜底。實現成本幾乎為零——只是多發一次檢索請求——但能有效避免改寫失誤導致的全鏈路崩塌。

Multi-Query:一個問題拆成多個檢索方向

使用者提出一個複合問題時,單一查詢往往只能命中部分相關文件。Multi-Query 的思路是讓 LLM 把一個問題展開為 3-5 個不同角度的子查詢,分別檢索後合併去重。

舉個例子,使用者問「你們的 SLA 具體是什麼」,可以展開為:

  • 服務可用性承諾比例
  • 故障響應與恢復時間要求
  • 違約賠償條款
  • 服務等級的具體分級定義

四路檢索各自取 Top-N,合併去重後候選池的覆蓋面遠超單次查詢。這對知識庫中資訊分散在多個文件的場景尤其有效。

工程落地注意事項

關注點建議
BM25 索引維護與向量索引同步更新,文件變更時兩路都要重建,避免資料不一致
去重策略按 chunk_id 去重即可;同一文件不同分塊視為不同候選
Multi-Query 子查詢數量3-5 條為宜,過多會拉高檢索延遲且收益遞減
Query Rewrite 模型選擇不需要最強模型,輕量級模型(如 GPT-3.5 級別)足夠,重點是保留原始查詢兜底
延遲控制多路檢索可並行發起,總延遲取決於最慢的一路而非累加

混合檢索的核心價值不在於「比純向量多了一路」,而在於它用工程手段對沖了單一檢索範式的系統性缺陷。語義理解和精確匹配是兩種互補能力,在企業知識庫場景下幾乎沒有只需要其中一種的情況。把兩路召回做紮實,給下游 Rerank 提供一個高品質候選池,才是整條 RAG 鏈路能跑出好效果的前提。

環節五:Rerank 重排序——從粗篩到精排的關鍵一跳

向量檢索的本質是雙塔架構:Query 和 Chunk 各自獨立編碼成向量,再算餘弦相似度。這個架構的天然缺陷是——兩段文本之間的細粒度互動資訊在編碼階段就丟了。比如 Query 問「合同終止後保密義務存續多久」,向量檢索能把包含「保密」「合同終止」的段落都撈回來,但哪一條真正回答了「存續期限」這個核心意圖,單靠向量距離排不準。

Cross-Encoder 解決的就是這個問題:把 (Query, Chunk) 拼接成一個序列餵給 Transformer,讓模型在每一層 Attention 中充分交叉計算兩段文本的語義關係,輸出一個精細相關性分數。代價是不能預計算——每對都要過一遍模型,所以只能用在候選池已經縮小之後。

分層 Top-K:粗召回→精排→入 Prompt 三級漏斗

工程上最常見的失誤是只設一個 Top-K 參數。合理做法是把檢索鏈拆成三級:

階段候選數量作用
粗召回(向量 + BM25 融合後)30–100 條保證 Recall,把正確答案兜進來
Rerank 精排後保留5–10 條按語義相關度重排,砍掉噪聲
最終進入 Prompt3–6 條控制 Token 開銷,減少模型被無關段落干擾的機率

這條漏斗的收益是雙重的:一方面精排後 Top 位置的準確率會有顯著提升;另一方面,因為最終只餵少量高品質片段進 Prompt,送入生成模型的 Token 量大幅縮減,既降低延遲又節省成本。

什麼時候該上 Rerank,什麼時候不該

判斷標準很簡單——先看粗召回階段(Top-50)裡有沒有正確答案:

  • 正確片段已在候選池中,但排名靠後(比如在第 15–40 位):這是 Rerank 的典型適用場景。問題出在排序精度不夠,Cross-Encoder 能把它提上來。
  • 正確片段根本不在候選池中:Rerank 無法憑空創造答案。這時候應該回頭排查上游——文件解析是否丟了內容、分塊是否把關鍵資訊切斷、後設資料過濾是否過於激進、Query 改寫是否偏離了原始意圖。在這些環節修好之前,加 Rerank 只是在垃圾堆裡精心排序。

一個簡單的診斷方法:對評測集跑 Recall@50,如果已經達到 90% 以上但 Precision@5 不理想,直接加 Rerank;如果 Recall@50 本身就低於 70%,優先排查召回鏈路。

工程實現要點

  • 模型選擇:中文場景下 bge-reranker-v2-m3、BAAI/bge-reranker-large 都是經過驗證的選項;英文場景 ms-marco 系列的 Cross-Encoder 仍然是穩定基線。
  • 候選池規模與延遲的權衡:Cross-Encoder 的推理耗時與候選條數線性相關。候選池控制在 50 條以內時,配合 GPU 推理,單次 Rerank 的延遲在工程可接受範圍內;超過 100 條建議先做一輪輕量預篩再送精排。
  • 分數閾值 vs 固定條數:實踐中建議兩者結合——先取 Top-N(如 5 條),再設一個最低分數門檻過濾掉明顯不相關的。避免出現「Top-5 裡最後兩條分數極低但仍被塞進 Prompt」的情況。

Rerank 是整條檢索鏈路中投入產出比最高的單點最佳化之一:不需要重建索引、不需要改分塊策略,只在推理時加一步精排,就能把最終進入生成環節的上下文品質拉高一個臺階。但它的前提是粗召回階段已經把正確答案兜住了——漏斗的第一層如果漏水,後面再精細的篩子也沒用。

環節六:上下文組裝與生成約束——最後一公里的工程細節

前面五個環節把召回和排序都調好了,如果最後拼給模型的上下文本身有問題,之前的功夫會打折扣。這一節講的是「檢索結果到 Prompt」之間那段容易被忽略的工程細節:傳什麼、傳多少、怎麼約束模型別瞎編。

父子塊檢索:檢索要精準,餵給模型要完整

做過分塊調優的人都遇到過這個矛盾:塊切小了,檢索命中精準,但內容碎片化,模型看到的只是半句話;塊切大了,語義完整,但檢索時容易被無關資訊稀釋,命中率下降。業內常見的兩種上下文增強思路,一種是句子視窗擴展——命中一個句子後,把它前後各擴展幾句再傳給模型;另一種是父子塊(父文件)檢索。綜合評測來看,父子塊方案在檢索精度和上下文完整性兩個維度上通常都表現更好,是更值得優先落地的方案。

做法是建兩級索引:切分時用小塊(比如幾百字一個)去建向量索引,檢索匹配也用小塊;但小塊命中後,系統實際返回給 LLM 的不是這個小塊本身,而是包含它的那個更大的父塊(可能是整篇文件或整個章節)。舉個例子,一份三千字的產品手冊切成六個五百字的子塊分別建索引,使用者提問命中第三個子塊後,最終傳給模型的是這份手冊的完整原文,而不是那孤立的五百字。這樣檢索階段享受小塊帶來的精準匹配,生成階段又不丟失上下文,兩頭都不吃虧。工程上需要維護子塊到父塊的對映關係,檢索層和生成層分離處理,實現成本不算高,是價效比較高的一步最佳化。

Context 壓縮:用一次額外的 LLM 呼叫換更乾淨的上下文

父子塊解決的是「要不要傳完整段落」的問題,Context 壓縮解決的是「傳進去的內容裡有多少是噪聲」的問題。具體做法是在正式生成答案之前,先讓 LLM(或者一個更輕量的模型)讀一遍檢索到的 chunk,把和使用者問題真正相關的句子提取出來,無關的背景資訊、重複表述直接丟掉,再把精簡後的內容拼進最終 Prompt。

這個方法能明顯降低上下文裡的噪聲佔比,尤其是在 chunk 偏大、裡面摻雜了大量非相關內容的場景下效果明顯。代價是多了一次 LLM 呼叫,意味著額外的延遲和成本。所以這個環節不建議無差別啟用,比較合適的場景是對答案準確性要求很高、同時使用者能接受多等一兩秒的場景,比如法律條款核查、合同審閱這類任務;如果是面向 C 端的即時問答,多一次呼叫帶來的延遲未必划得來,可以先只在父子塊檢索之後按需觸發,而不是全鏈路預設開啟。

生成階段的兩個約束:低溫度 + 引用格式

上下文組裝好之後,剩下的是對生成本身做約束,這兩點成本低、見效快,幾乎沒有理由不做。

  • Temperature 建議壓到 0.1–0.3 這個低值區間。RAG 場景要的是「忠實轉述檢索到的資訊」,不是讓模型自由發揮,溫度調低能明顯減少答案的隨機漂移,同一個問題多問幾次給出的答案會更一致,這對需要復現和除錯的生產環境很重要。
  • 在 Prompt 裡明確約束引用格式,比如要求模型每給出一個結論都要標註來源於第幾個檢索片段、對應哪份文件。這一條不是為了美觀,而是為了排查問題——一旦答案出錯,能直接定位是檢索環節召回錯了,還是生成環節讀錯了正確的檢索結果,兩種問題的修復方向完全不同。沒有這層約束,出了問題只能靠人工翻檢索日誌一條條對,效率很低。

綜合來看,這幾步的價值在哪

單獨看每一個環節,父子塊檢索、Context 壓縮、低溫度設定、引用約束,每一項帶來的提升都不算驚豔。但從實際落地的案例回饋來看,把語義切片、混合檢索、重排序、上下文壓縮、Prompt 約束這幾個環節串起來一起做,整體效果的提升是疊加的:召回率能從不足五成的水平提升到接近滿分割槽間,準確率同步從六成出頭提升到九成以上,響應時間能縮短近一半,token 消耗也能省下一部分。這也是為什麼這類最佳化不建議只挑一兩個環節做——單點最佳化容易遇到瓶頸,鏈路一起調整才能看到質變級別的效果。

需要提醒的是,這些環節不是越多越好,壓縮和 Rerank 都會引入額外延遲,具體上到什麼程度取決於業務對準確率和響應時間的權衡,下一節的排查 SOP 會給出更具體的優先順序判斷。

落地路徑:排查 SOP 與迭代優先順序

RAG 系統的最佳化不是一次性調參,而是逐環節收斂的工程過程。實踐中最常見的失敗模式是:跳過基礎資料治理,直接堆 Rerank 和 Prompt 技巧,結果花了大量精力卻發現問題出在解析層丟了關鍵段落。下面給出一條經過驗證的落地順序和排查路徑。

推薦迭代順序

按投入產出比從高到低排列,每一步都應量化 Recall@K 和端到端準確率的變化,確認收益後再進入下一步:

階段動作核心目標
1資料治理確保文件完整入庫,解析無丟段、無亂碼、表格/圖片已處理
2構建最小評估集建立可量化的基線,終結「感覺變好了」的主觀判斷
3Chunk 策略對比用評估集跑 A/B,選出當前語料最優的分塊參數
4Hybrid Search向量 + BM25 雙路互補,堵住單路召回的盲區
5Query Rewrite處理口語化、指代不清、多意圖等查詢品質問題
6Rerank 重排序在候選池已有正確證據的前提下,把它推到 Top 位置
7上下文壓縮減少噪聲 chunk 送入生成模型,降低幻覺機率和 Token 消耗
8生成約束Prompt 層兜底:引用標註、拒答規則、格式控制
9灰度監控線上持續收集 Bad Case,回到階段 2 形成閉環

這個順序的邏輯是:前四步解決「正確答案能不能進入候選池」,後五步解決「進了候選池能不能被正確使用」。順序顛倒會導致大量無效調優。

最小評估集:怎麼構建

起步規模 50–100 條即可,關鍵是覆蓋四類場景:

  • 高頻問題——線上日誌中出現最多的 Top 查詢,代表基本盤
  • 已知失敗 Case——使用者回饋過「回答錯誤」或「沒找到」的問題,代表當前短板
  • 精確匹配問題——涉及錯誤碼、版本號、SKU 編號等必須逐字正確的查詢
  • 應拒答問題——知識庫中確實沒有答案的問題,驗證系統是否會幻覺作答

每條評估資料包含三個欄位:question(使用者原始提問)、golden_context(期望命中的源文件片段)、golden_answer(標準答案)。golden_context 的存在讓你可以單獨度量檢索層的 Recall,而不是把檢索問題和生成問題混在一起診斷。

Bad Case 排查決策樹

當某條評估未通過時,按以下路徑定位瓶頸:

  • 第一步:檢查粗召回候選池(Top-50)是否包含正確證據
  • 如果不包含——問題在檢索層上游。依次排查:文件是否入庫 → 解析是否丟段 → 分塊是否把答案切碎 → Metadata 過濾是否過嚴 → Query 是否需要改寫 → 是否需要補充 BM25 通道
  • 如果包含——問題在排序或生成層。依次排查:Rerank 是否把正確 chunk 排低了 → 送入 LLM 的上下文是否被截斷 → Prompt 是否缺少引用約束或拒答規則

這條規則的核心原則:候選池裡沒有答案時,絕不要先上 Rerank——Rerank 只能調整已有候選的順序,無法憑空召回缺失的內容。把精力花在讓正確證據先進池子,再考慮怎麼把它排上去。

逐步收斂的度量紀律

每完成一個階段的改動,重新跑一遍評估集,記錄兩個核心指標:Recall@5(Top-5 是否包含 golden_context)和端到端準確率(最終回答是否匹配 golden_answer)。只有當某一步帶來可觀測的指標提升時才固化該改動,否則回滾。這種「改一步量一步」的紀律能避免多個變數同時變化時無法歸因的困境。

常見問題

chunk_size 到底設多大最合適?

沒有普適最優值,但有可操作的選擇框架:先看語料特徵。技術文件通常段落較長、上下文依賴強,chunk 偏大(500–700 token 區間)能保持語義完整;FAQ 和客服對話本身就是短文本,chunk 偏小(200–350 token)更貼合原始粒度;法律合同等長段落文本可以放到 800 token 以上,因為拆碎反而破壞條款完整性。確定候選區間後,用評估集跑對比實驗才是終局答案——不要相信任何「通用最佳值」。

已經用了向量檢索,還有必要加 BM25 嗎?

幾乎總是有必要。向量檢索擅長語義匹配(同義詞、換一種說法問同一件事),但在精確關鍵詞場景下表現不穩定——使用者查一個錯誤碼、產品型號或專有名詞時,向量模型可能把它對映到語義相近但事實不同的 chunk。BM25 的詞頻匹配恰好補這個短板。工程上兩路獨立召回再用 RRF 融合的成本很低,而對精確匹配類查詢的召回提升往往非常顯著。如果你的評估集中有「錯誤碼/版本號」類問題且單路向量檢索表現不佳,加 BM25 基本是確定性收益。

Rerank 會不會拖慢響應速度?

取決於候選池大小和模型選擇。Cross-Encoder 對每一對 (query, chunk) 做一次前向推理,候選池控制在 20–50 條時,主流 Rerank 模型的延遲對整體響應的影響在可接受範圍內。如果對延遲極度敏感(如對話場景要求 P99 低於 2 秒),可以縮小候選池到 20 條,或選用輕量級 Rerank 模型。另一個工程技巧是非同步預取:在使用者輸入過程中就開始觸發粗召回,等 Rerank 執行時使用者感知到的等待時間會更短。總之 Rerank 帶來的準確率提升通常值得這點延遲代價,真正的問題是候選池有沒有正確答案,而不是排序快不快。

怎麼判斷當前系統該優先最佳化哪個環節?

回到 Bad Case 排查決策樹。抽取最近 20–30 條失敗 Case,逐條標註失敗原因歸屬到哪個環節(解析丟失、分塊過碎、召回未命中、排序靠後、生成幻覺、應拒未拒)。哪個環節的失敗計數最高,就優先攻克那個環節。這比憑直覺選方向可靠得多。如果你還沒有評估集——那麼第一優先順序就是構建評估集本身,沒有度量就沒有最佳化。