Chroma, LanceDB y Faiss: prototipar sin infraestructura

Levantar una prueba en una tarde y saber exactamente dónde está la frontera que obliga a migrar.

Chroma, LanceDB y Faiss: prototipar sin infraestructura
Foto de Jakub Zerdzicki en Pexels

Quinta entrega del bloque de plataformas. Antes de decidir qué motor va a producción hay que probar si la idea funciona, y para eso montar infraestructura es una pérdida de tiempo. Estas tres opciones se levantan en minutos dentro de tu propio proceso. La parte interesante no es cómo empezar con ellas, sino saber exactamente cuándo hay que dejarlas.

Las tres comparten una característica que las define: no son servidores. No hay un proceso que arrancar, ni un puerto que abrir, ni credenciales. Se importan como una biblioteca, viven dentro de tu programa y guardan los datos en un directorio del disco. Es el mismo modelo que SQLite frente a PostgreSQL, y la analogía sirve para casi todo lo que viene después.

Faiss no es una base de datos

Conviene decirlo antes que nada, porque la confusión es constante y hace perder días.

Faiss es una biblioteca de índices de similitud desarrollada por el equipo de investigación de Meta. Su unidad de trabajo es un índice en memoria que contiene vectores identificados por un número entero, y su interfaz es esencialmente: añade estos vectores, búscame los k más próximos a este. Nada más.

Lo que Faiss no tiene: metadatos, filtrado, textos, actualizaciones cómodas, persistencia automática, concurrencia, control de acceso ni consultas. Si guardas un índice Faiss, guardas vectores y números. La correspondencia entre esos números y tus fragmentos de texto la mantienes tú, en otro sitio, y la coherencia entre ambos es tu problema. Borrar un vector concreto de ciertos tipos de índice es, directamente, reconstruirlo.

A cambio, es lo más rápido y lo más completo que hay en materia de índices: es la implementación de referencia de IVF, de la cuantización por producto y de media docena de variantes que después han copiado los demás. De hecho, varios de los motores de las entregas anteriores lo usan por debajo o se inspiran directamente en él.

La conclusión práctica: Faiss es la elección correcta cuando el índice es un componente dentro de un sistema que ya controlas —una tubería de procesamiento por lotes, un experimento de recuperación, un servicio propio donde los metadatos viven en tu base de datos—, y es la elección equivocada como sustituto de una base de datos vectorial. Comparar Faiss con Qdrant es comparar un motor con un coche.

Chroma

Chroma es lo contrario en filosofía: una base de datos vectorial pensada para que el primer ejemplo funcione en cuatro líneas. Almacena documentos, metadatos, identificadores y vectores juntos, filtra por metadatos con una sintaxis sencilla, y si no le pasas vectores, los calcula por ti con un modelo de embeddings por defecto.

Persiste en disco con SQLite como almacén subyacente, y puede funcionar tanto embebida en tu proceso como en modo cliente-servidor con un contenedor, lo que da un camino de crecimiento suave sin cambiar el código de la aplicación.

Su punto fuerte es la ergonomía. Su punto débil es que esa misma ergonomía invita a llevarla más lejos de lo razonable: al ser tan cómoda, muchos proyectos la dejan en producción sin haber comprobado si aguanta el patrón de carga real.

import chromadb

cliente = chromadb.PersistentClient(path="./indice")
col = cliente.get_or_create_collection("manual")

col.add(
    ids=["f1", "f2"],
    documents=["El plazo de devolución es de 30 días.",
               "Los envíos a Canarias tardan 5 días hábiles."],
    metadatas=[{"seccion": "devoluciones", "anio": 2025},
               {"seccion": "envios", "anio": 2025}],
)

res = col.query(
    query_texts=["cuánto tiempo tengo para devolver"],
    n_results=3,
    where={"anio": 2025},
)
print(res["documents"][0])

LanceDB

LanceDB también es embebida, pero parte de una decisión de diseño distinta: se apoya en un formato de fichero columnar propio, Lance, emparentado con Parquet y pensado para acceso aleatorio rápido.

Eso tiene dos consecuencias notables. La primera es que los datos no tienen que caber en memoria: el índice y los vectores se leen del disco según hacen falta, lo que le permite manejar conjuntos considerablemente mayores que una solución puramente en memoria en la misma máquina. La segunda es que el directorio de datos puede vivir en almacenamiento de objetos, de modo que varios procesos de lectura pueden apuntar al mismo conjunto sin servidor de por medio. Para cargas analíticas o de sólo lectura, es un modelo muy conveniente.

Además guarda versiones de la tabla, lo que permite volver a un estado anterior, y se integra de forma natural con el ecosistema de datos en Python. La escritura concurrente desde varios procesos sigue siendo su limitación estructural: es un formato de fichero, no un servidor con control de transacciones.

En qué se diferencian

Aspecto Faiss Chroma LanceDB
Qué es Biblioteca de índices Base de datos embebida Base de datos sobre formato columnar
Guarda texto y metadatos No Sí Sí
Filtrado No, salvo que lo montes tú Sí, sencillo Sí, con expresiones tipo SQL
Persistencia Manual, volcado del índice Automática, sobre SQLite Automática, con versiones
Datos mayores que la memoria Con índices sobre disco Mal Sí, por diseño
Modo servidor No Sí Sólo en su versión gestionada
Uso natural Componente interno, investigación Prototipo y aplicaciones pequeñas Análisis y lectura sobre conjuntos grandes

La frontera exacta: cuándo hay que migrar

Esta es la parte que justifica la entrega. Los cuatro síntomas que indican que una opción embebida se ha quedado corta, y no admiten interpretación.

Concurrencia de escritura. Es el primero que aparece y el más grave. Una base de datos embebida vive en un proceso. En cuanto tu aplicación corre con varios trabajadores —que es lo normal en cualquier despliegue web—, tienes varios procesos escribiendo sobre los mismos ficheros. Lo que ocurre entonces va desde bloqueos hasta corrupción, según la biblioteca y el sistema de ficheros. No hay configuración que lo arregle: es una limitación de diseño.

Tamaño. El orden de magnitud razonable para Chroma embebida es de decenas o cientos de miles de vectores; LanceDB aguanta bastante más por su diseño sobre disco. Cuando la carga del índice tarda minutos, cuando el proceso consume varios gigabytes sólo por arrancar o cuando reiniciar el servicio implica una espera perceptible, ya estás fuera de rango.

Filtrado que importa. Si el filtro pasa de ser una comodidad a ser un requisito —permisos por usuario, aislamiento entre clientes, ventanas temporales estrictas—, necesitas filtrado integrado en el recorrido del índice, con la semántica bien definida que vimos en la entrega 28. Las opciones embebidas no lo dan con garantías.

Actualizaciones frecuentes. Un corpus que se actualiza a diario, con borrados y reindexaciones parciales, castiga a estas opciones. Si tu operación normal incluye reconstruir el índice entero cada vez que cambia un documento, has llegado al final.

Hay un quinto síntoma, menos técnico y más decisivo: cuando el sistema empieza a importar. En el momento en que alguien fuera del equipo depende de que esas respuestas estén disponibles, necesitas copias de seguridad, monitorización y un procedimiento de restauración. Un directorio en el disco de un contenedor efímero no es ninguna de esas cosas.

Cómo prototipar sin arrepentirse

Un consejo que ahorra la peor parte de la migración: aísla el acceso al índice desde el primer día. Cuatro funciones —insertar, borrar, buscar, buscar con filtro— y todo el resto del código llamando sólo a esas cuatro. Con eso, pasar de Chroma a Qdrant o a pgvector es reescribir un archivo de cien líneas en una tarde.

El otro consejo es guardar siempre el texto y los metadatos originales fuera del índice, en ficheros o en una tabla. Los vectores se pueden recalcular; el trabajo de ingesta, troceado y enriquecimiento de metadatos de las entregas 08 a 12, no. Si tu única copia del corpus procesado está dentro de una base de datos embebida, migrar significa repetir todo el pipeline.

Qué viene ahora

La siguiente entrega es de referencia: una comparativa completa de las siete opciones que ha recorrido este bloque —pgvector, Qdrant, Weaviate, Milvus, Pinecone, Chroma y LanceDB— en una sola tabla, por modelo de despliegue, licencia, escala, filtrado, híbrido, cuantización, operativa y perfil de coste, con cuatro recomendaciones por escenario.

Los tres libros gratuitos de los que nace esta serie están disponibles en PDF y EPUB: RAG para tu negocio (nivel básico), RAG por dentro (intermedio) y RAG en producción (avanzado).


Aviso de contenido generado con inteligencia artificial.
Este artículo ha sido redactado con la asistencia de sistemas de inteligencia artificial y revisado antes de su publicación. Se informa de ello de forma expresa en cumplimiento de la normativa vigente sobre transparencia en el uso de IA.