Vector Database: Elección y Optimización para AI Engineering
Cuando se construye una pipeline RAG en producción, la elección del vector database no es un detalle de implementación: es una decisión arquitectónica que influye en la latencia, los costos operativos, el recall accuracy y la escalabilidad del sistema. En 2025 el mercado de los vector database supera los 2.65 mil millones de dólares y el número de soluciones disponibles ha crecido drásticamente, haciendo la selección cada vez más compleja.
Este artículo no es una panorámica de marketing de las características comerciales. Es un deep dive técnico sobre cómo funcionan internamente los vector database, qué algoritmos de indexación usan, cómo se configuran y optimizan para workloads reales. Analizaremos Qdrant, Pinecone, Milvus y Weaviate comparándolos en dimensiones concretas: arquitectura HNSW, estrategias de cuantización, filtered search, DiskANN vs in-memory, y tuning de parámetros para alcanzar el objetivo de recall/latencia definido por tu aplicación.
Qué Aprenderás
- Arquitectura interna de los vector database: cómo funciona HNSW a nivel algorítmico
- Comparativa IVF vs HNSW vs DiskANN: cuándo usar cada uno y por qué
- Cuantización de vectores: scalar, product quantization y binary
- Filtered search: combinar búsqueda vectorial con filtros de metadata
- Comparativa práctica: Qdrant vs Pinecone vs Milvus vs Weaviate
- Tuning de parámetros HNSW: ef_construction, M y sus efectos en recall/latencia
- Costos y escalabilidad: análisis económico para diferentes escalas
1. Cómo Funciona HNSW: El Algoritmo Detrás de los Vector Database
HNSW (Hierarchical Navigable Small World) es el algoritmo de indexación más utilizado en los vector database modernos. Construye un grafo multi-capa donde los nodos son vectores y los arcos conectan vectores cercanos. Las capas superiores tienen pocos nodos (búsqueda global rápida), las inferiores tienen todos los nodos (búsqueda local precisa).
PARÁMETROS HNSW CRÍTICOS:
M (número de conexiones por nodo):
- Valores típicos: 8-64
- M alto = mejor recall, más memoria
- M bajo = menos memoria, menor recall
- Recomendado: M=16 para la mayoría de los casos
ef_construction (tamaño de la lista candidata durante la construcción):
- Valores típicos: 100-500
- ef alto = mejor calidad del índice, construcción más lenta
- ef bajo = construcción rápida, calidad inferior
- Recomendado: ef_construction=200
ef_search (tamaño de la lista candidata durante la búsqueda):
- Valores típicos: 50-500
- ef alto = mejor recall, búsqueda más lenta
- ef bajo = búsqueda rápida, menor recall
- DEBE ser >= top_k (número de resultados solicitados)
- Recomendado: ef_search=128 para recall >95%
TRADE-OFFS:
Recall 99% + Latencia <10ms: M=32, ef_construction=400, ef_search=256
Recall 95% + Latencia <5ms: M=16, ef_construction=200, ef_search=128
Recall 90% + Latencia <1ms: M=8, ef_construction=100, ef_search=64
2. Comparativa: Qdrant vs Pinecone vs Milvus vs Weaviate
Comparativa Vector Database 2025
| Dimensión | Qdrant | Pinecone | Milvus | Weaviate |
|---|---|---|---|---|
| Tipo | Open source | SaaS | Open source | Open source |
| Lenguaje | Rust | Propietario | Go + C++ | Go |
| Índices | HNSW | Propietario | HNSW, IVF, DiskANN | HNSW |
| Filtered search | Excelente | Bueno | Bueno | Excelente |
| Multi-tenancy | Colecciones + payloads | Namespaces | Partitions | Tenants |
| Cuantización | Scalar, Binary | Automática | Scalar, PQ, SQ | PQ |
| Mejor para | RAG producción, Rust perf. | Startup, serverless | Escala masiva | Hybrid search nativo |
3. Implementación Práctica con Qdrant
from qdrant_client import QdrantClient
from qdrant_client.models import (
Distance, VectorParams, OptimizersConfigDiff,
HnswConfigDiff, QuantizationConfig, ScalarQuantization,
ScalarQuantizationConfig, ScalarType, PointStruct
)
# Conexión a Qdrant
client = QdrantClient(url="http://localhost:6333")
# Crear colección con configuración HNSW optimizada
client.create_collection(
collection_name="rag_production",
vectors_config=VectorParams(
size=1536, # Dimensión del embedding
distance=Distance.COSINE, # Métrica de distancia
hnsw_config=HnswConfigDiff(
m=16, # Conexiones por nodo
ef_construct=200, # Calidad de construcción
full_scan_threshold=10000 # Umbral para full scan vs HNSW
),
quantization_config=ScalarQuantization(
scalar=ScalarQuantizationConfig(
type=ScalarType.INT8, # Cuantización a INT8 (-75% memoria)
quantile=0.99, # Recorta el 1% de outliers
always_ram=True # Mantiene cuantizado en RAM
)
),
),
optimizers_config=OptimizersConfigDiff(
indexing_threshold=20000 # Construye HNSW después de 20K puntos
),
)
# Configurar el parámetro de búsqueda
# ef_search controla recall vs latencia
client.update_collection(
collection_name="rag_production",
hnsw_config=HnswConfigDiff(ef=128) # ef_search=128 para recall ~95%
)
# Ingesta de vectores por lotes
import numpy as np
from uuid import uuid4
def ingest_batch(embeddings, texts, metadatas, batch_size=100):
"""Ingesta eficiente por lotes"""
points = []
for i, (emb, text, meta) in enumerate(zip(embeddings, texts, metadatas)):
points.append(PointStruct(
id=str(uuid4()),
vector=emb.tolist(),
payload={"text": text, **meta}
))
if len(points) >= batch_size:
client.upsert(
collection_name="rag_production",
points=points
)
points = []
if points:
client.upsert(collection_name="rag_production", points=points)
4. Cuantización: Reducir Memoria sin Perder Calidad
La cuantización reduce la precisión numérica de los vectores (de float32 a int8 o binary) para reducir el consumo de memoria y aumentar la velocidad de búsqueda. Con la cuantización escalar a INT8 se reduce la memoria un 75% con una pérdida de recall típicamente inferior al 1%.
Tipos de Cuantización
- Scalar Quantization (INT8): cada componente float32 se mapea a un int8. Reducción 4x de memoria, pérdida de recall <1%.
- Product Quantization (PQ): divide el vector en subvectores y cuantiza cada uno. Reducción hasta 32x, pérdida de recall 2-5%.
- Binary Quantization: cada componente se convierte en 1 bit. Reducción 32x, pérdida de recall 5-10%. Ideal para pre-filtrado rápido.
5. Best Practices y Anti-Patterns
Best Practices Vector Database
- Mide recall antes de optimizar latencia: un sistema rápido pero impreciso es inútil. Primero alcanza recall >95%, luego optimiza velocidad.
- Usa cuantización scalar (INT8) siempre: la pérdida de recall es mínima (<1%) y el ahorro de memoria es significativo (75%).
- Pre-filtrado con metadata: filtrar por metadata antes de la búsqueda vectorial es más eficiente que post-filtrado.
- Benchmarks con tus datos: no confíes solo en benchmarks públicos. La distribución de tus datos influye significativamente en el rendimiento.
Anti-Patterns a Evitar
- Ignorar el tuning de HNSW: los parámetros por defecto raramente son óptimos para tu caso de uso. Prueba diferentes combinaciones de M, ef_construction y ef_search.
- Escalar sin índice: sin HNSW u otro índice, la búsqueda es lineal O(n) y se vuelve inutilizable con millones de vectores.
- Colecciones demasiado grandes sin particionado: para más de 10M de vectores, considera particionar por tenant o categoría.
Conclusiones
La elección del vector database es una decisión arquitectónica que afecta a todo el sistema RAG. Hemos explorado la arquitectura interna de HNSW, comparado Qdrant, Pinecone, Milvus y Weaviate, analizado estrategias de cuantización y visto la implementación práctica con Qdrant.
Los puntos clave:
- HNSW es el algoritmo estándar: comprende sus parámetros M, ef_construction y ef_search
- Qdrant destaca para RAG en producción (Rust, filtered search, cuantización nativa)
- La cuantización scalar (INT8) reduce la memoria un 75% con pérdida mínima de recall
- Siempre mide recall y latencia con tus datos reales, no solo benchmarks públicos
Continúa la Serie
- Artículo 2: Embeddings y Búsqueda Semántica
- Artículo 3: Vector Database (actual)
- Artículo 4: Hybrid Retrieval
- Artículo 5: RAG en Producción







