Ilustración técnica para: Bases de Datos Vectoriales en IA: Fundamentos y Aplicación Práctica con FAISS para Nivel Intermedio

Bases de datos vectoriales en 2026: cómo funcionan y cuál elegir (guía práctica)


El instinto habitual al montar búsqueda semántica o un sistema RAG es elegir la base de datos vectorial antes de medir nada. Es un error de orden: el cuello de botella inicial no suele ser el motor, sino el recall del retrieval, el troceado y la métrica de similitud. Esta guía va al revés: primero cómo funciona una base de datos vectorial por dentro; después, la elección de motor con tabla de siete opciones, árbol de decisión y ejemplo ejecutable.

¿Qué es una base de datos vectorial?

Una base de datos vectorial es un sistema especializado en almacenar y consultar vectores de alta dimensión: los embeddings que los modelos de IA generan para representar texto, imágenes o audio como puntos de un espacio donde la cercanía geométrica implica similitud semántica. Su consulta central no es 'dame la fila con id 42', sino 'dame los k vectores más parecidos a este' (k-NN).

Una base relacional puede guardar vectores; sin un índice vectorial, responderla exige un escaneo exacto cuyo coste crece linealmente con el corpus. La pieza diferencial es el índice de vecinos aproximados (ANN) — que extensiones como pgvector añaden al propio Postgres — y que sacrifica una fracción de exactitud a cambio de órdenes de magnitud de velocidad.

No todo lo 'vectorial' es una base de datos: las librerías (FAISS, Annoy) se embeben en tu proceso, sin escritura concurrente, filtrado por metadata ni transacciones; las bases de datos añaden persistencia gestionada, API de red y filtros. Confundirlas es un error frecuente según KX.

Métricas de similitud e índices: el trade-off recall-latencia

Tres métricas cubren casi todo: la distancia euclídea (L2), sensible a la magnitud del vector; la similitud coseno, que mide el ángulo y es el estándar en texto; y el producto escalar, útil cuando la magnitud codifica información. Con vectores normalizados, coseno y producto escalar dan el mismo ranking. Regla práctica: usa la métrica con la que se entrenó tu modelo de embeddings.

  • HNSW (grafo jerárquico): el paper de Malkov y Yashunin define sus dos mandos: M (conexiones por nodo en cada capa) y ef (tamaño de la lista de candidatos: efConstruction al construir, efSearch al consultar), el principal mando recall/velocidad en consulta.
  • IVF (listas invertidas): particiona el espacio en celdas y explora solo las más prometedoras; necesita datos cargados para entrenar. Construye más rápido y con menos memoria que HNSW, con peor recall/velocidad, según el README de pgvector.
  • Cuantización (escalar, binaria, PQ): comprime para caber en memoria. Qdrant reporta que la escalar (float32 a uint8) reduce memoria ~75% con error típico inferior al 1%, y que la binaria la reduce 32x y acelera hasta 40x apoyándose en rescoring; son cifras del proveedor, mide la pérdida en tu corpus.

ANN-Benchmarks compara decenas de algoritmos midiendo recall frente a QPS: a más recall, menos throughput; se elige un punto de la curva. Ojo: el recall medido en benchmark no se traslada tal cual a la distribución long-tail de las consultas reales de un RAG, y apurar el objetivo de recall encarece la latencia de forma no lineal. Mide el recall por segmento de frecuencia, no en promedio.

Arquitectura interna de un motor vectorial

Un motor vectorial resuelve, como mínimo, tres problemas: almacenamiento, índice ANN y consulta con filtros.

Almacenamiento. Con embeddings de 1536 dimensiones cada vector ocupa ~6KB en float32 — más de 600GB solo en vectores crudos a 100M —, y sumando el grafo HNSW y el overhead de tuplas el coste real por vector puede rondar 20-25KB, según ClickHouse; a esa escala la presión de memoria domina el diseño.

Índice. Milvus separa ingesta, indexado y consulta en componentes distribuidos; Pinecone es un serverless totalmente gestionado, sin versión self-hosted: su arquitectura es invisible.

Filtrado e híbrida. El fallo clásico es la trampa del post-filtrado: filtrar por metadata después del índice ANN descarta resultados en silencio y degrada el recall real sin que se note (ClickHouse); pgvector lo mitiga con iterative index scans. En búsqueda híbrida, Milvus integra BM25 nativo server-side, Qdrant fusiona dense y sparse con RRF o DBSF y Weaviate combina BM25F y vectores vía el parámetro alpha.

Tabla de decisión y árbol: qué motor elegir

Elegir motor es un problema de restricciones. Versiones verificadas a julio de 2026.

MotorTipoCuándo elegirloCuándo NO
pgvector 0.8.5Extensión de Postgres (self-hosted)Ya operas Postgres; corpus hasta decenas de millones de vectoresp99 agresivo, cientos de millones, GPU
Qdrant v1.18.2OSS, Cloud o Hybrid CloudFiltrado rico, híbrida dense+sparse nativa, cuantización agresivaTu Postgres ya cubre el caso
Milvus v2.6.19OSS standalone/distribuido o Zilliz CloudEscala distribuida, throughput sostenido, BM25 nativoProyectos pequeños: no se amortiza
PineconeSolo gestionado/serverlessCero operación, arranque rápidoSelf-host/soberanía de datos, metadata pesada
Weaviate v1.38.3OSS o Weaviate CloudHíbrida BM25F madura, objetos + vectoresSolo k-NN plano
Chroma 1.5.9Local embebida, single-node o Chroma CloudPrototipos y apps pequeñasSingle-node: pensado para menos de 10M de registros
FAISS 1.14.3Librería embebida, sin servidor (índices serializables a disco)Retrieval in-process, control fino, GPUConcurrencia, filtros, multi-cliente: no es una BD

Tiers gratuitos: Qdrant Cloud (0.5 vCPU, 1GB RAM, 4GB disco), Zilliz Cloud (5GB, ~1M vectores de 768 dims), Pinecone Starter (2GB, solo AWS us-east-1; el plan de pago más barato es Builder, 20 $/mes), Weaviate Sandbox (100.000 objetos) o Chroma Cloud (5 $ de créditos). pgvector no tiene servicio propio: pagas a tu proveedor de Postgres.

¿Ya tienes Postgres en producción?
├─ SÍ → ¿Corpus < ~10M vectores y sin p99 < 20 ms?
│   ├─ SÍ → pgvector con HNSW; mide el retrieval primero
│   └─ NO → ¿Cientos de millones, GPU o híbrida avanzada?
│       ├─ SÍ → motor dedicado (GPU de búsqueda → Milvus; filtrado/híbrida → Qdrant)
│       └─ NO → pgvector + cuantización/particionado; reevalúa hacia 100M
└─ NO → ¿Prototipo o app pequeña?
    ├─ SÍ → Chroma en local, o free tier de Qdrant/Zilliz
    └─ NO → ¿Quieres operar la infraestructura?
        ├─ NO → Pinecone, Zilliz Cloud o Weaviate Cloud
        └─ SÍ → ¿Filtrado + híbrida? → Qdrant o Weaviate
                ¿Escala distribuida? → Milvus

Los umbrales salen de la guía de ClickHouse (a 10M la cuantización y el particionado son críticos; a 100M toca replantear un HNSW en memoria) y del techo de 50-100M de vectores por índice que señala ByteByteGo al analizar el caso Instacart. Trátalos como heurísticas: dimensión, filtros, churn del corpus y SLO pueden moverlos un orden de magnitud.

Qué es FAISS: ejemplo práctico y cuándo no usarlo

FAISS 1.14.3 es una librería embebida, sin capa de red ni persistencia gestionada (los índices se serializan a disco, sin transacciones ni replicación): ideal para medir recall contra un baseline exacto:

import numpy as np
import faiss  # pip install faiss-cpu (Python 3.10+)

d = 768        # dimension del embedding
nb = 100_000   # tamano del corpus
nq = 100       # consultas de evaluacion
rng = np.random.default_rng(42)

xb = rng.standard_normal((nb, d), dtype='float32')
faiss.normalize_L2(xb)   # normalizados: inner product == coseno

flat = faiss.IndexFlatIP(d)   # baseline exacto
flat.add(xb)

nlist = 1280                  # ~4*sqrt(N)
ivf = faiss.IndexIVFFlat(faiss.IndexFlatIP(d), d, nlist,
                         faiss.METRIC_INNER_PRODUCT)
ivf.train(xb)                 # IVF requiere entrenamiento
ivf.add(xb)
ivf.nprobe = 32               # celdas exploradas: recall vs QPS

xq = rng.standard_normal((nq, d), dtype='float32')
faiss.normalize_L2(xq)

_, I_exact = flat.search(xq, 10)
_, I_ann = ivf.search(xq, 10)

recalls = [len(set(a) & set(e)) / 10 for a, e in zip(I_ann, I_exact)]
print(f'recall@10 medio del IVF frente al exacto: {np.mean(recalls):.2f}')

El nlist sigue la guía oficial de Faiss (nlist entre 4 y 16 veces la raíz de N por debajo de 1M de vectores).

El límite práctico: Instacart migró su servicio FAISS a pgvector porque no podía filtrar por atributos al recuperar y mantener dos sistemas generaba desincronización; la migración completa a Postgres trajo 10x menos carga de escritura y 2x más velocidad, y pgvector en concreto un 6% menos de búsquedas sin resultados.

Casos de uso en producción y sus fallos comunes

RAG. El fallo raíz suele estar en el troceado: Anthropic midió que añadir contexto a cada chunk antes de embeberlo reduce los fallos de retrieval top-20 un 35%; con BM25 contextual, un 49%; con reranker, un 67%, a ~1.02 $ por millón de tokens. El reranker reordena candidatos tras el retrieval; no lo sustituye.

Búsqueda semántica. El fallo común: el vector puro falla en matches exactos; el ejemplo típico es buscar getUserById y recibir getUserByName; en el A/B documentado por TigerData, combinar match exacto, full-text y vector con reranking mejoró la precisión un 23% y el recall un 37%.

Deduplicación. De sugerencias equivalentes en el autocompletado de Instacart a deduplicar decenas de miles de millones de documentos para entrenar un LLM, el caso que llevó a Milvus a añadir un índice MinHash LSH nativo.

Fallos transversales. Mezclar vectores de dos versiones del modelo de embeddings en el mismo índice no da error (misma dimensionalidad) y degrada el retrieval en silencio; mitigación: índices versionados con alias blue-green, validados con al menos 200 pares antes del cambio. Y añadir búsqueda híbrida a posteriori puede obligar a reindexar el corpus completo, según el motor y los campos ya almacenados (Elastic lo documenta en su esquema); decídela el día uno y, como norma, indexa en bulk.

Cuándo NO necesitas una base vectorial dedicada

Si ya operas Postgres, pgvector llega más lejos de lo que se asume: en el benchmark de Supabase con 1M de embeddings, HNSW superó a IVFFlat en más de 6x (accuracy@10 de 0.98) y, con ef_search en 250 y accuracy@10 de 0.99, superó a Qdrant. Con 50M de vectores, Timescale midió con pgvectorscale 28x menos latencia p95 y 16x más throughput que Pinecone al 99% de recall, un 75% más barato. Son benchmarks de parte interesada, pero el orden de magnitud pesa. Y hay motivos no vectoriales: Confident AI volvió de Pinecone a pgvector: el límite de 40KB de metadata forzaba una segunda query y el cuello de botella real era la latencia de red de la API externa.

Señales para migrar a un motor dedicado, según ClickHouse: p99 por debajo de 20ms, cientos de millones a miles de millones de vectores, GPU, o alta volatilidad del corpus que degrada el rendimiento por el MVCC de Postgres. A esa escala cambian los criterios: Reddit (~340M de vectores, camino de mil millones) eligió Milvus no por latencia bruta (ahí ganaba Qdrant), sino por throughput con replicación y rebalanceo automático.

Preguntas frecuentes

¿pgvector o Qdrant?

Con Postgres en producción y un corpus de hasta decenas de millones, pgvector: menos piezas, transacciones y joins gratis. Qdrant cuando filtrado rico, híbrida dense+sparse nativa o cuantización agresiva sean requisitos.

¿FAISS es una base de datos?

No: es una librería embebida, sin capa de red ni persistencia gestionada: serializa índices a disco, pero sin transacciones ni replicación. Sirve para experimentar con índices y retrieval in-process; con escrituras concurrentes, filtros o varios clientes, usa un motor o pgvector.

¿Necesito búsqueda híbrida?

Si tus usuarios buscan identificadores exactos (SKUs, nombres de función), probablemente: el vector puro falla justo ahí, aunque un lookup estructurado también puede resolverlo. Y decídela antes de indexar: añadirla después puede obligar a reindexar el corpus completo, según el motor y el esquema.

Conclusión: mide el retrieval antes de elegir motor

La elección de motor es la última decisión, no la primera. El orden que evita fallos caros: monta un set de evaluación con pares query-documento reales antes de tocar infraestructura; decide métrica, troceado e híbrida el día uno, porque cambiarlas suele implicar reindexar; empieza por el motor que menos piezas añade (con Postgres, pgvector); y migra solo ante señales concretas de escala, latencia o volatilidad del corpus. El motor se cambia con una migración; un retrieval mal medido se paga en cada respuesta.

Compartir X LinkedIn