前言

這陣子 LLM 應用紅翻天,其中最實用也最常被拿來解決「幻覺」(Hallucination)問題的,大概就是 RAG(Retrieval Augmented Generation,檢索增強生成)了。白話來說,就是讓 LLM 在回答問題前,先去參考一些「課外讀物」,這樣它就比較不會憑空捏造,回答也能更精確。

RAG 聽起來很美好,架構圖看起來也好像很直觀,但實際下去做,你會發現裡面眉角超多,一不小心就踩到雷。我最近在玩 RAG 應用也遇到不少坑,今天就來跟大家分享一下,實作 RAG 會碰到哪些常見問題,以及一些我整理出來的實戰解法。

RAG 的基本流程,我們快速複習一下

為了確保大家在同一個頻道上,我們先用一張圖快速回顧一下 RAG 的基本流程。其實就是三大塊:

  1. 資料準備(Ingestion):把你的原始文件(PDF、網頁、資料庫內容等等)切成小塊(Chunk),然後轉成向量(Embedding),存到向量資料庫裡。
  2. 檢索(Retrieval):使用者提問後,把問題轉成向量,去向量資料庫裡找出最相關的「小塊」(也就是前面切好的 Chunk)。
  3. 生成(Generation):把使用者問題跟找出來的相關資料,一起餵給 LLM,讓 LLM 根據這些資料來生成答案。
1
2
3
4
5
6
7
8
9
10
11
12
13
graph TD
A[使用者提問] --> B[Embedding Model (問題轉向量)]
B --> C[向量資料庫 (搜尋相似向量)]
C --> D[檢索出相關的資料 Chunk]
D --> E[建構給 LLM 的 Prompt (問題 + Chunk)]
E --> F[LLM (生成答案)]
F --> G[回答給使用者]

subgraph 資料準備階段
H[原始文件 (PDF/DOC/網頁)] --> I[文件處理/切割 (Chunking)]
I --> J[Embedding Model (Chunk轉向量)]
J --> C
end

好,概念清楚了,那我們來看看實作上最容易卡關的地方在哪裡。

第一雷:文件處理不當,Embedding 效果差

這是 RAG 的基石,如果這邊沒做好,後面怎麼補救都有限。

踩雷點

  • Chunking 策略沒想清楚:文件切太大,LLM Context Window 塞不下或噪音太多;切太小,語意破碎,LLM 讀不懂前後文。
  • PDF 轉文字的坑:PDF 檔案結構複雜,轉出來的文字可能斷行錯誤、表格亂掉、文字順序錯亂,導致 Embedding 亂七八糟。
  • 忽略 Metadata:沒有把資料的來源、建立時間、作者等資訊存下來,後面篩選就沒辦法用。

解法

  1. 多樣化的 Chunking 策略
    • 固定大小重疊(Fixed-size with overlap):最簡單,固定字數切,保留一點重疊部分確保語意連貫。例如 chunk_size=500, chunk_overlap=50
    • 語意切割(Semantic Chunking):用 LLM 或其他模型判斷語意段落再切,保持每個 Chunk 的完整語意。這比較進階,但效果通常更好。
    • 父子 Chunking(Parent-Child Chunking):儲存兩種 Chunk,一種是小而精確的 Chunk 用來檢索,另一種是包含更多前後文的「父 Chunk」給 LLM 閱讀。這樣可以兼顧檢索效率和 LLM 的理解力。
  2. 高品質的文件前處理
    • 針對 PDF,試試不同的函式庫(如 pypdf, unstructured)或服務,看看哪個轉文字效果最好。記得人工檢查幾份。
    • 清理多餘空白、特殊符號、合併斷裂的句子。
  3. 善用 Metadata
    • 在 Embedding 時,將 Chunk 的來源、主題、章節、時間等資訊一併存入向量資料庫。這對於後續的精準檢索超級重要。

第二雷:檢索策略不夠聰明,召回率低

就算你的 Chunking 完美,如果檢索邏輯不夠力,一樣找不到對的資料。

踩雷點

  • 只用單純的 Top-K 向量搜尋:這種方式容易受到 Embedding 模型的限制,有時候語意上很相關的詞,實際向量距離可能沒那麼近。
  • 沒有考慮使用者意圖:使用者可能問「2023 年財報」,但你的檢索只會找「財報」,而忽略了時間限制。
  • 關鍵字和語意搜尋的取捨:有些問題很適合關鍵字(例如找產品型號),有些適合語意(例如問概念)。只用其中一種會偏廢。

解法

  1. **Metadata Filtering (前過濾)**:結合向量搜尋和結構化篩選。例如,先用 Metadata 篩選出「2023 年」且「文件類型是財報」的資料,再對這些資料做向量搜尋。
    1
    2
    3
    4
    5
    6
    7
    # 範例:先篩選出2023年的「財報」文件,再做向量搜尋
    query_embedding = embedding_model.embed(user_query)
    results = vector_db.search(
    query_embedding,
    filter={'year': 2023, 'doc_type': 'financial_report'},
    top_k=10
    )
  2. 混合搜尋(Hybrid Search):同時利用關鍵字搜尋(如 BM25、Elasticsearch)和向量搜尋。兩者各有優勢,結合起來效果更好。常見做法是將兩邊的結果加權合併。
  3. Reranking(重排序):在檢索出 Top-K 的結果後,再用一個更精準(但通常也更慢)的模型(如 Cohere Rerank、Sentence Transformers)對這些結果進行二次排序,把最相關的 Chunk 往前排。
  4. Multi-query / Query Expansion:讓 LLM 自己對原始問題進行多角度改寫(例如把「今年公司營收如何?」改成「2024年公司營收報告」、「公司財務表現」等),再用這些多個問題去檢索,增加召回率。

第三雷:Prompt 設計不良,LLM 回答走鐘

即使你給了 LLM 最好的資料,Prompt 沒寫好,它還是可能給你亂七八糟的答案。

踩雷點

  • Prompt 太籠統:沒有明確指示 LLM 該怎麼利用這些檢索到的資料。
  • 沒有要求引用來源:LLM 有時候會自己腦補一些內容,但又說不出來源。
  • 溫度(Temperature)設定不對:太高容易發散,太低又可能太死板。

解法

  1. 明確的系統指令(System Prompt):告訴 LLM 你的角色和預期的行為。例如:
    1
    你是一個專業的知識顧問,請根據我提供的「參考資料」來回答問題。如果參考資料中沒有足夠的資訊,請禮貌地說明資料不足。回答時請引用參考資料的段落或標題。
  2. 具體的使用者指令(User Prompt):在每次提問時,清楚告知 LLM 哪些是問題,哪些是參考資料,以及希望的輸出格式。
    1
    2
    3
    4
    5
    6
    7
    參考資料如下:
    --- START REFERENCE ---
    {retrieved_chunks_here}
    --- END REFERENCE ---

    請根據上面的參考資料,回答以下問題:「{user_question}」
    回答時請務必從參考資料中提取資訊,並標註來源。如果資料不足,請直接說明。你的回答必須簡潔扼要。
  3. 調整 Temperature:對於需要精確事實的 RAG 應用,建議將 Temperature 設得低一些(例如 0.10.5),減少模型「創造」的機會。

第四雷:效能與成本考量

RAG 應用實際跑起來,錢跟時間都是考量點。

踩雷點

  • Embedding 速度慢或成本高:每次文件更新或新增都要重新 Embedding,如果資料量大,會花很多時間和錢。
  • 向量資料庫查詢慢:資料量爆炸性增長,查詢延遲飆高。
  • LLM API 費用:檢索到的 Chunk 太多,塞給 LLM 的 Context Window 太長,Input Token 成本飆升。

解法

  1. Embedding 批次處理與快取
    • 將多個 Chunk 組合成一個批次(Batch)送去 Embedding 模型,通常會比單個送效率高。
    • 已經 Embedding 過的 Chunk 存起來,避免重複計算。可以用 Hash 值來判斷 Chunk 是否變更。
  2. 選擇適合的 Embedding 模型
    • 不一定都要用最貴或最大的模型。評估你的應用場景,選擇性價比高的開源模型或較便宜的商用模型。
  3. 快取檢索結果
    • 對於頻繁出現的相同問題,可以快取檢索到的 Chunk 甚至 LLM 的生成結果。
  4. 最佳化檢索結果數量
    • 透過 Reranking 或更精準的檢索策略,確保只將最相關的少量 Chunk 傳給 LLM,減少 LLM 的 Input Token 量。

第五雷:評估與監控,不知道 RAG 到底好不好用

部署上去了,怎麼知道你的 RAG 表現如何?這是一個持續優化的過程。

踩雷點

  • 沒有明確的評估指標:不知道 RAG 的答案「準不準」、「有沒有幻覺」、「跟不跟資料」。
  • 缺乏使用者回饋機制:沒有辦法收集到使用者對答案滿不滿意的資訊。

解法

  1. 建立 RAG 評估指標
    • 忠實性(Faithfulness):LLM 的答案有多少內容是來自檢索到的資料?(避免幻覺)
    • 答案相關性(Answer Relevance):LLM 的答案是否真的回答了使用者的問題?
    • 上下文相關性(Context Relevance):檢索到的資料 Chunk 是否真的跟使用者的問題相關?
    • 這些指標可以透過人工評分,或是用另一個 LLM 來輔助評估(例如用 GPT-4 判斷 GPT-3.5 的回答)。
  2. A/B 測試不同的 RAG 策略
    • 當你調整了 Chunking、檢索或 Prompt 策略後,用 A/B 測試比較不同版本的效果,用數據說話。
  3. 使用者回饋機制
    • 在應用介面提供「讚/爛」按鈕或意見回饋表單,直接收集使用者對答案的滿意度,這是最直接的優化方向。

小結

RAG 應用看似只是把檢索和生成串起來,但實際魔鬼藏在細節裡。從文件處理、檢索策略、Prompt 設計到效能和評估,每個環節都充滿了優化的空間。

一開始你可能會覺得很挫折,但別灰心,這些問題都是可以透過持續測試、調整和學習來解決的。掌握了上面這些踩雷點和解法,相信你的 RAG 應用會變得更穩健、更聰明,也能提供更可靠的資訊給使用者!

希望這篇對正在開發 RAG 應用的你有所幫助,我們下篇文章見囉!