5.11 Cắm reranker vào một hệ thống thật
Mục này về kiến trúc: reranker gọi ở đâu, ai chịu latency, chuyện gì xảy ra khi nó chết, và làm sao trộn điểm liên quan với các tín hiệu nghiệp vụ mà không phá cả hai.
Ba chỗ có thể đặt nó, ba hệ quả khác nhau
Phần tiêu đề “Ba chỗ có thể đặt nó, ba hệ quả khác nhau”(A) TRONG search engine (B) Ở tầng ứng dụng (C) Trong agent loop ES/OpenSearch/Vespa app gọi 2 lần rerank như một tool
query ─► engine query ─► engine ─► k doc agent quyết định ├─ retrieve k │ có cần rerank không └─ rerank k ─► n app ─► reranker ─► n │ 1 lần gọi mạng 2 lần gọi mạng n lần gọi, khó dự đoán không kiểm soát chi tiết kiểm soát hoàn toàn linh hoạt nhất không lấy được điểm thô thấy được mọi điểm đắt và khó debug| (A) trong engine | (B) tầng ứng dụng | (C) trong agent | |
|---|---|---|---|
| Số lần round-trip | 1 | 2 | không xác định |
| Đổi model reranker | phải sửa cấu hình engine | đổi một biến môi trường | tuỳ prompt |
| Thấy điểm thô để log | thường không | có | có |
| Fallback khi reranker chết | engine lo (hoặc cả query chết) | bạn tự chủ động | phức tạp |
| Phù hợp | hệ đã dùng engine đó làm trung tâm | mặc định cho RAG | agent multi-hop |
→ Nên áp dụng vào AI Agent: bắt đầu bằng (B). Nó cho bạn log điểm thô — thứ bạn cần cho 5.3 và 5.13 — và cho bạn quyền tắt reranker bằng một biến môi trường lúc 2 giờ sáng.
Cascade: nhiều tầng, mỗi tầng đắt hơn và hẹp hơn
Phần tiêu đề “Cascade: nhiều tầng, mỗi tầng đắt hơn và hẹp hơn”Khi corpus lớn và budget latency chặt, một tầng rerank là không đủ mềm. Mẫu chuẩn:
1M doc ──BM25 + vector──► 1000 ──reranker nhỏ, nhanh──► 100 ──reranker lớn──► 10 ──► LLM ~10 ms ~20 ms ~50 msNguyên tắc của cascade: mỗi tầng chỉ cần đủ tốt để không đánh rơi tài liệu đúng, không cần xếp đúng thứ tự cuối. Tầng cuối mới cần chính xác. Điều đó cho phép tầng giữa dùng model nhỏ, quantize, seq length ngắn.
Chỉ làm cascade khi có bằng chứng cần: nó thêm một điểm hỏng, một model phải theo dõi, và một chỗ nữa để phân phối điểm trôi.
Rerank có điều kiện: đừng gọi khi không cần
Phần tiêu đề “Rerank có điều kiện: đừng gọi khi không cần”Không phải truy vấn nào cũng cần rerank. Trên corpus cẩm nang, lớp A đã đạt nDCG 0.971 với BM25 thuần (baseline đã đo) — rerank các truy vấn đó là trả tiền để có nguy cơ làm hỏng.
Các tín hiệu quyết định bỏ qua rerank, rẻ và đo được:
| Tín hiệu | Ngưỡng gợi ý | Lý do |
|---|---|---|
Truy vấn chứa mã định danh (E2003, sk_live, POST /v1/...) | regex khớp | Lexical đã đúng; reranker hay ưu tiên văn xuôi “đọc thấy hợp” hơn |
| Điểm stage 1 của top-1 bỏ xa top-2 | s1 ≥ 2·s2 | Đáp án đã rõ ràng |
| Chỉ có ≤ n ứng viên trả về | k ≤ n | Không có gì để xếp lại |
| Truy vấn là điều hướng (“mở trang thanh toán”) | phân loại ý định | Không phải bài toán liên quan ngữ nghĩa |
Ngược lại, các tín hiệu nên rerank: câu hỏi dài dạng tự nhiên, không có từ khoá trùng, nhiều ứng viên điểm sát nhau, hoặc truy vấn đến từ lớp paraphrase/multi-hop.
Cache: cache cái gì và khoá bằng gì
Phần tiêu đề “Cache: cache cái gì và khoá bằng gì”Reranker là ứng viên cache tốt vì đầu vào rời rạc và đầu ra nhỏ (một số).
khoá = hash(model_id + version, query_đã_chuẩn_hoá, doc_id, doc_content_hash)giá trị = điểmBốn thành phần của khoá, không được thiếu cái nào:
| Thành phần | Bỏ đi thì sao |
|---|---|
model_id + version | Nâng cấp model → phục vụ điểm của model cũ. Lỗi im lặng, rất khó truy |
| query đã chuẩn hoá | Cache miss vô ích với mọi khác biệt hoa/thường, khoảng trắng |
doc_id | — (bắt buộc hiển nhiên) |
doc_content_hash | Tài liệu được sửa → điểm cũ vẫn được dùng, nội dung mới không được đánh giá |
Tỷ lệ hit thực tế phụ thuộc hoàn toàn vào phân phối truy vấn của bạn: hệ hỏi-đáp nội bộ có đuôi truy vấn lặp rất dài (hit cao), hệ tìm kiếm mở gần như không lặp (hit thấp). Đo, đừng đoán. Ba tầng cache của một hệ RAG nói ở Tầng 10 — Production.
Reranker chết thì sao: fallback là một quyết định sản phẩm
Phần tiêu đề “Reranker chết thì sao: fallback là một quyết định sản phẩm”Reranker là một lời gọi mạng hoặc một GPU — nó sẽ chết, sẽ chậm, sẽ hết quota. Ba lựa chọn, và bạn phải chọn trước khi sự cố xảy ra:
| Chiến lược | Người dùng thấy | Khi nào đúng |
|---|---|---|
| Degrade — dùng luôn thứ tự stage 1 | Kết quả tệ hơn, vẫn có kết quả | Mặc định. Search kém vẫn tốt hơn không có search |
| Fail — trả lỗi | Thông báo lỗi | Khi trả lời sai đắt hơn không trả lời (y tế, pháp lý, tài chính) |
| Retry rồi degrade | Chậm hơn rồi tệ hơn | Chỉ khi timeout ngắn và budget còn chỗ |
Kèm theo, ba thứ bắt buộc phải có:
timeout cứng cho lời gọi rerank (ví dụ 200 ms — nhỏ hơn budget tổng)circuit breaker (lỗi liên tiếp → tắt rerank N phút, đừng thử mãi)metric riêng: tỷ lệ degrade ← nếu không đo, bạn sẽ chạy tháng trời KHÔNG có rerankDòng cuối là một chế độ hỏng thật và rất phổ biến: reranker âm thầm timeout 100% trong nhiều tuần, hệ thống vẫn trả kết quả, không ai biết chất lượng đã tụt về stage 1.
Trộn điểm liên quan với tín hiệu nghiệp vụ
Phần tiêu đề “Trộn điểm liên quan với tín hiệu nghiệp vụ”Trong sản phẩm thật, “liên quan nhất” không phải luôn là “nên đưa lên đầu”: tài liệu mới hơn, phiên bản đang dùng của khách, ngôn ngữ của người dùng, hàng còn tồn kho — đều là tín hiệu thật.
Cách làm sai: cộng thẳng điểm reranker với điểm nghiệp vụ. Hai thang không cùng đơn vị và không hiệu chuẩn (5.3) — kết quả là một hàm không ai hiểu, và mỗi lần đổi model reranker là một lần trọng số nghiệp vụ ngầm đổi theo.
Ba cách đúng, xếp theo độ phức tạp:
| Cách | Làm gì | Ưu / nhược |
|---|---|---|
| Lọc cứng trước | Bỏ tài liệu không đủ điều kiện trước khi rerank (sai ngôn ngữ, đã archive, không thuộc tenant) | Đơn giản, đúng, rẻ. Làm cái này trước tiên. Cảnh báo: lọc + vector có bẫy riêng — Tầng 5 |
| Xếp lại theo bậc | Rerank ra thứ tự liên quan, rồi trong các tài liệu xấp xỉ ngang điểm mới ưu tiên theo nghiệp vụ | Giữ được nghĩa của từng tín hiệu, dễ giải thích |
| Học một model ranking riêng | Đưa điểm reranker vào làm một feature của một model LTR có cả tín hiệu nghiệp vụ | Mạnh nhất, cần dữ liệu nhãn/log và một vòng huấn luyện (5.14) |
Chú ý cấu trúc của cách thứ ba: reranker không bị thay thế, nó trở thành một cột đầu vào. Đó là cách các hệ ranking lớn dùng — điểm liên quan ngữ nghĩa là một feature mạnh trong một hàm ranking rộng hơn.
Mặc định của các nền tảng — đọc kỹ, chúng khác nhau nhiều
Phần tiêu đề “Mặc định của các nền tảng — đọc kỹ, chúng khác nhau nhiều”Nếu bạn dùng reranker qua một search engine hay vector DB, các giá trị mặc định dưới đây quyết định hành vi hệ thống của bạn, và chúng không giống nhau:
| Nền tảng | Cơ chế | Mặc định đáng biết |
|---|---|---|
| Vespa | first-phase → second-phase → global-phase | second-phase chạy trên 100 hit tốt nhất mỗi content node; global-phase chạy trên 100 hit tốt nhất toàn cục. Có total-rerank-count làm chặn trên cứng |
| Elasticsearch | retriever text_similarity_reranker | rank_window_size mặc định 10 — rất nhỏ. Và nếu không truyền inference_id, nó dùng .rerank-v1-elasticsearch, tức một model chỉ tiếng Anh (5.8) |
| OpenSearch | rerank processor trong search pipeline | Bốn kiểu: cross-encoder (ml_opensearch), by_field, và hai kiểu kết hợp |
| Milvus | model ranker qua Function (2.6.x) | BGERerankFunction mặc định bge-reranker-v2-m3; CohereRerankFunction mặc định rerank-english-v2.0 — một mặc định đã cũ, đừng để nguyên |
| Weaviate | module reranker-cohere / reranker-transformers | reranker-transformers không có trên Weaviate Cloud vì cần chạy container model riêng |
| Qdrant | không có reranker phía server | Rerank là việc của tầng ứng dụng — cross-encoder hoặc late interaction do bạn gọi |
| LlamaIndex | node postprocessor | SentenceTransformerRerank mặc định cross-encoder/ms-marco-TinyBERT-L-2-v2 — model rất nhỏ, tiếng Anh |
| LangChain | ContextualCompressionRetriever | Reranker được bọc thành “document compressor” |
Hai dòng đáng gạch chân: rank_window_size = 10 của Elasticsearch nghĩa là mặc định
bạn chỉ rerank 10 kết quả — gần như không có tác dụng gì, vì thứ tự top-10 phần lớn đã do
stage 1 quyết. Và các mặc định model (.rerank-v1 tiếng Anh, rerank-english-v2.0,
ms-marco-TinyBERT) đều là model tiếng Anh nhỏ. Trên corpus tiếng Việt, chúng vẫn chạy
và vẫn trả về điểm — chỉ là điểm đó không có nghĩa.
Một quan sát về kiến trúc đáng học từ Vespa: các tín hiệu nghiệp vụ rẻ thuộc về
first-phase/second-phase (rộng, chạy trên nhiều tài liệu), còn cross-encoder ngữ nghĩa
đắt thuộc về global-phase sau khi đã gộp kết quả. Tức là ngược với trực giác thường
thấy: liên quan ngữ nghĩa là tầng cuối và hẹp nhất, không phải tầng đầu.
Một cấu hình production thật, có số
Phần tiêu đề “Một cấu hình production thật, có số”Đáng đọc vì nó là ví dụ đầy đủ về các quyết định của mục này, đo trên hệ thống thật (một sản phẩm hỗ trợ khách hàng dùng LLM làm reranker):
k = 40 ứng viênchia thành 4 shard song song (~10 đoạn/shard, ~200 token/đoạn)shard nào timeout → fallback: rerank lát đó bằng cross-encoder BGEround-robin batching → giảm thiên lệch vị trítheo dõi p95/p99 trên dashboardKết quả họ báo cáo: lần triển khai đầu thêm +5 giây; sau tối ưu còn dưới 1 giây (p50 +0,9 s) và chi phí giảm khoảng 8 lần — trong đó 28% tiết kiệm token đầu ra đến từ việc đổi định dạng, và thêm 50% từ việc đặt ngưỡng.
Chú ý hai chi tiết thiết kế: (1) họ nói thẳng xác suất timeout tăng theo số lời gọi song song — chia shard mua được latency nhưng bán đi độ tin cậy, nên phải có fallback; (2) fallback của họ là một model khác, rẻ hơn, không phải bỏ rerank hoàn toàn. Đó là một bậc degrade tinh hơn bảng ở trên.
Diversity: khi top-5 nói cùng một điều
Phần tiêu đề “Diversity: khi top-5 nói cùng một điều”Reranker tối ưu từng cặp độc lập, nên nó rất dễ trả về 5 đoạn gần như trùng nhau — lãng phí context window và tệ hại cho câu hỏi multi-hop (lớp C), nơi bạn cần các tài liệu khác nhau.
MMR (Maximal Marginal Relevance) chọn tuần tự, mỗi bước cân giữa liên quan và mới:
λ | Nghĩa |
|---|---|
1 | thuần liên quan (bỏ đa dạng) |
≈ 0,7 | điểm khởi đầu hợp lý |
0 | thuần đa dạng (bỏ liên quan) |
Đặt nó sau reranker, dùng rel là điểm reranker và sim là cosine giữa embedding
của các đoạn. Chi phí không đáng kể vì chỉ chạy trên n đoạn cuối. Một cách rẻ hơn nữa
mà thường đủ: chặn không lấy quá 1–2 đoạn từ cùng một tài liệu gốc.