你不能把一整本字典塞進 AI 的嘴巴裡

在了解了向量資料庫 (Vector DB) 的威力後,老闆很開心地把公司過去十年來的所有產品型錄、員工手冊、報表,總共 1000 個 PDF 檔案交給你,說:「把它們全部變成向量存進資料庫吧!」

如果你打開其中一本 500 頁的 PDF,試圖直接把它丟給 OpenAI 進行 Embedding,會發生什麼事? OpenAI 會立刻噴出一個紅色的錯誤畫面:TokenLimitExceeded (超過字數上限)

不管是做 Embedding,還是把文章丟給 ChatGPT 閱讀,每一家 AI 模型都有它大腦容量的極限 (我們稱為 Context Window,上下文窗口)。 就算現在有些模型號稱可以吃下 10 萬個字,如果你真的把整本 500 頁的說明書丟給它,然後問它「第 234 頁的保固條款是什麼?」,它也會因為資訊量太大而「失焦」,忽略掉細節,這在 AI 界被稱為 「Lost in the middle (迷失在中間)」 效應。

因此,在 RAG 系統中,我們有一個絕對的鐵則: 「在把文件丟給 AI 之前,必須先把它切成一塊一塊的『小肉丁』(Chunks)!」

這就像是你餵小孩吃牛排,你不能整塊牛排塞進去,你必須切成一口大小。


知識加工生產線的兩道關卡

LangChain 為我們準備了最完美的自動化生產線工具,總共分為兩道工序:

第一道工序:Document Loaders (文件載入器)

這是一群專門幫你「把各種格式的檔案,統一轉換成純文字」的機器人。 在公司裡,資料可能藏在 PDF 裡、Word 檔裡、甚至是一個 Notion 網頁裡。 LangChain 提供了超過 100 種的 Loaders!不管是 PyPDFLoaderDocx2txtLoader 還是 WebBaseLoader,你只要呼叫它,它就能把這些檔案裡面的文字扒得乾乾淨淨,變成乾淨的 Python 字串。

第二道工序:Text Splitters (文字切割器)

文字被扒乾淨後,接下來要進入這台「切肉機」。 如果我們只規定「每 500 個字切一刀」,那可能會發生慘劇。比如一句話是「極速旋風 3000 型的保固期為十年」,結果剛好在 500 字的時候,刀子切在「保固」中間,變成:

  • 肉塊 A:...極速旋風 3000 型的保
  • 肉塊 B:固期為十年...

如果這樣切,這兩塊肉丁的語意就全毀了!AI 看了也會一頭霧水。 所以 LangChain 提供了一個極度聰明的切肉機叫做 RecursiveCharacterTextSplitter。 它在切的時候,會盡量「以段落 (換行符號)」或「句號」為優先切割點。如果字數不夠切,它還會加上 Overlap (重疊區塊)。也就是說,肉塊 A 的結尾,會跟 肉塊 B 的開頭有一小段文字是重複的,確保語意不會被硬生生切斷。


Vibe Prompt 實戰:打造你的自動化切肉機

這段處理資料的程式碼,如果手寫會非常繁瑣,但我們只要對著 AI 詠唱,幾秒鐘就能搞定。

【RAG 文件處理自動化 Prompt】 我正在使用 LangChain 開發 RAG 系統。 我有一個名為 company_manual.pdf 的檔案。 請幫我寫一個 Python 函式,完成以下「知識加工」流程:

  1. 使用 PyPDFLoader 來載入這個 PDF 檔案。
  2. 使用 RecursiveCharacterTextSplitter 來切割文件。
  3. 切割的參數設定為:每個 Chunk 的大小 (chunk_size) 為 1000 個字元,重疊字數 (chunk_overlap) 為 200 個字元。
  4. 最後印出「總共切成了多少個 Chunks (肉塊)」,並印出「第一塊肉塊的內容」讓我檢查。
  5. 確保程式碼結構乾淨,並附上中文註解。

AI 產出的知識加工腳本:

from langchain_community.document_loaders import PyPDFLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter

def process_pdf_document():
    file_path = "company_manual.pdf"
    print(f"正在載入文件:{file_path} ...")
    
    try:
        # 第一道工序:呼叫 PDF 載入器,把整本 PDF 讀進來
        loader = PyPDFLoader(file_path)
        documents = loader.load()
        print(f"✅ PDF 載入成功!總共包含 {len(documents)} 頁。")
        
        # 第二道工序:設定一台聰明的文字切割機
        # chunk_size=1000 代表每一塊肉丁大約 1000 個字
        # chunk_overlap=200 代表每塊肉丁之間會有 200 個字的重疊,防止語意斷裂
        text_splitter = RecursiveCharacterTextSplitter(
            chunk_size=1000,
            chunk_overlap=200,
            separators=["\n\n", "\n", "。", "!", " ", ""] # 優先在段落或句號的地方下刀
        )
        
        # 把剛剛讀進來的 PDF 丟進切肉機!
        print("正在進行文字切割...")
        chunks = text_splitter.split_documents(documents)
        
        # 展現成果
        print("=========================================")
        print(f"✅ 加工完成!這本 PDF 被精準地切成了 {len(chunks)} 個小區塊 (Chunks)。")
        print("=========================================")
        print("【試吃第一塊肉丁的內容】:")
        print(chunks[0].page_content)
        
        # 在真實的 RAG 專案中,我們接下來就會把這些 chunks 送去 Embedding,然後存進 Chroma 資料庫。
        return chunks
        
    except Exception as e:
        print(f"🚨 處理文件時發生錯誤:{e}")

# 執行函式 (假設你的資料夾裡真的有 company_manual.pdf)
# chunks = process_pdf_document()

只要跑完這段程式碼,那厚達幾百頁、充滿機密的 PDF 說明書,就會完美地變成幾千個整整齊齊、長度適中、語意完整的「文字小積木」。

現在,我們有了小積木,也有了上一章學過的 Embedding 技術。 在下一章,我們將迎來最令人興奮的高潮:把所有的積木串接在一起,召喚出最終極的 RAG 問答機器人!

解鎖完整教學內容

本章為付費內容。加入專案即可解鎖超過 5000 字的深度解析,包含 10 個以上神級 Prompt 與真實 Source Code 範例!