Cover photo

Khi Donald Knuth Làm RAG: Tối Ưu Hóa Semantic Chunking Bằng Quy Hoạch Động

Bạn đã bao giờ tự hỏi: Tại sao hệ thống RAG (Retrieval-Augmented Generation) của mình thỉnh thoảng lại trả về những câu trả lời "ngơ ngác", thiếu đầu hụt đuôi, dù bạn đã dùng những mô hình LLM mạnh nhất và cơ sở dữ liệu vector xịn nhất?

Câu trả lời thường không nằm ở mô hình ngôn ngữ lớn (LLM) hay thuật toán tìm kiếm vector. Nó nằm ở bước thầm lặng, ít được chú ý nhưng lại là nền móng của toàn bộ hệ thống: Chunking (Phân mảnh tài liệu).

Hôm nay, chúng ta sẽ cùng nhau khám phá một phương pháp phân mảnh tài liệu đột phá: Semantic DP Chunking (Phân mảnh ngữ cảnh bằng Quy hoạch động). Điều kỳ diệu là giải pháp cho bài toán AI hiện đại này lại được tìm thấy trong một thuật toán có tuổi đời hơn nửa thế kỷ của giáo sư Donald Knuth dùng để sắp chữ trong hệ thống TeX huyền thoại.


Gót Chân Achilles Của RAG: Khi "Cắt Thô" Phá Nát Ngữ Cảnh

Thông thường, khi xây dựng hệ thống RAG, các nhà phát triển thường bắt đầu bằng hai phương pháp chunking truyền thống:

  1. Naive Character/Token Chunking (Cắt thô theo kích thước cố định): Ví dụ, cứ đúng 500 ký tự hoặc 256 tokens là "chặt" một nhát. Phương pháp này cực kỳ máy móc. Nó sẵn sàng chia đôi một câu văn cực kỳ quan trọng, chặt đứt mạch logic giữa chủ ngữ và vị ngữ, khiến vector embedding được tạo ra bị nhiễu nghiêm trọng.

  2. Greedy Semantic Chunking (Cắt ngữ cảnh tham lam): Thuật toán sẽ quét qua văn bản, tính toán độ tương đồng ngữ cảnh giữa các câu kề nhau. Ngay khi độ tương đồng này tụt xuống dưới một ngưỡng (threshold) nhất định, thuật toán sẽ quyết định cắt tại đó. Cách này khá hơn, nhưng nó mang tính cục bộ (local). Nó dễ rơi vào cái bẫy "tham lam" (greedy) — đưa ra quyết định cắt rất tốt ở hiện tại nhưng lại đẩy phần còn lại của tài liệu vào những mảnh cắt cực kỳ vụn vặt hoặc quá sát giới hạn kích thước ở phía sau.

Để giải quyết triệt để vấn đề này, chúng ta cần một góc nhìn tối ưu hóa toàn cục (global optimization). Đó là lúc Quy hoạch động (Dynamic Programming) bước lên sân khấu.


Từ Ý Tưởng Ngắt Dòng Của TeX Đến Phân Mảnh RAG Tối Ưu

Trong những năm 1970, khi Donald Knuth thiết kế hệ thống sắp chữ TeX, ông đối mặt với bài toán: Làm thế nào để ngắt một đoạn văn thành các dòng một cách đẹp mắt nhất?

Nếu xếp từ theo kiểu tham lam (cứ đầy dòng là xuống dòng), dòng cuối cùng có thể quá thưa thớt hoặc dòng hiện tại bị dồn nén. Knuth định nghĩa một khái niệm gọi là "độ xấu" (slop) của một dòng — tỷ lệ thuận với lập phương lượng khoảng trắng dư thừa. Mục tiêu của TeX là tìm cách ngắt toàn bộ đoạn văn sao cho tổng "độ xấu" của tất cả các dòng là nhỏ nhất. Ông đã giải bài toán này một cách hoàn hảo bằng Quy hoạch động.

Bài toán Chunking trong RAG hoàn toàn đồng cấu (isomorphic) với bài toán ngắt dòng của TeX!

Hãy tưởng tượng:

  • Từ trong TeX tương ứng với Đoạn văn (Paragraph) trong tài liệu RAG. (Chúng ta chọn đoạn văn làm đơn vị cơ sở thay vì câu, vì đoạn văn chứa một ý tưởng trọn vẹn và giải quyết tốt các vấn đề đại từ thay thế).

  • Dòng trong TeX tương ứng với Chunk (Phân mảnh) trong RAG.

  • Độ rộng dòng tối đa LL tương ứng với Giới hạn Token tối đa của Chunk.

  • "Độ xấu" (slop) của dòng tương ứng với Độ phạt ngữ cảnh (Semantic Penalty) khi chúng ta quyết định cắt đôi hai đoạn văn có liên kết chặt chẽ.


Mô Hình Toán Học: Ma Thuật Đằng Sau Quy Hoạch Động

Giả sử tài liệu của bạn gồm một chuỗi gồm $m$ đoạn văn P1,P2,,PmP_1, P_2, \dots, P_m. Mỗi đoạn văn PiP_i có độ dài ký tự là l[i]l[i]. Chúng ta cần chia tài liệu này thành các chunks sao cho độ dài mỗi chunk không vượt quá giới hạn tối đa LL.

Chúng ta định nghĩa bài toán con đệ quy:

Gọi MinCost(i)MinCost(i) là tổng chi phí tối ưu nhỏ nhất để phân mảnh phần tài liệu còn lại từ đoạn văn thứ PiP_i đến hết đoạn văn cuối cùng PmP_m.

Mục tiêu tối thượng của chúng ta là tính được MinCost(1)MinCost(1).

Áp dụng nguyên lý đệ quy thông minh (Smart Recursion) — bản chất của quy hoạch động là "đệ quy không lặp":

MinCost(i)={0neˆˊi>mminij<mLen(i,j)L{Cost(i,j)+MinCost(j+1)}khaˊcMinCost(i) = \begin{cases} 0 & \text{nếu } i > m \\\\ \min_{\substack{i \le j < m \\\\ \text{Len}(i, j) \le L}} \Big\{ Cost(i, j) + MinCost(j+1) \Big\} & \text{khác} \end{cases}

Trong đó:

  • Len(i,j)=k=ijl[k]\text{Len}(i, j) = \sum_{k=i}^j l[k] là tổng độ dài của các đoạn văn được gộp chung từ PiP_i đến PjP_j.

  • Cost(i,j)Cost(i, j)Hàm chi phí toàn cục, được thiết kế tinh tế để cân bằng giữa cấu trúc ngữ cảnh và kích thước mảnh:

Cost(i,j)=αSimilarity(Pj,Pj+1)+β(1.0Len(i,j)L)2Cost(i, j) = \alpha \cdot \text{Similarity}(P_j, P_{j+1}) + \beta \cdot \left(1.0 - \frac{\text{Len}(i, j)}{L}\right)^2

Giải mã hai thành phần của Hàm Chi Phí:

  1. Phạt Ngữ Cảnh (α\alpha - Semantic Penalty): Chúng ta đo lường độ tương đồng ngữ cảnh (ví dụ: Cosine Similarity trên đặc trưng TF-IDF hoặc Dense Vectors) giữa đoạn văn cuối của chunk hiện tại (PjP_j) và đoạn văn đầu của chunk tiếp theo (Pj+1P_{j+1}). Nếu hai đoạn văn này kề sát nhau và có tương đồng rất cao, việc cắt đôi chúng sẽ tạo ra một vết đứt ngữ cảnh nghiêm trọng \rightarrow thuật toán sẽ bị phạt cực kỳ nặng (α\alpha lớn). Ngược lại, nếu chúng thuộc hai chủ đề khác nhau, độ tương đồng gần bằng 0 \rightarrow chi phí cắt tại đây gần như bằng 0, thuật toán sẽ được khuyến khích cắt tại ranh giới tự nhiên này.

  2. Phạt Kích Thước (β\beta - Size Penalty): Nhóm các đoạn văn quá ngắn sẽ lãng phí tài nguyên và làm tăng số lượng vector truy vấn. Do đó, chúng ta phạt các chunk có kích thước quá nhỏ so với giới hạn lý tưởng LL bằng một hàm bình phương.


Tiến Thêm Một Bước: Tích Hợp Cơ Chế Gối Đầu (Overlap) Thông Minh

Trong RAG, cơ chế gối đầu (overlap) giữa các chunk là cực kỳ quan trọng để đảm bảo không có thông tin nào bị bỏ lỡ ở ranh giới cắt. Nhưng làm thế nào để tích hợp overlap vào một thuật toán Quy hoạch động vốn hoạt động theo tuyến tính một chiều mà không gây ra vòng lặp vô hạn?

Giải pháp toán học cực kỳ thanh lịch:

Khi quyết định gộp các đoạn văn từ PiP_i đến PjP_j thành một chunk, mảnh tiếp theo sẽ không bắt đầu từ Pj+1P_{j+1} nữa, mà bắt đầu lùi lại từ đoạn văn thứ nextstart=jO+1next_{\text{start}} = j - O + 1 (với OO là số lượng đoạn văn muốn gối đầu).

Để đảm bảo thuật toán luôn tiến về phía trước và không bị lặp vô hạn, ta áp dụng điều kiện bắt buộc: jO+1i+1    ji+Oj - O + 1 \ge i + 1 \implies j \ge i + O

Công thức Quy hoạch động có overlap hoàn chỉnh trở thành:

MinCost(i)=minij<mLen(i,j)Lj=m1 or ji+O{Cost(i,j)+MinCost(jO+1)}MinCost(i) = \min_{\substack{i \le j < m \\\\ \text{Len}(i, j) \le L \\\\ j = m-1 \text{ or } j \ge i + O}} \Big\{ Cost(i, j) + MinCost(j - O + 1) \Big\}


Kết Quả Thực Nghiệm: Sự Khác Biệt Giữa "Cắt Thô" và "Cắt Tối Ưu"

Hãy cùng xem thuật toán này thể hiện ra sao trên một tài liệu thực tế tổng hợp kiến thức từ giáo trình thuật toán quy hoạch động:

Kịch bản thử nghiệm:

  • Tài liệu đầu vào: Gồm 10 đoạn văn lớn bao quát các chủ đề từ Dãy Fibonacci, Phân mảnh văn bản, Khoảng cách biến đổi đến DP trên cây.

  • Giới hạn kích thước tối đa (LL): 1000 ký tự.

1. Kết quả từ Naive Paragraph Chunking (Gộp tham lam):

Phương pháp này gộp liên tục các đoạn văn từ trái sang phải cho đến khi việc thêm đoạn tiếp theo vượt quá 1000 ký tự thì ngắt.

  • Điểm cắt thảm họa: Thuật toán Naive quyết định ngắt ngay sau đoạn văn P2 (Tính toán dư thừa) vì nếu gộp thêm đoạn P3 (Kỹ thuật ghi nhớ - Memoization) thì kích thước sẽ là 1250 ký tự (vượt ngưỡng 1000).

  • Hậu quả: Ý tưởng cốt lõi "Giải quyết sự dư thừa của đệ quy bằng kỹ thuật ghi nhớ" bị chia cắt làm hai mảnh độc lập. Khi người dùng tìm kiếm về "cách giải quyết đệ quy dư thừa bằng memoization", hệ thống RAG sẽ chỉ truy xuất được một trong hai đoạn, khiến câu trả lời của LLM bị mất đầu hoặc mất đuôi!

2. Kết quả từ Semantic DP Paragraph Chunking:

Thuật toán Quy hoạch động phân tích toàn cục toàn bộ tài liệu:

  • Quyết định thông minh: Thuật toán phát hiện độ tương đồng ngữ cảnh giữa P2P3 cực kỳ cao. Thay vì cắt ngay lập tức như Naive, DP chấp nhận chịu phạt kích thước một chút để gộp cả P2 và P3 vào Chunk #1 (với tổng kích thước 845 ký tự - hoàn toàn nằm trong giới hạn 1000).

  • Điểm cắt hoàn hảo: Thuật toán quyết định cắt tại ranh giới giữa P4 (Hệ khuôn mẫu DP của Bellman)P5 (Bài toán phân mảnh văn bản). Tại đây, độ tương đồng ngữ cảnh tụt xuống chỉ còn 0.026 (một sự dịch chuyển chủ đề rõ rệt từ lý thuyết chung sang bài toán cụ thể). Điểm cắt này có chi phí phạt ngữ cảnh gần như bằng 0!


Kết Luận: Đừng Chỉ "Cắt", Hãy "Tối Ưu Hóa"!

Quy hoạch động không phải là một lý thuyết toán học khô khan bị bỏ quên trong những cuốn giáo trình thuật toán dày cộp của Richard Bellman. Trong kỷ nguyên của Trí tuệ nhân tạo, nó chính là chiếc chìa khóa vàng giúp chúng ta thiết kế các hệ thống xử lý dữ liệu thông minh hơn, mạch lạc hơn và hiệu quả hơn.

Bằng cách chuyển đổi từ phân mảnh thô (Naive Chunking) sang Semantic DP Paragraph Chunking, bạn đang cung cấp cho hệ thống RAG của mình những mảnh tri thức toàn vẹn về mặt ngữ cảnh, giúp mô hình ngôn ngữ lớn (LLM) phát huy 100% sức mạnh để đưa ra những câu trả lời chính xác và sắc bén nhất.

Hãy thử áp dụng Quy hoạch động vào pipeline RAG của bạn ngay hôm nay và chia sẻ kết quả ở phần bình luận phía dưới nhé!