Por qué el almacenamiento de embeddings puede ser un problema
En un sistema RAG, cada chunk de documento se representa como un embedding: un vector que coloca textos semánticamente parecidos cerca unos de otros.
Estos vectores suelen almacenarse como float32, es decir, 4 bytes por dimensión.
Para que la búsqueda sea rápida, esos vectores normalmente tienen que estar disponibles en memoria.
Leerlos desde disco en cada consulta haría que la búsqueda por similitud fuese mucho más lenta, así que la restricción práctica suele ser RAM, no solo almacenamiento en disco.
Ese detalle empieza a importar cuando llegamos a cierta escala. El coste de almacenamiento es aproximadamente:
número de embeddings x dimensiones del embedding x bytes por valor
Para un millón de embeddings de 1536 dimensiones guardados en float32, eso son unos 6.1 GB antes de contar metadata, overhead del índice vectorial, réplicas o infraestructura de serving.
Si la colección crece, o si hay que mantener varios índices online, el almacenamiento de embeddings pasa a ser una restricción.
Estudiamos cuánto se puede reducir este almacenamiento antes de que la calidad de retrieval empiece a degradarse demasiado.
Dos formas de comprimir
Hay dos formas directas de hacer que los vectores sean más pequeños.
La primera es la cuantización: mantener el mismo número de dimensiones, pero guardar cada valor con menos bits.
Por ejemplo, los tipos de dato float16 y bfloat16 reducen el almacenamiento 2x con una pérdida de calidad casi imperceptible, pero las variantes float8 son más interesantes: reducen almacenamiento 4x y se quedan muy cerca de la calidad base de float32.
La cuantización basada en enteros, como int8, también reduce almacenamiento 4x, pero rinde peor en nuestros experimentos y necesita un dataset de calibración, además de un paso extra de calibración antes de convertir los embeddings. En cambio, float8 se puede castear desde float32, lo que hace que sea más simple de usar.
Por último, la cuantización binary es la opción agresiva. Reduce 32x, pero la caída de calidad puede ser mucho mayor.
Calidad de retrieval usando distintos formatos de cuantización.
La segunda palanca es la reducción de dimensionalidad: guardar menos dimensiones intentando preservar la mayor cantidad posible de información semántica útil.
Para esto, probamos PCA, Kernel PCA, UMAP, autoencoders y proyecciones aleatorias, y PCA salió como la mejor opción porque conserva bien la calidad de retrieval bajo compresión y es fácil de entrenar y aplicar a embeddings.
Combinar cuantización y reducción de dimensionalidad
Los resultados más fuertes aparecen al combinar ambas palancas.
base float32
Comprimido
embeddings x dimensiones x bytes por valorMenos espacio
PCA por sí sola puede reducir almacenamiento, pero para ratios de compresión comparables suele degradar más que un formato de baja precisión robusto como float8.
El patrón útil es usar primero un formato que mantenga estable la señal, como float8, y después reducir dimensiones de forma moderada.
Tres observaciones importantes:
Los modelos de embeddings más grandes o de mayor dimensionalidad tienden a degradarse de forma más suave bajo compresión.
float8 combinado con PCA define una parte fuerte de la frontera entre almacenamiento y calidad entre 4x y 32x de compresión.
Un modelo más fuerte después de comprimir puede superar a un modelo más pequeño con un tamaño de almacenamiento comparable.
↑ Rendimiento relativo frente a float32 (%)
binaryint8float8 e5m2float8 e4m3bfloat16float16
Cómo leer el trade-off
El score de la gráfica sale del benchmark MTEB Retrieval. Usamos nDCG@10, una métrica que premia devolver documentos relevantes cerca de las primeras posiciones. Un score de 1 sería un ranking perfecto; aquí nos sirve para comparar configuraciones bajo el mismo setup de evaluación.
Cada punto es una configuración: modelo de embeddings, formato numérico y nivel de PCA. El eje x es almacenamiento y el eje y es calidad de retrieval. Las líneas muestran la frontera de Pareto de cada modelo.
Por ejemplo, bge-large-en-v1.5 con float8 y PCA al 25% usa unos 388 MB para almacenar 125k embeddings y alcanza un score cercano a 0.598. bge-small-en-v1.5 con float8 usa unos 524 MB y llega a unos 0.589. En esa zona, el modelo grande es más pequeño y mejor después de comprimir.
El proceso práctico es directo: decidir el presupuesto de memoria, mirar qué configuraciones caben dentro de ese límite y escoger la que tenga mejor score de retrieval.
Para compresión moderada hasta 4x, float8 es un buen punto de partida. Para presupuestos de memoria más estrictos, float8 con PCA es una opción interesante.
La idea general es que el modelo y la estrategia de compresión deberían elegirse juntos: cuando el almacenamiento es limitado, un modelo grande con la compresión adecuada puede ser un punto mejor de la frontera que un modelo pequeño con menos compresión.