Xây dựng công cụ tìm kiếm web từ đầu với 300 triệu neural embedding chỉ trong 2 tháng
(blog.wilsonl.in)- Tác giả chia sẻ trải nghiệm phát triển công cụ tìm kiếm web dựa trên 300 triệu embedding trong 2 tháng, xuất phát từ vấn đề chất lượng công cụ tìm kiếm suy giảm và sự tiến bộ của các mô hình embedding dựa trên Transformer
- Thông qua hạ tầng và thuật toán hiệu năng cao như 200 cụm GPU, crawler phân tán quy mô lớn, RocksDB, HNSW, hệ thống hiện thực hóa tìm kiếm hiểu ngôn ngữ tự nhiên theo thời gian thực
- Mục tiêu là hỏi đáp theo ý định thay vì khớp từ khóa, áp dụng nhiều kỹ thuật NLP/ML như chuẩn hóa, chunking, nối câu để phân tích tài liệu và giữ ngữ cảnh
- Bài viết giới thiệu cách thiết kế hệ thống phân tán quy mô lớn theo từng lớp như pipeline, storage, service mesh, vector index, cùng các phương án tối ưu nút thắt và chi phí
- Cuối cùng mô tả việc tạo ra một công cụ tìm kiếm cá nhân hóa có độ trễ cực thấp, phân tán ở quy mô lớn và độ chính xác cao
Tổng quan và động lực
- Tác giả gần đây nhận thấy vấn đề chất lượng công cụ tìm kiếm suy giảm, SEO spam và sự gia tăng của nội dung không liên quan, đồng thời trong bối cảnh các mô hình embedding dựa trên Transformer đã nâng cao mạnh năng lực hiểu ngôn ngữ tự nhiên, nên quyết định tự xây dựng một công cụ tìm kiếm từ đầu
- Giới hạn của các công cụ tìm kiếm hiện có bắt nguồn từ việc thiếu khả năng hiểu câu hỏi ở mức con người và chỉ dựa vào khớp từ khóa đơn giản
- Mục tiêu là xếp hạng theo ý định truy vấn, để nội dung chất lượng tốt luôn xuất hiện ở trên cao và vẫn khám phá đều cả phần long tail
- Quá trình xây dựng công cụ tìm kiếm web bao trùm nhiều lĩnh vực như khoa học máy tính, ngôn ngữ học, ontology, NLP, ML, hệ thống phân tán và kỹ thuật hiệu năng
- Dự án lần này là một thử thách: trong 2 tháng, bắt đầu hoàn toàn một mình, không có sẵn hạ tầng hay kinh nghiệm trước đó, để hiện thực một công cụ tìm kiếm hoàn toàn mới
Cấu trúc tổng thể của hệ thống
- Tạo 300 triệu text embedding dựa trên SBERT bằng 200 cụm GPU
- Hàng trăm crawler chạy đồng thời thu thập 50.000 trang mỗi giây, xây dựng tổng cộng 280 triệu mục chỉ mục
- Lưu trữ và lập chỉ mục bằng cách sharding RocksDB và HNSW trên hạ tầng 200 core CPU, 4TB RAM, 82TB SSD
- Tổng độ trễ phản hồi truy vấn được đặt ở mức khoảng 500ms
- Kiến trúc tổng thể và luồng xử lý được tách thành crawler, pipeline, storage, vector index embedding, service mesh và phần frontend/backend
Thử nghiệm và cải tiến tìm kiếm dựa trên embedding
Neural Embedding Playground
- Thử nghiệm xác nhận rằng tìm kiếm sử dụng các mô hình embedding như SBERT có khả năng hiểu truy vấn tự nhiên và độ chính xác cao hơn so với tìm kiếm truyền thống dựa trên từ khóa
- Có thể nắm bắt ý định của truy vấn đầu vào theo ngữ cảnh và cấp độ câu, rồi trích xuất đáp án thực sự liên quan
Ví dụ: tìm kiếm truyền thống vs. tìm kiếm neural
- Tìm kiếm truyền thống: kết quả mang tính ngẫu nhiên, chủ yếu dựa vào khớp từ khóa
- Tìm kiếm embedding: hiểu ngữ cảnh và ý định của câu hỏi, trả về kết quả tập trung vào câu hoặc khái niệm cốt lõi chính xác
- Với các truy vấn kết hợp khái niệm phức tạp, câu hỏi hàm ý/tổng hợp, hoặc truy vấn chứa tín hiệu chất lượng, có thể tìm ra đáp án dựa trên ngữ nghĩa
Phân tích và chuẩn hóa trang web
-
Mục tiêu chuẩn hóa là chỉ trích xuất các thành phần văn bản có ý nghĩa từ HTML, đồng thời loại bỏ nhiễu như bố cục và phần tử điều khiển
-
Tuân theo các tiêu chuẩn như WHATWG, MDN để giữ nguyên cấu trúc bảng của các phần tử như p, table, pre, blockquote, ul, ol, dl
-
Loại bỏ hoàn toàn các thành phần chrome như menu, điều hướng, bình luận, giao diện
-
Áp dụng quy tắc đặc thù theo từng site (ví dụ: en.wikipedia.org) để xử lý tình trạng trích xuất quá mức hoặc thiếu hụt
-
Cũng có thể tận dụng dữ liệu có cấu trúc dựa trên ngữ nghĩa (meta, OpenGraph, schema.org, v.v.) để xây dựng knowledge graph và cải thiện xếp hạng
Chunking và bảo toàn ngữ cảnh
Chunking theo đơn vị câu
- Để vượt qua giới hạn của mô hình embedding, hệ thống áp dụng chunking theo câu thay vì dùng toàn bộ trang
- Khi chunking, sử dụng spaCy sentencizer để phân tách chính xác nhiều trường hợp như ranh giới câu tự nhiên, ngữ pháp, từ viết tắt, URL và cách diễn đạt không chính thức
Bảo toàn ngữ cảnh và liên kết
- Hệ thống nắm bắt quan hệ phụ thuộc giữa các câu, heading, đoạn văn, bảng biểu rồi gộp cả thông tin ngữ cảnh đó vào embedding
- Ví dụ, với cấu trúc bảng, hệ thống nối chuỗi heading/điều khoản cấp trên để vẫn giữ được ý nghĩa của từng hàng khi nhúng
Chuỗi câu (Statement Chaining)
- Dùng bộ phân loại DistilBERT để phân tích đồng thời một câu và câu trước đó, tự động hóa việc xác định phụ thuộc ngữ cảnh và trích xuất chuỗi
- Khi embedding, hệ thống đưa vào toàn bộ các câu phụ thuộc cấp trên để tăng khả năng giữ ngữ cảnh
Kết quả từ nguyên mẫu
- Thử nghiệm nhiều truy vấn thực tế trong môi trường sandbox cho thấy hệ thống đạt khả năng hỏi đáp chính xác hơn rất nhiều, phù hợp ngữ cảnh so với cách truyền thống
- Ngay cả khi từ khóa không khớp, có lược bỏ, ẩn dụ hoặc câu hỏi phức hợp, ứng dụng vẫn nhận ra ý định và ghép đúng câu theo ngữ cảnh, đồng thời khai phá hiệu quả tri thức ẩn và các quan hệ
Web crawler quy mô lớn (dựa trên node)
- Xem xét nhiều yếu tố ổn định và hiệu quả như work stealing để phân phối tải, kiểm soát đồng thời/lưu lượng theo domain, xác thực DNS/URL/header
- Crawler áp dụng Promise dựa trên asynchronous I/O, cơ chế chống DDoS, quản lý tài nguyên (bộ nhớ, độ trễ, backoff), phát hiện domain nhiễu
- Tăng cường lọc URL trùng lặp/bất thường thông qua chuẩn hóa URL, giới hạn giao thức, cổng/thông tin người dùng và canonicalization
Pipeline (distributed task queue)
- Trạng thái của từng trang ban đầu được quản lý trong PostgreSQL, giai đoạn đầu dùng trực tiếp polling/transaction
- Trong môi trường phân tán quy mô lớn (hàng nghìn crawler), phát sinh vấn đề scale và nghẽn ở queue/lock → chuyển sang coordinator in-memory viết bằng Rust để quản lý trạng thái hàng đợi
- Cấu trúc task gồm nhiều cách lập chỉ mục như hash map, binary heap, nhóm domain, random poll, hoán đổi vị trí (
swap_remove) - Mỗi task chỉ chiếm khoảng 100B bộ nhớ, nên trên server 128GB có thể xử lý cả 1B task
- Sau đó tác giả còn phát triển hàng đợi mã nguồn mở dựa trên RocksDB để thay thế SQS, hỗ trợ 300.000 ops/giây trên một node
Thiết kế storage (Oracle → PostgreSQL → RocksDB)
- Ban đầu dùng Oracle Cloud (egress/storage chi phí thấp), sau đó đến PostgreSQL (TOAST), nhưng gặp giới hạn về mở rộng ghi và hiệu năng
- Do đặc tính của PostgreSQL như MVCC, write amplification, WAL, việc INSERT song song quy mô lớn bị nghẽn, cuối cùng chuyển sang RocksDB là KV store
- Với lưu blob riêng biệt của RocksDB (BlobDB), file SST, đa luồng, hash indexing, hệ thống tận dụng tối đa hiệu năng của NVMe SSD
- Mở rộng thành 64 shard RocksDB — mỗi shard được route dựa trên xxHash(key), dùng Serde + MessagePack để tuần tự hóa
- Cuối cùng hệ thống xử lý 200.000 ops/giây từ hàng nghìn client (crawler/parser/vectorizer), với metadata và blob được tách riêng rồi nén để lưu trữ
Service mesh và mạng
- Khi mở rộng hạ tầng, hệ thống được thiết kế dựa trên mTLS + HTTP2 để tự động khám phá service instance và bảo mật giao tiếp
- Mỗi node áp dụng chứng chỉ dựa trên root CA, dùng trực tiếp tuần tự hóa MessagePack, đồng thời phát triển DNS nội bộ, CoreDNS và custom client SDK
- Tác giả từng dùng VPN như ZeroTier, Tailscale, nhưng do vấn đề mạng, hiệu năng và vận hành nên chọn tự xây dựng bằng HTTP + mTLS
- Việc quản lý được thống nhất thông qua điều khiển system service (
systemd + cgroup + journald), giúp tinh gọn và chuẩn hóa
Pipeline tạo embedding GPU quy mô lớn
- Ban đầu sử dụng OpenAI API, sau đó chuyển sang môi trường GPU hiệu năng cao như Runpod vì chi phí
- Pipeline tách bất đồng bộ từng stage, đạt hiệu suất GPU trên 90%, và với 250 GPU có thể tạo 100.000 embeddings mỗi giây
- Pipeline viết bằng Rust, phần inference bằng Python → IPC qua named pipe, với backpressure có cấu trúc để tự động tinh chỉnh tài nguyên
Lập chỉ mục vector (HNSW/sharding)
- Dùng thuật toán HNSW cho vector search trong bộ nhớ, cung cấp ANN (Approximate Nearest Neighbor) với độ trễ cực thấp
- Khi chạm giới hạn RAM, hệ thống áp dụng sharding đồng đều theo node (64 node), mỗi shard là một chỉ mục HNSW riêng và được tìm kiếm song song
- Do HNSW cần rất nhiều RAM và có giới hạn với cập nhật trực tiếp, cuối cùng hệ thống chuyển sang CoreNN, một vector DB mã nguồn mở chạy trên đĩa
- CoreNN có thể truy vấn chính xác cao trên 3B embedding ngay cả với 128GB RAM và một node đơn
UX công cụ tìm kiếm và tối ưu độ trễ
- UX của công cụ tìm kiếm lấy phản hồi tức thì làm cốt lõi (không có load indicator, SSR truyền thống)
- Dùng Cloudflare Argo để đến gần edge PoP và áp dụng HTTP/3 nhằm giảm tối đa độ trễ truyền tải
- Chuẩn bị toàn bộ dữ liệu ở cấp app server, giảm tối thiểu round trip API riêng lẻ, phản hồi ngay trang đã minify và nén
Bản tóm tắt này hướng dẫn cụ thể các quyết định thiết kế và tối ưu hóa chính trên toàn bộ hệ thống, thuật toán và hạ tầng, cho thấy một công cụ tìm kiếm web quy mô lớn ứng dụng công nghệ NLP/ML hiện đại có thể được xây dựng end-to-end như thế nào chỉ trong 2 tháng.
1 bình luận
Ý kiến trên Hacker News
Điều gây ngạc nhiên là mô hình embedding mới nhất của OpenAI cung cấp mức giá cực thấp chỉ $0.0001 cho mỗi 1 triệu token khi suy luận theo lô, tính ra dù embedding 1 tỷ trang với 1.000 token mỗi trang thì tổng chi phí cũng chỉ $100, còn nếu tự chạy suy luận bằng GPU spot của Runpod thì đắt hơn ít nhất 100 lần, chưa tính các chi phí API khác, nên cũng tự hỏi liệu đây có phải một kiểu chiến lược honeypot của OpenAI để thu thập dữ liệu nguồn chuyên biệt theo miền hay không
Cuối bài có nhắc đến ý định bổ sung dữ liệu Common Crawl, tôi nghĩ thông tin xếp hạng dựa trên web graph của nhóm chúng tôi sẽ rất hữu ích trong việc chọn trang nào để crawl, thật thú vị khi được thấy một ví dụ quy mô lớn như vậy, cũng bất ngờ vì vector database hóa ra lại hiệu quả chi phí đến thế
Thật sự rất khâm phục, bài viết cũng được trình bày cực kỳ tốt, tôi đồng ý rằng cốt lõi của công cụ tìm kiếm là dữ liệu đã được làm sạch và lọc kỹ (rác vào thì rác ra), điều đó cũng một lần nữa cho thấy trong huấn luyện LLM, một lượng nhỏ dữ liệu chất lượng cao cuối cùng còn quan trọng hơn, cũng tò mò không biết hiệu năng sẽ ra sao nếu để LLM đánh giá toàn bộ nội dung để xây dựng công cụ tìm kiếm
Thật sự rất nể phục, việc gom được ngần ấy công nghệ và khiến chúng chạy cùng nhau là điều đáng kinh ngạc, tôi nghĩ giá trị quyết định của công cụ tìm kiếm nằm ở chính thuật toán xếp hạng, tôi chưa rõ LLM được dùng thế nào cho xếp hạng trong dự án này, trong các kỹ thuật xếp hạng cũ có cách thu thập dữ liệu tìm kiếm~nhấp chuột của người dùng thật, đây chính là dữ liệu train con người nhập truy vấn tìm kiếm → nhấp vào liên kết, chỉ cần vài lượt nhấp là thứ hạng đã cải thiện rõ rệt, nếu đưa dữ liệu này vào mạng nơ-ron thì có thể biến nó thành một bài toán phân loại để cải thiện xếp hạng, và càng nhiều người nhấp thì trọng số càng lớn
Chỉ có thể nói là quá ấn tượng, mà thực sự còn hoạt động khá tốt, nếu có thể bù chi phí bằng 10.000 người đăng ký $5 mỗi tháng thì một công cụ tìm kiếm được cộng đồng hậu thuẫn có lẽ cũng không hề viển vông
Với những ai biết về encoder-only LLM thì rõ ràng Google về cơ bản đã hết thời, lý do Google vẫn trụ được là vì việc crawl toàn bộ web thế giới và giữ cho chỉ mục luôn mới là thứ cần rất nhiều thời gian, nếu các tổ chức mở như Common Crawl hay dịch vụ trả phí giải được bài toán crawl web theo thời gian thực, thì hào lũy 25 năm của Google sẽ sụp đổ và bản thân tìm kiếm sẽ bị bình dân hóa
Hơn nữa, chúng ta đang chứng kiến việc thay thế theo thời gian thực cho mọi chức năng của Big Tech, và nhờ các mô hình mà rào cản công nghệ của doanh nghiệp giờ cũng giảm mạnh
Việc một người có thể làm được tới mức này là điều trước đây tôi chưa từng tưởng tượng nổi, có cảm giác nó không còn cách công cụ tìm kiếm thương mại quá xa, có lẽ thậm chí đã ở khoảng cách mà Google cũng phải đuổi theo, chỉ $50.000 một năm thì rẻ đến phi lý, đến mức tôi muốn gửi seed money ngay lập tức
Dự án thật sự rất tuyệt, tôi cũng thử dùng nó cho một câu hỏi mà các công cụ tìm kiếm nổi tiếng thường trả kết quả không tốt (các lựa chọn nên cân nhắc khi mua màn hình ultrawide độ phân giải cao), nhưng vẫn còn hiện tượng các trang meta chỉ chuyên xếp hạng quy mô lớn được ưu tiên hơn những trang có thông tin chuyên sâu, có vẻ như sự ám ảnh với ranking vẫn quá mạnh, nếu tự tìm câu trả lời thì tôi sẽ lọc ra vài diễn đàn phần cứng và blog rồi đối chiếu kỹ thông số, ưu nhược điểm, vì rất khó xác minh liệu một website có thực sự làm phân tích đó hay không nên trong các trường hợp đặc thù, việc đánh giá cao hơn các trang trích dẫn dữ liệu cụ thể sẽ hợp lý hơn, từ góc nhìn người dùng thì tôi muốn xem nguồn tư liệu gốc được dùng để phân tích, nhưng công cụ tìm kiếm thực tế lại không đưa các căn cứ nguồn lên theo cách từ dưới lên như vậy
Tôi thấy thật sự rất tuyệt, đã nghĩ tới chuyện thay toàn bộ bằng cái này, dù có thể sẽ hơi tốn thời gian nhưng tôi vẫn nhất định sẽ thử nhiều truy vấn rồi quay lại chia sẻ cảm nhận, nhìn chung nó dẫn đến gần đúng chỗ cần tìm nhưng chưa đạt 100%, ví dụ tôi thử tìm fediverse bằng lemmy thì nó trả về trang liberapay, nhất định hãy giữ lời hứa tích hợp Common Crawl và mong là cũng tham chiếu thêm các website khác như archive.org, trong khi ngành AI đang được đổ vào hàng chục tỷ USD thì tôi hy vọng những thử nghiệm như thế này có thể vận hành tốt và thành công dù chỉ nhờ cộng đồng tài trợ hay chia sẻ công sức, thật lòng mà nói rất nhiều người đã mệt mỏi với tình trạng gần như độc quyền của các công cụ tìm kiếm hiện nay, tôi cũng nghe nói Ecosia đang chuẩn bị công cụ tìm kiếm riêng nên hy vọng họ sẽ hợp tác hoặc nhận hỗ trợ từ dự án này, tôi thực sự muốn có một công cụ tìm kiếm phi tập trung, tôi hiểu việc còn do dự với mã nguồn mở vì vấn đề bền vững, nhưng thật bức bối khi quá nhiều tiền đang bị lãng phí gần như vô nghĩa trong khi dự án này có tiềm năng khổng lồ, nên tôi rất mong nó sẽ được open source, tôi tin cộng đồng cuối cùng sẽ tìm ra cách bền vững bằng crowdfunding hay cách nào đó tương tự, tôi vẫn chưa đọc xong bài viết nhưng đã quá háo hức nên vào dùng thử ngay, bản thân bài viết rất sâu sắc và tôi nghĩ cách làm này hoàn toàn có thể trở thành tài liệu tham khảo cho người khác, thành thật mà nói nó như ma thuật vậy, lâu lắm rồi tôi mới thấy một dự án khiến mình hào hứng từ đầu đến cuối, tôi hiểu open source là chuyện khó, cũng hiểu bối cảnh nước thứ ba, nhưng tôi thật sự sẵn sàng quyên góp dù chỉ $50 tiền túi, một người gần như chưa từng thanh toán online như tôi mà còn muốn ủng hộ đến mức đó, nên mong dự án sẽ tận dụng Common Crawl và đi cùng cộng đồng, chân thành chúc dự án và sự nghiệp của bạn thành công
Đây là bài viết sâu sắc nhất tôi đọc trong thời gian gần đây, tôi đặc biệt thích cách tác giả giải thích chi tiết những thành phần được chọn để giảm chi phí và chính xác đã tiết kiệm ở đâu, tuy tập trung vào neural search nhưng tôi muốn hỏi liệu đã thử tìm kiếm hybrid kết hợp BM-25 + embedding hay chưa, và những mô hình reranking nào tỏ ra hữu ích và hiệu quả nhất
Đây là một câu chuyện trải nghiệm thật sự rất thú vị, tôi cũng đang phát triển thứ gì đó tương tự cho tìm kiếm doanh nghiệp nên gặp rất nhiều thách thức giống nhau, nhiều người nghĩ việc crawl/xử lý/indexing sẽ dễ, nhưng làm ở quy mô lớn mà vẫn hiệu quả chi phí lại là một câu chuyện hoàn toàn khác, xin dành lời khen cho wilsonzlin, tôi rất muốn trao đổi thêm về chủ đề này, số người thực sự tự tay xây dựng những thứ như vậy theo kiểu e2e là cực kỳ ít