Product Management
Đăng nhập
ESC

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

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

Bài 2 — Thiết lập môi trường: embedding model và vector store

Đã đọ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.

Trước khi retrieval, bạn cần hai thành phần lõi: một embedding model (biến text thành vector) và một vector store (lưu và tìm vector theo độ tương đồng). Bài này hướng dẫn thiết lập cả hai để có index chạy được.

Chọn embedding model

Embedding model quyết định chất lượng retrieval nhiều hơn bạn tưởng. Vài tiêu chí:

  • Chiều vector (dimension): 384, 768, 1024, 1536 — cao hơn thường tốt hơn nhưng tốn bộ nhớ.
  • Ngôn ngữ: với tiếng Việt, chọn model đa ngôn ngữ (multilingual) hoặc model chuyên tiếng Việt.
  • Độ dài context tối đa của model: quyết định chunk lớn tối đa.
  • Chi phí & độ trễ: API trả phí vs. model chạy local.
Ví dụ lựa chọn phổ biến: text-embedding-3-small (1536 chiều, đa ngôn ngữ, rẻ) cho MVP, hoặc bge-m3 chạy local nếu cần riêng tư.

Chọn vector store

LoạiKhi nào dùng
FAISS (in-memory)Prototype, dữ liệu < 1 triệu chunk
Chroma / LanceDBLocal, dễ dùng, nhúng vào app
Qdrant / WeaviateProduction, cần filter metadata, scale
pgvectorĐã có Postgres, muốn 1 database duy nhất

Các bước thiết lập

  • Cài thư viện:
pip install sentence-transformers qdrant-client
  • Khởi tạo embedding model:
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("BAAI/bge-m3")

def embed(texts):
    return model.encode(texts, normalize_embeddings=True)
normalize_embeddings=True rất quan trọng: chuẩn hóa vector để dùng cosine similarity chính xác.

  • Tạo collection trong vector store:
from qdrant_client import QdrantClient
from qdrant_client.models import VectorParams, Distance

client = QdrantClient(":memory:")
client.create_collection(
    collection_name="docs",
    vectors_config=VectorParams(size=1024, distance=Distance.COSINE),
)
Chú ý: size phải khớp đúng chiều vector của model (bge-m3 = 1024). Sai chiều là lỗi phổ biến nhất.

  • Nạp thử một vài chunk:
from qdrant_client.models import PointStruct

chunks = ["Phép năm được quy đổi tối đa 5 ngày.", "Giờ làm việc từ 8h đến 17h."]
vecs = embed(chunks)
points = [PointStruct(id=i, vector=v.tolist(), payload={"text": c})
          for i, (c, v) in enumerate(zip(chunks, vecs))]
client.upsert(collection_name="docs", points=points)
  • Kiểm tra truy vấn:
q = embed(["quy đổi phép năm"])[0]
hits = client.search("docs", query_vector=q.tolist(), limit=2)
for h in hits:
    print(h.score, h.payload["text"])

Lưu metadata cùng vector

Đừng chỉ lưu text. Luôn kèm metadata để filter và trích dẫn:

payload = {
    "text": chunk,
    "source": "quy-che-2026.pdf",
    "page": 4,
    "section": "4.2",
    "updated_at": "2026-06-01"
}
Metadata updated_at sẽ dùng ở Bài 8 để xử lý index freshness.

Checklist thiết lập môi trường

  • [ ] Chiều vector của model == size của collection.
  • [ ] Bật normalize embeddings + dùng distance COSINE (hoặc dot khi đã normalize).
  • [ ] Mỗi point có metadata: source, vị trí, thời gian cập nhật.
  • [ ] Test embed một câu và search được kết quả hợp lý.
  • [ ] Ghi lại tên model + version để tái lập.

Sai lầm thường gặp

  • Trộn model embedding khác nhau giữa lúc index và lúc query: vector không cùng không gian → kết quả rác. Query PHẢI dùng đúng model đã index.
  • Quên normalize rồi lại dùng cosine: điểm số méo.
  • Không lưu metadata: sau này không trích dẫn được, không lọc theo phòng ban được.
  • Chọn vector DB nặng ngay từ đầu: prototype nên bắt đầu bằng FAISS/Chroma cho nhanh, đổi sau khi cần scale.
Bài 3 ta đi sâu vào chunking — khâu quyết định chất lượng nhất.

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