Consejos y trucos prácticos para desarrolladores que crean aplicaciones RAG
¡La búsqueda vectorial no es sencilla!
La búsqueda vectorial, también conocida como búsqueda de similitud vectorial o búsqueda de vecinos más cercanos, es una técnica utilizada en la recuperación de datos para aplicaciones RAG y sistemas de recuperación de información con el fin de encontrar elementos o puntos de datos que sean similares o estén estrechamente relacionados con un vector de consulta dado. A menudo se comercializa como algo sencillo al manejar grandes conjuntos de datos. La percepción general es que simplemente puedes introducir datos en un modelo de embeddings para generar embeddings vectoriales y luego transferir estos vectores a tu base de datos vectorial para recuperar los resultados deseados.
cómo realizar una búsqueda vectorial
Muchos proveedores de bases de datos vectoriales promocionan sus capacidades con descriptores como "fácil", "intuitivo" y "simple". Afirman que puedes lograr resultados significativos con solo unas pocas líneas de código, evitando las complejidades del aprendizaje automático, la IA, los procesos ETL o el ajuste detallado del sistema.
Y tienen razón; la búsqueda vectorial es tan sencilla como usar una biblioteca numérica básica como NumPy. Para demostrar este concepto, escribí una breve demo en solo diez líneas de código Python utilizando el algoritmo de k vecinos más cercanos (KNN). Este enfoque directo es eficaz y preciso para aplicaciones a pequeña escala con conjuntos de datos de hasta mil o diez mil vectores.
import numpy as np
# Function to calculate Euclidean distance
def euclidean_distance(a, b):
return np.linalg.norm(a - b)
# Function to perform KNN
def knn(data, target, k):
# Calculate distances between target and all points in data
distances = [euclidean_distance(d, target) for d in data]
# Combine distances with data indices
distances = np.array(list(zip(distances, range(len(data)))))
# Sort by distance
sorted_distances = distances[distances[:, 0].argsort()]
# Get the top k closest indices
closest_k_indices = sorted_distances[:k, 1].astype(int)
# Return the top k closest vectors
return data[closest_k_indices]
Sin embargo, este enfoque no funcionará cuando tu conjunto de datos crezca hasta un nivel modesto de más de un millón o diez millones de vectores. Esto se debe simplemente a que las aplicaciones del mundo real deben interactuar con usuarios, estar disponibles y siempre son mucho más complicadas. Crear una aplicación escalable del mundo real requiere considerar a fondo diversos factores más allá de la codificación, incluida la calidad de búsqueda, la escalabilidad, la disponibilidad, la multi-tenencia, el costo, la seguridad y mucho más.
Así que seamos honestos. ¿Recuerdas el dicho: "Funciona en mi máquina"? La búsqueda vectorial no es diferente: tu prototipo siempre funciona; la búsqueda vectorial en producción suele ser compleja, así que ¿cuáles son las mejores prácticas para crear una aplicación impulsada por búsqueda vectorial en producción?
Para ayudarte a afrontar estos desafíos, compartiremos tres consejos esenciales para implementar eficazmente tu base de datos vectorial en el entorno de producción de tu aplicación RAG con Milvus:
Diseña un esquema eficaz: Considera cuidadosamente tu estructura de datos y cómo se consultará para crear un esquema que optimice el rendimiento y la escalabilidad.
Planifica la escalabilidad: Anticipa el crecimiento futuro y diseña tu arquitectura para acomodar volúmenes de datos y tráfico de usuarios crecientes.
Selecciona el índice óptimo y ajusta el rendimiento: Elige el método de indexación más adecuado para tu caso de uso y supervisa y ajusta continuamente la configuración de rendimiento.
Siguiendo estas mejores prácticas, estarás en el camino correcto para crear una aplicación robusta y eficiente impulsada por búsqueda vectorial. En los comentarios a continuación, comparte tus experiencias y cualquier consejo adicional que te haya resultado útil.
Diseñar una estrategia de esquema eficaz
Un esquema define la estructura de una base de datos, incluidas las tablas, los campos, las relaciones y los tipos de datos. Este marco organizado garantiza que los datos se almacenen de manera coherente y predecible, lo que simplifica la gestión, las consultas y el mantenimiento. Seleccionar un esquema adecuado es especialmente crítico para bases de datos vectoriales como Milvus, que manejan vectores y varios tipos de datos estructurados, incluidos metadatos y datos escalares. Estos datos pueden mejorar la búsqueda filtrada y optimizar los resultados generales de búsqueda. Esta sección explorará los factores clave que se deben considerar al elegir la estrategia de esquema más eficaz.
Esquema dinámico frente a esquema fijo
En los sistemas de bases de datos, los esquemas dinámicos y fijos representan dos enfoques principales para estructurar datos. Los esquemas dinámicos ofrecen flexibilidad, simplificando la inserción y recuperación de datos sin necesidad de una amplia alineación de datos ni procesos ETL. Este enfoque es perfecto para aplicaciones que requieren cambios rápidos en la estructura de datos. Por otro lado, los desarrolladores valoran los esquemas fijos por su eficiencia de rendimiento y ahorro de memoria, gracias a sus formatos de almacenamiento compactos.
Un enfoque de esquema híbrido puede beneficiar a los desarrolladores que trabajan en aplicaciones eficientes de bases de datos vectoriales. Este método combina la solidez de los esquemas fijos para rutas de datos esenciales con la flexibilidad de los esquemas dinámicos para adaptarse a diversos casos de uso. Por ejemplo, en un sistema de recomendación, elementos como los nombres de productos y los ID de productos pueden variar en importancia según el contexto. Al emplear un esquema híbrido, los desarrolladores pueden garantizar un rendimiento óptimo donde sea necesario, manteniendo al mismo tiempo la capacidad de adaptarse a requisitos de datos cambiantes.
Configuración de claves primarias y claves de partición
Las claves primarias y de partición son dos conceptos importantes en las bases de datos vectoriales. Usando la base de datos vectorial Milvus como ejemplo, podemos profundizar en cómo funcionan estas claves dentro de las bases de datos vectoriales.
La arquitectura de Milvus segmenta los datos en varios componentes: hay campos fijos y dinámicos (denominados colectivamente payload), un campo vectorial obligatorio y campos del sistema como marcas de tiempo e identificadores únicos universales (UUID), que son similares a los que se encuentran en las bases de datos relacionales convencionales.
Claves primarias: En Milvus, la clave primaria suele servir como un identificador único, que en un caso de uso de RAG puede aplicarse a un ID de fragmento. Se accede a esta clave con frecuencia y puede configurarse para generarse automáticamente. Desempeña un papel en la localización y recuperación rápidas de entradas de datos específicas dentro de la base de datos.
Claves de partición: Cuando creas una colección en Milvus, puedes especificar una clave de partición. Esta clave permite a Milvus almacenar entidades de datos en diferentes particiones según sus valores de clave, organizando eficazmente los datos en segmentos manejables. Una forma sencilla de pensar en las claves de partición es considerar el uso de una clave de partición si hay conjuntos de datos sobre los que deseas filtrar. Por ejemplo, el aislamiento de datos y la distribución eficiente son necesarios en situaciones multiinquilino, por lo que almacenarlos en particiones separadas puede ayudar a lograrlo. Las claves de partición también son útiles para la escalabilidad, ya que particionar los datos en shards mediante hashing permite que la base de datos gestione bases de usuarios a gran escala y multiinquilino de manera más eficiente.
Tanto las claves primarias como las de partición son fundamentales para mantener la integridad estructural y la eficiencia operativa de las bases de datos vectoriales, lo que las hace indispensables para manejar conjuntos de datos extensos y garantizar un acceso y una recuperación de datos rápidos.
Elección de tipos de embeddings vectoriales
Al elegir embeddings vectoriales para aplicaciones RAG, es imprescindible elegir el modelo de ML adecuado para la creación de vectores y comprender los diferentes tipos de embeddings disponibles: embeddings densos, dispersos y binarios.
Tres categorías populares de embeddings vectoriales
Embeddings densos son el tipo más comúnmente utilizado en aplicaciones de bases de datos vectoriales para la búsqueda por similitud semántica. Son conocidos por su robustez y aplicabilidad general en diversos tipos de datos. Los modelos populares de embeddings densos incluyen OpenAI, BGE y Cohere.
Embeddings dispersos están ganando popularidad por su eficiencia en la búsqueda de datos fuera de dominio. Los avances recientes en modelos como Splade y BGE M3 han mejorado su utilidad en búsquedas heterogéneas, lo que los convierte en una opción versátil para diversas aplicaciones.
Embeddings binarios, caracterizados por su formato binario (ceros y unos), están diseñados para ser eficientes en memoria, lo que los hace ideales para casos de uso especiales como la secuenciación de proteínas. Modelos como Meta ESM-2 se utilizan normalmente para generar estos embeddings, proporcionando soluciones específicas para necesidades de búsqueda concretas.
Para garantizar la precisión de los resultados de búsqueda para aplicaciones RAG, necesitamos usar más que solo embeddings densos. Por lo tanto, necesitamos encontrar soluciones que admitan diferentes algoritmos de indexación para buscar de manera eficiente y efectiva diferentes tipos de embeddings vectoriales. Milvus admite varios índices para gestionar embeddings densos, dispersos, binarios e incluso híbridos dispersos y densos, lo que permite búsquedas eficientes en diversas dimensiones de datos y garantiza un rendimiento óptimo en aplicaciones de bases de datos vectoriales.
Diseñando tu esquema: un ejemplo práctico
Reunamos estos elementos que acabamos de revisar para ayudarnos a diseñar eficazmente una arquitectura de esquema que aumentará la precisión de nuestros resultados de búsqueda:
| Nombre del campo | Tipo | Descripción | Valor de ejemplo |
|---|---|---|---|
| chunkID | Int64 | Clave primaria, identifica de forma única diferentes partes de un documento | 123456789 |
| userID | Int64 | Clave de partición, la partición de datos se basa en userID para garantizar que las búsquedas ocurran dentro de un único userID | 987654321 |
| docID | Int64 | Identificador único de un documento, utilizado para asociar diferentes fragmentos del mismo documento | 555666777 |
| chunkData | varchar | Una parte del documento, que contiene varios cientos de bytes de texto | "Esta es una parte del documento..." |
| dynamicParams | JSON | Almacena parámetros dinámicos del documento, como nombre, URL de origen, etc. | {"name": "Documento de ejemplo", "source": "example.com"} |
| sparseVector | Formato específico | Datos que representan un vector disperso. El formato específico tendrá valores distintos de cero solo en ciertas posiciones para representar la dispersión. | [0.1, 0, 0, 0.8, 0.4] |
| denseVector | Formato específico | Datos que representan un vector denso. El formato específico tendrá un número fijo de dimensiones con valores en cada una. | [0.2, 0.3, 0.4, 0.1] |
Una demostración de esquema para una aplicación típica de Generación Aumentada por Recuperación (RAG)
Al examinar este esquema, es crucial observar la presencia de campos adicionales, que van más allá de la clave primaria y el campo vectorial. Estos campos adicionales desempeñan un papel en la construcción y utilización de tu base de datos vectorial. Profundicemos:
Lo básico: Estos incluyen tu clave primaria (chunkID) y tus embeddings (denseVector), que necesita cada entrada en la base de datos.
Soporte multiinquilino: Hemos añadido un campo para particionar los datos según los inquilinos de nuestra solución con la adición de un userID. Esta adición ayuda a segregar y gestionar el acceso a los datos por usuario, mejorando la seguridad y la personalización.
Refinando tus resultados de búsqueda: Hemos añadido algunos otros campos para ayudarnos con este refinamiento, incluyendo:
docID: Este campo indica el origen del fragmento y puede utilizarse para aprovechar la función de búsqueda por agrupación de Milvus. En nuestro ejemplo, dividimos nuestro documento en fragmentos y almacenamos la incrustación vectorial representativa en el campo denseVector, y en este campo (docID), almacenamos la información del documento asociado. Puedes incluir el argumentogroup_by_fielden la operación search() para agrupar los resultados por el ID del documento y encontrar documentos relevantes en lugar de pasajes o fragmentos similares. Esto ayuda a devolver los documentos relevantes en lugar de fragmentos separados del mismo documento.dynamicParams: Este campo se puede filtrar, lo que te permite gestionar y recuperar datos que se ajusten a tus necesidades. Es un tesoro de metadatos, como el nombre del documento, la URL de origen, etc. Configuramos el campo json para almacenar múltiples pares clave-valor en un solo campo.sparseVector: Este campo contiene la incrustación dispersa del fragmento, lo que nos permite realizar una búsqueda ANN y recuperar resultados basados en un valor escalar asociado con el vector disperso.
El diagrama muestra que podemos recopilar resultados de consultas separadas y luego reordenarlos para refinar los resultados de búsqueda.
Al diseñar un esquema que incluya estos campos adicionales, puedes crear una base de datos vectorial más robusta y flexible que satisfaga los requisitos de tu aplicación RAG. Te permite aprovechar las fortalezas de la búsqueda vectorial al tiempo que incorporas técnicas tradicionales de gestión y recuperación de datos.
Plan de escalabilidad
Una vez que hayas logrado el éxito con tu aplicación RAG MVP, es hora de comenzar a prepararte para el despliegue en producción. Esto implica anticipar el crecimiento futuro y diseñar tu arquitectura para adaptarse al aumento de los volúmenes de datos y del tráfico de usuarios.
Para garantizar que tu aplicación pueda escalar de manera efectiva, debes tener en cuenta que la escalabilidad en las bases de datos vectoriales plantea desafíos únicos en comparación con las bases de datos relacionales tradicionales, porque los datos se almacenan en un índice grande y centralizado. Esta configuración puede provocar dos problemas principales: velocidades de indexación lentas y degradación de la calidad del índice debido a actualizaciones frecuentes, lo que a su vez puede reducir la calidad de la búsqueda.
The sharding strategy of Milvus
Milvus puede abordar estos desafíos dividiendo todo el conjunto de datos en segmentos manejables; podemos realizar actualizaciones diferidas o compactar segmentos una vez que se vuelven inestables, manteniendo una calidad de búsqueda constante. Esta segmentación facilita un equilibrio de carga eficaz, lo que nos permite distribuir las consultas de manera uniforme entre todos los núcleos de procesamiento.
Usar particiones para la multitenencia también puede ayudar con la escalabilidad y el rendimiento, ya que las búsquedas se limitan a los datos relevantes para la partición. Este enfoque organiza los datos de manera efectiva y mejora la seguridad y la privacidad al restringir la visibilidad a los usuarios adecuados. Además, Milvus puede gestionar eficientemente hasta diez mil millones de puntos de datos en una sola colección. ¡Eso es muchísimo!
Para aplicaciones multitenant con menos de 10.000 inquilinos, gestionar los datos por colección proporciona un mayor control de los datos. Sin embargo, las claves de partición pueden admitir eficazmente inquilinos ilimitados segmentando dinámicamente los datos para servicios con millones de usuarios.
Milvus es un sistema distribuido diseñado para manejar grandes volúmenes de consultas con facilidad. ¿Y lo mejor? Simplemente añadir más nodos puede aumentar significativamente el rendimiento, abriendo un mundo de posibilidades para tus aplicaciones. Para conjuntos de datos más pequeños que inicialmente no requieren recursos extensos, escalar las reservas de memoria —normalmente de dos a tres veces la asignación actual— puede duplicar eficazmente las consultas por segundo (QPS). Este marco escalable garantiza que, a medida que tus datos crecen, las capacidades de tu base de datos puedan crecer junto con ellos, asegurando un rendimiento eficiente y fiable en todos los ámbitos.
Elegir, evaluar y ajustar tu índice
Durante la fase de prototipo, cargar todos los datos en memoria es común para lograr un procesamiento más rápido y un desarrollo más sencillo. Sin embargo, a medida que pasas a producción y tus datos crecen, se vuelve inviable almacenar todo en memoria. Esto se debe a que:
La memoria es limitada y costosa en comparación con el almacenamiento en disco.
Los conjuntos de datos grandes pueden superar la capacidad de memoria disponible.
Cargar todos los datos en memoria puede aumentar significativamente el tiempo de inicio y el consumo de recursos.
Para manejar conjuntos de datos más grandes de manera eficiente en producción, necesitas elegir una estrategia de indexación adecuada. El índice correcto puede optimizar el rendimiento de tu aplicación RAG en términos de velocidad de consulta, requisitos de almacenamiento y latencia.
Índices que admite Milvus
Este diagrama ayuda a visualizar las diferencias entre varios índices en función de tres métricas clave:
Consultas por segundo (QPS): Esto mide cuántas consultas de búsqueda puede manejar el índice por segundo, reflejando su rendimiento y eficiencia.
Almacenamiento: Esto representa la cantidad de espacio en disco necesaria para almacenar el índice, lo que puede afectar los costos de infraestructura y la escalabilidad.
Latencia se refiere al tiempo que se tarda en procesar una sola consulta y devolver los resultados, lo que afecta la capacidad de respuesta de tu aplicación.
Al comparar estas métricas entre diferentes índices, puedes decidir qué índice se adapta mejor a tu caso de uso específico y a tus requisitos de rendimiento.
En Milvus, ofrecemos un marco flexible de selección de índices adaptado a diversas necesidades de almacenamiento y rendimiento:
GPU Index es nuestra opción principal para entornos de alto rendimiento, que admite el procesamiento y la recuperación rápidos de datos.
Memory Index es una opción de nivel intermedio que equilibra el rendimiento con la capacidad, ofreciendo tasas sólidas de consultas por segundo (QPS) y la capacidad de escalar hasta terabytes de almacenamiento con una latencia promedio de alrededor de 10 milisegundos.
Disk Index puede gestionar decenas de terabytes con una latencia razonable de aproximadamente 100 milisegundos, adecuado para conjuntos de datos más grandes y menos sensibles al tiempo. Milvus es la única base de datos vectorial de código abierto que admite índice en disco.
Swap Index facilita el intercambio de datos entre S3 u otras soluciones de almacenamiento de objetos y la memoria. Este enfoque reduce significativamente los costos —aproximadamente diez veces— al tiempo que gestiona eficazmente la latencia. Los tiempos de acceso típicos son de alrededor de 100 milisegundos, pero pueden extenderse a unos pocos segundos para datos accedidos con menor frecuencia ("más fríos"), lo que lo hace viable para casos de uso offline y aplicaciones sensibles a los costos.
Después de seleccionar un índice, puedes evaluar su rendimiento en función de su tiempo de compilación, precisión, rendimiento y consumo de recursos. Por ejemplo, un índice no optimizado podría admitir solo 20 consultas por segundo sin requerir ninguna construcción. Optimizar un índice podría mejorar significativamente el QPS, aumentando potencialmente diez veces con cada iteración de ajuste, aunque a costa de un mayor tiempo de visualización.
Para seleccionar y ajustar eficazmente tu índice, debes:
Elegir el tipo de índice adecuado en función de tus necesidades específicas.
Ajustar los parámetros del índice para optimizar el rendimiento.
Comparar tus casos de uso para garantizar que el índice funcione según lo esperado.
Ajustar los parámetros de búsqueda para mejorar aún más el rendimiento.
Si no estás seguro sobre el proceso de optimización, aprovecha el poder de las herramientas de benchmarking como VectorDBBench. Esta herramienta, desarrollada y de código abierto por Zilliz, puede evaluar todas las bases de datos vectoriales principales. Te permite realizar experimentos completos y ajustar tu sistema para obtener un rendimiento óptimo.
Para una referencia rápida, hemos preparado una práctica hoja de trucos que describe el rendimiento de cada índice en nuestro catálogo de índices de GPU. Este recurso puede ayudarte a optimizar el rendimiento y la rentabilidad guiándote hacia el índice que mejor se adapte a las necesidades de tu aplicación.
Una hoja de trucos de índices
Resumen
En esta guía completa, hemos explorado el multifacético mundo de las bases de datos vectoriales y los enfoques prácticos necesarios para maximizar su eficiencia y escalabilidad. Desde los aspectos básicos del diseño de un esquema hasta las complejidades de gestionar grandes conjuntos de datos, hemos cubierto las estrategias esenciales y las mejores prácticas que los desarrolladores necesitan conocer al trabajar con bases de datos vectoriales.
A medida que las bases de datos vectoriales evolucionan, mantenerse informado sobre estos aspectos permitirá a los desarrolladores crear aplicaciones más robustas, eficientes y escalables. Ya seas un profesional de bases de datos con experiencia o un recién llegado a este campo, las ideas proporcionadas aquí te ayudarán a navegar las complejidades de las bases de datos vectoriales con mayor confianza y competencia.
Sigue leyendo

Zilliz Named "Highest Performer" and "Easiest to Use" in G2's Summer 2025 Grid® Report for Vector Databases
Zilliz shines in G2's Summer 2025 Grid® Report as both "Highest Performer" and "Easiest to Use," solving the performance-usability dilemma.

How to Build RAG with Milvus, QwQ-32B and Ollama
Hands-on tutorial on how to create a streamlined, powerful RAG pipeline that balances efficiency, accuracy, and scalability using the QwQ-32B and Milvus.

DeepSeek-VL2: Mixture-of-Experts Vision-Language Models for Advanced Multimodal Understanding
Explore DeepSeek-VL2, the open-source MoE vision-language model. Discover its architecture, efficient training pipeline, and top-tier performance.



