你不能把一整本字典塞進 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!不管是 PyPDFLoader、Docx2txtLoader 還是 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 函式,完成以下「知識加工」流程:
- 使用
PyPDFLoader來載入這個 PDF 檔案。- 使用
RecursiveCharacterTextSplitter來切割文件。- 切割的參數設定為:每個 Chunk 的大小 (chunk_size) 為 1000 個字元,重疊字數 (chunk_overlap) 為 200 個字元。
- 最後印出「總共切成了多少個 Chunks (肉塊)」,並印出「第一塊肉塊的內容」讓我檢查。
- 確保程式碼結構乾淨,並附上中文註解。
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 問答機器人!