Bỏ qua để đến nội dung
Search & RAG

Tầng 0 — Bài toán nền: vocabulary mismatch

Search không phải bài toán khớp chuỗi. Nó là bài toán khớp ý định với nội dung, và trở ngại trung tâm có tên: vocabulary mismatch — người hỏi và tài liệu dùng từ khác nhau cho cùng một khái niệm.

Ba họ biểu diễn, ba cách tấn công, ba điểm mù:

HọBiểu diễnMạnh
Lexical (BM25)vector thưa, chiều = từ vựng, giá trị = tf-idftừ khoá lạ, mã lỗi, tên riêng, số hiệudiễn đạt khác từ
Dense (embedding)vector đặc 256–4096 chiều, học đượcdiễn giải khác từ, đa ngôn ngữtừ khoá chính xác, số, định danh mới
Learned sparse (SPLADE)vector thưa trong không gian từ vựng, nhưng học đượclai hai bên: mở rộng từ đồng nghĩa mà vẫn giữ được tính khớp chính xácnặng hơn BM25, cần model

Điểm mù là đối xứng, không phải một bên tốt hơn. Đây là toàn bộ lý do hybrid tồn tại — không phải “cho chắc”, mà vì các điểm mù bổ trợ nhau.

idf(t)=ln ⁣(1+Ndf+0.5df+0.5)score(d)=tidf(t)tf(k1+1)tf+k1 ⁣(1b+bdlavgdl)\begin{aligned} \mathrm{idf}(t) &= \ln\!\left(1 + \frac{N - \mathrm{df} + 0.5}{\mathrm{df} + 0.5}\right) \\[4pt] \mathrm{score}(d) &= \sum_t \mathrm{idf}(t) \cdot \frac{tf\,(k_1+1)}{tf + k_1\!\left(1 - b + b\,\dfrac{dl}{avgdl}\right)} \end{aligned}

Ba thứ cần hiểu, không phải nhớ:

idf — từ xuất hiện ở ít tài liệu thì mang nhiều thông tin phân biệt hơn. Hệ quả trực tiếp: với BM25, đừng bỏ stopword. Từ xuất hiện ở gần mọi tài liệu có idf ≈ 0, tự động không đóng góp điểm. Đo thực tế: bỏ stopword làm lớp B tụt −11%, lớp C tụt −6.5%, lớp D không đổi. Bỏ stopword là di sản từ thời đếm-từ-thuần.

k1 — độ bão hoà tần suất. Phần tf(k1+1)/(tf + k1·…) tiến tới tiệm cận (k1+1) khi tf → ∞. Nghĩa là: nhắc 20 lần không liên quan gấp 20 lần nhắc 1 lần.

  • k1 = 0 → bỏ qua hoàn toàn tần suất, chỉ cần từ xuất hiện. Điểm thu về đúng bằng tổng idf. Thực nghiệm xác nhận đại số này: hàng k1=0 phẳng tuyệt đối qua mọi giá trị b (0.736 ở cả 5 cột) — vì khi k1=0, b mất hoàn toàn tác dụng.
  • k1 lớn → hành xử dần giống TF-IDF tuyến tính.

b — mức chuẩn hoá độ dài. b=0: không quan tâm dài ngắn (tài liệu dài thắng vì chứa nhiều từ hơn). b=1: chuẩn hoá tối đa. Trực giác chọn b: tài liệu dài vì nói nhiều chủ đềb cao (phạt mạnh). Tài liệu dài vì chi tiết về đúng một chủ đềb thấp.

Chunking (Tầng 5) chính là can thiệp vào biến số này ở tầng dữ liệu. Nếu bạn đã chunk tốt thì b bớt quan trọng; nếu chunk kém thì b là băng dán.

Grid k1×b đầy đủ, khoảng giá trị nên dùng, và checklist cấu hình BM25 cho tiếng Việt: 3.15.

Ba đoạn trên là phần đủ để dùng. Xuất xứ của công thức — mô hình xác suất, eliteness và 2-Poisson (vì sao bão hoà phải có tiệm cận), idf âm, tám biến thể BM25 đang lưu hành, và BM25F cho tài liệu nhiều field — ở 3.4b.

Bài học đắt nhất của tầng này: tokenizer ăn kiến trúc

Phần tiêu đề “Bài học đắt nhất của tầng này: tokenizer ăn kiến trúc”

Chỉ đổi tokenizer, giữ nguyên BM25: lớp A nDCG 0.804 → 0.971 (+20.8%). Đổi cả thuật toán TF-IDF → BM25: +1.2%. Tinh chỉnh (k1,b) tối ưu: +2.4%.

Tokenizer kiểu “làm sạch văn bản” ([^\W\d_]+) làm thế này:

'E2003' -> []
'POST /v1/transactions' -> ['post', 'transactions']
'uptime 99,9%' -> ['uptime']
'AES-256' -> ['aes']

Mã lỗi, số phiên bản, endpoint, định danh — bốc hơi khỏi index. Đây là loại lỗi tệ nhất: không exception, không log, hệ thống chỉ đơn giản không bao giờ tìm ra.

Đặc thù tiếng Việt: quyết định lượng hoá được

Phần tiêu đề “Đặc thù tiếng Việt: quyết định lượng hoá được”
indextruy vấnnDCG@5lớp C
có dấucó dấu0.7870.834
có dấukhông dấu0.6650.520
bỏ dấubất kỳ0.7660.803

Index bỏ dấu bất biến với việc user gõ dấu hay không, giá là −2.7% ở trường hợp lý tưởng. Index có dấu cao hơn nhưng sập −15.5% khi truy vấn mất dấu.

Điểm hoà vốn: gọi p là tỷ lệ truy vấn không dấu. 0.787 − 0.122p = 0.766p ≈ 17%.

Nên áp dụng vào AI Agent: đo p trên log truy vấn thật. Nó là một câu SQL và nó quyết định một thiết kế. Production đúng thì index cả hai dạng (field có dấu trọng số cao + field bỏ dấu trọng số thấp), không chọn một.

Phần 4 — Lý thuyết