Most teams build their first retrieval system the same way: slice every document into fixed 512-token chunks, push them into a vector database, and hope the embedding model does the hard work. That hope gets you through a demo. It does not survive contact with real users.

In production, a legal contract falls apart when you sever a liability clause from its exceptions. API documentation turns useless when a code sample gets detached from its function signature. A customer support thread becomes noise when you rip a single complaint out of its conversational history. The problem is rarely the language model sitting at the end of the pipeline. The problem is what you feed it.

We learned this the hard way. Our initial retrieval layer looked standard but behaved inconsistently. So we rebuilt it around a simple idea: treat retrieval as measured infrastructure, not magic. Here is exactly what changed, and how we pushed recall to 95 percent while cutting the 95th-percentile latency from 850 ms to 320 ms.

The Fixed-Chunk Trap

Uniform token counts are easy to code and easy to explain. That convenience masks a basic truth: documents have structure. When you ignore that structure, you destroy signal.

Consider a ten-page master service agreement. A fixed 512-token slice will land mid-obligation, splitting a clause from the very cap table that limits it. The retrieval step then returns half a thought. The generator hallucinates the rest. In API documentation, a chunk that is too large dilutes the embedding with boilerplate headers, burying the specific method a developer needs. In support tickets, a fixed window treats a conversation as a bag of sentences, stripping away the back-and-forth that reveals what actually failed.

We stopped treating chunk size as a hyperparameter we guessed. We started treating it as a mapping exercise between the document type and the information architecture inside it.

Match Your Chunking to the Data

The fix is not one perfect chunk size. The fix is three distinct strategies tuned to three distinct data shapes.

Legal documents now go through recursive splitting. The algorithm first looks for the largest natural boundaries—sections, then subsections, then numbered clauses—and only falls back to smaller splits when necessary. This keeps a termination clause attached to its survival conditions. The retrieval step sees complete logical units, which sharply reduces the model’s temptation to invent missing exceptions.

API and code documentation get structure-aware chunking. Markdown headers, code fences, and parameter tables are parsed as atomic units. We do not split inside a code block. We keep docstrings adjacent to their signatures. The result is that a query for a specific class method retrieves the full context a developer needs: the description, the typed parameters, and the working example.

Support and conversational data use semantic chunking. Instead of counting tokens, we look for shifts in topic or intent. If a customer describes a bug in message three and pastes a stack trace in message seven, we chunk by meaning, not by message index. The retrieval layer then returns the full arc of the problem rather than a orphaned sentence.

Why Vector Search Alone Fails

Even perfect chunks die in a pure vector search. Dense embeddings excel at capturing meaning and synonymy, but they are notoriously fuzzy on exact strings. If an engineer searches for the precise error code ERR_CONNECTION_REFUSED, vector similarity might return a dozen conceptual neighbors and miss the exact match buried at rank fourteen.

Keyword search with BM25 has the opposite problem. It finds exact tokens but misses semantic intent. A user asking “why is my database down” will never match a document that says “troubleshooting connection timeouts.”

We now run both. Vector and keyword results are fed into Reciprocal Rank Fusion, which blends the two ranked lists without requiring calibrated scores. The fused list is then passed through a cross-encoder reranker. The reranker is slower than the initial retrieval, but it is far more precise because it judges query-document relevance directly rather than through compressed embeddings. That hybrid pipeline alone lifted our recall by 15 percent.

Fixing Bad Queries Before They Hit the Index

Người dùng không viết các truy vấn tìm kiếm lý tưởng. Họ dán các dòng nhật ký (log) bị cắt cụt. Họ gõ “nó bị hỏng rồi.” Họ sử dụng các thuật ngữ chuyên môn mà tài liệu của bạn chưa bao giờ áp dụng. Nếu bạn tin vào truy vấn thô, bạn đang tin vào những nhiễu loạn.

Hiện tại, chúng tôi mở rộng mọi truy vấn đầu vào thành ba đến năm biến thể trước khi gửi chúng đến lớp truy xuất (retrieval layer). Một biến thể có thể là một cách diễn đạt khác trực tiếp. Một biến thể khác có thể là một tiêu đề tài liệu lý tưởng giả định. Biến thể thứ ba sẽ loại bỏ các từ thừa trong hội thoại và chỉ giữ lại các từ khóa kỹ thuật. Mỗi biến thể sẽ được nhúng (embedded) và tìm kiếm. Sau đó, chúng tôi khử trùng lặp và hợp nhất các nhóm ứng viên.

Việc này không hề miễn phí. Những lần gọi embedding bổ sung đó tốn tiền và làm tăng thêm vài mili giây. Nhưng hiệu quả đối với độ triệu hồi (recall) là rất đáng kể: chúng tôi đã tăng từ 78% lên 96% bằng cách mở rộng truy vấn trước khi truy xuất. Vì việc truy xuất tốt hơn giúp thu hẹp cửa sổ tạo văn bản (generation window) và giúp mô hình bám sát vào ngữ cảnh chính xác, cuối cùng chúng tôi đã tiết kiệm được chi phí ở các bước sau. Một bước truy xuất đắt hơn một chút sẽ rẻ hơn một bước tạo văn bản dài và bị ảo giác (hallucinated).

Ngừng đoán mò. Hãy bắt đầu tìm kiếm.

Khi đã có phương pháp chia nhỏ (chunking), truy xuất hỗn hợp (hybrid retrieval) và mở rộng truy vấn phù hợp, chúng tôi vẫn phải đối mặt với một mớ hỗn độn về tổ hợp. Kích thước chunk, độ chồng lấp (overlap) của chunk, độ sâu truy xuất top-k, ngưỡng reranker và trọng số hợp nhất (fusion weights) đều tương tác với nhau. Việc tìm kiếm lưới (grid search) thủ công sẽ mất hàng tuần và vẫn chỉ đưa chúng tôi đến một cực đại cục bộ (local maximum).

Chúng tôi đã chuyển sang tối ưu hóa Bayesian để khám phá không gian này. Thay vì kiểm tra kiệt quệ mọi sự kết hợp, thuật toán tìm kiếm duy trì một niềm tin về việc cấu hình nào có khả năng hoạt động tốt và dần dần thu hẹp phạm vi vào các vùng đầy triển vọng.

Kết quả không phải là một thiết lập hoàn hảo duy nhất. Đó là một biên Pareto (Pareto frontier) của các lựa chọn. Ở một đầu, chúng tôi có một cấu hình tinh gọn được tối ưu hóa cho điểm cuối hỗ trợ API thông lượng cao: suy luận nhanh, độ triệu hồi vừa phải và độ trễ thấp nhất có thể. Ở đầu kia, chúng tôi có một cấu hình mạnh mẽ cho việc xem xét pháp lý: truy xuất sâu hơn, reranking nặng hơn và độ chồng lấp chặt chẽ hơn, đánh đổi mili giây để lấy sự kỹ lưỡng. Vì biên này được xác định rõ ràng, chúng tôi có thể chọn điểm phù hợp cho sản phẩm thay vì giả vờ rằng một kích cỡ sẽ phù hợp cho tất cả.

Những con số thực tế trông như thế nào

Những thay đổi này đã đưa hệ thống từ một bản mẫu mong manh thành một đường ống sản xuất có đo lường được.

Độ triệu hồi tại mười (Recall at ten) đã cải thiện từ 78% lên 95%. Điều đó có nghĩa là khi câu trả lời chính xác tồn tại trong kho dữ liệu của chúng tôi, chúng tôi sẽ tìm thấy nó 19 trên 20 lần.

Độ trễ ở phân vị thứ 95 (95th percentile) đã giảm từ 850 ms xuống 320 ms. Nghe có vẻ như ngăn xếp hỗn hợp (hybrid stack) sẽ nặng nề hơn trên lý thuyết, nhưng việc lập chỉ mục thông minh hơn, các bộ reranker nhỏ hơn và khả năng chỉ phục vụ các chunk mạnh mẽ khi cần thiết đã giúp toàn bộ hệ thống nhanh hơn.

Tỷ lệ ảo giác—được theo dõi bởi những người chú thích con người trên một tập dữ liệu vàng (golden dataset) được giữ lại—đã giảm từ 12% xuống 3%. Khi mô hình nhận được ngữ cảnh đầy đủ và có liên quan, nó sẽ ngừng bịa đặt các sự thật.

Chi phí cho mỗi truy vấn đã giảm từ $0.008 xuống $0.005. Truy xuất tốt hơn đồng nghĩa với các prompt LLM ngắn hơn, tập trung hơn và ít nỗ lực phục hồi hơn. Chi phí embedding tăng thêm cho việc mở rộng truy vấn là không đáng kể so với số tiền tiết kiệm được trong quá trình tạo văn bản.

Xây dựng một Tập dữ liệu Vàng và Đối xử với Truy xuất như là Mã nguồn

Nếu bạn rút ra được một điều từ việc này, thì đó nên là kỷ luật trong việc đo lường. Chúng tôi đã xây dựng một tập dữ liệu vàng nhỏ gồm các câu hỏi thực tế và các vị trí câu trả lời đã được xác minh. Trước khi bất kỳ thay đổi nào được đưa vào sản xuất, nó phải chạy thử trên tập dữ liệu đó. Độ triệu hồi và độ trễ được giám sát trong thời gian thực, chứ không phải chỉ nhìn bằng mắt trong một notebook.

Truy xuất không phải là một bản demo nghiên cứu. Nó là cơ sở hạ tầng. Nó xứng đáng có các bài kiểm tra đơn vị (unit tests), các điểm chuẩn hồi quy (regression benchmarks) và tối ưu hóa tự động giống như phần còn lại trong ngăn xếp của bạn. Hãy chia nhỏ (chunk) theo cấu trúc tài liệu, chứ không phải theo sự mê tín về token. Hãy kết hợp tìm kiếm vector và từ khóa với một bộ reranker. Hãy mở rộng các truy vấn mà người dùng thực sự viết. Sau đó, hãy để một thuật toán tìm kiếm tinh chỉnh các nút điều khiển thay vì dựa vào trực giác của bạn.

Đường ống mà chúng tôi mô tả không phải là lý thuyết. Bạn có thể đọc bài viết gốc tại đây, và nếu bạn muốn thảo luận về kỹ thuật truy xuất với một cộng đồng quan tâm đến những vấn đề này, nhóm GyaanSetu AI luôn rộng mở.