Vector Database - Trái tim của hệ thống AI hiện đại

Posted on: 4/14/2026 7:33:02 AM

Table of contents

  1. Mục lục
  2. 1. Vector Database là gì và tại sao quan trọng?
    1. Hiểu đơn giản
  3. 2. Embedding - Biến dữ liệu thành vector
    1. 2.1. Embedding hoạt động như thế nào?
    2. 2.2. Các metric đo khoảng cách
      1. Mẹo thực tế
  4. 3. Các thuật toán tìm kiếm vector
    1. 3.1. Brute Force (Exact KNN)
    2. 3.2. HNSW (Hierarchical Navigable Small World)
      1. Trade-off quan trọng
    3. 3.3. IVF (Inverted File Index)
    4. 3.4. Product Quantization (PQ)
  5. 4. Kiến trúc bên trong Vector Database
    1. 4.1. Sharding và Replication
    2. 4.2. Write-Ahead Log (WAL) và Consistency
    3. 4.3. Hybrid Search: Vector + Metadata Filtering
      1. Cạm bẫy: Pre-filter vs Post-filter
  6. 5. So sánh các Vector Database phổ biến
    1. Lựa chọn nhanh
  7. 6. Tích hợp Vector Database vào pipeline RAG
    1. 6.1. Chunking Strategy - Nghệ thuật chia nhỏ tài liệu
    2. 6.2. Reranking - Tinh chỉnh kết quả
  8. 7. Tối ưu hiệu năng và chi phí
    1. 7.1. Quantization - Nén vector để tiết kiệm RAM
      1. Chiến lược tối ưu tiết kiệm nhất
    2. 7.2. Disk-based Index
  9. 8. Các kỹ thuật nâng cao
    1. 8.1. Multi-vector Representation
    2. 8.2. Sparse-Dense Hybrid
    3. 8.3. Multi-modal Vector Search
  10. 9. Triển khai thực tế: Từ prototype đến production
    1. 9.1. Prototype nhanh với ChromaDB
    2. 9.2. Production với Qdrant
    3. 9.3. Checklist triển khai production
      1. Chọn Embedding Model phù hợp
      2. Thiết kế Chunking Strategy
      3. Xây dựng Evaluation Pipeline
      4. Monitoring và Alerting
      5. Backup và Disaster Recovery
  11. 10. Kết luận
    1. Đọc thêm trong series AI Infrastructure

1. Vector Database là gì và tại sao quan trọng?

Trong kỷ nguyên AI, dữ liệu không chỉ đơn thuần là các bảng, dòng và cột. Mỗi đoạn văn bản, hình ảnh, đoạn âm thanh đều mang trong mình một "ý nghĩa ngữ nghĩa" — thứ mà cơ sở dữ liệu truyền thống không thể nắm bắt được. Vector Database ra đời để giải quyết chính xác vấn đề này: lưu trữ và tìm kiếm dữ liệu dựa trên ý nghĩa, không phải từ khóa.

Thay vì so khớp chuỗi ký tự như SQL LIKE '%keyword%', Vector Database cho phép bạn hỏi: "Tìm những đoạn văn bản có ý nghĩa tương tự với câu hỏi của tôi" — và nó trả về kết quả chính xác đáng kinh ngạc, kể cả khi không có từ nào trùng khớp.

$4.3B Quy mô thị trường Vector DB 2026
~50ms Thời gian truy vấn trên 1 tỷ vector
95%+ Recall@10 với HNSW
1536D Chiều vector phổ biến (OpenAI)

Hiểu đơn giản

Nếu cơ sở dữ liệu truyền thống (SQL) giống như tìm sách theo mã ISBN, thì Vector Database giống như tìm sách theo nội dung và cảm xúc — "tìm cho tôi một cuốn sách có cảm giác như Harry Potter nhưng dành cho người lớn".

2. Embedding - Biến dữ liệu thành vector

Trái tim của mọi hệ thống Vector Database là embedding — quá trình biến đổi dữ liệu phi cấu trúc (văn bản, hình ảnh, âm thanh) thành các vector số học trong không gian nhiều chiều. Hai mẫu dữ liệu càng giống nhau về mặt ngữ nghĩa, vector của chúng càng gần nhau trong không gian này.

2.1. Embedding hoạt động như thế nào?

graph LR A["📄 Văn bản gốc"] --> B["🤖 Embedding Model"] B --> C["📊 Vector [0.12, -0.34, 0.56, ...]"] D["📄 Câu hỏi"] --> E["🤖 Cùng Model"] E --> F["📊 Vector [0.11, -0.32, 0.58, ...]"] C --> G["📐 Tính khoảng cách"] F --> G G --> H["✅ Kết quả tương tự"] style A fill:#e94560,stroke:#fff,color:#fff style D fill:#0f3460,stroke:#fff,color:#fff style G fill:#27ae60,stroke:#fff,color:#fff style H fill:#27ae60,stroke:#fff,color:#fff

Hình 1: Quy trình embedding và tìm kiếm ngữ nghĩa

Mỗi embedding model sẽ biến đổi dữ liệu đầu vào thành một vector có số chiều cố định. Ví dụ:

  • OpenAI text-embedding-3-large: 3072 chiều (có thể giảm xuống 256-1536)
  • Cohere embed-v3: 1024 chiều
  • BGE-M3 (BAAI): 1024 chiều — hỗ trợ đa ngôn ngữ, bao gồm tiếng Việt
  • Sentence-BERT: 384-768 chiều
  • CLIP (OpenAI): 512-768 chiều — hỗ trợ cả text và image

2.2. Các metric đo khoảng cách

Khi đã có vector, cần một phương pháp để đo "mức độ giống nhau" giữa chúng. Ba metric phổ biến nhất:

Metric Công thức Phạm vi Khi nào dùng
Cosine Similarity cos(θ) = A·B / (||A|| × ||B||) [-1, 1] Text search, NLP — phổ biến nhất
Euclidean (L2) √Σ(ai - bi)² [0, ∞) Khi magnitude quan trọng
Dot Product Σ(ai × bi) (-∞, ∞) Khi vector đã normalized

Mẹo thực tế

Cosine Similarity là lựa chọn mặc định an toàn cho hầu hết ứng dụng NLP. Nó bỏ qua độ dài vector và chỉ quan tâm đến "hướng" — phù hợp khi so sánh các văn bản có độ dài khác nhau. Nếu vector đã được normalize (||v|| = 1), Cosine Similarity và Dot Product cho kết quả giống nhau, nhưng Dot Product tính nhanh hơn.

3. Các thuật toán tìm kiếm vector

Khi cơ sở dữ liệu có hàng triệu vector, việc so sánh từng cặp (brute-force) trở nên không khả thi. Đây là lúc các thuật toán Approximate Nearest Neighbor (ANN) phát huy sức mạnh — đánh đổi một chút độ chính xác để đạt được tốc độ tìm kiếm hàng nghìn lần nhanh hơn.

3.1. Brute Force (Exact KNN)

So sánh vector truy vấn với mọi vector trong database. Độ chính xác 100% nhưng độ phức tạp O(N×D) — không thể mở rộng khi N lớn.

# Brute force search - O(N*D) complexity
import numpy as np

def brute_force_search(query_vec, database_vecs, top_k=10):
    # Tính cosine similarity với MỌI vector
    similarities = np.dot(database_vecs, query_vec) / (
        np.linalg.norm(database_vecs, axis=1) * np.linalg.norm(query_vec)
    )
    # Sắp xếp và trả về top-k
    top_indices = np.argsort(similarities)[-top_k:][::-1]
    return top_indices, similarities[top_indices]

# Với 1 triệu vector 1536-D: ~2-5 giây mỗi truy vấn
# Với 100 triệu vector: ~200-500 giây = KHÔNG KHẢ THI

3.2. HNSW (Hierarchical Navigable Small World)

HNSW là thuật toán ANN phổ biến nhất hiện nay, được sử dụng mặc định bởi hầu hết Vector Database. Ý tưởng cốt lõi: xây dựng một đồ thị nhiều tầng, mỗi tầng cao hơn chứa ít node hơn nhưng kết nối xa hơn — giống như hệ thống giao thông có cả đường cao tốc (tầng cao) và đường nội thành (tầng thấp).

graph TD subgraph L2["Layer 2 - Express"] A2["Node A"] --- B2["Node B"] B2 --- C2["Node C"] end subgraph L1["Layer 1 - Highway"] A1["Node A"] --- B1["Node B"] B1 --- D1["Node D"] A1 --- E1["Node E"] E1 --- C1["Node C"] D1 --- C1 end subgraph L0["Layer 0 - Local Roads"] A0["A"] --- B0["B"] B0 --- D0["D"] A0 --- E0["E"] E0 --- F0["F"] F0 --- C0["C"] D0 --- C0 B0 --- G0["G"] G0 --- H0["H"] H0 --- C0 E0 --- I0["I"] I0 --- D0 end A2 -.-> A1 B2 -.-> B1 C2 -.-> C1 A1 -.-> A0 B1 -.-> B0 C1 -.-> C0 D1 -.-> D0 E1 -.-> E0 style L2 fill:#fff3f5,stroke:#e94560 style L1 fill:#f0f4ff,stroke:#0f3460 style L0 fill:#f0fff0,stroke:#27ae60

Hình 2: Cấu trúc đồ thị HNSW với 3 tầng — tìm kiếm bắt đầu từ tầng cao nhất và "zoom in" dần

Quy trình tìm kiếm HNSW:

  1. Bắt đầu từ entry point ở tầng cao nhất (Layer 2)
  2. Di chuyển tham lam (greedy) đến node gần query nhất ở tầng hiện tại
  3. Khi không thể tiến gần hơn, "xuống" tầng dưới và tiếp tục
  4. Ở tầng thấp nhất (Layer 0), mở rộng tìm kiếm với beam search

Tham số quan trọng của HNSW:

  • M (max connections per node): Thường 16-64. M cao hơn → recall tốt hơn nhưng tốn RAM hơn
  • efConstruction: Beam size khi build index. Giá trị 200-500 cho kết quả tốt
  • efSearch: Beam size khi query. Tăng ef → recall cao hơn, latency tăng

Trade-off quan trọng

HNSW ưu tiên tốc độ truy vấn nhưng tiêu tốn nhiều RAM vì toàn bộ index phải nằm trong bộ nhớ. Với 100 triệu vector 1536-D (float32), riêng vector data đã cần ~572 GB RAM, chưa kể graph structure. Đây là lý do các kỹ thuật quantization trở nên quan trọng.

3.3. IVF (Inverted File Index)

IVF chia không gian vector thành nhiều cluster bằng K-Means. Khi tìm kiếm, chỉ cần quét các cluster gần query nhất thay vì toàn bộ database.

# IVF Search Process (Pseudo-code)
# 1. Training phase: Chia N vectors thành K clusters
centroids = kmeans(all_vectors, n_clusters=1024)

# 2. Indexing: Gán mỗi vector vào cluster gần nhất
for vec in all_vectors:
    cluster_id = find_nearest_centroid(vec, centroids)
    inverted_lists[cluster_id].append(vec)

# 3. Search: Chỉ quét nProbe clusters gần nhất
def ivf_search(query, nprobe=16, top_k=10):
    nearest_clusters = find_nearest_centroids(query, centroids, n=nprobe)
    candidates = []
    for cluster_id in nearest_clusters:
        candidates.extend(inverted_lists[cluster_id])
    return brute_force_search(query, candidates, top_k)

# nProbe=16/1024 → chỉ quét 1.6% dữ liệu → nhanh ~60x

3.4. Product Quantization (PQ)

PQ nén vector bằng cách chia vector D-chiều thành M sub-vector nhỏ hơn, mỗi sub-vector được lượng tử hoá thành 1 byte (256 centroids). Kết quả: giảm bộ nhớ 32-64 lần với chỉ ~5% mất mát recall.

Thuật toán Tốc độ Build Tốc độ Query Recall RAM Phù hợp
Brute Force Không cần Chậm nhất 100% Thấp < 100K vectors
HNSW Chậm Nhanh nhất 95-99% Rất cao Low-latency search
IVF Trung bình Nhanh 90-98% Trung bình Dataset lớn, cân bằng
IVF-PQ Chậm Nhanh 85-95% Rất thấp Tỷ vector+, ngân sách hạn chế
ScaNN Trung bình Rất nhanh 95-99% Trung bình Google-scale, throughput cao

4. Kiến trúc bên trong Vector Database

Một Vector Database production-grade không chỉ là "index + search". Nó cần giải quyết hàng loạt vấn đề phức tạp: phân tán dữ liệu, nhất quán, sao lưu, lọc metadata, và cập nhật real-time.

graph TD Client["Client SDK"] --> LB["Load Balancer"] LB --> QN1["Query Node 1"] LB --> QN2["Query Node 2"] LB --> QN3["Query Node 3"] QN1 --> Shard1["Shard 1
Vector Index + Metadata"] QN1 --> Shard2["Shard 2
Vector Index + Metadata"] QN2 --> Shard2 QN2 --> Shard3["Shard 3
Vector Index + Metadata"] QN3 --> Shard1 QN3 --> Shard3 Shard1 --> S3["Object Storage
(S3/GCS)"] Shard2 --> S3 Shard3 --> S3 WAL["Write-Ahead Log"] --> Shard1 WAL --> Shard2 WAL --> Shard3 Coord["Coordinator
(etcd/ZooKeeper)"] --> QN1 Coord --> QN2 Coord --> QN3 style Client fill:#e94560,stroke:#fff,color:#fff style LB fill:#0f3460,stroke:#fff,color:#fff style Coord fill:#f39c12,stroke:#fff,color:#fff style S3 fill:#27ae60,stroke:#fff,color:#fff

Hình 3: Kiến trúc phân tán điển hình của một Vector Database (tham khảo Milvus)

4.1. Sharding và Replication

Dữ liệu được chia thành nhiều shard dựa trên hash hoặc range partitioning. Mỗi shard có thể có nhiều replica để đảm bảo tính sẵn sàng cao (HA). Khi query, hệ thống scatter request tới tất cả các shard liên quan, sau đó gather và merge kết quả.

4.2. Write-Ahead Log (WAL) và Consistency

Mỗi thao tác insert/update/delete đều được ghi vào WAL trước khi áp dụng vào index. Điều này đảm bảo:

  • Durability: Dữ liệu không mất khi node crash
  • Consistency: Có thể replay WAL để rebuild index
  • Replication: WAL được replicate giữa các replica

4.3. Hybrid Search: Vector + Metadata Filtering

Trong thực tế, hiếm khi chỉ tìm kiếm thuần vector. Thường cần kết hợp: "Tìm tài liệu tương tự với câu hỏi này, nhưng chỉ trong danh mục 'Kỹ thuật' và được tạo sau 01/2025".

# Qdrant hybrid search example
from qdrant_client import QdrantClient
from qdrant_client.models import Filter, FieldCondition, MatchValue, Range

client = QdrantClient(url="http://localhost:6333")

results = client.search(
    collection_name="documents",
    query_vector=embedding_model.encode("kiến trúc microservices"),
    query_filter=Filter(
        must=[
            FieldCondition(
                key="category",
                match=MatchValue(value="engineering")
            ),
            FieldCondition(
                key="created_at",
                range=Range(gte="2025-01-01T00:00:00Z")
            )
        ]
    ),
    limit=10,
    score_threshold=0.7  # Chỉ trả về kết quả có score >= 0.7
)

Cạm bẫy: Pre-filter vs Post-filter

Pre-filter lọc metadata trước, rồi tìm vector trong tập đã lọc — chính xác nhưng chậm nếu filter quá hẹp. Post-filter tìm vector trước, rồi lọc — nhanh nhưng có thể trả về ít hơn top_k kết quả. Hầu hết Vector Database hiện đại (Qdrant, Weaviate) dùng chiến lược hybrid tự động chọn approach tối ưu dựa trên selectivity của filter.

5. So sánh các Vector Database phổ biến

Thị trường Vector Database đang rất sôi động với nhiều lựa chọn, từ open-source đến fully managed. Dưới đây là phân tích chi tiết các giải pháp hàng đầu:

Tiêu chí Milvus Qdrant Weaviate Pinecone ChromaDB pgvector
License Apache 2.0 Apache 2.0 BSD-3 Proprietary Apache 2.0 PostgreSQL
Ngôn ngữ Go + C++ Rust Go - Python C
Scale tối đa Tỷ+ vector 100M+ vector 100M+ vector Tỷ+ vector ~1M vector ~10M vector
Index HNSW, IVF, DiskANN HNSW HNSW Proprietary HNSW IVFFlat, HNSW
Hybrid Search Tốt Xuất sắc Xuất sắc Tốt Cơ bản SQL-native
Multi-tenancy Partition key Collection + payload Native Namespace Không Schema/RLS
Disk-based DiskANN Memmap Không - Không
Phù hợp Enterprise, tỷ vector Startup, production AI-native apps Zero-ops, enterprise Prototype, dev Đã dùng PostgreSQL

Lựa chọn nhanh

Prototype/MVP: ChromaDB — cài đặt 1 dòng, chạy ngay. Production nhỏ-vừa: Qdrant hoặc Weaviate — hiệu năng tốt, dễ vận hành. Enterprise/tỷ vector: Milvus hoặc Pinecone. Đã có PostgreSQL: pgvector — không cần thêm infrastructure mới, đủ tốt cho <10M vector.

6. Tích hợp Vector Database vào pipeline RAG

Vector Database là thành phần không thể thiếu trong kiến trúc Retrieval-Augmented Generation (RAG). Nó đóng vai trò "bộ nhớ dài hạn" cho LLM, cung cấp context chính xác để giảm hallucination và cập nhật kiến thức real-time.

graph LR subgraph Ingestion["📥 Data Ingestion Pipeline"] Doc["Documents
PDF, HTML, MD"] --> Chunk["Chunking
512-1024 tokens"] Chunk --> Embed["Embedding
Model"] Embed --> VDB["Vector DB
Store"] end subgraph Query["🔍 Query Pipeline"] Q["User Query"] --> QEmbed["Embedding"] QEmbed --> Search["Semantic
Search"] Search --> Rerank["Reranker
(Cross-encoder)"] Rerank --> Context["Top-K
Contexts"] end subgraph Generate["🤖 Generation"] Context --> Prompt["Prompt
Assembly"] Q --> Prompt Prompt --> LLM["LLM
(Claude, GPT)"] LLM --> Ans["Answer"] end VDB --> Search style Doc fill:#e94560,stroke:#fff,color:#fff style VDB fill:#0f3460,stroke:#fff,color:#fff style LLM fill:#27ae60,stroke:#fff,color:#fff style Ans fill:#27ae60,stroke:#fff,color:#fff

Hình 4: Pipeline RAG hoàn chỉnh — từ ingestion đến generation

6.1. Chunking Strategy - Nghệ thuật chia nhỏ tài liệu

Chunking là bước quan trọng nhất và thường bị đánh giá thấp. Chunk quá lớn → nhiễu, mất focus. Chunk quá nhỏ → mất context. Các chiến lược phổ biến:

  • Fixed-size chunking: Chia theo số token cố định (512-1024), có overlap 10-20%. Đơn giản, hiệu quả cho đa số trường hợp
  • Semantic chunking: Sử dụng embedding để phát hiện "ranh giới ngữ nghĩa" — chia tại điểm embedding thay đổi đột ngột
  • Recursive character splitting: Chia theo cấu trúc document (heading → paragraph → sentence). Ưu tiên giữ nguyên đơn vị ngữ nghĩa tự nhiên
  • Parent-child chunking: Lưu chunk nhỏ để search, nhưng retrieve chunk lớn hơn (parent) để giữ context
# Semantic Chunking with LangChain
from langchain_experimental.text_splitter import SemanticChunker
from langchain_openai import OpenAIEmbeddings

embeddings = OpenAIEmbeddings(model="text-embedding-3-small")

# Chia tại điểm embedding thay đổi > ngưỡng
chunker = SemanticChunker(
    embeddings,
    breakpoint_threshold_type="percentile",
    breakpoint_threshold_amount=90  # Chia tại top 10% điểm thay đổi
)

chunks = chunker.create_documents([document_text])
# Mỗi chunk là một đơn vị ngữ nghĩa hoàn chỉnh

6.2. Reranking - Tinh chỉnh kết quả

Sau khi Vector DB trả về top-K kết quả (thường K=20-50), một cross-encoder reranker sẽ đánh giá lại chính xác hơn mức độ liên quan giữa query và mỗi document, rồi chọn top-N tốt nhất (N=3-5) đưa vào LLM.

# Reranking with Cohere
import cohere

co = cohere.Client("your-api-key")

# Bước 1: Vector search trả về top-20
vector_results = vector_db.search(query_embedding, limit=20)

# Bước 2: Rerank để chọn top-5 chính xác nhất
reranked = co.rerank(
    model="rerank-v3.5",
    query="kiến trúc microservices cho hệ thống thanh toán",
    documents=[r.text for r in vector_results],
    top_n=5
)

# Reranker thường cải thiện recall@5 thêm 10-15%

7. Tối ưu hiệu năng và chi phí

7.1. Quantization - Nén vector để tiết kiệm RAM

Với dataset lớn, chi phí RAM có thể trở thành bottleneck. Quantization giúp giảm đáng kể:

Phương pháp Kích thước / vector Giảm RAM Mất recall
Float32 (gốc) 6,144 bytes (1536-D) Baseline 0%
Scalar Quantization (INT8) 1,536 bytes 4x ~1-2%
Product Quantization ~192 bytes 32x ~3-5%
Binary Quantization 192 bytes 32x ~5-10%
Matryoshka + Binary 32 bytes (256-D) 192x ~8-15%

Chiến lược tối ưu tiết kiệm nhất

Sử dụng Matryoshka embeddings (hỗ trợ bởi OpenAI text-embedding-3) để giảm chiều từ 3072 xuống 256, kết hợp với Binary Quantization. Kết quả: mỗi vector chỉ còn 32 bytes — đủ lưu 1 tỷ vector trong ~32 GB RAM. Dùng reranking ở bước sau để bù đắp mất mát recall.

7.2. Disk-based Index

Thay vì giữ toàn bộ index trong RAM, một số hệ thống hỗ trợ disk-based indexing:

  • Milvus DiskANN: Graph-based index trên SSD. Chỉ cần ~10% RAM so với HNSW thuần, latency tăng 2-3x
  • Qdrant memmap: Memory-mapped files, OS quản lý page cache. Hiệu quả khi working set < RAM
  • pgvector: Tự nhiên disk-based vì dựa trên PostgreSQL storage engine

8. Các kỹ thuật nâng cao

8.1. Multi-vector Representation

Thay vì biểu diễn mỗi document bằng 1 vector duy nhất, kỹ thuật ColBERT (Contextualized Late Interaction) tạo một vector cho mỗi token. Khi search, tính MaxSim giữa mỗi query token với tất cả document tokens, rồi sum lại. Kết quả: recall vượt trội, đặc biệt với query phức tạp.

8.2. Sparse-Dense Hybrid

Kết hợp tìm kiếm sparse (BM25/TF-IDF — khớp từ khóa chính xác) với dense (vector — hiểu ngữ nghĩa) để có kết quả tốt nhất cho cả hai trường hợp:

# Weaviate hybrid search
result = client.query.get(
    "Document", ["content", "title"]
).with_hybrid(
    query="cách tối ưu hiệu năng database",
    alpha=0.7,  # 70% dense (semantic), 30% sparse (keyword)
    fusion_type="RELATIVE_SCORE"  # Chuẩn hoá score trước khi kết hợp
).with_limit(10).do()

Với model embedding đa phương thức như CLIP, ImageBind, hay Jina CLIP v2, bạn có thể tìm kiếm xuyên modality — dùng text để tìm ảnh, dùng ảnh để tìm text, hoặc thậm chí dùng audio để tìm video.

graph LR T["🔤 Text Query"] --> CLIP["CLIP
Encoder"] I["🖼️ Image"] --> CLIP A["🎵 Audio"] --> CLIP CLIP --> VS["Shared Vector
Space"] VS --> R1["🖼️ Ảnh liên quan"] VS --> R2["📄 Tài liệu liên quan"] VS --> R3["🎥 Video liên quan"] style CLIP fill:#e94560,stroke:#fff,color:#fff style VS fill:#0f3460,stroke:#fff,color:#fff

Hình 5: Multi-modal search — mọi dữ liệu cùng sống trong một không gian vector thống nhất

9. Triển khai thực tế: Từ prototype đến production

9.1. Prototype nhanh với ChromaDB

# Cài đặt: pip install chromadb sentence-transformers
import chromadb

client = chromadb.Client()
collection = client.create_collection(
    name="my_docs",
    metadata={"hnsw:space": "cosine"}
)

# Thêm documents — ChromaDB tự embed
collection.add(
    documents=[
        "Vector database lưu trữ embedding cho tìm kiếm ngữ nghĩa",
        "Redis là in-memory data store hỗ trợ nhiều cấu trúc dữ liệu",
        "Kafka là distributed event streaming platform",
    ],
    ids=["doc1", "doc2", "doc3"],
    metadatas=[
        {"category": "database"},
        {"category": "database"},
        {"category": "streaming"},
    ]
)

# Tìm kiếm
results = collection.query(
    query_texts=["cơ sở dữ liệu cho AI"],
    n_results=2,
    where={"category": "database"}
)
print(results["documents"])
# → [['Vector database lưu trữ embedding...', 'Redis là in-memory...']]

9.2. Production với Qdrant

# docker-compose.yml cho Qdrant production
version: "3.8"
services:
  qdrant:
    image: qdrant/qdrant:v1.12.1
    ports:
      - "6333:6333"   # REST API
      - "6334:6334"   # gRPC
    volumes:
      - qdrant_data:/qdrant/storage
    environment:
      QDRANT__SERVICE__GRPC_PORT: 6334
      QDRANT__STORAGE__OPTIMIZERS__MEMMAP_THRESHOLD_KB: 20000
      QDRANT__STORAGE__ON_DISK_PAYLOAD: true
    deploy:
      resources:
        limits:
          memory: 8G
        reservations:
          memory: 4G

volumes:
  qdrant_data:

9.3. Checklist triển khai production

1

Chọn Embedding Model phù hợp

Benchmark trên dữ liệu thực của bạn, không chỉ dựa vào MTEB leaderboard. Nếu có tiếng Việt, ưu tiên BGE-M3 hoặc multilingual-e5-large.

2

Thiết kế Chunking Strategy

Thử nghiệm nhiều chunk size (256, 512, 1024 tokens) và đo recall trên test set. Sử dụng overlap 10-20% để tránh mất context ở ranh giới.

3

Xây dựng Evaluation Pipeline

Tạo golden dataset với câu hỏi + đáp án mong muốn. Đo recall@k, MRR, và NDCG. Tự động chạy khi thay đổi model hoặc chunking.

4

Monitoring và Alerting

Theo dõi: latency P95/P99, recall trend, disk usage, query throughput. Alert khi latency vượt SLA hoặc recall giảm đột ngột.

5

Backup và Disaster Recovery

Snapshot định kỳ toàn bộ collection. Test restore flow. Đừng quên backup cả embedding model version — nếu model thay đổi, tất cả vector phải re-embed.

10. Kết luận

Vector Database không chỉ là một trend công nghệ — nó đang trở thành infrastructure layer thiết yếu cho mọi ứng dụng AI, từ chatbot đến recommendation system, từ semantic search đến multimodal AI.

Điểm mấu chốt cần nhớ:

  • Embedding quality quyết định tất cả — Vector DB chỉ tốt bằng embedding model bạn chọn
  • Bắt đầu đơn giản — ChromaDB cho prototype, pgvector nếu đã có PostgreSQL, Qdrant/Weaviate cho production
  • Chunking là nghệ thuật — Không có one-size-fits-all, phải thử nghiệm với dữ liệu thực
  • Reranking không thể thiếu — Luôn kết hợp reranker để cải thiện precision
  • Monitor continuously — Recall có thể drift theo thời gian khi dữ liệu thay đổi

Khi kết hợp Vector Database với các kỹ thuật như RAG, GraphRAG, và Agentic AI, bạn sẽ có nền tảng vững chắc để xây dựng những hệ thống AI thực sự thông minh — hiểu ngữ cảnh, truy xuất kiến thức chính xác, và đưa ra câu trả lời đáng tin cậy.

Đọc thêm trong series AI Infrastructure

Bài viết này là một phần trong chuỗi bài về hạ tầng AI. Tham khảo thêm các bài về RAG, GraphRAG & Knowledge Graph, và MCP Protocol trên anhtu.dev để có cái nhìn toàn diện về cách xây dựng hệ thống AI production-ready.