Inicio / Artículos

Pruebas de rendimiento de cinco almacenamientos de vectores integrados: FAISS, Chroma, LanceDB, VectLite

Cinco bases de datos vectoriales incrustadas evaluadas para RAG local: FAISS, Chroma, LanceDB, VectLite y NumPy se compararon en términos de precisión, latencia, filtros y tiempo de inicio en entornos fríos.

Editor: REACTAPP.TOP8 min de lectura1791 palabras

Fuentes: I Benchmarked 5 Vector Databases for a Local RAG. Only One Actually Surprised Me.

La mayoría de las comparaciones de “mejor base de datos vectorial” parecen ser páginas de inicio de los propios proveedores reformuladas: Pinecone es rápido, Qdrant es sólido, Chroma es sencillo; todos ganan. Esta comparación parte de una necesidad más específica. Sin clústeres, sin Docker, sin puertos abiertos, sin planes gestionados. Solo un almacén vectorial embebido que consiste en un archivo local, un pip install y tres líneas de código en Python. Así que aquí hay una prueba de rendimiento hecha en casa con cinco motores para ese uso concreto.

Los números

El conjunto de datos contenía 5,000 vectores de 384 dimensiones, consultados 50 veces mediante similitud de coseno. Todo se ejecutó en macOS (x86_64) con Python 3.12.8, utilizando la configuración predeterminada de cada motor.

Motor Ingestión (vectores/s) Búsqueda p95 Recuperación@10 Filtro p95 Recuperación del filtro@10
FAISS 743,099 0.65 ms 1.000 n/a sin filtrado
NumPy exacto 2,412,231 2.59 ms 1.000 9.25 ms 1.000
Chroma 2,011 3.14 ms 0.840 18.76 ms 1.000
VectLite 0.10.0 154 5.71 ms 0.966 10.28 ms 0.966
LanceDB 20,120 12.20 ms 1.000 14.11 ms 1.000

En diez segundos: FAISS es el más rápido, aunque apenas se puede considerar una base de datos. Chroma es la opción más sencilla para comenzar, pero su tasa de recuperación por defecto del 84% es un problema que muchas personas ignoran. VectLite alcanza una tasa de recuperación del 96.6% en modo integrado sin necesidad de ajustes, lo cual fue una sorpresa. LanceDB busca una tasa de recuperación perfecta, pero a costa de mayor latencia. NumPy actúa como árbitro y no como competidor.

Por qué “el más rápido” es una clasificación errónea

El mercado de bases de datos vectoriales es un campo de batalla de marketing. Cada proveedor publica un punto de referencia en el que resulta ganador, los artículos comparativos repiten esas cifras sin contexto, y todos se centran en la latencia. La latencia por sí sola engaña. Responder en medio milisegundo con vecinos incorrectos es peor que tardar 5 ms en devolver los correctos. Eso es lo que miden las métricas de recuperación, y por eso suites serias como ANN-Benchmarks (https://ann-benchmarks.com/) grafican la recuperación en relación con el rendimiento.

Por lo tanto, esta prueba mide ambos aspectos al mismo tiempo: por un lado, la latencia p50, p95 y p99 y las consultas por segundo; y por el otro, la recuperación@10 en comparación con una búsqueda por coseno exacta utilizando NumPy puro.

Qué se probó y qué no

El proyecto es un pequeño paquete de Python, vectlite-benchmark-lab. Cada motor implementa una interfaz compartida VectorStore y el ejecutor los llama uno tras otro. Cubre lo siguiente:

  • Ingestión por lotes
  • Búsqueda k-NN con medición de precisión
  • Filtrado de metadatos por coincidencia exacta según tenant_id
  • Tiempo de inicio en condiciones de bajo uso
  • Respaldo y portabilidad
  • Exportación a CSV, JSON y gráficos de Matplotlib

Y lo que excluye, dicho de antemano: no hay configuración distribuida ni multi-nodo, nada más allá de 5,000 vectores en esta ronda, sin ajustes de índice alguno, y tampoco Qdrant ni pgvector, ya que requieren un servidor en ejecución y el objetivo era un funcionamiento puramente local. Esa última elección es intencionada. La primera pregunta útil no es quién gana después de dos semanas de ajustes, sino cómo se comporta un motor cuando se instala sin modificar nada.

Método

La verdad de referencia es una búsqueda de coseno por fuerza bruta en NumPy. El recuerdo de un motor es la proporción de vecinos reales que devuelve, promediada entre todas las consultas. Configuración para la ejecución:

vectlite      : 0.10.0
vectors       : 5,000 (synthetic, normalized)
dimensions    : 384
queries       : 50
top_k         : 10
metric        : cosine
filter        : tenant_id (exact-match)
warmup        : 5 queries discarded
hardware      : macOS x86_64, Python 3.12.8

Para reproducirlo en su equipo, ejecute la orden completa:

PYTHONPATH=src python -m vectlite_benchmark_lab run \
  --stores vectlite,faiss,chroma,lancedb,numpy_exact \
  --vectors 5000 --dimensions 384 --queries 50 \
  --top-k 10 --batch-size 500 \
  --output-dir results/vectlite-0.10.0 \
  --data-dir data/vectlite-0.10.0

Luego compare sus resultados con estos y observe las diferencias.

FAISS: el techo de velocidad

FAISS gana en todas las columnas de latencia: 0,65 ms p95 con un recuerdo perfecto, lo cual es más o menos lo que se esperaría de una biblioteca en C++ optimizada específicamente para esto durante una década. Pero no es una base de datos. No cuenta con filtrado nativo de metadatos, ni persistencia integrada, ni copias de seguridad portátiles. Se puede envolver en una capa que añada estas funcionalidades, y así se hace en la práctica, pero tal como viene por defecto está más cerca de una biblioteca matemática que de algo que se pueda entregar a los clientes. Compararlo con Chroma es como comparar un motor de F1 con un Toyota: uno es más rápido en la pista, el otro se encarga de llevar las compras a casa. Se mantiene en la tabla como referencia. Si lo único que necesita es una búsqueda de vectores en bruto, es la opción obvia.

Chroma: inicio sencillo, preste atención al recuerdo

Chroma es la opción predeterminada para los prototipos de RAG, y la experiencia del desarrollador lo justifica. Instale chromadb, escriba cinco líneas y los documentos ya estarán indexados.

El problema radica en la capacidad de recuperación. Con estos datos y sin aplicar filtros, Chroma solo encuentra el 84 % de los documentos relevantes, lo que significa que aproximadamente uno de cada seis resultados esperados no aparece. Eso está bien para un prototipo. En un sistema RAG en producción, donde la calidad de la recuperación determina la respuesta del modelo, se trata de una pérdida silenciosa de relevancia que la API no revela. Ajustar la configuración de HNSW puede recuperar la mayor parte de esa brecha, siempre y cuando se sepa que es necesario. Con filtros, la capacidad de recuperación es del 100 %, pero la latencia p95 aumenta a 18,76 ms, lo que es notablemente más lento que el resto en la misma tarea. Veredicto: excelente desde el primer día y aún bueno al cabo de treinta días, siempre y cuando se realicen ajustes antes de la producción.

VectLite: la sorpresa

La versión 0.10.0 alcanza un 96.6% de precisión con los ajustes predeterminados, la más alta de todos los motores incrustados aquí. La búsqueda simple tiene un tiempo de respuesta p95 de 5.71 ms, situándose en el promedio (Chroma 3.14, LanceDB 12.20). Con cargas de trabajo filtradas, su tiempo de respuesta p95 es de 10.28 ms, frente a 18.76 ms en Chroma, lo que significa que es casi dos veces más rápido en este caso.

Se puede observar el progreso desde las primeras versiones. En comparación con v0.1.x, la tasa de ingesta pasó de 47 a 154 vectores por segundo (aproximadamente 3.3 veces más rápido), la precisión aumentó de 0.948 a 0.966, y el tiempo de respuesta p95 para operaciones de filtrado disminuyó de 18.6 ms a 10.3 ms, lo que representa una reducción del 45%.

La ingesta es el punto débil. 154 vectores por segundo es lento en comparación con los 2,000 o más de Chroma, y muy lento también frente a LanceDB. Para unos pocos miles de documentos indexados una sola vez, eso no supone un problema. Pero para un millón de vectores, implica tener que esperar toda la noche, por lo que probablemente sea lo siguiente que haya que mejorar. Aun así, este fue el único motor del grupo cuyos resultados no necesitaban excusas.

LanceDB: recuperación perfecta, búsqueda más lenta

LanceDB logra una recuperación del 100% y procesa 20,120 vectores por segundo, lo cual suena impresionante en teoría. El costo es la latencia de búsqueda: 12.20 ms p95, la más lenta de las cinco. Para un proceso por lotes que procese miles de consultas durante la noche, eso no es un problema. Pero para una herramienta interactiva en la que alguien espera frente al teclado, la latencia se vuelve significativa. Es adecuado para procesos por lotes y análisis, pero un poco lento para uso interactivo.

NumPy: el árbitro

La búsqueda por coseno por fuerza bruta sobre toda la matriz garantiza, por definición, una recuperación perfecta, con una latencia aceptable hasta unas decenas de miles de vectores; después de eso, la performance cae drásticamente. No se trata de un producto en sí, sino del estándar contra el cual se evalúan los demás motores.

¿Cuál elegir?

El benchmark no determina un ganador; más bien revela los compromisos que se deben tomar. Una aproximación según el caso de uso:

  • Prototipo rápido de RAG: Chroma, gracias a una configuración de dos minutos y a un amplio ecosistema
  • Memoria de IA integrada: VectLite, para la mejor recuperación por defecto y un archivo portátil
  • Proceso por lotes local: LanceDB, para una recuperación perfecta y una ingestión rápida
  • ANN puro sin filtrado: FAISS, para una latencia insuperable
  • Producción distribuida: Qdrant o Milvus, una categoría diferente que no se ha probado aquí

Arranque en frío y respaldo

Dos métricas que la mayoría de las pruebas de rendimiento omiten. Arranque, el tiempo necesario para volver a abrir la base de datos después de un reinicio: FAISS tarda 0,001 ms, LanceDB 2 ms, Chroma 5 ms y VectLite 3.059 ms. VectLite paga un alto precio al volver a abrir la base de datos. Eso no supone un problema para un proceso que funciona de forma continua, pero para una función sin servidor o una herramienta de línea de comandos que se inicia bajo demanda, un arranque en frío de tres segundos es un gran obstáculo y probablemente lo primero que hay que solucionar.

Respaldo: VectLite genera un archivo portátil de 19 MB en 54 ms. Copiarlo, gestionar sus versiones y desplegarlo es simplemente un proceso de manejo de archivos. Esa es la característica de “incrustado” que permite que el sistema funcione, la misma propiedad que mantuvo vivo a SQLite durante dos décadas.

Límites de esta prueba

Cada prueba de rendimiento necesita un asterisco. Aquí hay cinco:

  1. 5,000 vectores es una cantidad pequeña; el comportamiento cambia a partir de 100,000 vectores o más.
  2. Solo se utilizaron los ajustes predeterminados; es casi seguro que Chroma y VectLite puedan optimizarse aún más.
  3. Ningún motor de servidor participó: Qdrant, Milvus, Weaviate y pgvector quedan excluidos.
  4. Se realizó una sola prueba, sin intervalos de confianza ni repeticiones.
  5. La prueba se ejecutó en una sola máquina, por lo que otro hardware podría dar resultados diferentes.

El código es de código abierto y los resultados son reproducibles, por lo que cualquier sesgo o error detectado merece ser reportado.

Siguientes pasos y conclusiones

Esta prueba es un punto de partida, no un veredicto. La lista reducida para la siguiente ronda incluye: un vector de 100k, una prueba de 768 dimensiones en todos los motores; una prueba de estilo RAG utilizando un corpus de Markdown y PDF con consultas redactadas por personas; un ajuste en la capacidad de recuperación para que los motores compitan con una precisión comparable; un inicio en frío más rápido con VectLite; y pruebas repetidas con intervalos de confianza.

La búsqueda de “la mejor base de datos vectorial” termina sin una respuesta universal, ya que depende de cómo se equilibren la recuperación de información con la latencia, la ingesta de datos y el tiempo de inicio. Lo que destacó no fue un líder indiscutible, sino que cada motor tiene su propia característica distintiva. FAISS es un referente de velocidad que se presenta como base de datos. Chroma es una opción sencilla de usar pero que requiere ajustes antes de su uso en entornos de producción. LanceDB es el perfeccionista que no le importa ser lento. NumPy es el juez imparcial que no puede escalar. VectLite es el que logra silenciosamente el objetivo de recuperación de información sin necesidad de negociaciones.

Para un agente local, una herramienta de línea de comandos o un sistema RAG offline en una laptop, VectLite ofrece una alternativa convincente: SQLite hizo que los datos relacionales locales fueran aburridos y poco portátiles, y VectLite busca desempeñar el mismo papel con la memoria basada en IA. Esto significa un archivo de 19 MB que responde en aproximadamente 6 ms.

Enlaces de referencia: ANN-Benchmarks en https://ann-benchmarks.com/, notas de pruebas de Qdrant en https://qdrant.tech/benchmarks/, FAISS en https://github.com/facebookresearch/faiss, documentación de Chroma en https://docs.trychroma.com/ y LanceDB en https://lancedb.github.io/lancedb/.