Nguyên tắc: cắt theo cấu trúc của tài liệu trước, cắt theo độ dài sau. Cắt cứng theo số ký tự sẽ chia đôi một bảng hoặc một khối code, và cả hai mảnh đều trở nên vô nghĩa khi truy xuất.
Thứ tự ưu tiên khi tách:
- Theo heading (Markdown #, thẻ <h1>/<h2> của HTML): mỗi mục thành một nhóm, giữ đường dẫn heading cha trong metadata.
- Theo khối nguyên vẹn: bảng, code fence, danh sách đánh số không được cắt giữa chừng.
- Cuối cùng mới theo độ dài với bộ tách đệ quy (thử ngắt ở đoạn văn, rồi câu, rồi từ).
from langchain_text_splitters import MarkdownHeaderTextSplitter, RecursiveCharacterTextSplitter
header_splitter = MarkdownHeaderTextSplitter(
headers_to_split_on=[("#", "h1"), ("##", "h2")]
)
sections = header_splitter.split_text(doc)
# only sections still too long get a length-based second pass
splitter = RecursiveCharacterTextSplitter(chunk_size=800, chunk_overlap=120)
chunks = splitter.split_documents(sections)Hai điểm hay bị bỏ sót: overlap khoảng 10-15% để câu bị cắt ở biên vẫn xuất hiện đủ ở một chunk, và prepend tiêu đề mục vào nội dung chunk để chunk tự đứng được khi bị lấy ra khỏi ngữ cảnh.