3.3 固定大小分塊策略
最簡單的切法:每隔固定的字數切一刀,相鄰的塊再重疊一點。
最直接的分塊方法是固定大小分塊(fixed-size chunking):不管內容是什麼,每隔固定的長度就切一刀。
怎麼運作
設定兩個參數:
- size:每一塊多長。
- overlap:相鄰兩塊重疊多少。
程式從頭開始,每次取 size 這麼長的一段,下一段的起點往前移 size - overlap,這樣相鄰的塊就會共用一小段內容。
為什麼要重疊
沒有重疊的話,一個完整的句子或概念,剛好被切在兩塊中間,兩邊都只有一半。有了重疊,被切開的地方會同時出現在前後兩塊裡,至少有一塊能保有完整的上下文。
重疊的代價是:資料量變多、儲存和搜尋成本增加,也可能檢索到內容重複的兩塊。一般會設 size 的 10% 到 20% 左右。
實作
用純 Python 寫就只要幾行:
def fixed_chunks(text, size, overlap):
"""固定大小:每 size 個字切一刀,相鄰兩塊重疊 overlap 個字"""
step = size - overlap
chunks = []
for start in range(0, len(text), step):
piece = text[start:start + size]
if piece.strip():
chunks.append(piece)
if start + size >= len(text):
break
return chunks
拿一份簡單的員工手冊(共 214 個字),用 size=80, overlap=20 去切,得到這樣的結果:
[1] (80 字) '# 員工手冊\n\n## 特別休假\n\n員工在同一公司服務滿六個月未滿一年者,每年有三天特別休假。滿一年未滿兩年者,有七天。滿兩年未滿三年者,有十天。\n\n特別休假的日'
[2] (80 字) '兩年未滿三年者,有十天。\n\n特別休假的日期,由員工和公司協商安排。年度結束時沒有休完的天數,公司應該折算成工資發給員工。\n\n## 加班規定\n\n加班必須事先經主管'
[3] (80 字) '\n\n## 加班規定\n\n加班必須事先經主管同意。平日加班前兩小時,以平日每小時工資的 1.34 倍計算。第三小時起,以 1.67 倍計算。\n\n休息日加班另有規定,'
[4] (34 字) '.67 倍計算。\n\n休息日加班另有規定,不得低於勞動基準法的標準。\n'
看看問題在哪
仔細看這個結果:
- 第 1 塊的結尾是「特別休假的日」,句子被切到一半。
- 第 3 塊的結尾是「休息日加班另有規定,」,下一塊開頭卻是「.67 倍計算」,一個數字被切成兩半(1.67 變成「1」和「.67」)。
- 標題「## 加班規定」被拆開,第 2 塊最後有一半,第 3 塊開頭有一半。
- 重疊確實發揮作用:第 1、2 塊都有「兩年未滿三年者,有十天」這段。
這就是固定大小分塊的特性。
優缺點
優點
- 簡單,幾行程式就能做。
- 結果可預測,每塊大小一致,容易估算成本。
- 不依賴文件格式,什麼文字都可以切。
缺點
- 完全不管內容,可能在句子、段落、表格中間切開。
- 同一個主題可能被分散到好幾塊,不同主題也可能被混在同一塊。
中文要注意的事
- 切的單位是「字數」還是 token 數要分清楚。嵌入模型的長度上限通常是用 token 算的,而中文一個字常常對應一個或多個 token,所以要預留空間。
- 要用的 size 可以先用字數估,再用實際的 tokenizer 驗證有沒有超過模型的限制。
什麼時候用它
- 快速做第一版原型。
- 資料本身沒有結構,例如逐字稿、長篇純文字。
- 作為基準:之後試了更複雜的方法,拿它來比較有沒有真的進步。
如果文件本身有標題、段落或句子等明顯結構,內容感知分塊通常更合適。