API 開發

RAG 文本切片怎麼切?四種 chunking 策略一次講清楚

文本切片(chunking)是把文件切成小塊供檢索的前處理步驟。常見四種策略:按長度切最簡單也最不挑文件、按結構切最乾淨但要求格式、按句子切是實用的折衷、按語意切品質最好但成本最高。沒有唯一正解,要依文件特性與可接受的複雜度取捨。
RAG 文本切片怎麼切?四種 chunking 策略一次講清楚:文章重點卡

RAG 文本切片怎麼切?四種 chunking 策略一次講清楚

上一篇我們講了 RAG 為什麼存在:先把文件切成小塊,提問時只送相關的段落給模型。這篇要處理整條管線的第一道關卡:到底怎麼切

別小看這一步。切片的方式直接決定整個系統的品質,切壞了,後面的檢索與生成做得再好也救不回來。

你將學到什麼

切不好會怎樣

一個「bug」字義誤導檢索的具體例子。

四種切法

按長度、按結構、按句子、按語意的原理與程式碼。

overlap 的作用

為什麼相鄰切塊之間要重疊一小段。

怎麼選策略

依文件給你的保證,挑出合適切法的判斷準則。

切錯一刀,整個系統跟著錯

先看一個具體情境。你有一份文件,裡面同時有醫學研究軟體工程兩個章節。醫學章節剛好提到一種沒見過的「bug」(病菌),軟體章節則在講系統裡的臭蟲。

如果切片切得不好,使用者問「工程師今年修了幾個 bug」,檢索出來的可能是醫學研究的段落,只因為那一段也出現了 bug 這個字。

不相關的段落被塞進 prompt,模型就會拿著錯的材料,一本正經地答錯。記住這條因果鏈:檢索只能從你切出來的塊裡挑,塊本身切壞了,再聰明的檢索也只能在壞塊裡挑一個沒那麼壞的。

更麻煩的是,這種錯誤很難在事後察覺:使用者只看到答非所問,不會知道問題出在前處理的那一刀。這就是為什麼切片策略值得認真選。以下是三大類做法,外加一種實用的折衷。

按長度切:最簡單,也最不挑文件

按長度切(size-based chunking)就是把文字切成等長的字串。它最好實作、什麼文件都適用,但缺點也很直白:

  • 單字或句子會在中間被硬生生切斷。
  • 切塊少了前後文,脈絡不完整。
  • 章節標題可能跟它的內文被切散在兩塊裡。

解法是加上 overlap:讓每個切塊多含一小段鄰居的內容。這樣邊界上的句子有機會在某一塊裡是完整的,每塊也帶著一點周圍的脈絡。代價是切塊總量會多一些、儲存與計算也跟著多一點,但換來的邊界品質通常划算。

原始文件一整條連續的文字切成三塊,帶 overlap切塊一切塊二切塊三重疊區
相鄰切塊之間重疊一小段,邊界上的句子才不會兩邊都殘缺。

基本實作長這樣:

def chunk_by_char(text, chunk_size=150, chunk_overlap=20):
    chunks = []
    start_idx = 0

    while start_idx < len(text):
        end_idx = min(start_idx + chunk_size, len(text))
        chunk_text = text[start_idx:end_idx]
        chunks.append(chunk_text)

        start_idx = (
            end_idx - chunk_overlap if end_idx < len(text) else len(text)
        )

    return chunks

按結構切:最乾淨,但要文件配合

按結構切(structure-based chunking)是順著文件的天然結構下刀:標題、段落、章節。拿 Markdown 文件來說,直接照標題符號切就行:

def chunk_by_section(document_text):
    pattern = r"\n## "
    return re.split(pattern, document_text)

這種切法給你最乾淨、最有意義的切塊,每一塊就是一個完整的章節。但它有個前提:你得對文件結構有把握。現實世界裡很多文件是純文字或 PDF,根本沒有清楚的結構記號,這招就使不上力。

判斷方式很簡單:你能不能對「每份進系統的文件都長這樣」打包票?公司內部的制式報告可以,使用者上傳的任意檔案就不行。

按語意切與按句子切:兩種折衷

按語意切(semantic-based chunking)是最講究的做法:先把文字拆成句子,再用自然語言處理判斷相鄰句子的關聯程度,把相關的句子聚成一塊。它產出的切塊品質最好,但計算成本高,實作也最複雜。

實務上有個好用的中間路線:按句子切。先用正規表示式把文字拆成句子,再固定幾句組成一塊,一樣可以加 overlap:

def chunk_by_sentence(text, max_sentences_per_chunk=5, overlap_sentences=1):
    sentences = re.split(r"(?<=[.!?])\s+", text)

    chunks = []
    start_idx = 0

    while start_idx < len(sentences):
        end_idx = min(start_idx + max_sentences_per_chunk, len(sentences))
        current_chunk = sentences[start_idx:end_idx]
        chunks.append(" ".join(current_chunk))

        start_idx += max_sentences_per_chunk - overlap_sentences

        if start_idx < 0:
            start_idx = 0

    return chunks

怎麼選:看你的文件給了什麼保證

選策略的關鍵不是哪招最炫,而是你的文件能給你什麼保證

策略適合的情境取捨
按結構切格式有把握的文件,例如公司內部的制式報告品質最好,但文件沒結構就不能用
按句子切大多數一般的文字文件折衷之選,實作與品質都中等
按長度切任何內容,包含程式碼與格式混亂的文件最可靠的保底,品質不完美但穩定
按語意切願意投入計算成本追求檢索品質的場景切塊最準,但最貴也最複雜
生產環境的常見預設按長度切加上 overlap,往往是生產環境的首選:簡單、可靠、什麼文件都切得動。它不保證完美,但穩定產出「不會弄壞管線」的合理切塊,先跑起來再迭代。

我自己的習慣是把這個決定當成可以回頭改的假設:先用最穩的切法讓整條管線跑通,再拿真實提問的檢索結果回頭調整。切片不是一次定生死的決定,而是一個可以迭代的參數。

記住:沒有唯一最佳的切片策略。答案取決於你的文件長相、使用情境,以及你願意在實作複雜度與切塊品質之間怎麼交換。下一篇,我們來看切好的塊要怎麼被「找到」:embedding 與向量檢索。

參考出處本文取材自 Anthropic 官方 Claude Academy 免費課程「Building with the Claude API」,由酒Ann 消化後以自己的視角重新編寫。想看英文原版課程,可到 Claude Academy 修習。

延伸學習

把這篇文章分享給需要的人FacebookLINEThreadsX

常見問答

什麼是 chunk overlap?
讓每個切塊往前後多含一小段鄰居的內容。這樣切在邊界上的句子不會被硬生生截斷,每塊也保有周圍的脈絡。
哪種切片策略最好?
沒有單一最佳解。按長度切加上 overlap 是生產環境常見的預設,因為它簡單可靠、什麼文件都切得動;但如果你的文件格式有保證,按結構切的品質更好。
切片大小要設多少?
沒有通用答案。課程示範用 150 字元搭配 20 字元重疊做教學,實務上要拿自己的文件與真實提問去測,才知道哪個組合檢索得最準。
程式碼或格式混亂的文件適合哪種切法?
按長度切。它不依賴任何格式假設,包含程式碼在內的任何內容都切得動,是最可靠的保底選擇。