簡介
RAG 管道從 資料 開始 - 資料可以是 任何格式:PDF、Word、網頁、YouTube 影片、程式碼儲存庫...本課程教您如何 載入 所有常見文件類型到 RAG 管道中。
規則: 垃圾輸入 = 垃圾輸出。文檔載入高品質 = RAG 高品質。
1. 文件載入器概述
1.1 熱門資料來源
| 來源 | 格式 | 挑戰 |
|---|---|---|
| 表格、圖形、多列、掃描 | ||
| 字 | .docx、.doc | 格式、頁首/頁尾 |
| 網頁 | HTML | JavaScript 渲染,噪音 |
| YouTube | 影片/音訊 | 需要成績單、時間戳記 |
| 程式碼儲存庫 | .py、.js、.md | 結構、依賴關係 |
| CSV/Excel | .csv、.xlsx | 表格資料→文字 |
| 資料庫 | SQL | 查詢、模式理解 |
1.2 LangChain文件載入器
LangChain提供了豐富的文件載入器生態系統:
from langchain_community.document_loaders import (
PyPDFLoader, # PDF
Docx2txtLoader, # Word
WebBaseLoader, # Web pages
YoutubeLoader, # YouTube
GitLoader, # Git repos
CSVLoader, # CSV files
TextLoader, # Plain text
UnstructuredExcelLoader, # Excel
)
2. PDF — 最受歡迎的文件類型
2.1 PyPDFLoader — 基礎知識
"""Load PDF đơn giản nhất — PyPDFLoader"""
from langchain_community.document_loaders import PyPDFLoader
# Load từng trang
loader = PyPDFLoader("company_handbook.pdf")
pages = loader.load()
print(f"Số trang: {len(pages)}")
for i, page in enumerate(pages[:3]):
print(f"\n--- Trang {i+1} ---")
print(f"Nội dung: {page.page_content[:200]}...")
print(f"Metadata: {page.metadata}")
# metadata = {"source": "company.pdf", "page": 0}
2.2 進階 PDF — 處理表格和圖形
PyPDF 很簡單,但在表格和圖形方面弱。對複雜的 PDF 使用 非結構化:
"""Unstructured: xử lý PDF phức tạp (bảng, hình, multi-column)"""
from langchain_community.document_loaders import UnstructuredPDFLoader
# Partition strategy: "hi_res" cho chất lượng cao
loader = UnstructuredPDFLoader(
"financial_report.pdf",
mode="elements", # Tách từng element (text, table, image)
strategy="hi_res", # OCR + layout analysis
)
elements = loader.load()
# Lọc theo loại element
for elem in elements[:10]:
elem_type = elem.metadata.get("category", "unknown")
print(f"[{elem_type}] {elem.page_content[:100]}...")
2.3 比較 PDF 載入器
| 裝載機 | 表 | 圖 | OCR(掃描) | 速度 | 設定 |
|---|---|---|---|---|---|
| PyPDFLoader | ❌ | ❌ | ❌ | ⚡ 快 | pip install pypdf |
| PyMuPDFLoader | ⚠️ | ❌ | ❌ | ⚡ 快 | pip install pymupdf |
| 非結構化PDFLoader | ✅ | ✅ | ✅ | 🐢 慢 | pip install unstructured[pdf] |
| 亞馬遜 Textract | ✅ | ✅ | ✅ | ⚡ | AWS 帳號 |
建議: 從 PyPDFLoader 開始。如果 PDF 包含表格/圖形,請使用 非結構化。
3. 網頁
3.1 載入網站
"""Load nội dung từ trang web"""
from langchain_community.document_loaders import WebBaseLoader
# Load 1 trang
loader = WebBaseLoader("https://blog.xdev.asia/ai/")
docs = loader.load()
print(f"Content length: {len(docs[0].page_content)} chars")
print(docs[0].page_content[:500])
# Load nhiều trang
urls = [
"https://blog.xdev.asia/blog/post-1",
"https://blog.xdev.asia/blog/post-2",
"https://blog.xdev.asia/blog/post-3",
]
loader = WebBaseLoader(urls)
docs = loader.load()
print(f"Loaded {len(docs)} pages")
3.2 爬取網站(網站地圖)
"""Crawl tất cả trang từ sitemap"""
from langchain_community.document_loaders.sitemap import SitemapLoader
loader = SitemapLoader(
web_path="https://blog.xdev.asia/sitemap.xml",
filter_urls=["https://blog.xdev.asia/blog/"], # Chỉ blog
)
docs = loader.load()
print(f"Crawled {len(docs)} pages from blog")
4. YouTube 腳本
"""Load transcript từ YouTube video"""
from langchain_community.document_loaders import YoutubeLoader
# Load transcript (auto-generated hoặc manual)
loader = YoutubeLoader.from_youtube_url(
"https://www.youtube.com/watch?v=dQw4w9WgXcQ",
add_video_info=True, # Thêm title, description
language=["vi", "en"], # Ưu tiên tiếng Việt
)
docs = loader.load()
print(f"Title: {docs[0].metadata.get('title')}")
print(f"Duration: {docs[0].metadata.get('length')} seconds")
print(f"Transcript: {docs[0].page_content[:300]}...")
5. 程式碼儲存庫
"""Load code từ Git repo"""
from langchain_community.document_loaders import GitLoader
# Clone + load tất cả files
loader = GitLoader(
clone_url="https://github.com/user/project",
repo_path="./temp_repo",
branch="main",
file_filter=lambda f: f.endswith((".py", ".md", ".yaml")),
)
docs = loader.load()
print(f"Loaded {len(docs)} files")
for doc in docs[:5]:
print(f" {doc.metadata['file_path']} ({len(doc.page_content)} chars)")
6. 批次處理-處理多個文件
6.1 載入資料夾
"""Load tất cả tài liệu trong folder"""
from langchain_community.document_loaders import DirectoryLoader, PyPDFLoader
from pathlib import Path
# Load tất cả PDF trong folder
loader = DirectoryLoader(
"./company_docs/",
glob="**/*.pdf", # Recursive, chỉ PDF
loader_cls=PyPDFLoader,
show_progress=True,
use_multithreading=True, # Parallel loading
)
docs = loader.load()
print(f"Loaded {len(docs)} pages from PDF files")
# Thêm custom metadata
for doc in docs:
filename = Path(doc.metadata["source"]).stem
doc.metadata["department"] = "HR" if "hr" in filename.lower() else "General"
doc.metadata["doc_type"] = "policy"
6.2 多格式載入器
"""Unified loader cho nhiều format"""
from langchain_community.document_loaders import (
PyPDFLoader, Docx2txtLoader, TextLoader, CSVLoader
)
from pathlib import Path
def load_document(file_path: str):
"""Load document dựa trên extension."""
ext = Path(file_path).suffix.lower()
loaders = {
".pdf": PyPDFLoader,
".docx": Docx2txtLoader,
".txt": TextLoader,
".md": TextLoader,
".csv": CSVLoader,
}
loader_cls = loaders.get(ext)
if not loader_cls:
raise ValueError(f"Unsupported format: {ext}")
return loader_cls(file_path).load()
# Usage
all_docs = []
for f in Path("./docs/").glob("**/*"):
if f.suffix in [".pdf", ".docx", ".txt", ".md", ".csv"]:
try:
docs = load_document(str(f))
all_docs.extend(docs)
print(f"✅ {f.name}: {len(docs)} chunks")
except Exception as e:
print(f"❌ {f.name}: {e}")
print(f"\nTotal: {len(all_docs)} documents loaded")
💡練習 6: 編寫一個腳本來載入資料夾中的所有文件(混合 PDF + DOCX + TXT)。列印輸出:檔案名稱、頁數/區塊數、總字元數。優雅地處理錯誤。
7. 提示與最佳實踐
| 提示 | 說明 |
|---|---|
| 裝載前清潔 | 刪除頁首/頁尾、頁碼、浮水印 |
| 新增元資料 | 來源、日期、類別-用於稍後過濾 |
| 處理編碼 | 越南語:UTF-8。查看 chardet 如果未知 |
| 批次 | 對大型資料夾(100+ 個檔案)使用多執行緒 |
| 測試品質 | 裝載後抽查 10% 文件 |
| 錯誤處理 | 日誌檔已損壞,不要默默跳過 |
總結
| 來源 | 裝載機 | 筆記 |
|---|---|---|
| PyPDFLoader / 非結構化 | 非結構化表格/數字 | |
| 網頁 | WebBaseLoader / 網站地圖載入器 | 透過網站地圖抓取整個網站 |
| YouTube | YoutubeLoader | 自動轉錄 + 元資料 |
| 程式碼 | GitLoader | 副檔名檔案過濾器 |
| 資料夾 | 目錄載入器 | 多執行緒、遞迴 |
一般練習
- ✅ 完成小練習(6)
- 建立攝取管道: 編寫函數
ingest(folder_path)載入資料夾中的所有檔案 → 傳回包含完整元資料的文件清單。 - PDF基準: 拍攝一個複雜的PDF(有表格+圖片)。比較 PyPDFLoader 與非結構化之間的輸出。品質有何不同?
- 網路爬蟲: 從喜愛的網站爬取 10 篇部落格文章 → 載入到 ChromaDB → 建立「與部落格聊天」。
下一篇文章: 分塊策略 — 如何將文件分割為最佳區塊以供檢索。