Product Management
Đăng nhập
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Bài 3 — Chunking: cắt tài liệu đúng cách

Đã đọc 0/9 mục · còn khoảng 3 phút
Cách chúng tôi ghi nhận

Một mục được tính là đã đọc khi nó nằm giữa màn hình đủ lâu so với độ dài của nó (bảng và sơ đồ tính một nửa), bạn vẫn đang cuộn hoặc bấm phím, và bạn đã thấy tới cuối mục. Lướt nhanh hoặc để tab mở không được tính. Chúng tôi chỉ lưu thời gian đọc từng mục — không lưu gì khác.

Chunking là khâu quyết định chất lượng RAG nhiều nhất nhưng lại hay bị làm ẩu. Nếu chunk quá to, retrieval trả về đoạn dài loãng thông tin; nếu quá nhỏ, mất ngữ cảnh, câu trả lời rời rạc. Bài này dạy cắt tài liệu để mỗi chunk là một "đơn vị ý nghĩa" trọn vẹn.

Nguyên tắc vàng

Một chunk tốt = đủ ngữ cảnh để tự trả lời một câu hỏi, nhưng không lẫn nhiều chủ đề. Mục tiêu: khi retrieval kéo chunk này ra, LLM đọc là đủ hiểu.

Các chiến lược chunking

  • Fixed-size (theo số token): cắt mỗi 300–500 token. Đơn giản, nhanh, nhưng cắt giữa câu, giữa ý.
  • Theo cấu trúc (structure-aware): cắt theo tiêu đề, đoạn, mục — giữ nguyên ranh giới ngữ nghĩa. Tốt nhất cho tài liệu có heading.
  • Recursive: thử cắt theo đoạn trước, nếu vẫn dài thì cắt theo câu, cuối cùng mới cắt cứng.
  • Semantic chunking: dùng embedding phát hiện chỗ chủ đề đổi để cắt. Chất lượng cao, tốn tính toán.

Overlap — chồng lấn giữa các chunk

Để tránh mất ngữ cảnh ở ranh giới, cho các chunk chồng lấn 10–20%. Ví dụ chunk 500 token, overlap 75 token: câu bị cắt ở cuối chunk A vẫn xuất hiện đầu chunk B.

Ví dụ cụ thể

Tài liệu quy chế có đoạn:

> "4.2 Quy đổi phép năm. Nhân viên có phép năm chưa dùng được quy đổi tối đa 5 ngày thành tiền, tính theo lương cơ bản. Phần vượt quá 5 ngày sẽ bị hủy vào 31/12."

  • Chunk xấu (fixed-size cắt cứng): dừng ở "quy đổi tối đa 5 ngày thành" → mất phần "tính theo lương cơ bản", agent trả lời thiếu.
  • Chunk tốt (structure-aware): giữ trọn mục 4.2 làm một chunk → agent trả lời đầy đủ.

Các bước triển khai

  • Trích xuất text sạch từ PDF/HTML, giữ lại tiêu đề mục.
  • Cắt recursive theo separator ưu tiên: \n\n (đoạn) → \n → . → space.
  • Gắn tiêu đề mục vào đầu mỗi chunk (contextual header) để chunk tự mang ngữ cảnh:
def chunk_with_header(section_title, body, size=500, overlap=75):
    words = body.split()
    chunks, i = [], 0
    while i < len(words):
        piece = " ".join(words[i:i+size])
        chunks.append(f"[{section_title}] {piece}")
        i += size - overlap
    return chunks
  • Đo độ dài mỗi chunk bằng đúng tokenizer của embedding model, không đếm từ thô.
  • Kiểm tra thủ công 10 chunk ngẫu nhiên: mỗi cái có tự đứng vững không?

Chọn kích thước theo loại tài liệu

Loại tài liệuKích thước gợi ý
FAQ, Q&A ngắn100–200 token, mỗi Q&A một chunk
Tài liệu chính sách300–500 token theo mục
Bài kỹ thuật dài500–800 token + overlap
Code / API docsTheo hàm/endpoint

Checklist chunking

  • [ ] Đo kích thước bằng tokenizer thật, không bằng ký tự.
  • [ ] Có overlap 10–20% ở ranh giới.
  • [ ] Mỗi chunk mang theo tiêu đề/ngữ cảnh nguồn.
  • [ ] Không cắt giữa bảng, giữa đoạn code, giữa câu quan trọng.
  • [ ] Đã đọc tay 10 chunk mẫu và thấy chúng "tự đứng được".

Sai lầm thường gặp

  • Chunk quá to (2000+ token): retrieval trả về đúng nhưng LLM phải lọc trong biển chữ, dễ bỏ sót.
  • Chunk quá nhỏ, không overlap: mất ngữ cảnh, đại từ "nó", "khoản này" mất tham chiếu.
  • Cắt cứng theo ký tự giữa từ tiếng Việt có dấu → hỏng token.
  • Không gắn header: chunk "tối đa 5 ngày" không nói rõ 5 ngày của cái gì → retrieval kém.
  • Một size cho mọi loại tài liệu: FAQ và hợp đồng cần chiến lược khác nhau.
Bài 4 ta chuyển sang khâu retrieval và cách đo recall@k.

Học xong bài này rồi? Tạo tài khoản miễn phí để lưu lại — lần sau vào là biết ngay đang dở ở đâu, và học hết khóa thì có chứng chỉ. Lưu tiến độ của tôi