A
返回 AI 知識
AI 知識2026/05/10 君澤智庫研究員 Bryan Chan11 分鐘閱讀

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

檢索增強生成 (RAG) 的完整技術棧:Embedding 選擇、Chunking 策略、向量數據庫對比、Rerank 優化,附帶實際代碼示例。

RAG 是什麼?

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

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

核心組件拆解

1. Embedding 模型選擇

模型 維度 語言 成本 適用場景
text-embedding-3-small 1536 多語言 $0.02/1M tokens 通用、成本敏感
text-embedding-3-large 3072 多語言 $0.13/1M tokens 高精度需求
bge-large-zh-v1.5 1024 中文 免費 (本地) 中文場景首選
bge-m3 1024 多語言 免費 (本地) 多語言混合
jina-embeddings-v3 1024 多語言 免費 (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 無上限 不想管基礎設施
pgvector PostgreSQL 擴展 百萬級 已有 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 代碼

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 多語言模型

推薦閱讀