latentSource

Bases de datos vectoriales: la capa de memoria de la IA moderna

Los embeddings son el lenguaje de la búsqueda semántica, y las bases de datos vectoriales son el lugar donde residen. Aprende cómo los índices ANN potencian la recuperación a escala.

·7 min read
Compartir
Bases de datos vectoriales: la capa de memoria de la IA moderna

Antes de que el RAG estuviera en cada presentación, la infraestructura que lo hace posible ya estaba madurando en el entorno open source. La búsqueda vectorial no es nueva. Lo que cambió es que los embedding models se volvieron lo suficientemente buenos como para que la matemática realmente rinda frutos.

Cada sistema de generación aumentada por recuperación (RAG), cada motor de búsqueda semántica y cada recomendador que entiende el significado en lugar de las palabras clave se apoya en la misma primitiva: encontrar los puntos más cercanos a una consulta en un espacio de alta dimensionalidad. Las bases de datos vectoriales existen para que esa operación sea rápida, escalable y no se convierta en un proyecto de investigación. Si estás construyendo algo que recupere información por significado, terminarás usando una. Vale la pena saber cómo funcionan realmente antes de elegir.

Por qué las bases de datos tradicionales fallan en la búsqueda semántica

Una cláusula WHERE en PostgreSQL busca coincidencias exactas. LIKE busca patrones. La búsqueda de texto completo (full-text search) busca tokens. Ninguna de ellas captura el significado.

"¿Cómo soluciono una fuga de memoria en Python?" y "Aplicación de Python consumiendo demasiada RAM" significan lo mismo, pero casi no comparten palabras. La búsqueda por palabras clave pierde la conexión. Sus vectores de embedding, por otro lado, se ubicarán uno al lado del otro en el espacio vectorial.

Ese es el cambio. Buscar por lo que el texto significa en lugar de lo que contiene. Y la "cercanía en el significado" se traduce en "cercanía en el espacio vectorial", lo que se convierte en un problema de vecinos más cercanos sobre vectores de alta dimensionalidad.

Las bases de datos tradicionales no están diseñadas para esto. Un índice B-tree asume un orden natural por el cual puede realizar una búsqueda binaria; en 1,536 dimensiones no hay nada que buscar binariamente. Calcular la distancia entre una consulta y cada vector almacenado funciona bien para miles de documentos, se desmorona con millones y es imposible con miles de millones.

Repaso de embeddings

Un recordatorio rápido de lo que estamos almacenando.

Un embedding es un vector denso, típicamente de 256 a 3,072 números de punto flotante, que representa el contenido semántico de un fragmento de texto o imagen. El modelo que lo produjo fue entrenado para que las entradas semánticamente similares queden cerca unas de otras, medido por la similitud de coseno: el coseno del ángulo entre dos vectores:

cos(θ)=abab=iaibiiai2ibi2\cos(\theta) = \frac{{\mathbf{{a}} \cdot \mathbf{{b}}}}{{\lVert \mathbf{{a}} \rVert \, \lVert \mathbf{{b}} \rVert}} = \frac{{\sum_i a_i b_i}}{{\sqrt{{\sum_i a_i^2}}\,\sqrt{{\sum_i b_i^2}}}}

Rango desde 1-1 (opuesto) pasando por 00 (ortogonal, no relacionado) hasta 11 (dirección idéntica). Para vectores normalizados por unidad, el denominador es 1, por lo que la similitud de coseno se reduce al producto punto simple ab\mathbf{{a}} \cdot \mathbf{{b}} — razón por la cual la mayoría de los vector stores normalizan los datos al ingresar.

from openai import OpenAI client = OpenAI() response = client.embeddings.create( model="text-embedding-3-small", input="How do I fix a memory leak in Python?" ) vector = response.data[0].embedding # list of 1536 floats print(len(vector)) # 1536 print(vector[:5]) # [0.0023, -0.0091, 0.0142, ...]

La calidad de tu recuperación está limitada por el embedding model. La mejor base de datos vectorial del mundo no puede encontrar un documento relevante si el modelo de embedding no lo colocó cerca de la consulta. Elegir el modelo adecuado y realizar un buen chunking de los documentos importa al menos tanto como elegir la base de datos correcta.

Qué hace realmente una base de datos vectorial

En su núcleo, realiza cuatro operaciones:

  1. Insertar: almacenar un vector con metadatos (ID del documento, URL de origen, marcas de tiempo, etiquetas).
  2. Indexar: construir una estructura que permita una búsqueda rápida de vecinos más cercanos aproximados (ANN).
  3. Consultar: dado un vector de consulta y un valor de k, devolver los k vectores almacenados más similares.
  4. Filtrar: combinar la similitud vectorial con predicados de metadatos ("los 10 documentos más similares que también tengan la etiqueta 'ingeniería' y hayan sido creados después del 2024-01-01").

La parte difícil es la operación 3. La búsqueda exacta de vecinos más cercanos es O(n) con constantes altas debido a la dimensionalidad. Un millón de vectores con 1,536 dimensiones significa más de 6 mil millones de operaciones de punto flotante por consulta. Los algoritmos aproximados sacrifican un poco de precisión a cambio de órdenes de magnitud en velocidad.

Algoritmos ANN: la sala de máquinas

Tres familias de algoritmos predominan.

HNSW (Hierarchical Navigable Small World)

Es el algoritmo ANN más utilizado en producción. Construye un grafo multicapa donde cada nodo es un vector y las aristas conectan a los cercanos. La capa superior es dispersa con conexiones de largo alcance; la inferior es densa con conexiones locales.

Una consulta comienza en la parte superior, avanza de forma voraz (greedy) hacia el vector objetivo y baja a una capa inferior cuando deja de progresar. Es como hacer zoom en un mapa: continente, país, ciudad, calle.

Pros: recall muy alto a una velocidad muy alta, funciona bien en memoria, no requiere paso de entrenamiento. Cons: alto uso de memoria debido al grafo, el tiempo de inserción crece logarítmicamente, no es ideal para datasets que cambian rápidamente.

Los dos parámetros de ajuste son M (aristas por nodo; a mayor valor, mejor recall y más memoria) y ef_construction / ef_search (candidatos explorados; a mayor valor, mejor recall y consultas más lentas).

IVF (Inverted File Index)

IVF divide el espacio vectorial en clusters utilizando k-means. Al momento de la consulta, solo se buscan los clusters cercanos a la consulta. Esto reduce las comparaciones de N a aproximadamente N/k * nprobe, donde nprobe es cuántos clusters revisas.

Fase de entrenamiento:
  1. Ejecutar k-means en una muestra de vectores → k centroides
  2. Asignar cada vector a su centroide más cercano

Fase de consulta:
  1. Encontrar los nprobe centroides más cercanos a la consulta
  2. Buscar solo los vectores asignados a esos clusters
  3. Devolver los resultados top-k

Pros: menor sobrecarga de memoria que HNSW, escala a datasets muy grandes. Cons: requiere una fase de entrenamiento, el recall se degrada cuando los clusters son desiguales, débil con un nprobe bajo.

PQ (Product Quantization)

PQ comprime los vectores para ahorrar memoria y acelerar el cálculo de distancias. Divide cada vector en subvectores y cuantiza cada uno en uno de 256 centroides (1 byte). Un vector float32 de 1,536 dimensiones (6,144 bytes) se reduce a 192 bytes — 32 veces más pequeño.

PQ casi siempre se combina con IVF como IVF-PQ: IVF para la búsqueda gruesa y PQ para el cálculo de distancia comprimido dentro de los clusters. Esta combinación potencia sistemas a escala de miles de millones en Meta y Spotify.

Pros: ahorro masivo de memoria, los datasets que nunca cabrían en RAM comienzan a caber. Cons: la compresión con pérdida afecta la precisión, requiere paso de entrenamiento, es excesivo para datasets pequeños.

Los actores clave

El mercado se ha vuelto concurrido. Aquí un desglose pragmático:

Pinecone: totalmente gestionado, serverless, cero ops. Te conectas a una API y ellos manejan el indexado, escalado y replicación. Ideal para equipos que quieren lanzar productos sin gestionar infraestructura. Se paga con costo y dependencia del proveedor (lock-in).

Qdrant: open source, escrito en Rust, rápido. Filtrado enriquecido, vectores dispersos, búsqueda híbrida (densos más dispersos). Puedes auto-hospedarlo o usar su nube gestionada.

Weaviate: open source, enfocado en la ergonomía para el desarrollador. Tiene módulos de vectorización integrados para que puedas entregarle texto plano y él haga el embedding por ti. Conveniente si buscas eso, una abstracción extra si no.

Chroma: ligero, nativo de Python, diseñado para prototipado y cargas pequeñas a medianas. In-process o como servidor. La forma más rápida de tener un demo de RAG funcionando en una tarde.

pgvector: una extensión de PostgreSQL. Merece su propia sección.

pgvector: búsqueda vectorial en tu stack existente

La mayoría de los equipos ya utilizan PostgreSQL. Si es tu caso, pgvector es difícil de descartar. En lugar de añadir una nueva base de datos a la arquitectura, añades una extensión a la que ya operas.

-- Habilitar la extensión CREATE EXTENSION vector; -- Crear una tabla con una columna vectorial CREATE TABLE documents ( id SERIAL PRIMARY KEY, title TEXT, content TEXT, source TEXT, created_at TIMESTAMP DEFAULT NOW(), embedding vector(1536) ); -- Insertar un documento con su embedding INSERT INTO documents (title, content, source, embedding) VALUES ( 'Memory Management in Python', 'Python uses reference counting and a cyclic garbage collector...', 'internal-docs', '[0.0023, -0.0091, 0.0142, ...]' -- Vector de 1536 dimensiones );

Las consultas son SQL familiar con operadores vectoriales:

-- Encontrar los 5 documentos más similares a un vector de consulta SELECT id, title, content, embedding <=> '[0.0031, -0.0087, ...]'::vector AS distance FROM documents ORDER BY embedding <=> '[0.0031, -0.0087, ...]'::vector LIMIT 5;

El operador <=> es la distancia de coseno. pgvector también soporta <-> (L2) y <#> (producto interno negativo).

Para un rendimiento real, necesitas un índice. pgvector soporta tanto IVFFlat como HNSW:

-- Crear un índice HNSW (predeterminado para la mayoría de los casos de uso) CREATE INDEX ON documents USING hnsw (embedding vector_cosine_ops) WITH (m = 16, ef_construction = 200); -- O IVFFlat para datasets más grandes con restricciones de memoria CREATE INDEX ON documents USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);

La fortaleza de pgvector es la consistencia transaccional. Los vectores y los metadatos viven en la misma base de datos, participan en las mismas transacciones y se respaldan juntos. Puedes unir resultados vectoriales con datos relacionales en una sola consulta:

-- Búsqueda semántica con filtrado de metadatos SELECT d.id, d.title, d.content, t.name AS tag FROM documents d JOIN document_tags dt ON d.id = dt.document_id JOIN tags t ON dt.tag_id = t.id WHERE t.name = 'engineering' AND d.created_at > '2024-01-01' ORDER BY d.embedding <=> $1::vector LIMIT 10;

El límite es la escala. pgvector funciona bien hasta aproximadamente 1-5 millones de vectores, dependiendo de la dimensionalidad y el hardware. Más allá de eso, las bases de datos vectoriales distribuidas dedicadas (Qdrant, Pinecone, Milvus) manejan mejor la carga.

Filtrado de metadatos: el patrón híbrido

La búsqueda vectorial pura recupera por significado. Las aplicaciones reales casi siempre combinan eso con restricciones estructuradas: "Encuentra documentos similares, pero solo de este departamento, creados en los últimos 30 días, con un puntaje de confianza superior a 0.8".

Cómo una base de datos maneja esto importa mucho para el rendimiento de la consulta. Dos estrategias:

El prefiltrado aplica primero los predicados de metadatos y luego busca en el subconjunto filtrado. Es eficiente cuando los filtros son muy selectivos. El riesgo es perder resultados semánticamente relevantes que queden fuera del filtro.

El postfiltrado realiza primero la búsqueda vectorial, recupera más candidatos de los necesarios y luego aplica los filtros de metadatos. Preserva el recall, pero desperdicia cómputo en candidatos que luego se descartan.

La mayoría de los sistemas en producción utilizan un híbrido: un prefiltrado laxo para estrechar el conjunto de candidatos, luego búsqueda vectorial y finalmente un postfiltrado para cualquier predicado restante.

Eligiendo la herramienta adecuada

El árbol de decisión es más simple de lo que implica el marketing:

  • ¿Ya usas PostgreSQL y tienes menos de 5 millones de vectores? Empieza con pgvector. Menos superficie operativa y transacciones incluidas.
  • ¿Necesitas simplicidad gestionada y no te importa pagar por ello? Pinecone te lleva a producción más rápido.
  • ¿Necesitas control, rendimiento y código abierto? Qdrant o Milvus, auto-hospedados.
  • ¿Estás prototipando esta misma tarde? Chroma in-memory, cero configuración.

La base de datos vectorial es la capa de memoria de la IA moderna. Es donde viven los embeddings, donde ocurre la búsqueda semántica y donde el RAG encuentra el contexto que mantiene a un LLM conectado a la realidad. Los algoritmos están maduros, las herramientas están listas para producción y la parte más difícil ya no es la infraestructura. Es el modelo de embedding y la estrategia de segmentación (chunking) con la que lo alimentas.