
Lỗi retrieval không nằm ở embedding model: hai chỗ cần đo
Hai thí nghiệm RAG công bố tuần này: chunker cắt cố định rơi giữa câu 98% số lần, còn một column comment thì bị đếm ba lần trên bốn kênh xếp hạng.
Retrieval trả về sai đoạn, và nghi phạm đầu tiên luôn là embedding model. Hai thí nghiệm công bố tuần này chỉ ra chỗ khác: lỗi nằm ở cách bạn cắt và cách bạn đếm.
Chỗ thứ nhất: đường cắt rơi giữa câu
Một dev đo bốn chiến lược chunking trên cùng một tài liệu — RFC 9562, bản đặc tả UUID, 114.629 ký tự, với mức chunk mục tiêu 1.000 ký tự. Chỉ số anh dùng không phải kích thước chunk mà là vị trí đường cắt: thu thập mọi ranh giới hợp lệ trong tài liệu trước, rồi hỏi mỗi chiến lược có bao nhiêu nhát cắt trượt ra ngoài.
Kết quả: cắt cố định theo số ký tự rơi vào giữa câu 98% số lần. Cắt theo đoạn văn — coi mỗi paragraph là một khối không chia được — trượt 0 lần.
Lập luận của anh đáng chú ý hơn con số: nếu chunk kéo về dừng giữa chừng câu chứa câu trả lời, thì câu trả lời không nằm trong index của bạn, và không embedding model nào dựng lại được nó. Chunking thường được quyết một lần trong tham số khởi tạo rồi không ai nhìn lại. Recursive splitter — thứ hầu hết framework đặt làm mặc định — đi xuống thang phân tách theo thứ tự: ngắt đoạn, xuống dòng, câu, rồi khoảng trắng.
Chỗ thứ hai: cùng một câu chữ bị đếm ba lần
Thí nghiệm thứ hai bắt đầu bằng một kết luận sai. Tác giả sinh mô tả cho 1.245 object trong database để retrieval tốt lên, nhưng retrieval tệ đi. Xóa mô tả đi thì điểm tăng ở mọi mức cắt, trên cả hai embedder. Bảng số đó, đọc trần, khuyên bạn xóa hết prose.
Chính điểm vô lý ấy là manh mối: một thiết kế lấy tiền đề "prose giúp ích" thì không nên thua chính việc xóa prose. Khi mổ ra, anh thấy cùng một column comment được index ba lần — vào _prose_text cho kênh prose, và vào embed_text() vốn nuôi cả kênh body lẫn vector. Ba trong bốn tín hiệu xếp hạng cùng mang một chuỗi chữ.
Hệ quả: bảng nào nhiều cột thì khớp trên ba trong bốn kênh với bất kỳ câu hỏi nào trùng một từ với một cột bất kỳ của nó. Các bảng rộng thành nam châm, đè bẹp bảng hẹp nhưng đúng. Xóa mô tả "giúp ích" chỉ vì nó gỡ đi hai phần ba của một lần đếm ba.
Tách từng kênh trên cùng 212 câu hỏi cho thấy thiệt hại nằm ở đâu: bỏ column comment khỏi riêng kênh prose cứu được 4 câu ở k=10, bỏ khỏi riêng embed_text() cứu được 11 câu. Mười một trong mười lăm câu nằm ở đường embedding — đúng kênh anh nói mình sẽ không đoán ra, vì kênh mang tên "prose" trông đáng ngờ hơn.
Ràng buộc khiến bản vá trông kỳ lạ
Bản sửa bỏ column comment khỏi kênh body và kênh prose, nhưng giữ nguyên embed_text() — tức là để yên chính chỗ chứa phần lớn thiệt hại. Lý do không phải lười: vector là một cam kết đã công bố và đã ghim. Đổi thứ đi vào vector thì mọi index mà người dùng thư viện đã dựng sẽ âm thầm sai. Theo lời anh, một bản vá retrieval làm hỏng index của người dùng không phải bản vá, mà là một cuộc migration không báo trước.
Làm gì trước khi đổi embedding model
Hai phép đo, không cần đổi hạ tầng. Một, log vị trí mọi đường cắt chunker của bạn tạo ra và đếm xem bao nhiêu nhát rơi ngoài ranh giới câu hoặc đoạn — phần chấm điểm trong thí nghiệm trên chỉ khoảng mười dòng Node, không phụ thuộc thư viện nào. Hai, liệt kê từng kênh xếp hạng và truy xem mỗi trường văn bản đi vào bao nhiêu kênh; nếu một trường xuất hiện ở ba kênh, thứ bạn đang đo là trọng số, không phải ngữ nghĩa.
Không spam, hủy đăng ký bất kỳ lúc nào.


