Agentic Research
首頁/學習/RAG 深入原理與實踐:從 Chunking 到 Rerank 的完整指南

RAG 深入原理與實踐:從 Chunking 到 Rerank 的完整指南

2026/05/1011 分鐘Bryan Chan最後更新 2026/05/10
這篇屬於學習主題RAGLLMDeep Learning

先讀這些

這篇文章在學習路徑上假設你已經讀過下列內容。

RAG 是什麼?

RAG(Retrieval-Augmented Generation)讓 LLM 在回答前先從外部知識庫檢索相關文檔,再基於檢索結果生成答案。這解決了 LLM 的兩個核心問題:

  1. 知識截止日期:LLM 只知道訓練數據中的信息
  2. 幻覺 (Hallucination):LLM 可能編造不存在的事實
用戶提問 → Embedding → 向量搜索 → Top-K 文檔 → LLM 生成 → 帶來源的答案

核心組件拆解

1. Embedding 模型選擇

模型維度語言成本適用場景
text-embedding-3-small1536多語言$0.02/1M tokens通用、成本敏感
text-embedding-3-large3072多語言$0.13/1M tokens高精度需求
bge-large-zh-v1.51024中文免費 (本地)中文場景首選
bge-m31024多語言免費 (本地)多語言混合
jina-embeddings-v31024多語言免費 (API)長文檔 (8K tokens)

建議:中文為主用 bge-large-zh-v1.5,多語言用 bge-m3,API 方案用 text-embedding-3-small。

# Ollama 本地 Embedding
ollama pull nomic-embed-text
# 或 bge-m3
ollama pull bge-m3

2. Chunking 策略

這是最容易被忽略但最關鍵的環節。錯誤的 Chunking 直接導致檢索失敗。

策略適合場景優點缺點
固定大小 (500 tokens)通用簡單、可預測可能在句子中間截斷
語義分割 (按段落/章節)結構化文檔保持語義完整性塊大小不一致
遞歸分割 (按 \n\n → \n → 。)混合文檔自適應實現複雜
句子窗口精確檢索每句獨立丟失上下文

最佳實踐:

  • Chunk size: 256-512 tokens(太小丟失上下文,太大稀釋語義)
  • Overlap: 10-20%(確保關鍵信息不被截斷)
  • 使用 LangChain 的 RecursiveCharacterTextSplitter
from langchain.text_splitter import RecursiveCharacterTextSplitter

splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,
    chunk_overlap=50,
    separators=["\n\n", "\n", "。", ",", " ", ""]
)
chunks = splitter.split_text(document)

3. 向量數據庫對比

方案部署規模適合場景
Chroma本地/嵌入式<100K docs原型/個人項目
Qdrant本地/Docker百萬級生產環境
Milvus分佈式億級企業級
Pinecone雲端 SaaS無上限不想管基礎設施
pgvectorPostgreSQL 擴展百萬級已有 PG 的項目

推薦路徑:原型用 Chroma → 生產用 Qdrant Docker → 超大規模用 Milvus。

# Qdrant 快速啟動
docker run -p 6333:6333 qdrant/qdrant

4. Rerank(重排序)

初次向量檢索後,用更精確的 Cross-encoder 對 Top-K 結果重新排序,大幅提升準確度。

模型語言說明
bge-reranker-v2-m3多語言開源最佳
Cohere Rerank多語言API,效果最好
bge-reranker-large中/英中文場景推薦

為什麼需要 Rerank? 向量相似度 ≠ 語義相關性。Rerank 用 Cross-encoder 逐對比較 query 和 document,更精準。

# 典型流程
# 1. 向量檢索 → 20 個候選
candidates = vector_db.search(query, top_k=20)

# 2. Rerank → 取前 5
from FlagEmbedding import FlagReranker
reranker = FlagReranker('BAAI/bge-reranker-v2-m3')
scores = reranker.compute_score([[query, doc] for doc in candidates])
top_5 = sorted(zip(candidates, scores), key=lambda x: x[1], reverse=True)[:5]

# 3. LLM 生成
answer = llm.generate(query, context=top_5)

完整 RAG Pipeline 代碼

RAG 管線:AI 怎麼「知道」你的文件RAG 分兩個階段,而且把它們混在一起講是多數解釋讓人困惑的原因。上半是一次性的索引建立:你的文件被切成塊,每一塊被轉成一串數字(向量),存進向量庫等待。下半是每次提問都跑的檢索:你的問題也被轉成向量,在向量庫裡找出意思最接近的幾塊(不是字面符合),把問題與那幾塊一起塞進同一個提示裡送給模型,模型引用它看到的內容回答。關鍵是:**RAG 不會讓模型學會任何東西,它只是在你提問那一刻把對的那一頁拿給它看。** 這個區分改變四個實務判斷:同一個問題不同天可能答得不一樣(變的是檢索到的塊);它會自信地給錯答案(從提示內部看,錯誤的塊與正確的塊長得一樣);改了文件不會有變化直到索引重建(過期答案是管線問題不是模型問題);塊的大小是真實取捨(太小失去上下文,太大稀釋相關段落)。RAG 不會讓模型學會任何東西。它是在你提問的那一刻,把對的那一頁拿給它看。一次性 —— 建立索引你的文件PDF、筆記、wiki、工單切成塊塊的大小決定了什麼找得到轉成向量每一塊變成一串數字向量庫存起來等著每一次提問 —— 檢索你的問題也被轉成一個向量找最相近的塊意思最接近,不是字面符合塞進提示裡問題 + 幾塊內容共用同一個視窗回答引用它看到的為什麼這個區分會改變你的做法· 同一個問題不同天可能答得不一樣 —— 變的是檢索到的塊,不是模型。· 它會自信地給錯答案:從提示內部看,錯誤的塊與正確的塊長得一模一樣。· 改了文件不會有任何變化,直到索引重建。過期的答案是管線問題,不是模型問題。· 塊的大小是真實的取捨:太小會失去上下文,太大會稀釋真正相關的那段。1文件進去
1/6文件進去
PDF、筆記、wiki、工單
第 1 步,共 6 步 文件進去
圖:RAG 管線的完整流程。文件切塊、向量化、檢索、重排、組進 prompt,每一步的輸入與輸出。
from langchain_community.embeddings import OllamaEmbeddings
from langchain_community.vectorstores import Chroma
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.llms import Ollama

# 1. 加載文檔
with open("knowledge_base.txt") as f:
    text = f.read()

# 2. Chunking
splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
chunks = splitter.split_text(text)

# 3. Embedding + 存入向量庫
embeddings = OllamaEmbeddings(model="bge-m3")
vectorstore = Chroma.from_texts(chunks, embeddings)

# 4. 檢索
retriever = vectorstore.as_retriever(search_kwargs={"k": 5})
docs = retriever.get_relevant_documents("什麼是 RAG?")

# 5. 生成
llm = Ollama(model="qwen2.5:7b")
context = "\n".join([d.page_content for d in docs])
answer = llm.invoke(f"基於以下文檔回答問題:\n{context}\n\n問題:什麼是 RAG?")

常見踩坑

坑原因解法
檢索結果不相關Chunk size 太大或太小調優 256-512,加 overlap
檢索速度慢未建索引Qdrant/Milvus 建 HNSW 索引
Embedding 成本高每次查詢都調 API本地部署 bge-m3
答案幻覺LLM 無視檢索結果Prompt 中強制引用來源
中英混合查詢失敗Embedding 模型不支持用 bge-m3 多語言模型

推薦閱讀

在這條路徑上的下一步