對應原題(Common ‧ RAG and Retrieval)

  • How would you evaluate the quality of a RAG pipeline: retrieval and generation separately? — Asked at: Cohere
  • What causes semantic drift in embedding search and how do you detect it? — Asked at: Cohere
  • How do you keep an index fresh when the underlying corpus changes continuously?
    — Asked at: Perplexity, Cursor

🎯 什麼情境該想到我

當你「改了 RAG 的某個環節,但不知道有沒有變好」的時候。
★ RAG 是一條有多個環節的管線,端到端的分數無法歸因。不分層評估,所有優化都是瞎調。

⚙️ Part 1:分層評估

為什麼一定要分開

查詢 →【檢索】→ 上下文 →【生成】→ 答案
        ↑                    ↑
     可能爛在這          也可能爛在這

端到端分數掉 5% —— 是 embedding 模型退步?切塊改壞了?prompt 改了?換模型?混在一起就永遠查不出來。

檢索層

指標:

指標問的問題何時用
recall@k正確片段有沒有被撈進前 k 名★ 最重要。它是整條管線的上限
precision@k前 k 名裡有多少是相關的決定上下文的訊噪比
MRR第一個正確答案排第幾(倒數)只在乎第一名時
nDCG@k考慮位置與分級相關性的綜合排序品質有多級相關性標註時

★ 怎麼建 ground truth(沒有標註資料時):

方法做法注意
反向生成對每個 chunk 叫 LLM 生成「這段能回答的問題」,該 chunk 就是答案⚠️ 生出來的問題太像原文,會高估 recall。要求它用口語、換詞、加入脈絡
真實日誌標註從查詢日誌抽樣,人工標出正確 chunk最貴也最真
既有 FAQ / 工單已經有「問題—答案文件」配對的資料★ 免費的黃金資料,優先找
隱式回饋使用者點擊 / 複製 / 追問有偏誤但量大

實務起手式:先用反向生成做 200–500 題的快速回歸集(幾小時就有),再慢慢累積人工標註的高品質集。
沒有評估集就開始調參數,是 RAG 專案最常見的浪費。

生成層

★ 關鍵技巧:用「黃金上下文」評估生成,而不是實際檢索的結果。

評估檢索: 查詢 →【檢索】→ 比對 ground truth chunk
評估生成: 查詢 + ★人工標定的正確上下文 →【生成】→ 評分

這樣兩層就解耦了。 生成分數掉了,一定是 prompt / 模型 / 上下文組裝的問題,與檢索無關。

指標:

指標問的問題怎麼量
Faithfulness / Groundedness答案有沒有超出上下文(= 幻覺)拆成原子主張,逐一做 NLI entailment
Answer Relevance有沒有答到使用者的問題LLM-as-judge
Completeness上下文裡有的資訊,有沒有漏講對照 ground truth 答案
拒答正確性上下文沒有答案時,有沒有誠實說不知道★ 必測。評估集要刻意包含「無答案」樣本

★ 「無答案」樣本是最常被漏掉的一類。 沒有它,你的評估會獎勵「永遠給出答案」的行為——而那正是幻覺的來源。

★ 診斷矩陣

檢索分數生成分數端到端結論
低高低修檢索:切塊、hybrid、查詢改寫、reranker
高低低修生成:prompt、模型、上下文組裝
高高低⚠️ 上下文組裝有問題:順序(lost-in-the-middle)、截斷、格式、去重
高高高好。去看失敗的那些個案

⚙️ Part 2:語意漂移

★ 三種不同的漂移(別混為一談)

類型發生什麼嚴重度
查詢分布漂移使用者開始問新東西(新產品、新術語、新事件)中——索引裡可能真的沒有
語料漂移文件內容更新,同一個詞的指涉變了(「v2 API」現在指的是不同東西)中——新舊混雜會矛盾
★ 模型漂移換了 embedding 模型或版本致命

★ 模型漂移是唯一會讓索引「直接壞掉」的一種:
不同模型(甚至同模型不同版本)的向量空間完全不可比。
索引裡混了兩代向量 = 一半的資料變成隨機噪音,而且不會報錯,只會安靜地變爛。
→ 鐵律:換 embedding 模型 = 重建全部索引,且要原子切換。

怎麼偵測

訊號怎麼看意義
★ top-1 相似度分數的分布追蹤每日的中位數與 p10持續下降 = 查詢越來越「不像」索引內容。最靈敏的單一指標
低分查詢比例最高分低於閾值的查詢佔比上升代表覆蓋率在退化
查詢 embedding 的分布與建索引時的分布比(MMD、聚類中心位移)查詢分布漂移
★ 固定 golden set 回歸每天/每次部署跑同一組題最實用。任何原因造成的退化都會在這裡現形
使用者回饋點擊率、追問率、負評率滯後但真實
新詞監測查詢中出現的未知詞彙提示該擴充語料或詞典

對策

  • 查詢分布漂移 → 擴充語料;BM25 側加同義詞詞典(見 稀疏與密集檢索);查詢改寫
  • 語料漂移 → 把版本/時間放進 metadata 並在檢索時過濾;舊版文件降權或下架
  • 模型漂移 → 排定期的模型評估;升級時走「雙寫雙索引 → A/B → 原子切換」

⚙️ Part 3:索引新鮮度

需求分級(先定清楚再設計)

場景要求例子
秒級幾乎即時新聞、Perplexity 的網路檢索
分鐘級提交後很快可搜程式碼庫(Cursor)、工單
小時級當天生效內部文件、知識庫
天級批次歸檔資料

★ 增量更新的四個難題

1. 變更偵測
webhook(快、會漏)/輪詢(穩、有延遲)/CDC(資料庫可行)/內容 hash 比對(最可靠的兜底)。
實務:webhook 為主 + 定期全量 hash 掃描兜底。

2. ★ chunk 邊界的不穩定性

一份文件改了一個字,如果用「第幾個 chunk」當 ID,後面所有 chunk 的 ID 全部位移 → 整份文件都要重新 embed。

解法:chunk ID 用內容 hash(sha256(breadcrumb + text))。
改一個字只有那一個 chunk 的 hash 變,其餘完全命中快取,不用重算。
→ 這是增量索引能不能做到分鐘級的關鍵設計。

3. 刪除傳播

4. 版本一致性
更新中途查詢,可能同時撈到新舊兩版的 chunk → 答案自相矛盾。
→ chunk 帶 doc_version,檢索後只保留同一份文件的最新版本。

架構選擇

方案適用
雙索引 + 原子切換(藍綠)換模型、換切塊策略。安全,但全量重建成本高
增量寫入 + 定期全量重建✅ 實務主流。增量顧新鮮度,定期重建清墓碑與碎片
分層:熱索引即時 + 冷索引批次新資料進小的即時索引,定期合併進大索引

Cursor 的場景(程式碼庫持續變動):用 git diff 驅動增量,並依 AST 邊界切塊——函式邊界比字元位置穩定得多,一個函式改動只影響一個 chunk。

要監控的營運指標

  • 索引延遲 —— 文件更新 → 可被檢索的時間(p50 / p99)
  • 索引失敗率 —— 解析失敗、embedding 失敗、寫入失敗各自分開看
  • 墓碑比例 —— 觸發重建的依據
  • 索引大小與成長率 —— 容量規劃

⚠️ 注意 / 什麼時候不適用

  • LLM-as-judge 有偏誤(偏好長答案、偏好自己模型的風格、位置偏誤)。用它當相對比較(A vs B)比當絕對分數可靠。詳見批次 3 的評估區。
  • 反向生成的評估集會高估 recall,因為問題和 chunk 用詞太像。務必要求模型改寫用詞、加入口語與脈絡。
  • 評估集會過擬合。調參數調久了就是在對著評估集調,要保留一個從不用來調參的 holdout。
  • 離線分數好 ≠ 線上體驗好。最後還是要看線上訊號(見批次 3 的線上評估)。
  • 別同時改兩件事。切塊和 embedding 模型一起換,分數變了你什麼也學不到。
  • 全量重建的成本要先算。千萬級文件重新 embed 可能是幾千美金與數小時——這個數字決定你多久能換一次模型。

🧪 我實際套用的紀錄

  • 2026-09-20:從面試題庫展開。待辦:任何 RAG 專案第一週就用反向生成做出 200 題回歸集。

🔗 相關