這是「RAG 實戰筆記」系列的第一篇。我正在打造一個企業文件問答平台(黃金問答集實測檢索命中率 100%、答案正確率 89%),這個系列會把過程中搞懂的觀念和踩過的坑整理成文。第一篇先把地基打好:RAG 到底在解決什麼問題、完整管線長什麼樣、以及每個環節的實戰細節。
一、RAG 在解決什麼問題?
LLM 很聰明,但有三個先天限制:
- 知識有截止日——模型訓練完成後發生的事它不知道。
- 不知道你的私有資料——公司的規章、合約、會議記錄,模型從沒看過。
- 會一本正經地胡說——被問到不知道的事,它傾向生成「看起來合理」的答案,而不是承認不知道。
RAG(Retrieval-Augmented Generation,檢索增強生成)的解法直觀得近乎樸素:回答之前,先把相關資料找出來塞給模型看。模型不再憑記憶作答,而是「開書考」——而且書是你指定的。
1 | 傳統 LLM: 問題 ──────────────────▶ 模型憑訓練記憶回答 |
這帶來三個直接的好處:答案有依據(可以強制標來源,錯了能追溯)、資料可以隨時更新(加文件就好,不用重訓模型)、私有資料不用送去訓練(我的專案裡 embedding 完全在本機跑,文件內容不出機器)。
二、完整管線:兩條路徑
RAG 系統有兩條獨立的資料流——建索引(把文件變成可檢索的形式,離線做)和查詢(把問題變成答案,即時做):
1 | 【建索引 · Ingestion】 |
以下逐段拆解,每一段都附上我實際的做法與理由。
三、載入:文件世界比你想的髒
教學文章的 RAG 都從乾淨的純文字開始,現實裡你面對的是:有文字層的 PDF、沒有文字層的掃描 PDF、Word 裡的表格、Excel 的多工作表、PPT 的文字框。每種都要有對應的處理:
| 類型 | 處理方式 |
|---|---|
| PDF(有文字層) | 直接抽文字(pypdf) |
| PDF(掃描檔) | 轉圖 → OCR(tesseract,中文繁體+英文) |
| Word | 段落 + 表格 |
| Excel | 逐工作表逐列串接 |
| PPT | 逐投影片文字框 |
一個實用的小設計:怎麼判斷 PDF 是不是掃描檔? 我的做法是「平均每頁字元數 < 20 就當掃描檔走 OCR」。閾值很土,但有效——有文字層的 PDF 每頁隨便都幾百字,掃描檔抽出來幾乎是空的。
四、切塊:RAG 品質的第一個決勝點
文件不能整份塞給模型(塞不下,也不精準),要切成小塊。切塊策略直接決定檢索品質,這是我整個專案裡投資報酬率最高的一個環節。
起手式:固定長度滑動視窗。 每塊 700 字、相鄰塊重疊 120 字,以字元數計(對中文最直覺),切點盡量落在自然斷點(換行 > 句末標點 > 逗號),避免硬切在詞中間。
為什麼從最笨的方法開始?先笨後巧——第一階段要驗證的是「檢索+切塊能不能回答問題」這個大方向,固定切塊最穩、最好除錯;結構感知切塊是優化題,過早引入只會多一個出錯變數。
進化:表格列感知切塊。 固定切塊遇到表格會出災難——表格被橫向硬切,切塊開頭是上一筆資料的尾巴,「不能安全駕駛」被切成「不能安全駕/駛」,表頭和內容分家,切塊語意完全破碎。解法是先把版面文字還原成「一筆一列」的紀錄,再以固定筆數(我用 12 筆)完整列組成一個切塊,每塊都冠上表頭與文件日期,讓每個切塊能被獨立讀懂:
1 | 臺灣桃園地方檢察署公告(民國115年03月10日)偵查案件一覽 |
偵測不到已知表格樣式時自動退回固定長度切塊,一般文件不受影響。實測效果:答案正確率 50% → 72%(+22 個百分點)、檢索命中率 93% → 100%。 一個切塊策略的改進,比換模型、調 prompt 都有效——這是我想強調的重點:RAG 的瓶頸常常在資料工程,不在模型。
五、Embedding:把語意變成座標
Embedding 模型把文字轉成高維向量,讓「語意相近」變成「距離相近」——這是整個檢索的數學基礎。我用 bge-m3(本機執行,文件不出機器),它一次產生兩種向量:
- dense(稠密向量):1024 維的語意向量。「請假規定」和「休假辦法」字面不同但語意近,dense 向量抓得到。
- sparse(稀疏向量):詞彙級的權重表。專有名詞、案號、代碼這種「一字不差才算命中」的查詢,sparse 才可靠——dense 對「115年偵字第7615號」這種字串是很遲鈍的。
⚠️ 單向門:embedding 模型一旦定案就很難換
查詢時的向量必須跟建索引時用同一顆模型產生,否則兩邊的向量空間對不上,檢索結果全錯。這意味著換 embedding 模型 = 整個向量庫重算。所以選型時要想清楚,而且開發與正式環境用同一顆模型——品質一致、零重算。這是 RAG 架構裡少數「決定了就回不太了頭」的選擇。
六、檢索:混合搜尋 + 重排
單靠 dense 或單靠 sparse 都有盲區,所以用混合檢索:
- dense 搜 20 筆 + sparse 搜 20 筆
- 用 RRF(Reciprocal Rank Fusion)融合兩份排名——不比較兩邊的分數(量綱不同沒法比),只看名次
- 廣撈 30 筆候選
- 交給 reranker(bge-reranker-v2-m3)精排——它把「問題+候選切塊」成對送進模型打分,比純向量距離準得多,但慢,所以只用在最後一哩
- 取 top-15 進生成
這個「粗篩廣撈 → 精排收斂」的兩段式,是檢索系統的經典架構:粗篩要快、召回要廣(寧可多撈);精排要準(把真正相關的排上來)。
七、生成:把模型鎖在證據裡
檢索到的切塊連同問題一起組成 prompt 送給 LLM(我用 Claude),關鍵的設計有兩個:
- 強制標來源:要求模型每個論點都標註出處(
[1]、[2]對應到具體文件與切塊)。這不只為了可信度——它實質上改變了模型的行為,讓它傾向「只說找得到依據的話」。 - 多輪改寫:對話中的追問常常是「那第二種呢?」這種缺乏上下文的句子,直接拿去檢索必死。所以檢索前先用 LLM 把問題改寫成獨立完整的查詢(query rewrite),這一步用 LangGraph 把「改寫 → 檢索 → 生成」串成明確的流程圖。
八、沒有評測,一切都是感覺
最後、也是最容易被跳過的一環:黃金問答集。準備一組「問題 + 標準答案 + 答案所在文件」的測試集,每次改動(換切塊策略、調檢索參數、改 prompt)都跑一遍,量兩個數字:
- 檢索命中率:正確答案所在的切塊,有沒有進到 top-k?
- 答案正確率:模型的回答對不對?
沒有這個,你只能憑感覺判斷「好像有變好」;有了它,前面提到的「表格切塊 +22pt」才有辦法被驗證。RAG 是資料工程,資料工程要量測。
小結:一張圖記住 RAG
1 | 品質好壞的責任分佈(個人體感) |
下一篇會深入資料層的一個常見疑問:向量資料庫和 MongoDB 到底差在哪?為什麼我的專案兩個都用?
留言