RAG 調(diào)優(yōu)核心:文本切分決定 70% 的性能表現(xiàn)
分塊(Chunking)是構(gòu)建高效RAG(檢索增強生成)系統(tǒng)的核心。從固定分塊、遞歸分塊到語義分塊、結(jié)構(gòu)化分塊和延遲分塊,每種方法都在優(yōu)化上下文理解和準確性上扮演了關(guān)鍵角色。這些技術(shù)能大幅提升檢索質(zhì)量,減少“幻覺”(hallucination),并充分發(fā)揮你的RAG pipeline的潛力。
在我近一年構(gòu)建可擴展AI系統(tǒng)的經(jīng)驗中,我發(fā)現(xiàn)RAG系統(tǒng)的成功大多取決于檢索(retrieval)。你如何切分和存儲文檔——也就是分塊(chunking)——往往是成功背后的隱形推手。
引言
RAG(Retrieval-Augmented Generation)pipeline的性能很大程度上取決于你如何切分文檔(分塊)。在這篇文章中,我會帶你了解RAG的流程,重點講講分塊在其中的位置,然后深入探討固定分塊、遞歸分塊、語義分塊、基于結(jié)構(gòu)的分塊和延遲分塊這五種技術(shù),包括它們的定義、權(quán)衡和偽代碼,幫你選擇適合自己場景的方法。
RAG工作流程(高層次概覽)
標準流程如下:

- 文檔攝取與分塊
拿來大份文檔(PDF、HTML、純文本) → 切分成小塊(chunk) → 計算embeddings → 存儲到vector DB中。 - 查詢與檢索
用戶輸入查詢 → 將查詢轉(zhuǎn)為embedding → 檢索top-k最相似的塊(通過cosine similarity)。 - 增強與提示構(gòu)建
將檢索到的塊(加上metadata)注入到LLM的提示中,通常會用模板和過濾器。 - 生成
LLM基于檢索到的上下文和模型先驗知識生成答案。
因為生成器(generator)只能看到你喂給它的內(nèi)容,檢索質(zhì)量直接決定了結(jié)果。如果分塊不合理或無關(guān)緊要,哪怕最好的LLM也救不回來。這就是為什么很多人說RAG的成功70%靠檢索,30%靠生成。
在深入探討技術(shù)之前,先說說為什么好的分塊不是可有可無的:
- Embedding和LLM模型有context window限制,你沒法直接處理超大文檔。
- 分塊需要語義連貫。如果你在句子或概念中間切開,embedding會變得雜亂或誤導(dǎo)。
- 如果分塊太大,系統(tǒng)可能會漏掉細粒度的相關(guān)內(nèi)容。
- 反過來,如果分塊太小或重疊太多,你會存儲冗余內(nèi)容,浪費計算和存儲資源。
接下來,我們來探索五種主流的分塊技術(shù),從最簡單到最復(fù)雜。
1. 固定分塊(Fixed Chunking)
按固定大?。ò磘oken、單詞或字符)把文本切成等大的塊,通常塊之間會有重疊。
這是RAG項目的良好起點,適合文檔結(jié)構(gòu)未知或內(nèi)容單一的場景(比如日志、純文本)。
實現(xiàn)代碼示例:
def fixed_chunk(text, max_tokens=512, overlap=50):
tokens = tokenize(text)
chunks = []
i = 0
while i < len(tokens):
chunk = tokens[i : i + max_tokens]
chunks.append(detokenize(chunk))
i += (max_tokens - overlap)
return chunks2. 遞歸分塊(Recursive Chunking)
先按高層邊界(比如段落或章節(jié))切分。如果某個塊還是太大(超過限制),就遞歸地進一步切分(比如按句子),直到所有塊都在限制范圍內(nèi)。
適合半結(jié)構(gòu)化文檔(有章節(jié)、段落),你想盡量保留語義邊界,同時控制塊大小。
它能盡量保留邏輯單元(段落),避免不自然的切分,生成適合內(nèi)容變化的多種塊大小。
遞歸分塊示例(LangChain):
from langchain.text_splitter import RecursiveCharacterTextSplitter
# 示例文本
text = """
輸入文本占位符...
"""
# 定義遞歸分塊器
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=200, # 每個塊的目標大小
chunk_overlap=50, # 塊之間的重疊以保持上下文連貫
separators=["\n\n", "\n", " ", ""] # 遞歸切分的優(yōu)先級
)
# 切分文本
chunks = text_splitter.split_text(text)
# 顯示結(jié)果
for i, chunk inenumerate(chunks, 1):
print(f"Chunk {i}:\n{chunk}\n{'-'*40}")這能確保后續(xù)embedding和檢索時,不會丟失邊界處的關(guān)鍵上下文。
3. 語義分塊(Semantic Chunking)
根據(jù)語義變化來切分文本。用embeddings(比如sentence embeddings)決定一個塊的結(jié)束和下一個塊的開始。如果相鄰段落的相似度很高,就把它們放在一起;當相似度下降時,就切分。
適合需要高檢索精度的場景(法律文本、科學(xué)文章、支持文檔),但要注意embedding和相似度計算的成本,定義相似度閾值也需要仔細調(diào)整。
實現(xiàn)代碼示例:
from sentence_transformers import SentenceTransformer, util
model = SentenceTransformer("all-MiniLM-L6-v2")
defsemantic_chunk(text, sentence_list, sim_threshold=0.7):
embeddings = model.encode(sentence_list)
chunks = []
current = [sentence_list[0]]
for i inrange(1, len(sentence_list)):
sim = util.cos_sim(embeddings[i-1], embeddings[i]).item()
if sim < sim_threshold:
chunks.append(" ".join(current))
current = [sentence_list[i]]
else:
current.append(sentence_list[i])
chunks.append(" ".join(current))
return chunks4. 基于結(jié)構(gòu)的分塊(Structure-based Chunking)
利用文檔的固有結(jié)構(gòu)(比如標題、副標題、HTML標簽、表格、列表項)作為自然的切分邊界。
比如,每個章節(jié)或標題可以成為一個塊(或者再遞歸切分)。
適合HTML頁面、技術(shù)文檔、類似Wikipedia的內(nèi)容,或任何有語義標記的內(nèi)容。
根據(jù)我的經(jīng)驗,這種策略效果最好,尤其是結(jié)合遞歸分塊時。
但它需要解析和理解文檔格式,如果章節(jié)太大,可能會超過token限制,可能需要結(jié)合遞歸切分。
實現(xiàn)提示:
- 用HTML/Markdown/PDF結(jié)構(gòu)解析庫。
- 以章節(jié)/等作為塊的根。
- 如果某部分太大,就回退到遞歸切分。
- 對于表格/圖片,要么單獨作為一個塊,要么總結(jié)其內(nèi)容。
5. 延遲分塊(Late Chunking / 動態(tài)/查詢時分塊)
定義
延遲分塊是指推遲文檔的切分,直到查詢時才決定。不是提前把所有內(nèi)容切好,而是存儲更大的段落甚至整個文檔。收到查詢時,只對相關(guān)段落動態(tài)切分(或過濾)。這樣做的目的是在embedding時保留完整上下文,只在必要時切分。
Weaviate將延遲分塊描述為“顛倒傳統(tǒng)的embedding和chunking順序”。
- 先用長上下文模型對整個文檔(或大段)做embedding。
- 然后池化并創(chuàng)建塊的embeddings(基于token范圍或邊界線索)。
概念流程:
- 在索引中存儲大段或整個文檔。
- 查詢時,檢索1-2個最相關(guān)的段落。
- 在這些段落中,動態(tài)切分(比如語義或重疊)出匹配查詢的部分。
- 過濾或排序這些塊,喂給生成器。
這種方法就像編程中的late binding,推遲到有更多上下文時再決定。

適用場景:
- 大型文檔集(技術(shù)報告、長篇內(nèi)容),跨段落的上下文很重要。
- 文檔內(nèi)容經(jīng)常變化的系統(tǒng),避免重新切分節(jié)省時間。
- 高風(fēng)險或精度敏感的RAG應(yīng)用(法律、醫(yī)療、監(jiān)管),誤解代詞或引用可能代價高昂。
聽起來很高級,但它也有成本。
對整個文檔(或大段)做embedding計算成本高,可能需要支持長token限制的模型。
查詢時的計算成本和潛在延遲也會更高。
本文轉(zhuǎn)載自??PyTorch研習(xí)社??,作者:AI研究生

















