所有入門單元免費開放 · 課程內容持續更新中

文件切塊的策略

一份文件只換成一個座標,意思會被平均掉、搜尋就不準。這堂課教你把文件切成大小剛好的「塊」:依照段落組合、相鄰重疊一點、每塊記下出處,為下一堂的搜尋打好基礎。

第 12.2 堂約 13 分鐘

上一堂你看到 embedding 能把一句話變成座標,再用距離找出意思相近的句子。但你的資料不是一句一句的,而是一份份文件:員工手冊、產品說明、會議紀錄。

整份文件直接變成一個座標可以嗎?可以,但效果很差。這堂課就來解決這件事。

為什麼要切塊?

想像一份員工手冊,同時寫了請假、報帳、遠端工作。如果整份只換成一個座標,這個座標會落在三個話題的「中間」:什麼問題都有點像,但什麼問題都不夠像。

反過來,一句一塊也不行。「需在三天前提出。」單獨看完全不知道在講什麼,就算被找到,模型也沒辦法根據它回答。

三欄比較:太大的塊把所有話題擠在一起,座標變成平均值;太小的塊只有一句,上下文被切斷;剛好的塊一個主題一塊,自己看得懂、意思集中

好的塊像一張便利貼:拿出來單獨看,也知道它在說什麼。

所以切塊(chunking)就是把文件切成大小剛好的片段,每一塊各自變成一個座標。搜尋時找的是「最相關的那幾塊」,不是「最相關的那份文件」。

三個實用原則

1. 順著文件結構切

文件本來就有結構:標題、段落、清單。作者已經幫你把相關的內容放在一起了,順著它切,最不容易把一句話從中間切斷。

最簡單的做法是用「空行」找出段落,再把相鄰的段落組合起來,直到快超過字數上限,就開新的一塊。

2. 相鄰兩塊重疊一點

不管怎麼切,總有資訊剛好落在交界上。讓相鄰兩塊重疊一個段落,交界的內容兩邊都有,就不怕被切成兩半而找不到。

五個段落依序組合:第 0 塊是段落 1、2、3,第 1 塊是段落 3、4、5,段落 3 同時出現在兩塊裡

重疊會多存一點資料,換來的是不漏接。

3. 每一塊都記下出處

切開之後,每一塊要帶著自己的「身分證」:來自哪個檔案、屬於哪個標題。第四堂課要讓模型附上引用,靠的就是這些資料。

另外有一個小技巧:把文件標題加在每一塊的開頭。一塊寫著「需在三天前提出申請」的內容,加上「【請假規定】」之後,意思就清楚多了,搜尋也會更準。

準備練習用的文件

建立一個 docs 資料夾,放進三份虛構的員工手冊。內容可以直接複製,也可以換成你自己的文件(記得先拿掉個人資料)。

docs/leave.md:

# 請假規定

## 特別休假(特休)
到職滿六個月的同仁享有特休。天數依年資計算,請到人資系統的「我的假勤」頁面查詢。

特休請在預計休假日的三個工作天前,於人資系統提出申請,經直屬主管核准後生效。

當年度沒休完的特休,可以遞延到隔年六月底前使用;逾期未休的天數,依規定折算工資。

## 病假
因病需要請假時,請在當天上班時間開始前通知主管,回到公司後再補登系統。

連續請病假超過三天,需要附上醫療院所開立的證明。

docs/expense.md:

# 報帳規定

## 可以報帳的項目
因公務產生的交通費、文具與餐費可以報帳。交通費包含捷運、公車與高鐵。

計程車費只限晚上十點後下班,或需要攜帶大型器材時使用。

## 報帳流程
請在費用發生後三十天內,於報帳系統上傳發票或收據照片並填寫用途。主管審核後,財務部會在次月十號匯入薪資帳戶。

## 發票遺失
發票或收據遺失時,請填寫「支出證明單」並請主管簽名。每人每年最多使用三次。

docs/remote.md:

# 遠端工作辦法

## 申請資格
通過試用期的同仁,每週最多可以申請兩天遠端工作。

## 申請方式
請在前一週的週五前,於團隊行事曆登記遠端日期,並告知直屬主管。

## 遠端工作的規範
遠端工作日的上班時間與進辦公室相同,上午十點到下午四點之間需要保持通訊軟體在線。

公司筆電可以帶回家使用,但不可以連接公共 Wi-Fi 處理客戶資料。

寫一個切塊程式

建立 chunking.py。這個檔案之後幾堂課都會用到:

from pathlib import Path

MAX_CHARS = 150  # 每塊最多幾個字元(要配合 embedding 模型的長度上限)
OVERLAP = 1      # 相鄰兩塊重疊幾個段落


def split_paragraphs(text: str) -> list[str]:
    """用空行切出段落,並去掉頭尾空白。"""
    return [p.strip() for p in text.split("\n\n") if p.strip()]


def make_chunks(text: str, max_chars: int = MAX_CHARS, overlap: int = OVERLAP) -> list[str]:
    """把段落依序裝箱:裝不下就封箱,並把最後幾段帶進下一箱。"""
    chunks = []
    current = []
    for para in split_paragraphs(text):
        if current and len("\n\n".join(current + [para])) > max_chars:
            chunks.append("\n\n".join(current))
            current = current[-overlap:] if overlap else []
        current.append(para)
    if current:
        chunks.append("\n\n".join(current))
    return chunks


def load_chunks(folder: str = "docs") -> list[dict]:
    """讀取資料夾裡所有 .md 檔,切成塊並記下出處。"""
    results = []
    for path in sorted(Path(folder).glob("*.md")):
        lines = path.read_text(encoding="utf-8").splitlines()
        if not lines:
            continue
        title = lines[0].lstrip("#").strip()  # 第一行當作文件標題
        body = "\n".join(lines[1:])
        for i, chunk in enumerate(make_chunks(body)):
            results.append({
                "id": f"{path.name}#{i}",       # 例如 leave.md#0
                "source": path.name,
                "title": title,
                "text": f"【{title}】\n{chunk}",  # 每塊開頭都加上標題
            })
    return results


if __name__ == "__main__":
    for c in load_chunks():
        print(f"--- {c['id']}({len(c['text'])} 字)")
        print(c["text"])

執行:

python chunking.py

你會看到每一塊的編號、長度和內容。花一分鐘用眼睛讀一遍:每塊單獨看懂嗎?有沒有哪一塊只剩半句話?這個檢查比任何公式都重要。

逐段看懂

  • split_paragraphs:以「空行」作為段落的分界。Markdown 文件和多數文字檔都適用。
  • make_chunks:像在打包行李。把段落一段一段放進箱子,下一段放不下了就封箱,再把最後一段(OVERLAP)複製到新箱子裡,達成重疊。
  • load_chunks:每一塊都是一個字典,帶著 id、source、title。id 用「檔名#編號」,之後一看就知道出處。

切塊沒有標準答案

塊要多大、重疊多少,沒有放諸四海皆準的數字。不同文件、不同模型、不同問題,最佳值都不一樣。幾個起步的建議:

  • 先從段落組合開始,大小配合 embedding 模型的上限。
  • 表格、程式碼、條列清單盡量不要切開,切開後很難單獨看懂。
  • 文件很長、結構清楚(例如有很多二級標題),可以改成「每個標題一塊」。
  • 不確定時,選一個合理的設定先往下做。第五堂課會教你用測試題實際比較,讓數據告訴你哪個比較好,而不是靠感覺。
可以這樣問 AI

這是我的 chunking.py,會依照空行把 Markdown 文件切塊。請幫我新增一個選項:改成以「## 二級標題」為單位切塊,每塊開頭加上文件標題和該段的小標題,例如「【請假規定|病假】」。如果某個標題底下的內容超過 MAX_CHARS,再用原本的段落方式切。請保留原本的函式,讓我可以比較兩種切法。

行動練習
  1. 建立 docs 資料夾和三份手冊,執行 chunking.py,數數看總共切出幾塊。
  2. 用眼睛讀每一塊,找出一塊「單獨看不太懂」的,想想是切太小還是切錯位置。
  3. 執行上面的長度檢查程式,確認沒有塊超過模型上限。
  4. 把 OVERLAP 改成 0 再執行一次,比較前後的塊有什麼不同。
  5. 放一份你自己的文件進 docs(例如課程筆記或產品說明),看看這個切法適不適合它。

讀完了嗎?

標記完成後,單元與專案的進度會自動更新(只存在這台裝置的瀏覽器)。

卡住了?讓 AI 當你的家教複製這段提問範本,貼到 Claude 或其他 AI 工具,再補上你卡住的地方。

留言與討論

卡關了、有心得,或發現內容需要更新?都歡迎留言。留言使用 GitHub 帳號登入。

留言區即將開放。現在可以先到 GitHub 討論區 發問,或看看 交流頁 的其他管道。