跳轉到

RAG 完整指南:檢索增強生成的原理、架構與實作

摘要

大型語言模型(LLM)天生有兩個限制:知識截止日幻覺。RAG(Retrieval-Augmented Generation,檢索增強生成)是目前業界最主流的解決方案——在生成答案之前,先從外部知識庫撈出相關文件,再把它們塞進 Prompt,讓模型「有憑有據」地回答。

維度 純 LLM RAG
知識來源 訓練資料(固定) 外部知識庫(可更新)
幻覺風險 低(有文件支撐)
可追溯性 可引用來源
更新成本 重新訓練(高) 更新索引(低)
延遲 較高(多一次檢索)

RAG 不是萬能的。它適合「知識密集型」任務(文件問答、客服、法規查詢),不適合純推理或創作任務。


本篇在系列的哪一站

本站的 RAG 筆記是一個五站的系列。本篇是第 1 站:把整條管線走一遍,建立骨架與詞彙,各層的選型與調優細節交給後面的專篇,不在這裡重複。

你在問的問題 讀哪篇
0 我到底該用 RAG,還是 prompting / fine-tuning? Fine-tuning vs RAG vs Prompting
1 RAG 整條管線長什麼樣? 本篇
2 embedding 和向量庫怎麼選? Embeddings 與向量資料庫實務
3 naive RAG 效果不好,怎麼推到生產級? RAG 進階系列
4 加槓桿還不夠,要不要換架構? GraphRAG(換索引標的)/Agentic RAG(換控制流)

第 4 站的兩篇是平行的分岔,不是先後:GraphRAG 改的是「索引什麼」,Agentic RAG 改的是「誰決定何時檢索」。

重要提醒:第 0 站其實該最先讀。很多 RAG 專案的失敗不是做得不好,而是根本不該做 RAG——靜態小語料直接塞長 context 更省事,要改的是模型行為就該 fine-tune。


為什麼需要 RAG

LLM 在訓練後知識便固定下來。面對以下情境,單靠模型本身無法可靠回答:

  • 時效性問題:「今天台股大盤收幾點?」
  • 私有領域知識:公司內部文件、個人筆記、私有資料庫
  • 長尾細節:訓練資料中罕見的專業技術文件
  • 可信度要求:需要引用具體來源的法律、醫療場景

RAG 的核心思路:不改模型,改 Prompt。把外部知識即時注入 Prompt,讓模型用提供的文件作答,而不是憑記憶猜測。


RAG 三階段架構

RAG 三階段架構

整個 RAG 系統分為兩個時間維度:

離線(Indexing):資料準備階段,只需執行一次(或增量更新)。

線上(Query → Retrieve → Generate):每次用戶提問都會走一遍。

[離線]  Document → Chunk → Embed → Vector DB
[線上]  Query → Embed → 相似度搜尋 → Top-K Chunks → Prompt → LLM → Answer

這條管線是整個系列的骨架。後面每一篇專篇,都是在把其中一段換成更好的做法。


第一階段:索引(Indexing)

1.1 文件載入(Document Loading)

原始文件格式多元,需轉換為純文字:

格式 工具
PDF pypdf, pdfplumber, unstructured
Word/Excel python-docx, openpyxl
HTML/網頁 BeautifulSoup, Playwright
資料庫 SQL → 文字摘要
程式碼 直接讀取 + AST 解析

這一步的損失是不可逆的:parsing 丟掉的表格結構與圖表數值,後面再強的檢索也救不回來。若文件視覺結構豐富,考慮本頁後段的 PixelRAG。

1.2 文件分塊(Chunking)

文件通常比 LLM 的 context window 大,必須切分。切塊的核心張力是大小:切太大會把多個主題塞進同一塊,稀釋檢索訊號;切太小則失去上下文,答案拼不起來。相鄰 chunk 通常保留一段重疊(overlap),避免跨邊界的重要資訊被切斷。

不要抄別人的 chunk 大小。 最佳值取決於你的語料與 embedding 模型,必須用 recall@K 實測。切塊策略(fixed-size / sentence / recursive / semantic / heading-aware)的取捨與實測方法見 RAG 進階系列 §1

1.3 嵌入(Embedding)

用 Embedding Model 把每個 chunk 轉成向量,語意相近的 chunk 向量距離相近。

兩條不能違反的規則

  1. 查詢與文件必須用同一個 Embedding Model。 不同模型的向量空間不相通,混用等於在比較兩種不同的座標系。
  2. 換模型就要全量重嵌。 舊向量與新向量不可混存,這是常態維運成本,選型時就要算進去。

模型怎麼挑(MTEB 排行榜怎麼用、中文語料看什麼、維度與成本的取捨)見 Embeddings 與向量資料庫實務

1.4 向量資料庫(Vector Database)

儲存向量並支援快速近似最近鄰搜尋(ANN)——用一點點準確率換數量級的速度。除了向量本身,還應該把 source、date、authority 等 metadata 一起存,查詢時先過濾再比相似度,時效與權限控管都靠它。

選型(Chroma / FAISS / Qdrant / Pinecone / pgvector / Weaviate / Milvus)、HNSW 與 IVF 的取捨、量化壓縮與生產考量,同樣見 Embeddings 與向量資料庫實務


第二階段:檢索(Retrieval)

2.1 基礎向量檢索

用戶問題 → Embed → 向量相似度搜尋 → 取回 Top-K chunks。

相似度計算方式:

  • Cosine Similarity(方向相似,最常用)
  • Dot Product(向量已正規化時等同 Cosine)
  • L2 Distance(歐氏距離,適合密集向量)

這就是 naive RAG 的檢索層。它的三個典型弱點,正好對應下面三個補強手法。

弱點:純向量搜尋擅長語意相近,但會漏掉需要精確字面命中的查詢(產品型號、人名、錯誤碼)。

補法:把向量檢索(dense)與關鍵字檢索 BM25(sparse)兩條排名合併,常用 RRF(Reciprocal Rank Fusion)。細節與評估方式見 RAG 進階系列 §2

2.3 Query Transformation(查詢轉換)

弱點:用戶的問法常和文件的用詞對不上。

補法:在檢索之前改寫或擴展查詢。

Query Transformation 策略

手法 做什麼
Multi-Query 把一個問題改寫成數個不同角度的問法,分別搜尋再去重
HyDE 先讓 LLM 假設一個理想答案,用答案去搜尋——答案的語意空間與文件更接近
Step-Back 先問更廣泛的背景問題,再搜尋
Decomposition 把複雜問題拆解為子問題,各自搜尋後合併

各手法的適用時機見 RAG 進階系列 §4。在 agentic 架構裡,這會進一步變成「檢索失敗 → 改寫 → 重試」的迴圈,見 Agentic RAG

2.4 重排序(Re-ranking)

弱點:初次 Top-K 撈得夠廣,但順序不夠準。

補法:兩階段。先用 hybrid 廣撈候選(追 recall),再用 Cross-Encoder 逐一打分重排、截到最終進 context 的小集合(追 precision)。

向量搜尋(快)→ Top-20 候選 → Cross-Encoder 重排(慢但準)→ Top-5 → LLM

Cross-Encoder 比向量內積準,是因為它讓「查詢 + 候選」一起進模型算相關性,而非各自編碼再比距離;代價是慢,所以只用在縮小後的候選集上。Reranker 選型與「別把 recall 殺掉」的調法見 RAG 進階系列 §3


第三階段:生成(Generation)

檢索做得再好,生成端沒約束住,模型照樣可以無視文件亂答。這一階段全系列只有本篇談。

3.1 Prompt 設計

將檢索到的 chunks 組合進 Prompt,標準模板:

你是一個知識問答助理。請根據以下「參考資料」回答用戶問題。
如果參考資料中沒有足夠資訊,請明確說「資料中未找到相關內容」,不要憑空猜測。

## 參考資料
{retrieved_chunks}

## 用戶問題
{user_query}

## 回答

關鍵設計原則:

  • 明確限制來源:防止模型混用訓練知識
  • 處理無資訊情境:讓模型說「不知道」而非幻覺
  • 可引用來源:要求模型標注引用的文件編號

第三點不只是體貼使用者。沒有 citation,當 faithfulness 分數偏低時,你連「它在瞎掰哪一句」都定位不了——見 RAG 進階系列 §5

3.2 Context 放置位置

研究顯示 LLM 對 Prompt 中間位置的文字注意力最低(Lost in the Middle 現象)。將最相關的文件放在最前面或最後面

這也是為什麼「檢索少而準」勝過「檢索多而雜」——同樣的道理在 Context Engineering 實作篇 有更完整的討論。


超越 Naive RAG:先診斷,再決定加槓桿還是換架構

naive RAG 效果不好時,先確認是哪一種不好,再選對應的解法。多數問題出在檢索端:

症狀 原因 解法 屬於
召回率低 問題與文件語意差異大 HyDE、Multi-Query、Hybrid Search 加槓桿(第 3 站)
精確度低 Top-K 有雜訊 Re-ranking 加槓桿(第 3 站)
答案用了舊資料 索引過期 Freshness 維運 加槓桿(第 3 站)
跨文件推理失敗 資訊分散在多份文件 GraphRAG 換架構(第 4 站)
需要多輪自我修正 一次檢索不足以判斷 Agentic RAG 換架構(第 4 站)
回答不忠實 模型忽視上下文 Self-RAG、CRAG 見下
視覺內容遺失 文字 parsing 丟棄表格/圖表 PixelRAG 見下

值得記住的經驗法則:「80% 的 RAG 問題是檢索問題,不是生成問題。」 除錯先從 chunk 相關性分數逐段追,別急著換更大的生成模型。

Self-RAG

讓 LLM 自己決定:「這個問題需要檢索嗎?檢索到的結果有用嗎?我的回答是否忠實於來源?」

引入三個特殊 Token:

  • [Retrieve]:判斷是否需要檢索
  • [IsRel]:判斷檢索結果是否相關
  • [IsSup]:判斷回答是否被來源支持

Corrective RAG(CRAG)

加入「反思」步驟:評估檢索到的文件品質。

  • 品質高 → 直接生成
  • 品質低 → 用搜尋引擎補充
  • 模糊 → 混合兩者

PixelRAG(Berkeley SkyLab / BAIR)

傳統 RAG 把文件 parse 成文字——這個過程會丟棄表格結構、圖表數值、排版資訊。PixelRAG 的做法完全相反:不解析,直接截圖

核心流程:

文件 / 網頁
    ↓  pixelshot(Playwright / CDP)
截圖 Tiles(圖片分塊)
    ↓  Qwen3-VL-Embedding(LoRA fine-tuned on screenshot data)
視覺向量
    ↓  FAISS 相似度索引
    ↓  VLM 讀取截圖回答問題

傳統 RAG 碰到「表格第三欄第五行的數值是多少?」這類問題會失敗,因為 HTML parsing 後表格結構已不存在。PixelRAG 保留了整頁的視覺結構,VLM 直接看圖就能找到答案。

技術細節:

  • Embedding 模型:Qwen/Qwen3-VL-Embedding-2B,在 Wikipedia 截圖資料上 LoRA fine-tune
  • 預建索引:8.28M 筆 Wikipedia 頁面,提供公開 API(api.pixelrag.ai
  • 索引大小:FAISS 索引約 217 GB

快速試用:

pip install pixelrag

# 截圖並搜尋 Wikipedia 預建索引(無需 API key)
pixelshot https://en.wikipedia.org/wiki/Python --output ./tiles

curl -X POST https://api.pixelrag.ai/search \
  -H "Content-Type: application/json" \
  -d '{"queries": [{"text": "Python 的發明者是誰?"}], "n_docs": 5}'

和 GraphRAG 的差異——兩者都是「換索引標的」,但換的方向不同:

PixelRAG GraphRAG
索引的是什麼 頁面截圖(像素) 實體關係圖譜
解決的問題 視覺內容被 parsing 丟失 跨文件多跳推理
讀取模型 VLM(看圖) LLM(讀文字+圖譜)
適合場景 含大量表格/圖表的文件 需理解實體關係的大量文件

適合:含豐富視覺結構的文件(財報表格、技術規格書、網頁截圖)。GraphRAG 的建圖四階段與成本代價見 GraphRAG 專篇


RAG 評估框架

評估 RAG 系統需要同時衡量檢索品質生成品質。沒有評估就沒有儀表板,後面所有調優都是盲調——這是進到第 3 站之前的前置條件。

RAGAS 指標

指標 評估對象 含義
Faithfulness 生成 答案是否完全基於檢索到的上下文(不幻覺)
Answer Relevancy 生成 答案是否回應了用戶問題
Context Precision 檢索 檢索到的文件有多少是真正相關的(精確度)
Context Recall 檢索 真正相關的文件有多少被成功檢索(召回率)
from ragas import evaluate
from ragas.metrics import faithfulness, answer_relevancy, context_precision

results = evaluate(
    dataset,
    metrics=[faithfulness, answer_relevancy, context_precision],
)

黃金測試集(Golden Dataset)

自動評估需要事先準備「問題-答案-來源」三元組。方法:

  1. 從文件中讓 LLM 自動生成 Q&A 對(合成測試集)
  2. 人工標注少量高品質測試案例作為核心基準

生產環境的目標值、指標掉了該往哪查,見 Agentic RAGLLM Evaluation 實務


工具生態與選型

主流框架比較

框架 定位 優點 缺點
LangChain 通用 LLM 應用框架 生態最大、整合最多 抽象層厚、debug 困難
LlamaIndex 專注於資料索引與查詢 RAG 功能最完整 較 LangChain 小衆
Haystack 企業級搜尋+RAG 生產成熟度高 學習曲線較陡
DSPy 自動最佳化 Prompt 系統性調優 概念抽象,新穎

最小可行 RAG 實作(LangChain)

from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain_anthropic import ChatAnthropic
from langchain_community.vectorstores import Chroma
from langchain.chains import RetrievalQA

# 1. 載入文件
loader = PyPDFLoader("document.pdf")
docs = loader.load()

# 2. 分塊
splitter = RecursiveCharacterTextSplitter(chunk_size=512, chunk_overlap=50)
chunks = splitter.split_documents(docs)

# 3. 建立索引
vectordb = Chroma.from_documents(chunks, OpenAIEmbeddings())

# 4. 建立 RAG Chain
qa = RetrievalQA.from_chain_type(
    llm=ChatAnthropic(model="claude-opus-5"),
    retriever=vectordb.as_retriever(search_kwargs={"k": 5}),
)

# 5. 查詢
answer = qa.invoke("這份文件的主要結論是什麼?")

上面的 chunk_size=512, chunk_overlap=50 只是讓程式跑起來的預設值,不是建議值——正式使用前務必對自己的語料實測。


下一步

這一站建立了骨架。往下走的三個方向:

  • 底層選型還沒決定Embeddings 與向量資料庫實務(第 2 站)
  • 跑起來了但效果不好RAG 進階系列(第 3 站,六個槓桿與落地優先序)
  • 槓桿加滿仍不夠Agentic RAG 有完整的架構光譜比較(Naive / Advanced / Agentic / GraphRAG / Adaptive),含延遲與成本量級

其他相關:Prompt Engineering 核心技術Context EngineeringAI Agent Harness Engineering