5.6 Late interaction: mua tương tác bằng dung lượng index
5.2 đặt ra một trục: tương tác giữa truy vấn và tài liệu bị đẩy sớm (bi-encoder, một vector cho cả tài liệu) hay muộn (cross-encoder, không có vector nào). Late interaction là điểm ở giữa, và nó là một điểm được thiết kế cẩn thận chứ không phải một sự thoả hiệp cẩu thả.
Ý tưởng: một vector cho mỗi token
Phần tiêu đề “Ý tưởng: một vector cho mỗi token”Bi-encoder: tài liệu ──► [một vector 768 chiều]Late interaction: tài liệu ──► [v₁][v₂][v₃]…[v₂₀₀] ← một vector cho MỖI tokenCross-encoder: tài liệu ──► không vector nào, phải có truy vấn mới tính đượcCác vector token tính trước được (không cần biết truy vấn), nên vẫn index được như bi-encoder. Nhưng lúc truy vấn, thay vì một phép nhân vô hướng, bạn cho các token gặp nhau bằng MaxSim:
Đọc bằng lời: với mỗi token của câu hỏi, tìm token khớp nhất trong tài liệu, rồi cộng lại. Mỗi token của truy vấn được “khớp mềm” vào chỗ tốt nhất của nó trong tài liệu.
Đó là thứ mà một vector duy nhất không làm được. Với câu hỏi “tiền đã bị trừ mà đơn
không thành công”, token trừ tìm được hoàn, token thất bại tìm được không thành công — mỗi từ tự tìm chỗ neo của nó, thay vì cả câu bị nén thành một điểm.
Cái giá: index
Phần tiêu đề “Cái giá: index”Đây là chỗ phải nhìn số. ColBERT bản gốc, trên MS MARCO (8,8 triệu đoạn):
| Cấu hình | Dung lượng index |
|---|---|
| 128 chiều × 4 byte/chiều | 286 GiB |
| 24 chiều × 2 byte/chiều | 27 GiB — mất khoảng 1% chất lượng |
Hai dòng đó nói hai điều. Thứ nhất: mặc định thì late interaction rất tốn — 286 GiB cho một corpus mà bi-encoder xử lý trong vài chục GB. Thứ hai: phần lớn chi phí đó mua lại được bằng giảm chiều và quantize, với tổn thất nhỏ. Toàn bộ dòng nghiên cứu sau ColBERT là về việc đó.
Ba đợt tối ưu, và số của từng đợt
Phần tiêu đề “Ba đợt tối ưu, và số của từng đợt”ColBERTv2 (2021) — nén dư (residual compression) quanh các centroid: giảm dung lượng của late interaction 6–10× so với bản gốc.
PLAID (2022) — engine phục vụ, cắt tỉa theo centroid trước khi chấm điểm đầy đủ.
MS MARCO v1, k = 1000:
| Phần cứng | ColBERTv2 | + PLAID |
|---|---|---|
| GPU | 259,6 ms | 38,4 ms |
| CPU 8 luồng | 4568,5 ms | 101,3 ms |
| CPU 1 luồng | 3485,1 ms | 352,3 ms |
Nhìn dòng giữa: 4,5 giây → 0,1 giây trên CPU, không mất chất lượng. Đó là khác biệt giữa “không dùng được ngoài GPU” và “dùng được”. Dung lượng index cùng lúc đó: 21,6 GiB (PLAID) so với 24,6 GiB.
ConstBERT (ECIR 2025) — bỏ luôn ràng buộc một vector mỗi token, học một số vector cố định cho mỗi tài liệu. MS MARCO:
| Model | Index | MRR@10 |
|---|---|---|
| ColBERT | 22 G | 39,99 |
| ConstBERT (32 vector/doc) | 11 G | 39,04 |
| ConstBERT (16 vector/doc) | 5 G | 37,84 |
| ConstBERT (128 vector/doc) | 40 G | 39,53 |
Một nửa dung lượng cho gần một điểm MRR@10. Và đường cong này là thứ bạn nên nhớ về late interaction nói chung: có một núm đánh đổi liên tục giữa dung lượng và chất lượng, và nó khá phẳng ở giữa.
MUVERA (NeurIPS 2024) — tấn công từ phía phục vụ: mã hoá đa vector thành một vector chiều cố định sao cho inner product xấp xỉ độ tương đồng đa vector, để dùng lại được hạ tầng MIPS/ANN một-vector có sẵn. Báo cáo: cùng recall với các heuristic trước đó nhưng lấy về ít ứng viên hơn 2–5×, và đo đầu-cuối là recall cao hơn 10% với độ trễ thấp hơn 90%.
Late interaction có còn đắt không? Hai số nói ngược lại
Phần tiêu đề “Late interaction có còn đắt không? Hai số nói ngược lại”Hai dữ kiện làm suy yếu ấn tượng “ColBERT là thứ xa xỉ”:
answerai-colbert-small-v1: một ColBERT 33 triệu tham số vượt ColBERTv2 gốc (110M) trên toàn bộ benchmark được thử, kể cả các tập chưa từng thấy như LoTTe.- Jina-ColBERT-v2: late interaction đa ngữ 14 thứ tiếng, huấn luyện với loss kiểu Matryoshka nên cắt chiều token sau khi huấn luyện được: giảm 128 → 64 chiều (một nửa dung lượng) chỉ mất 0,01 nDCG@10 (1,59% tương đối). BEIR trung bình 53,1 so với ColBERTv2 49,6; MIRACL 19 thứ tiếng 62,3.
Dòng thứ hai đáng chú ý với người làm tiếng Việt: đây là một trong ít model late interaction công khai được huấn luyện đa ngữ tử tế.
Và lĩnh vực này vẫn đang chạy: ECIR 2026 có workshop riêng cho late interaction và multi-vector retrieval.
Nó là stage 1 hay stage 2?
Phần tiêu đề “Nó là stage 1 hay stage 2?”Chỗ dễ lẫn nhất về ColBERT, nên nói thẳng: cả hai, và bạn phải chọn.
| Cách dùng | Nghĩa là | Đánh đổi |
|---|---|---|
| Stage 1 (end-to-end retrieval) | Index toàn corpus dưới dạng đa vector, tìm trực tiếp trên đó | Recall tốt hơn bi-encoder. Trả bằng dung lượng index + engine riêng (PLAID) |
| Stage 2 (reranker) | Chấm điểm MaxSim cho k ứng viên đã có | Không đổi stage 1. Nhưng vector token phải từ đâu ra: lưu sẵn (phồng index) hay tính lúc truy vấn (mất phần lớn cái lợi tốc độ) — xem ba cách cắm dưới đây |
Bản stage 2 tính vector lúc truy vấn nghe hấp dẫn nhưng thường không hợp lý: nếu dù
sao cũng phải chạy model trên k tài liệu lúc truy vấn, thì chạy hẳn một cross-encoder —
nó chất lượng cao hơn. Late interaction chỉ thật sự thắng khi các vector token được
tính trước: hoặc index cả corpus (stage 1), hoặc lưu sẵn rồi chỉ MaxSim trên k
ứng viên (mục dưới).
Con số so sánh trực tiếp, từ bài báo ColBERT gốc: MS MARCO dev MRR@10 34,9 (ColBERT) so với 36,0 (reranker BERT-base của cùng nhóm) — thấp hơn một chút về chất lượng, nhưng “nhanh hơn hơn 170×” và “ít FLOPs hơn 14.000 lần mỗi truy vấn”. Đó chính là mệnh giá của việc tính trước vector token.
Late interaction hay “hybrid + rerank”?
Phần tiêu đề “Late interaction hay “hybrid + rerank”?”Đây là câu hỏi kiến trúc thật, và cái bẫy nằm ở chỗ hai phương án không cùng một tầng:
hybrid + rerank: BM25 ─┐ ├─ RRF ─► top-k ─► cross-encoder ─► top-5 dense ─┘ → đổi stage 2, index cũ giữ nguyên
late interaction: index đa vector ─► MaxSim trên toàn corpus ─► top-k → đổi chính stage 1Nói gọn: rerank chữa bệnh “lấy đúng, xếp sai”; late interaction chữa bệnh “không lấy được về” (5.4). Chọn sai bệnh thì tiêu tiền không ra kết quả.
Một bảng cùng harness
Phần tiêu đề “Một bảng cùng harness”Phần lớn so sánh trên mạng ghép số từ hai bài báo khác nhau. BEIR (2021) chạy cả hai trong cùng một harness — 18 tập dữ liệu, nDCG@10 trung bình, so với BM25:
| Kiến trúc | Chất lượng so với BM25 | Index (DBPedia 1M) | Latency (DBPedia 1M) |
|---|---|---|---|
| ColBERT (late interaction, end-to-end) | +2,5% | 20 GB | 350 ms GPU — bảng không có số CPU |
| BM25 + cross-encoder rerank top-100 | +11% | 0,4 GB | 450 ms GPU · 6100 ms CPU |
Ba cột phải đọc cùng nhau. Rerank mua gấp hơn bốn lần phần chất lượng, với index nhỏ hơn 50× — nhưng trả bằng CPU: 6,1 giây một truy vấn nếu không có GPU. Late interaction đắt index mà rẻ latency GPU. Cùng bài báo đó: index ColBERT cho BioASQ (~15 triệu tài liệu) là ~900 GB, so với 18 GB của BM25.
Đây là số 2021, và phải nói rõ, vì cả hai bên đều đã tiến từ đó: phía late interaction có ColBERTv2 → PLAID → ConstBERT → MUVERA (các mục trên); phía rerank có listwise reranker đạt BEIR nDCG@10 63,20 (5.8). Dùng bảng này để hiểu hình dạng của đánh đổi, không phải để chốt điểm số hôm nay.
Chỗ late interaction thắng mà rerank không tranh được
Phần tiêu đề “Chỗ late interaction thắng mà rerank không tranh được”Bảng 2 của bài ColBERT gốc, MS MARCO 8,8 triệu đoạn — cùng một model, chỉ khác chỗ cắm:
| Cách cắm ColBERT | MRR@10 | Recall@1000 |
|---|---|---|
| Rerank top-1000 của BM25 | 34,8 | 81,4 ← đúng bằng trần của BM25 |
| Tìm end-to-end trên index đa vector | 36,0 | 96,8 |
+15 điểm recall@1000 chỉ vì stage 1 không còn là BM25. Đây là 5.4
viết dưới dạng số: recall@1000 của nhánh “rerank BM25” bằng chính xác recall của BM25 —
rerank không bao giờ đổi được recall@k, chỉ đổi thứ tự trong k. Không reranker nào
đưa 81,4 lên 96,8.
Ba cách cắm, không phải hai
Phần tiêu đề “Ba cách cắm, không phải hai”Mục trên chia “stage 1 hay stage 2”. Thực tế có ba, và cái ở giữa hay bị bỏ sót:
| Cách | Index | Lúc truy vấn | Đánh giá |
|---|---|---|---|
| 1. Stage 1 đa vector | phồng, cần engine riêng (PLAID/MUVERA) | MaxSim trên toàn corpus | Chữa recall. Hạ tầng nặng nhất |
| 2. Rerank bằng vector token lưu sẵn | phồng, nhưng không cần index ANN cho nó | MaxSim trên k ứng viên | Rẻ latency, không đổi stage 1 |
| 3. Rerank bằng vector token tính lúc truy vấn | không phồng | encode k tài liệu rồi MaxSim | Đừng. Đã encode k tài liệu thì chạy cross-encoder cho chất lượng cao hơn |
Cách 2 là thứ các vendor đang bán. Qdrant lưu multivector ColBERT với hnsw_config(m=0) —
“các embedding này dùng để rerank, không dùng để retrieval ANN, nên không cần index HNSW” —
và OpenSearch (12/2025) khuyến nghị đúng hình đó: bi-encoder lấy ứng viên, late interaction
chấm điểm lại.
Cách 2 làm bảng đánh đổi mềm hơn hẳn: trả dung lượng, nhưng không phải dựng engine đa vector, và latency rerank thấp hơn cross-encoder rõ rệt — 61 ms so với 10.700 ms trong Bảng 1 của bài ColBERT (7 tỉ FLOPs so với 97 nghìn tỉ). Cái mất là chất lượng đỉnh: 34,9 so với 36,0 MRR@10 ở cùng bảng đó.
“Index phồng 10–100×” đúng đến mức nào
Phần tiêu đề ““Index phồng 10–100×” đúng đến mức nào”Con số hay được nhắc (OpenSearch, 12/2025) là 10–100×, và nó đúng cho tài liệu dài với vector chưa nén. Nhưng hệ số phụ thuộc mạnh vào độ dài tài liệu và số chiều của vector đơn mà bạn đang so: bảng của Weaviate (4/2025) cho 10.000 tài liệu × 100 token ra 20,48 MB (một vector 1024 chiều) so với 27,07 MB (ColBERTv2 128 chiều) — khoảng 1,3×, không phải 10×. Đo trên chunk thật của bạn trước khi tin bất kỳ hệ số nào.
Với hệ tiếng Việt: giấy phép cắt trước benchmark
Phần tiêu đề “Với hệ tiếng Việt: giấy phép cắt trước benchmark”Cửa số 1 của Bảng 3 ở 5.15 loại bỏ phần lớn lựa chọn:
jina-colbert-v2 — late interaction đa ngữ tốt nhất công khai, có tiếng Việt tường minh,
8192 token, ba mức chiều 128/96/64 — phát hành dưới CC-BY-NC-4.0, tức không dùng
thương mại được. Thay thế công khai gần nhất, answerai-colbert-small-v1, mạnh nhưng
tiếng Anh.
Nghĩa là với một sản phẩm thương mại tiếng Việt, “hybrid + rerank” không chỉ nhẹ hơn về hạ tầng — nó còn là con đường có nhiều model dùng được hơn.
→ Nên áp dụng vào AI Agent: mặc định là hybrid + rerank. Chỉ đổi sang late interaction
khi đã đo và thấy recall@k của stage 1 là chỗ nghẽn — sau khi đã sửa tokenizer, đã bật
hybrid, đã sửa chunking, theo đúng thứ tự ở 5.4. Muốn thử late
interaction với chi phí thấp nhất thì thử cách 2 trước, đừng dựng engine đa vector ngay.
Khi nào chọn cái gì
Phần tiêu đề “Khi nào chọn cái gì”| Tình huống | Nên |
|---|---|
| Corpus vừa (≲ 1M đoạn), đã có ANN, muốn chất lượng cao ở top | Cross-encoder rerank. Đơn giản nhất, không đổi index |
| Recall@k của stage 1 là chỗ nghẽn, và bạn kiểm soát được hạ tầng index | Late interaction làm stage 1 — nó chữa đúng bệnh recall (5.4) |
| Đa ngữ, có tiếng Việt, cần chất lượng stage 1 tốt hơn bi-encoder | Kiểm tra giấy phép trước: jina-colbert-v2 là CC-BY-NC. Nếu là sản phẩm thương mại → bi-encoder đa ngữ + cross-encoder rerank |
| Dung lượng lưu trữ là ràng buộc cứng | Bi-encoder + cross-encoder rerank. Đừng chạm vào đa vector |
| Đang chạy tốt với bi-encoder + cross-encoder | Đừng đổi. Late interaction là một hạ tầng nữa phải vận hành |
→ Nên áp dụng vào AI Agent: trong đa số trường hợp, câu trả lời là chưa. Late interaction là công cụ đúng cho bài toán recall ở quy mô lớn, không phải cho bài toán “top-5 xếp chưa tốt” — cái đó cross-encoder giải rẻ hơn nhiều. Đọc mục này để biết nó tồn tại và biết khi nào cần, đừng đọc nó như một việc phải làm.