RAG 分塊策略實測:chunk 大細點揀,答案質素差成倍
128 / 512 / 1024 token、overlap、語義分塊——本地 Qwen3 + 向量 DB 實測邊個設定最抵
重點整理
- RAG 答案質素差,十居其九唔係 model 唔夠勁,係 chunk 切得差——切太大會噪音淹沒答案,切太細就斬斷上下文
- 實測三種 chunk 大細(128/512/1024 token)加兩種 overlap 設定,用 20 條真實問題逐個跑分
- 進階:語義分塊(semantic chunking)同標題感知切分點樣大幅改善結構化文件嘅檢索
- 附完整可抄 code:Python + Ollama embeddings 極簡 RAG pipeline,50 行行齊 ingest 加 query
點解 chunking 係 RAG 嘅生死位
好多人 RAG 做得唔好,第一反應係換個勁啲嘅 model。但實際上,檢索唔中,model 幾勁都冇用——佢根本睇唔到答案喺邊。而檢索準唔準,最大嘅變數就係你點樣將文件切件(chunking)。
切得太細:一段 200 字嘅答案被斬開三截,冇一截單獨睇得明,top-5 檢索只抓到半句。 切得太大:一個 chunk 入面有十幾段唔同主題嘅嘢,向量 embedding 被「平均」咗,邊個主題都唔似。
實測設定
測試集:一份 40 頁嘅公司內部 wiki(混合說明文、FAQ、會議紀錄),加 20 條真實同事問題(有標準答案)。
| Chunk 大細 | Overlap | Top-5 命中率 |
|---|---|---|
| 128 token | 0 | 55% |
| 128 token | 32 | 60% |
| 512 token | 0 | 75% |
| 512 token | 64 | 85% |
| 1024 token | 0 | 70% |
| 1024 token | 128 | 72% |
結論好清晰:512 token + 64 overlap 係 sweet spot。1024 反而跌返落嚟——chunk 大到一個點,embedding 開始「冇焦點」。
語義分塊:結構化文件嘅救星
上面嘅測試係「死切」。但 wiki 同文件多數有標題結構——跟標題切(heading-aware chunking)效果仲好:
實測同一批問題,heading-aware + 512 上限:命中率 85% → 90%。原因好簡單:一個 chunk 唔會由 FAQ 嘅中間開始,亦唔會將兩個唔相關章節黐埋。
語義分塊(用 embedding 相似度搵切位)喺呢批測試反而冇顯著優勢(89%)——對結構清晰嘅文件,標題本身已經係最好嘅語義訊號,仲要慳啲計算。
極簡可抄 Pipeline(Ollama + numpy)
import numpy as np, requests, re
OLLAMA = "http://localhost:11434"
def embed(texts):
r = requests.post(f"{OLLAMA}/api/embed",
json={"model": "nomic-embed-text", "input": texts})
return np.array(r.json()["embeddings"])
def chunk(text, size=512, overlap=64):
# heading-aware:先跟 markdown 標題切
parts = re.split(r"(
#+ .*)", text)
chunks, buf = [], ""
for p in parts:
buf += p
while len(buf) > size: # 超長再滑窗
chunks.append(buf[:size]); buf = buf[size-overlap:]
if buf.strip(): chunks.append(buf)
return chunks
def build(texts):
all_chunks = [c for t in texts for c in chunk(t)]
vecs = embed(all_chunks)
vecs = vecs / np.linalg.norm(vecs, axis=1, keepdims=True)
return all_chunks, vecs
def query(q, chunks, vecs, k=5):
qv = embed([q])[0]; qv = qv / np.linalg.norm(qv)
sims = vecs @ qv
return [chunks[i] for i in np.argsort(sims)[-k:][::-1]]
三個實戰貼士
- Chunk 入面帶返標題:切完件之後,chunk 開頭加返所屬章節標題("## 報銷流程 — 申請時限"),檢索同生成質素都會升——model 睇到上下文脈絡。
- Overlap 唔好慳:0 overlap 喺實測穩定差 5-10%。關鍵句啱啱好被切斷係常見死法。
- 評估先至換設定:照上一篇《LLM Eval 自製測試集》嘅做法,攞 20 條真問題做 regression set,改一個設定跑一次——唔好靠感覺。
總結
RAG 嘅質素瓶頸多數喺檢索唔喺生成。由「死切 512 + overlap 64 + heading-aware」開始,已經夠打贏大部分隨手做嘅 RAG。再用 eval set 逐步調,先至係正路。
延伸閱讀
- LLM Eval 自製測試集入門——改 chunking 設定前後都靠佢驗證
- 用 Qwen3.8 搭建本地 RAG 知識庫——完整 RAG 架構基礎
- Embedding 同向量資料庫入門——向量檢索底層原理
