Cross-Encoder & Reranking — Recall rẻ trước, precision đắt sau
Giải thích two-stage retrieval pipeline: dùng bi-encoder rẻ tiền để lấy rộng top-1000, cross-encoder đắt đỏ để chọn lọc top-10 chính xác.
Thay vì bắt một model khổng lồ phải đọc cả triệu tài liệu để tìm câu trả lời, chúng ta chia nhiệm vụ thành hai giai đoạn: lưới rộng bắt cá nhiều, rồi tay tinh chọn cá ngon. Đây là cách Google, Bing và mọi hệ thống RAG hiện đại vận hành — không phải bằng ma thuật, mà bằng sự tách biệt giữa recall rẻ và precision đắt.
Vấn đề
Bạn có một triệu tài liệu và một câu hỏi. Làm sao tìm ra 10 tài liệu liên quan nhất?
Cách 1: Dense Retrieval (Bi-encoder) — Encode query và doc thành vector 768 chiều rồi tìm bằng cosine similarity. Nhanh như chớp (sub-millisecond trên triệu docs), nhưng mang bệnh nén mất mát (lossy compression). Hãy tưởng tượng hai người mô tả bức tranh qua điện thoại chỉ bằng 768 tính từ: "0.7 xanh, 0.3 buồn..." Họ không thể thảo luận chi tiết kiểu "cái cây ở góc trái hay phải?" hay phân biệt "bank (tiền)" vs "bank (sông)". Thông tin bị nén quá mức trong vector cố định, tạo bottleneck thông tin khiến false positive cao.
Cách 2: Cross-Encoder — Ghép query và doc thành một chuỗi "[CLS] query [SEP] doc", cho qua Transformer để tính relevance score trực tiếp. Tokens nhìn nhau qua full self-attention, bắt được mọi nuance ngữ nghĩa như negation handling ("không nên" vs "nên"). Nhưng độ phức tạp là O((query_len + doc_len)²) — với 1 triệu docs, bạn phải chạy model 1 triệu lần. Chậm kinh khủng (5–50ms mỗi cặp), tốn kém và không khả thi cho real-time search.
Bạn phải chọn: hoặc nhanh nhưng cẩu thả, hoặc chính xác nhưng chậm chạp. Đây là nghịch lý cốt lõi của information retrieval hiện đại.
Ý tưởng cốt lõi
Đừng chọn. Dùng cả hai — theo thứ tự: recall rẻ trước, precision đắt sau.
Cross-Encoder Reranking là kiến trúc hai tầng (two-stage retrieval) tách biệt rõ ràng:
Tầng 1: Recall rẻ — Dùng bi-encoder (hoặc BM25, SPLADE) để "lưới rộng". Lấy top-K (thường 100–1000) candidates nhanh nhất có thể. Đây là giai đoạn "đừng bỏ sót gì cả" — chấp nhận precision thấp để đổi lấy coverage tối đa với chi phí rẻ mạt. Vì embeddings đã được pre-compute và index trong FAISS/HNSW, bạn chỉ tốn ~1ms để lướt qua triệu vectors.
Tầng 2: Precision đắt — Dùng cross-encoder để "rà lọc". Chỉ chạy trên 100–1000 docs đã lọc ở tầng 1, rerank lại để chọn top-N (thường 10–20) chính xác nhất. Vì chỉ xử lý < 1% corpus, chi phí chấp nhận được (thêm 500ms latency), nhưng chất lượng tăng vọt 20–30% về nDCG@10.
Thuật ngữ trong ngành gọi đây là "Retrieve-then-Rerank".
Tại sao điều này elegant? Vì nó phân phối lại ngân sách tính toán theo đúng nơi cần thiết. Bạn không cần biết chính xác doc thứ 10,001 có liên quan không — bạn chỉ cần chắc chắn rằng trong 1000 docs đầu tiên không bỏ sót cái nào tốt. Ngược lại, khi đã thu hẹp xuống 100 candidates, bạn cần biết chính xác cái nào là #1, #2 — đây là lúc cross-encoder tỏa sáng với khả năng "nhìn" trực tiếp vào từng cặp query-doc và bắt được subtle signals như "từ 'không' trong query đổi dấu toàn bộ ý nghĩa của doc".
The "Fisherman" Analogy: Weaviate team đưa ra phép ẩn dụ hay: Bi-encoder như ngư dân thả lưới rộng bắt trăm con cá. Cross-encoder như người thợ chọn lọc tại bến — chỉ nhìn kỹ những con đã bắt được, không cần lặn xuống biển kiểm tra từng con cá. Điều này giải quyết bài toán kinh tế: lưới rẻ tiền (sub-millisecond), tay chọn lọc đắt đỏ (chục ms) nhưng chỉ cần làm vài chục lần, không phải triệu lần.
Misconception buster: Nhiều người nghĩ cross-encoder "hiểu ngữ nghĩa sâu hơn" nên có thể thay thế hoàn toàn bi-encoder. Đây là lỗi chiến lược. Cross-encoder không thể pre-compute document representations — bạn phải encode query+doc cùng lúc tại thời điểm query. Nếu dùng nó cho cả triệu docs, bạn sẽ burn $15k/tháng như cảnh báo trên Reddit. Vai trò của nó gắn chặt vào "reranker", không phải "retriever".
That's it. Không phải một model thần kỳ, chỉ là sự phân chia lao động hợp lý giữa cái rẻ (recall) và cái chính xác (precision).
Tại sao nó hoạt động
Bản chất toán học của sự khác biệt:
Bi-encoder tính similarity bằng dot product độc lập: sim(q, d) = E_q(q) · E_d(d). Hai vector được sinh ra riêng lẻ, không "biết" về nhau cho đến phút cuối. Đây là lossy compression ép thông tin vô hạn (text) vào hộp 768 chiều. Thông tin về mối quan hệ token-level bị mất sạch khi đã thành vector cố định.
Cross-encoder thực hiện full cross-attention. Khi concatenate [CLS] query [SEP] doc, token "không" trong query attend trực tiếp vào token "nên" trong doc ở tầng attention đầu tiên. Score relevance được tính từ [CLS] token cuối cùng, nhưng nó đã "nhìn" toàn bộ câu và capture được interaction giữa mọi cặp token. Độ phức tạp O((L_q + L_d)²), nhưng chất lượng cao hơn vì không có information bottleneck.
Chi phí thực tế:
- Bi-encoder: ~1ms cho triệu docs (dùng FAISS/HNSW ANN search trên vectors đã pre-computed).
- Cross-encoder: 5–50ms mỗi cặp (MiniLM-L6 vs ELECTRA-base). Rerank 100 docs thêm ~500ms latency, chấp nhận được cho hầu hết ứng dụng.
NVIDIA blog tính toán: Rerank 1000 docs bằng cross-encoder rẻ hơn gấp 100 lần so với feed 1000 docs vào Llama 3.1 70B để tự nó chọn. Đây là lý do cross-encoder vẫn sống khỏe dù LLM ngày càng mạnh — chúng là bộ lọc hiệu quả trước khi đốt tiền vào LLM generation.
Tại sao không dùng LLM reranker luôn? GPT-4 hay Llama-3.1 70B có thể rerank tốt hơn cross-encoder chuyên dụng, nhưng chậm hơn 10–100 lần và đắt hơn tương ứng. Cross-encoder như ms-marco-MiniLM-L-6-v2 (19M params) đủ tốt cho 90% use cases với throughput cao hơn hẳn và vẫn capture được fine-grained semantic matching mà bi-encoder bỏ sót.
Ý nghĩa thực tế
Impact thực tế:
- Relevance boost: Các benchmark cho thấy reranking cải thiện 20–30% độ chính xác top-10 (Superlinked, NVIDIA). Với RAG pipeline, điều này có nghĩa là LLM nhận được context chất lượng cao hơn, giảm hallucination và cải thiện factual accuracy.
- Kiến trúc chuẩn: NVIDIA NeMo Retriever, Weaviate (native reranker module), Cohere Rerank API, Jina AI, Voyage AI đều triển khai theo pattern này. Amazon Lexical và Azure AI Search cũng tích hợp cross-encoder như một tầng option.
- RAG pipeline: Đây là khâu "cuối cùng trước LLM" — đảm bảo context window quý giá (thường chỉ 4k–128k tokens) được lấp đầy bằng tài liệu thực sự liên quan, không phải noise từ bi-encoder.
Limitations — những cái bẫy:
- Không pre-compute được: Bạn phải chạy cross-encoder tại query time. Nếu query traffic cao, cost tăng tuyến tính. Có startup từng "burn $15k/month" vì vô tình rerank quá nhiều candidates (Reddit warning).
- Context length: Cross-encoder thường giới hạn 512–1024 tokens. Doc dài phải chunk, có thể mất thông tin nếu relevant content nằm ở phần bị cắt bỏ.
- Quadratic cost: Rerank >1000 candidates/query là không khả thi về mặt kinh tế. Lựa chọn K đúng (thường 100–200) là hyperparameter quan trọng cần tune theo latency budget.
Trade-off: Bạn đánh đổi latency (thêm 100–500ms) để lấy chất lượng. Với chatbot real-time, có thể skip reranking hoặc dùng cross-encoder nhẹ (MiniLM). Với analysis pipeline offline, bạn có thể rerank sâu hơn với model lớn hơn.
Đào sâu hơn
Paper gốc:
- "A Thorough Comparison of Cross-Encoders and LLMs for Reranking" (arXiv:2403.10407, 2024) — Naver Labs benchmark so sánh cross-encoder vs LLM reranker trên SPLADE retrieval, chỉ ra khi nào dùng cái nào.
- "Beyond Retrieval: Ensembling Cross-Encoders and GPT Rerankers with LLMs for Biomedical QA" (arXiv:2507.05577, 2025) — Kết hợp cả hai loại cho lĩnh vực chuyên biệt.
Bài liên quan TroiSinh:
Cùng cụm (RAG & Retrieval):
- Dense Retrieval — Bi-encoder biến query và doc thành vector, tìm bằng cosine — Hiểu rõ tầng recall rẻ tiền, cách bi-encoder hoạt động và tại sao nó "lossy".
- Vector Databases — FAISS, HNSW, tìm nearest neighbor trong triệu vector — Cách lưu trữ và index cho tầng 1, ANN search sub-linear.
- RAG — Tìm trước, generate sau, model biết cả điều chưa được train — Big picture của pipeline, nơi reranking fit vào giữa retrieval và generation.
Đọc tiếp:
- Word Embeddings — Nền tảng vector hóa văn bản, hiểu sâu về semantic space mà cả bi-encoder và cross-encoder đều dựa vào.
- Multi-Agent Systems — Khi retrieval và reranking xong, nhiều agent có thể cùng phân tích kết quả để đưa ra quyết định phức tạp hơn (Level 2).
External resources:
- Weaviate blog: "Using Cross-Encoders as reranker in multistage vector search" — Phép ẩn dụ ngư dân/lưới rất trực quan.
- NVIDIA NeMo blog (Mar 2025): "How Using a Reranking Microservice Can Improve Accuracy and Costs" — Phân tích chi tiết cost-performance trade-offs.
- Reddit r/LocalLLaMA: Thảo luận về việc burn $15k/month vì rerank quá nhiều candidates — cảnh báo thực tế cho production.
Dense Retrieval — Bi-encoder biến query và doc thành vector, tìm bằng cosine
Tại sao tìm kiếm từ khóa 'start car' bỏ lỡ tài liệu về 'vehicle ignition'? Dense Retrieval dùng bi-encoder để biến text thành vector ngữ nghĩa, giải quyết lexical mismatch bằng cosine similarity trong không gian embedding.
Vector Databases — FAISS, HNSW, tìm nearest neighbor trong triệu vector
Giải mã cơ chế tìm kiếm vector tương tự trong triệu embedding chỉ trong miliseconds — từ HNSW graph đến Product Quantization, và tại sao RAG không thể tồn tại thiếu chúng.