Mở đầu — vì sao bài này quan trọng
Hãy tưởng tượng bạn đang xây một tính năng tìm kiếm cho sàn thương mại điện tử. Người dùng gõ "áo khoác giữ ấm mùa đông", nhưng sản phẩm trong kho lại có tên "jacket lông cừu chống lạnh". Nếu hệ thống của bạn chỉ so khớp từ khóa (keyword matching), nó sẽ trả về con số 0 kết quả — dù trong kho có đúng thứ khách cần. Khách bỏ đi, bạn mất một đơn hàng, và tệ hơn là mất niềm tin.
Vấn đề nằm ở chỗ máy tính không hiểu ý nghĩa. Nó chỉ thấy chuỗi ký tự. "Áo khoác" và "jacket" với nó là hai thứ hoàn toàn khác nhau, giống như "mèo" và "con hổ" — không liên quan gì.
Embeddings chính là công nghệ giải quyết vấn đề này. Đây là "lớp nền" (foundation layer) đứng phía sau gần như mọi tính năng AI hiện đại mà bạn dùng hằng ngày: tìm kiếm ngữ nghĩa, gợi ý sản phẩm, phân loại tự động, phát hiện trùng lặp, và đặc biệt là hệ thống RAG (Retrieval-Augmented Generation). Nếu bạn từng nghe về "vector database", "similarity search", hay "semantic search" mà thấy mơ hồ — thì embeddings chính là mảnh ghép còn thiếu.
Trong bài này, chúng ta sẽ đi từ trực giác cơ bản đến cách áp dụng thực tế: embedding là gì, tại sao vector lại "hiểu" được ý nghĩa, cách chọn model, cách đưa vào sản phẩm, và những cái bẫy khiến nhiều đội ngũ phải trả giá đắt. Sau bài này, bạn sẽ không còn coi embedding là "hộp đen ma thuật", mà là một công cụ bạn hoàn toàn kiểm soát được.
Khái niệm cốt lõi
Embedding là gì
Embedding là cách biểu diễn một đối tượng (văn bản, hình ảnh, âm thanh) dưới dạng một vector số trong không gian nhiều chiều. Nói đơn giản: bạn đưa vào một câu văn, model trả ra một dãy số — ví dụ 768 hoặc 1536 con số thực.
Điều kỳ diệu không nằm ở bản thân dãy số, mà ở tính chất của chúng: những đối tượng có ý nghĩa gần nhau sẽ có vector gần nhau trong không gian. Câu "tôi yêu con mèo của tôi" và "tôi thích con mèo cưng" sẽ cho ra hai vector rất sát nhau. Còn "tôi đang sửa xe máy" sẽ nằm ở một vùng khác hẳn.
Hãy hình dung một bản đồ. Trên bản đồ đó, các thành phố gần nhau về địa lý thì nằm cạnh nhau. Embedding cũng vậy, nhưng thay vì 2 chiều (kinh độ, vĩ độ), nó dùng hàng trăm đến hàng nghìn chiều, và "khoảng cách" thể hiện mức độ gần nhau về ý nghĩa chứ không phải vị trí.
Vì sao vector lại "hiểu" được ý nghĩa
Model embedding được huấn luyện trên khối lượng văn bản khổng lồ. Trong quá trình đó, nó học được rằng những từ hay xuất hiện trong cùng ngữ cảnh thì có liên hệ với nhau. "Bác sĩ", "bệnh viện", "y tá", "khám bệnh" thường đi cùng nhau, nên chúng được đặt gần nhau trong không gian vector.
Một ví dụ kinh điển thể hiện sức mạnh này là phép toán trên vector: vua - đàn ông + phụ nữ ≈ nữ hoàng. Model không được dạy điều này một cách trực tiếp — nó tự học ra quan hệ ngữ nghĩa từ dữ liệu. Đây là lý do embedding mạnh hơn hẳn so với so khớp từ khóa: nó nắm được cả những mối liên hệ mà con người không viết ra tường minh.
Đo độ tương đồng: cosine similarity
Khi đã có vector, làm sao biết hai thứ có gần nhau không? Phổ biến nhất là cosine similarity — đo góc giữa hai vector.
- Giá trị gần 1: hai vector cùng hướng, ý nghĩa rất giống nhau.
- Giá trị gần 0: không liên quan.
- Giá trị âm (gần -1): trái ngược nhau.
Số chiều (dimensions) nói lên điều gì
Mỗi model cho ra vector với số chiều cố định. Ví dụ text-embedding-3-small của OpenAI mặc định 1536 chiều, text-embedding-3-large là 3072 chiều. Nhiều chiều hơn thường (nhưng không phải luôn luôn) nghĩa là biểu diễn tinh tế hơn, nhưng cũng tốn bộ nhớ lưu trữ và tính toán chậm hơn.
Một xu hướng mới là Matryoshka embeddings — vector được thiết kế để bạn có thể "cắt bớt" số chiều (ví dụ từ 1536 xuống 512) mà vẫn giữ phần lớn chất lượng, giúp tiết kiệm chi phí lưu trữ đáng kể.
Vector database — nơi lưu và tìm kiếm
Khi bạn có hàng triệu vector, việc so sánh vector truy vấn với từng vector một sẽ quá chậm. Vector database (Pinecone, Weaviate, Qdrant, hoặc extension pgvector cho PostgreSQL) giải quyết bằng thuật toán tìm kiếm gần đúng (ANN — Approximate Nearest Neighbor). Nó đánh đổi một chút độ chính xác để đổi lấy tốc độ nhanh gấp hàng nghìn lần, cho phép tìm trong hàng triệu vector chỉ trong mili-giây.
Tình huống thực tế
Ví dụ 1: Tiki và bài toán tìm kiếm sản phẩm
Giả sử đội kỹ thuật của một sàn TMĐT lớn như Tiki phát hiện: 18% lượt tìm kiếm trả về "không có kết qu" dù trong kho có sản phẩm phù hợp. Nguyên nhân là khách gõ theo cách nói tự nhiên ("đồ chơi cho bé 3 tuổi thông minh"), còn tên sản phẩm lại là ngôn ngữ marketing ("bộ xếp hình phát triển trí tuệ Montessori").
Giải pháp: họ tạo embedding cho toàn bộ mô tả sản phẩm và lưu vào vector database. Khi khách tìm kiếm, câu truy vấn cũng được embed, rồi hệ thống tìm các sản phẩm có vector gần nhất. Kết quả: dù không trùng một từ khóa nào, "đồ chơi thông minh cho bé" vẫn khớp được với "bộ xếp hình Montessori".
Bài học: Semantic search không thay thế keyword search mà bổ sung cho nó. Cách làm tốt nhất trong thực tế là hybrid search — kết hợp cả so khớp từ khóa (để bắt chính xác mã sản phẩm, tên thương hiệu) lẫn semantic (để bắt ý định). Đừng vứt bỏ keyword search chỉ vì embedding nghe "xịn" hơn.
Ví dụ 2: Chatbot chăm sóc khách hàng của một ngân hàng số
Một ngân hàng số tại Việt Nam muốn xây chatbot trả lời câu hỏi dựa trên 2.000 trang tài liệu quy định nội bộ. Họ không thể nhồi toàn bộ 2.000 trang vào mỗi lần gọi model (vượt giới hạn context và cực kỳ tốn tiền).
Cách làm: cắt tài liệu thành từng đoạn nhỏ (chunk) khoảng 300–500 từ, tạo embedding cho mỗi đoạn, lưu vào vector database. Khi khách hỏi "phí chuyển khoản liên ngân hàng là bao nhiêu", câu hỏi được embed, hệ thống lấy ra 5 đoạn tài liệu liên quan nhất, rồi mới đưa 5 đoạn đó cho LLM để soạn câu trả lời. Đây chính là xương sống của RAG.
Con số thực tế: thay vì gửi 2.000 trang (hàng triệu token) mỗi lần, họ chỉ gửi khoảng 2.000 token ngữ cảnh — giảm chi phí gọi model hơn 99%, và độ chính xác câu trả lời tăng vì model không bị "nhiễu" bởi thông tin thừa.
Bài học: Chất lượng embedding và cách cắt chunk quyết định trực tiếp chất lượng câu trả lời. Chunk quá lớn thì loãng ý; chunk quá nhỏ thì mất ngữ cảnh. Đây là chỗ cần thử nghiệm nhiều, không có công thức chung.
Ví dụ 3: Phát hiện tin tuyển dụng trùng lặp trên nền tảng việc làm
Một startup tuyển dụng ở Đông Nam Á gặp vấn nạn nhà tuyển dụng đăng đi đăng lại cùng một tin với vài chữ khác nhau để "lên top". So khớp chuỗi ký tự không bắt được, vì chỉ cần đổi vài từ là qua mặt.
Họ dùng embedding: mỗi tin đăng được biến thành một vector. Nếu một tin mới có cosine similarity trên 0.95 với tin đã tồn tại, hệ thống đánh dấu nghi ngờ trùng lặp và gửi qua kiểm duyệt. Nhờ vậy, họ giảm 40% lượng tin rác mà không cần đội ngũ duyệt tay khổng lồ.
Bài học: Embedding không chỉ dùng cho tìm kiếm. Nó là công cụ đa năng cho phân cụm (clustering), phát hiện trùng lặp, phân loại, và phát hiện bất thường. Hãy nghĩ về nó như một "thước đo mức độ giống nhau" phổ quát cho mọi loại dữ liệu.
Hướng dẫn từng bước
Giả sử bạn muốn xây một tính năng tìm kiếm ngữ nghĩa cho tài liệu nội bộ. Đây là quy trình chuẩn:
Bước 1 — Chuẩn bị và cắt dữ liệu (chunking). Gom toàn bộ văn bản cần tìm kiếm. Cắt thành các đoạn hợp lý về mặt ngữ nghĩa — ưu tiên cắt theo đoạn văn, mục, hoặc câu, thay vì cắt cứng theo số ký tự. Kích thước phổ biến là 200–500 từ mỗi chunk, có phần chồng lấn (overlap) khoảng 10–15% để không mất ngữ cảnh ở ranh giới.
Bước 2 — Chọn model embedding. Cân nhắc ba yếu tố: chất lượng, chi phí, và ngôn ngữ. Với tiếng Việt, hãy kiểm tra kỹ model có hỗ trợ tốt không — nhiều model đa ngôn ngữ (multilingual) như của OpenAI, Cohere, hay các model mã nguồn mở như multilingual-e5 xử lý tiếng Việt khá ổn. Đừng mặc định model tiếng Anh là tốt cho tiếng Việt.
Bước 3 — Tạo embedding hàng loạt. Gọi API embedding cho toàn bộ chunk. Nên xử lý theo batch để tiết kiệm số lần gọi. Lưu ý: hãy lưu lại cả text gốc lẫn metadata (nguồn tài liệu, ngày tháng) đi kèm mỗi vector.
Bước 4 — Lưu vào vector database. Với dự án nhỏ, pgvector trên PostgreSQL là đủ và không cần thêm hạ tầng mới. Với quy mô lớn (hàng chục triệu vector), cân nhắc Qdrant, Weaviate hoặc Pinecone. Tạo index (như HNSW) để tăng tốc tìm kiếm.
Bước 5 — Xử lý truy vấn. Khi người dùng nhập câu tìm kiếm, embed câu đó bằng cùng một model đã dùng ở bước 3 (điểm cực kỳ quan trọng — trộn model là hỏng). Sau đó tìm k vector gần nhất (thường k = 5 đến 20).
Bước 6 — Đánh giá và tinh chỉnh. Tạo một bộ câu hỏi mẫu có đáp án đúng, đo xem hệ thống có trả về đúng tài liệu không. Điều chỉnh kích thước chunk, số lượng kết quả trả về, và cân nhắc thêm bước re-ranking (dùng một model chuyên xếp hạng lại kết quả để tăng độ chính xác top đầu).
Lỗi thường gặp & mẹo
Lỗi 1 — Trộn lẫn các model embedding. Vector từ model A và model B nằm trong hai không gian hoàn toàn khác nhau, so sánh chúng là vô nghĩa. Nếu bạn đổi model, phải tạo lại embedding cho toàn bộ dữ liệu (re-embed). Đây là lỗi phổ biến nhất và tốn kém nhất.
Lỗi 2 — Chunking cẩu thả. Cắt cứng mỗi 500 ký tự bất kể ngữ nghĩa sẽ chặt ngang câu, ngang ý, khiến embedding phản ánh sai nội dung. Luôn cắt theo ranh giới tự nhiên và thêm overlap.
Lỗi 3 — Quên chuẩn hóa văn bản. Chữ hoa/thường, dấu tiếng Việt bị lỗi encoding, khoảng trắng thừa đều ảnh hưởng chất lượng. Làm sạch dữ liệu trước khi embed.
Lỗi 4 — Tưởng embedding hiểu mọi thứ. Embedding giỏi bắt ý nghĩa tổng quát nhưng yếu với thông tin cần chính xác tuyệt đối: mã sản phẩm, số điện thoại, ngày tháng, giá tiền. Với những thứ này, kết hợp keyword/filter là bắt buộc.
Lỗi 5 — Bỏ qua chi phí lưu trữ ẩn. 10 triệu vector 1536 chiều chiếm khoảng 60GB RAM nếu lưu dạng float32. Ở quy mô lớn, hãy cân nhắc giảm chiều (Matryoshka) hoặc lượng tử hóa (quantization) để cắt giảm chi phí.
Mẹo hay: Luôn cache embedding của những truy vấn phổ biến. Nếu 30% người dùng hỏi cùng vài câu, bạn không cần embed lại mỗi lần — tiết kiệm cả tiền lẫn độ trễ. Ngoài ra, hãy log lại các truy vấn trả về kết quả kém để cải thiện dần.
Bài tập thực hành
- Thử nghiệm trực giác: Dùng một API embedding bất kỳ, tạo vector cho 5 câu: ba câu cùng chủ đề (ví dụ về cà phê) và hai câu khác chủ đề. Tính cosine similarity giữa các cặp. Quan sát: các câu cùng chủ đề có số cao hơn không? Điều này giúp bạn "cảm" được embedding hoạt động thế nào.
- Xây mini semantic search: Lấy khoảng 50 đoạn văn (có thể là FAQ của một sản phẩm), embed hết, lưu vào một mảng đơn giản. Viết hàm nhận câu hỏi, embed, và trả về 3 đoạn gần nhất. So sánh kết quả với tìm kiếm bằng từ khóa thông thường — trường hợp nào semantic thắng, trường hợp nào keyword thắng?
- Kiểm tra tiếng Việt: Chọn 2 model embedding khác nhau, chạy cùng bộ câu hỏi tiếng Việt có dấu, và so sánh xem model nào xếp hạng kết quả hợp lý hơn. Ghi lại nhận xét về khả năng xử lý tiếng Việt của từng model.
- Thí nghiệm chunking: Lấy một tài liệu dài, cắt theo hai cách (chunk 200 từ và chunk 800 từ), embed cả hai, rồi thử cùng một câu hỏi. Cách nào cho kết quả liên quan hơn? Rút ra kết luận cho dự án của bạn.
Tóm tắt
Embedding là cách biến văn bản, hình ảnh, âm thanh thành vector số nhiều chiều, trong đó những thứ gần nhau về ý nghĩa thì gần nhau trong không gian. Đây là nền tảng cho semantic search, RAG, gợi ý, phân loại và phát hiện trùng lặp.
Những điểm cần nhớ:
- Ý nghĩa được mã hóa thành khoảng cách: vector gần nhau = ý nghĩa giống nhau. Cosine similarity là thước đo phổ biến nhất.
- Vector database cho phép tìm kiếm gần đúng trong hàng triệu vector chỉ trong mili-giây; với dự án nhỏ, pgvector là đủ.
- Quy trình chuẩn: cắt chunk hợp lý, chọn model phù hợp (chú ý tiếng Việt), tạo embedding, lưu trữ, truy vấn bằng cùng model, rồi đánh giá và tinh chỉnh.
- Cạm bẫy lớn nhất: trộn model, chunk cẩu thả, và kỳ vọng embedding xử lý được thông tin cần chính xác tuyệt đối. Hãy dùng hybrid search để có kết quả tốt nhất.