El reflejo que sale caro
Montas tu primer RAG, lees que necesitas buscar por similitud y el siguiente paso parece obvio: dar de alta una base de datos vectorial. Pinecone, Weaviate, Qdrant, Milvus. Un servicio más que aprovisionar, pagar y mantener.
En la mayoría de los proyectos ese paso llega demasiado pronto. Una base de datos vectorial dedicada resuelve un problema concreto, y ese problema no lo tienes con diez mil fragmentos de texto. Lo tienes con diez millones. Confundir las dos situaciones es una de las formas más comunes de complicar una arquitectura sin ganar nada.
Vamos a poner la línea donde de verdad está.
Qué hace especial a una base de datos vectorial
Una base de datos normal encuentra filas por coincidencia exacta o por rango: dame los pedidos del cliente 42, dame las facturas de marzo. Una base de datos vectorial hace otra cosa: dado un vector, encuentra los más parecidos entre millones. Esa es la operación de la búsqueda semántica y del RAG.
El problema es que comparar contra todos los vectores uno a uno (búsqueda exacta) se vuelve lento cuando el índice crece. La respuesta del sector es el ANN (approximate nearest neighbor): estructuras como HNSW que renuncian a un poco de precisión a cambio de responder en milisegundos aunque tengas millones de vectores.
Eso es lo único que una base de datos vectorial hace mejor que el resto: ANN a escala, con buen rendimiento y sin que te lo montes tú. Todo lo demás (guardar metadatos, filtrar, versionar) lo hace igual o mejor una base de datos que ya tienes.
La búsqueda por fuerza bruta rinde más de lo que crees
Antes de aprovisionar nada, haz la cuenta. Si tienes unos pocos miles de fragmentos, compararlos todos contra la consulta es cuestión de milisegundos con NumPy. Sin servicio, sin índice, sin red de por medio.
import numpy as np
# corpus: matriz (n_docs, dim) ya normalizada a norma 1
# consulta: vector (dim,) también normalizado
def top_k(corpus, consulta, k=5):
# con vectores normalizados, el producto escalar ES la similitud del coseno
similitudes = corpus @ consulta # una multiplicación, todo el corpus
idx = np.argpartition(-similitudes, k)[:k] # los k mayores sin ordenar entero
return idx[np.argsort(-similitudes[idx])] # y ahora sí, ordenados
# 50.000 docs x 1.536 dim -> del orden de un milisegundo en un portátil
Cincuenta mil fragmentos entran de sobra en memoria y se comparan en un abrir y cerrar de ojos. Ese es el 90 % de los proyectos reales. La complejidad de una base de datos vectorial dedicada resuelve un problema que todavía no tienes.
El punto intermedio que casi nadie considera: pgvector
Entre el array en memoria y la base de datos dedicada hay una opción que se salta
mucha gente: añadir búsqueda vectorial a la base de datos que ya usas. Si tu
aplicación corre sobre PostgreSQL, la extensión pgvector te da un tipo de columna
vector e índices ANN dentro de tu Postgres de siempre.
La ventaja no es técnica, es operativa. Tus embeddings viven junto a tus datos.
Filtras por usuario, por fecha o por permisos con un WHERE normal y buscas por
similitud en la misma consulta. Una transacción, una copia de seguridad, un sitio
donde mirar cuando algo falla.
-- fragmentos del usuario 42, ordenados por cercanía a la consulta
SELECT contenido
FROM fragmentos
WHERE usuario_id = 42
ORDER BY embedding <=> $1 -- <=> es distancia coseno en pgvector
LIMIT 5;
Para millones de vectores con miles de consultas por segundo, pgvector se queda corto y una base de datos dedicada gana. Pero ese umbral está mucho más arriba de lo que la mayoría cree.
La tabla que zanja la decisión
| Situación | Herramienta sensata | Por qué |
|---|---|---|
| Menos de ~50.000 vectores | Array en memoria (NumPy) | Fuerza bruta en milisegundos, cero infraestructura |
| Ya usas Postgres, hasta varios millones | pgvector | Embeddings junto a tus datos, filtros SQL, una sola copia de seguridad |
| Muchos millones y baja latencia estricta | Base de datos vectorial dedicada | ANN optimizado, escalado horizontal, filtrado a gran escala |
| Equipo sin ganas de operar otra pieza | La que ya tengas | El coste operativo también cuenta |
La columna que más pesa no es la del volumen, es la última. Cada servicio nuevo es algo que aprovisionar, monitorizar, actualizar y pagar. Ese coste es real desde el primer día; el de la escala llega puede que nunca.
Las señales de que sí ha llegado el momento
Hay cuatro que de verdad justifican dar el salto a una base de datos dedicada.
El volumen: pasas de varios millones de vectores y la búsqueda empieza a notarse. La latencia: necesitas percentiles p99 por debajo de decenas de milisegundos con carga alta y sostenida. El filtrado a escala: combinas ANN con filtros de metadatos sobre millones de registros, algo en lo que estas bases están especializadas. Y la actualización constante: insertas y borras vectores sin parar y quieres que el índice se mantenga solo, sin reconstruirlo a mano.
Si marcas dos o más, adelante. Si no marcas ninguna, lo que necesitas es enviar el producto, no otra pieza de infraestructura.
En resumen
Una base de datos vectorial es una herramienta excelente para un problema concreto: búsqueda por similitud a gran escala. No es el punto de partida de un RAG, es una optimización que se justifica cuando los números aprietan.
Empieza por un array en memoria. Cuando se quede pequeño, casi siempre pgvector es el siguiente escalón, no el salto a un servicio dedicado. Y cuando de verdad tengas millones de vectores y latencia exigente, lo sabrás por las métricas, no por un hilo que leíste. Elige por el problema que tienes hoy, no por el que quizá tengas algún día.