Product Management
Đăng nhập
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Bài 3 — Embedding, số chiều và distance metric

Đã đọc 0/7 mục · còn khoảng 3 phút
Cách chúng tôi ghi nhận

Một mục được tính là đã đọc khi nó nằm giữa màn hình đủ lâu so với độ dài của nó (bảng và sơ đồ tính một nửa), bạn vẫn đang cuộn hoặc bấm phím, và bạn đã thấy tới cuối mục. Lướt nhanh hoặc để tab mở không được tính. Chúng tôi chỉ lưu thời gian đọc từng mục — không lưu gì khác.

Vector DB nào cũng chỉ tốt bằng embedding bạn đưa vào. Bài này làm rõ ba thứ hay bị làm sai: chọn embedding model, số chiều (dimension), và distance metric.

Embedding model: chọn thế nào

Một vài lựa chọn phổ biến:

  • text-embedding-3-small (OpenAI, 1536 chiều) — rẻ, đủ tốt cho hầu hết agent.
  • text-embedding-3-large (3072 chiều) — chất lượng cao hơn, đắt và nặng hơn.
  • Model đa ngôn ngữ (multilingual) — quan trọng nếu dữ liệu tiếng Việt lẫn tiếng Anh.
Nguyên tắc: cùng một model cho lúc ghi và lúc truy vấn. Nếu bạn index bằng model A rồi query bằng model B, vector không cùng "hệ quy chiếu", kết quả sẽ vô nghĩa.

# ĐÚNG: cùng model
def embed(text):
    return client.embeddings.create(
        model="text-embedding-3-small", input=text
    ).data[0].embedding

index_vec = embed("chính sách đổi trả 30 ngày")  # ghi
query_vec = embed("tôi trả hàng được không")       # truy vấn — cùng model

Số chiều (dimension)

  • Số chiều là cố định theo model. text-embedding-3-small = 1536. Collection của bạn phải khai báo đúng con số này.
  • Chiều nhiều hơn không phải lúc nào cũng tốt hơn: tốn bộ nhớ, chậm hơn, và lợi ích giảm dần.
  • Một số model hỗ trợ Matryoshka (cắt bớt chiều, ví dụ 1536 → 512) để đánh đổi độ chính xác lấy tốc độ/chi phí.
Khai báo sai chiều là lỗi số 1 của người mới:

Error: expected 1536 dimensions, got 3072

→ Bạn đã đổi model mà quên tạo lại collection.

Distance metric: Cosine, Dot, hay L2?

  • Cosine similarity — đo góc, bỏ qua độ dài vector. Mặc định an toàn cho text embedding. Dùng cái này nếu bạn phân vân.
  • Dot product — nhanh, nhưng nhạy với độ dài vector; chỉ dùng khi vector đã normalized (chuẩn hóa về độ dài 1). Nhiều model xuất vector đã normalized, khi đó dot = cosine.
  • Euclidean (L2) — khoảng cách thẳng; ít dùng cho text, hợp một số bài toán khác.
Quy tắc thực dụng: Cosine cho text. Chọn metric ở lúc tạo collection và giữ nhất quán.

# Qdrant
c.create_collection("mem", vectors_config={"size":1536,"distance":"Cosine"})

Khung tư duy chọn cấu hình embedding

  • Dữ liệu ngôn ngữ gì? → chọn model (đa ngôn ngữ nếu có tiếng Việt).
  • Ưu tiên chất lượng hay chi phí? → small vs large.
  • Metric: mặc định Cosine.
  • Ghi lại model + dimension + metric vào tài liệu — coi như "hợp đồng" của collection.

Ví dụ tính điểm tương đồng

import numpy as np
def cosine(a, b):
    a, b = np.array(a), np.array(b)
    return a @ b / (np.linalg.norm(a) * np.linalg.norm(b))

sim = cosine(embed("giao hàng trễ"), embed("đơn đến muộn"))
# ~0.7-0.9: gần nghĩa. Gần 0: không liên quan.

Sai lầm thường gặp

  • Trộn hai model giữa index và query — kết quả tìm kiếm hỏng hoàn toàn nhưng không báo lỗi rõ ràng, rất khó debug.
  • Dùng Dot product với vector chưa normalize → mẩu text dài bị thiên vị (điểm cao oan).
  • Đổi embedding model mà không re-embed lại toàn bộ dữ liệu cũ — collection lẫn lộn hai hệ quy chiếu.
  • Chọn model 3072 chiều "cho chắc" khi 1536 đã đủ — tăng gấp đôi chi phí lưu trữ và độ trễ mà chất lượng cải thiện không đáng kể.
  • Không log lại metadata của model (tên, version). Khi nhà cung cấp cập nhật model, bạn cần biết để re-embed.
Bài sau: có vector rồi, làm sao tìm nhanh trong hàng triệu vector — đó là câu chuyện của index (HNSW/IVF).

Học xong bài này rồi? Tạo tài khoản miễn phí để lưu lại — lần sau vào là biết ngay đang dở ở đâu, và học hết khóa thì có chứng chỉ. Lưu tiến độ của tôi