RAG(Retrieval-Augmented Generation)問答系統是現在最常被考的 AI 系統設計題之一——因為它幾乎是每家公司導入 LLM 的第一個落地專案。這題考的是:怎麼讓 LLM 根據「你的私有文件」回答問題,而且答得準、有依據、不亂編。
這篇沿用我前面的系統設計風格:題目 → 分層解法 → 面試官追問。
📋 題目
設計一個基於 RAG 的文件問答系統(例如企業內部知識庫 / 客服助手)。用戶用自然語言提問,系統根據私有文件庫給出有引用依據的答案,並支援多輪對話。
一、釐清需求
- 功能性:自然語言問答、標註引用來源、多輪對話;支援哪些文件格式(PDF、網頁、Confluence、Slack…)?
- 非功能性:規模(文件數、用戶數、QPS)、延遲(端到端 < 2–3 秒)、資料新鮮度(即時 / 每日更新)、權限控管(用戶只能查到有權限的文件)、「不知道就說不知道」。
🎤 追問:「為什麼用 RAG 而不是把知識 fine-tune 進模型?」答:知識會頻繁變動(RAG 改文件即可、fine-tune 要重訓)、要能附引用、成本更低、可做權限控制。
二、整體架構:兩條 Pipeline
RAG 系統一定要拆成離線索引與線上查詢兩條獨立 pipeline:
【離線 Ingestion】 文件 → 解析清洗 → Chunking → Embedding → 向量庫索引
【線上 Query】 問題 → 改寫 → Embedding → 檢索 → Rerank → 組 Prompt → LLM 生成 → 引用後處理
🎤 追問:「離線和線上為什麼要分開?」答:索引是重、批次、可預先算好的;查詢要即時低延遲。分開才能各自擴容。
三、離線:文件攝取與索引
- 解析清洗:抽取文字(PDF/HTML),去雜訊、保留結構(標題層級)。
- Chunking(切塊):把長文件切成片段。大小常見 200–500 tokens + 重疊(overlap);進階用語義切塊(依段落/語意邊界)。每塊保留 metadata(來源、標題、權限標籤、時間)。
- Embedding:用 embedding 模型把每塊轉成向量;批次處理。
- 向量庫:用 ANN 索引(HNSW / IVF)做近似最近鄰;選型如 pgvector、Faiss、Milvus、Pinecone;支援 metadata 過濾。
🎤 追問:「Chunk 切多大?太大、太小各有什麼問題?」答:太大 → 檢索到的內容含太多無關資訊、稀釋相關度、吃 context;太小 → 語意被切碎、缺上下文。用 overlap 緩解邊界資訊遺失。
四、線上:檢索與生成
- Query 改寫:多輪對話時,把帶代詞的 follow-up(「那它呢?」)改寫成獨立完整問題;可選 HyDE(先讓 LLM 生一個假設答案再去檢索)。
- 檢索(Retrieval):把問題 embedding 後做向量檢索取 top-k。實務上用 Hybrid Search=向量(dense)+關鍵字(BM25/sparse)併用,兼顧語意與精確詞。
- Rerank(精排):用 cross-encoder 對 top-k 候選重新打分,取最相關的幾段。檢索是「粗篩」、rerank 是「精排」。
- Prompt 組裝:System prompt(角色 + 規則)+ 檢索到的內容(含來源)+ 對話歷史 + 當前問題 + 引用指示。
- 生成:要求 LLM 只根據提供的內容作答、標註引用、找不到就說「我不知道」;串流輸出。
🎤 追問:「檢索已經給分數了,為什麼還要 rerank?」答:向量檢索用的是雙塔式 embedding(快但粗),cross-encoder 能讓 query 和 chunk 做深度交互、排序更準;但慢,所以只對 top-k 做。「Hybrid search 為什麼比純向量好?」答:純向量對「精確關鍵字 / 專有名詞 / 代碼」常失準,BM25 補這塊。
五、評估(RAG 一定要分兩層評)
- 檢索層:Recall@k、MRR、NDCG——檢索回來的內容有沒有包含正確答案的依據。
- 生成層:
- Faithfulness / Groundedness:答案是否忠於檢索內容(沒亂編)。
- Answer Relevance:答案是否切題。
- 有沒有正確引用。
- 方法:建 Golden QA Set(問題+標準答案+應引用的文件);用 LLM-as-judge 或 RAGAS 自動打分。
🎤 追問:「RAG 答錯了,你怎麼知道是檢索的錯還是生成的錯?」答:分層評估——先看檢索層 Recall@k(沒檢索到 → 檢索問題:chunking/embedding/檢索策略);檢索到了但答錯 → 生成問題(prompt/grounding)。
六、三大進階痛點:幻覺、權限、新鮮度
- 幻覺控制:強制 grounding(「只根據以下內容回答」)、要求逐句標引用、低信心時拒答、檢索不到就回「找不到相關資料」。
- 權限控管(安全關鍵):在檢索層就用 metadata filter——每個用戶只能檢索到自己有權限的 chunk。絕不能先檢索全部再過濾(會洩漏存在性與內容)。
- 新鮮度:文件更新時做增量索引(只重新 embed 變動的塊);刪除文件要同步刪向量;可加版本/時間戳。
🎤 追問:「用戶 A 不該看到 HR 機密文件,怎麼保證?」答:檢索時帶上 user 的權限標籤做 metadata 過濾,從源頭就不召回無權限內容。「知識庫每天更新,怎麼辦?」答:增量 re-index + 刪改同步。
七、延遲 / 成本優化 + 監控
- 延遲拆解:embedding(快)+ 檢索(快)+ rerank(中)+ LLM 生成(主要瓶頸)。用串流降低體感延遲。
- Semantic Cache:相似問題直接回快取答案,省 LLM 呼叫與延遲。
- 監控:檢索命中率、引用率 / groundedness、端到端延遲、每問成本、用戶讚/踩、無答案率(拒答率)、檢索 top-k 相關度分佈。
🎤 追問:「端到端延遲哪一段最慢?怎麼壓?」答:LLM 生成最慢 → 串流、較小模型、semantic cache、減少塞進 prompt 的 chunk 數。
一張圖記住整套架構
【離線】 文件 → 解析 → Chunking(+metadata) → Embedding → 向量庫(HNSW)
│
【線上】 問題 →(多輪改寫)→ Embedding → 檢索(Hybrid: 向量+BM25) ┘
→ Rerank(cross-encoder) → 組 Prompt(內容+引用指示)
→ LLM 生成(grounding/引用/拒答) → 串流回用戶
權限: 檢索層 metadata filter 新鮮度: 增量索引
評估: 檢索層(Recall@k) + 生成層(faithfulness) 監控: 引用率/延遲/成本
答題口訣
- 先分兩條 pipeline:離線索引 + 線上查詢。
- 線上五步:改寫 → 檢索(hybrid)→ rerank → 組 prompt → 生成(grounded + 引用)。
- 評估分兩層:檢索(Recall@k)vs 生成(faithfulness),答錯能歸因。
- 講三大痛點:幻覺(grounding/引用/拒答)、權限(檢索層過濾)、新鮮度(增量索引)。
- 收尾:延遲(LLM 是瓶頸)、semantic cache、監控引用率。
能把「兩條 pipeline → 檢索+rerank → 分層評估 → 幻覺/權限/新鮮度」講完整,這題就穩了。