Retrieval Augmented Generation (RAG): ¿Qué debo saber para empezar?
Introducción La inteligencia artificial generativa ha transformado la manera en que interactuamos con la tecnología. Sin embargo, los modelos tradicionales tienen una limitación: solo pueden generar respuestas basadas en el conocimiento adquirido durante su entrenamiento. ¿Cómo asegurarnos de que puedan acceder a información actualizada y específica? Aquí es donde entra en juego la Recuperación Aumentada por Generación (RAG, por sus siglas en inglés). RAG es una técnica que combina la recuperación de información con modelos generativos para mejorar la precisión y relevancia de las respuestas. Si con esta breve explicación te quedas con ganas de saber más, ya tratamos sobre ello en esta entrada del blog. Implementar sistemas RAG mejora la precisión de los modelos generativos y permite un acceso inteligente y contextualizado a la información, imprescindible para adaptar la IA a las aplicaciones empresariales." En este artículo vamos a profundizar sobre los elementos clave de este enfoque: las bases de datos vectoriales, los embeddings y la segmentación del contenido (chunks). Comprender estos conceptos es fundamental para optimizar el rendimiento de los sistemas RAG y maximizar su capacidad de recuperación de información relevante. Bases de datos vectoriales y su rol en RAG Las bases de datos tradicionales almacenan información en tablas estructuradas, lo que permite realizar consultas basadas en coincidencias exactas de palabras clave, seguramente hayas trabajado u oído hablar sobre el lenguaje SQL. Sin embargo, este enfoque es insuficiente cuando se trata de buscar información de manera semántica. Para solucionar este problema, en los sistemas RAG se utilizan bases de datos vectoriales. Las bases de datos vectoriales permiten representar el significado de los datos en un espacio multidimensional, facilitando la búsqueda semántica. Esto significa que, en lugar de buscar coincidencias exactas, estas bases de datos identifican la similitud entre los conceptos. Por ejemplo, si un usuario busca automóvil, el sistema también podrá encontrar información relacionada con coche o vehículo sin necesidad de que estas palabras aparezcan exactamente en el documento. Algunas de las bases de datos vectoriales más utilizadas pueden ser: ElasticSearch, Milvus, AI search de Azure, la mayoría de empresas de hiperescalares como podréis comprobar, aunque también hay opciones abiertas como OpenSearch. ¿Cómo funcionan las bases de datos vectoriales? Conversión del texto a un vector numérico: Cada fragmento de información es convertido en un embedding (una representación matemática en un espacio de alta dimensión). Almacenamiento en la base de datos: Estos embeddings se almacenan en una base de datos vectorial optimizada para consultas rápidas. Búsqueda de similitud: Cuando un usuario realiza una consulta, esta también se transforma en un embedding, utilizando el mismo modelo que se usó para almacenar la información. Esto es fundamental, ya que de lo contrario sería como tener toda la información almacenada en un idioma (por ejemplo, inglés) y hacer la pregunta en otro (como español); no habría una base común para comparar. Al convertir tanto la información como la consulta en vectores numéricos, es posible calcular su similitud utilizando métricas como la similitud del coseno o la distancia euclidiana. En definitiva, al tratarse de representaciones numéricas, las similitudes se determinan mediante operaciones matemáticas sobre esos vectores. Después de comprender la teoría detrás de los embeddings y las métricas de similitud, pasamos a un ejemplo práctico para ilustrar cómo funciona la búsqueda semántica frente a una búsqueda tradicional basada en texto. Ejemplo práctico: búsqueda semántica vs búsqueda tradicional basada en texto Supongamos que creamos una base de datos con los siguientes términos: camión, automóvil, vehículo, libro, serpiente, bicicleta, motocicleta. Si realizamos una búsqueda léxica (por ejemplo, con SQL), consultando exactamente por la palabra vehículo (con tilde incluida), solo obtendremos como resultado esa coincidencia exacta. Esto se debe a que en este tipo de búsqueda no se analiza el significado de las palabras, sino simplemente sí coinciden en su forma escrita. import sqlite3
# Crear base de datos y tabla
conn = sqlite3.connect('busqueda.db')
cursor = conn.cursor()
cursor.execute("DROP TABLE IF EXISTS terminos")
cursor.execute("CREATE TABLE terminos (palabra TEXT)")
# Insertar valores
terminos = ["camión", "automóvil", "vehículo", "libro", "serpiente", "bicicleta", "motocicleta"]
cursor.executemany("INSERT INTO terminos (palabra) VALUES (?)", [(t,) for t in terminos])
conn.commit()
busqueda = 'vehículo'
cursor.execute("SELECT palabra FROM terminos WHERE palabra = ?", (busqueda,))
resultados = cursor.fetchall()
print("Resultados búsqueda léxica:", resultados)
____________ Resultados búsqueda léxica: [('vehículo',)] ____________ En cambio, al aplicar una búsqueda semántica utilizando embeddings y una métrica como la similitud del coseno, podemos calcular el grado de similitud entre la palabra vehiculo (sin tilde, en este caso) y el resto de términos de la base de datos. Como resultado, obtendremos una puntuación entre 0 y 1 para cada palabra, donde 1 indica una similitud muy alta y 0 una ausencia total de relación semántica. from sentence_transformers import SentenceTransformer, util
import numpy as np
import warnings
import sqlite3 # Asegurar conexión con BD
warnings.filterwarnings("ignore")
# Modelo de embeddings
model = SentenceTransformer("all-MiniLM-L6-v2")
# Obtener términos desde la BD (asegura que tienes conexión)
conn = sqlite3.connect("busqueda.db") # Cambia por tu BD real
cursor = conn.cursor()
cursor.execute("SELECT palabra FROM terminos")
terminos = [row[0] for row in cursor.fetchall()]
# Obtener embeddings
terminos_embeddings = model.encode(terminos)
# Embedding de la consulta
query = "vehículo"
query_embedding = model.encode(query)
# Calcular similitud coseno usando util.pytorch_cos_sim
cos_sim = util.pytorch_cos_sim(query_embedding, terminos_embeddings)
# Mostrar resultados ordenados
print("Resultados búsqueda semántica:")
for palabra, score in sorted(zip(terminos, cos_sim[0].tolist()), key=lambda x: x[1], reverse=True):
print(f"{palabra}: {score:.4f}")
____________ Resultados búsqueda semántica:
vehículo: 1.0000
bicicleta: 0.3503
automóvil: 0.3076
motocicleta: 0.3061
camión: 0.2938
serpiente: 0.2471
libro: 0.2063 ____________ Veremos que palabras como camión, automóvil, bicicleta o motocicleta obtienen puntuaciones relativamente altas por pertenecer a la misma categoría conceptual (medios de transporte), mientras que otras como libro o serpiente muestran puntuaciones más bajas, al no tener relación directa con la palabra buscada. Un detalle interesante es observar que, por ejemplo, automóvil puede no alcanzar una puntuación tan alta como cabría esperar. Esto puede deberse a las particularidades del modelo de embedding utilizado. Por eso, la elección del modelo adecuado es clave según el dominio de aplicación y el tipo de consultas esperadas. Este enfoque es precisamente el que aprovechan los sistemas RAG (Retrieval-Augmented Generation), permitiendo recuperar información relevante incluso cuando no se produce una coincidencia exacta entre los términos de la consulta y los datos almacenados. ¿Qué son los embeddings y por qué son esenciales? Si el término embedding no te es familiar, puedes imaginarlo como la forma en que una IA 'traduce' el lenguaje humano en números que los ordenadores pueden entender. Más específicamente, un embedding es una representación numérica de un texto en un espacio vectorial de alta dimensión. Esto significa que cada palabra, frase o documento se transforma en un vector, y la distancia o similitud entre estos vectores refleja lo parecidos que son en cuanto a significado. Gracias a este enfoque, los modelos de IA pueden entender, por ejemplo, que vehículo y automóvil están estrechamente relacionados, aunque no sean la misma palabra exacta —como vimos en el ejemplo práctico de búsqueda semántica anterior. Tipos de embeddings Existen diferentes tipos de embeddings dependiendo del nivel de granularidad: Word Embeddings: Representan palabras individuales (ejemplo: Word2Vec, GloVe). Sentence Embeddings: Capturan el significado de oraciones completas (ejemplo: MiniLM, SBERT). Los modelos más utilizados actualmente son de este tipo. Por ello son los utilizados tanto en el ejemplo anterior como en los posteriores. Document Embeddings: Representan textos largos en un único vector. La importancia de elegir el modelo adecuado No todos los modelos de embeddings son iguales, y la elección del modelo correcto puede marcar una gran diferencia en el rendimiento del sistema RAG. Algunos factores a tener en cuenta son: Tamaño del modelo: Modelos más grandes suelen ser más precisos, pero requieren más recursos computacionales. Idioma: Algunos modelos están entrenados solo en inglés, por lo que pueden no funcionar bien en otros idiomas como español o francés. Dominio específico: Existen modelos entrenados en áreas como medicina o derecho, lo que mejora la recuperación de información en esos campos específicos. En el ejemplo anterior, utilizamos el modelo 'all-MiniLM-L6-v2' para calcular la similitud entre la palabra vehículo y el resto de los términos. Aunque obtuvimos resultados razonables, algunas puntuaciones no fueron tan altas como esperábamos por ejemplo, automóvil, que debería haber mostrado una relación mucho más fuerte con vehículo. from sentence_transformers import SentenceTransformer, util
import numpy as np
import warnings
import sqlite3 # Asegurar conexión con BD
warnings.filterwarnings("ignore")
# Modelo de embeddings
model = SentenceTransformer("paraphrase-multilingual-MiniLM-L12-v2")
# Obtener términos desde la BD (asegura que tienes conexión)
conn = sqlite3.connect("busqueda.db") # Cambia por tu BD real
cursor = conn.cursor()
cursor.execute("SELECT palabra FROM terminos")
terminos = [row[0] for row in cursor.fetchall()]
# Obtener embeddings
terminos_embeddings = model.encode(terminos)
# Embedding de la consulta
query = "vehículo"
query_embedding = model.encode(query)
# Calcular similitud coseno usando util.pytorch_cos_sim
cos_sim = util.pytorch_cos_sim(query_embedding, terminos_embeddings)
# Mostrar resultados ordenados
print("Resultados búsqueda semántica:")
for palabra, score in sorted(zip(terminos, cos_sim[0].tolist()), key=lambda x: x[1], reverse=True):
print(f"{palabra}: {score:.4f}")
____________ Resultados búsqueda semántica:
vehículo: 0.9830
automóvil: 0.9422
camión: 0.7876
motocicleta: 0.4804
bicicleta: 0.4235
libro: 0.4017
serpiente: 0.2485
____________ Utilizando exactamente el mismo código, pero sustituyendo el modelo de sentence transformers por 'paraphrase-multilingual-MiniLM-L12-v2', se puede observar una mejora notable en los resultados. Por ejemplo, la similitud entre vehículo y automóvil es ahora mucho más alta, lo cual refleja mejor la relación semántica entre ambos términos. Esta mejora no se debe únicamente a que el modelo sea más potente, sino principalmente a que es multilingüe. Es importante tener en cuenta que la mayoría de los modelos de embeddings han sido entrenados principalmente en inglés, por lo que suelen ofrecer mejores resultados cuando se trabaja en ese idioma. Esto puede limitar su rendimiento en otros idiomas, como el español. En cambio, paraphrase-multilingual-MiniLM-L12-v2 ha sido entrenado con textos en más de 50 idiomas, lo que le permite manejar consultas en español (y otros idiomas) con mucha mayor precisión. ■ La elección del embedding adecuado impacta directamente en la calidad de las respuestas generadas, por lo que es un factor clave en la implementación de sistemas RAG. La importancia de los 'chunks' y cómo segmentar documentos Hasta ahora, hemos visto cómo funciona la búsqueda semántica a nivel de palabras o frases cortas, como en el caso de vehículo y automóvil. Estos ejemplos nos permitieron entender la lógica de los embeddings y la similitud de vectores. Sin embargo, en escenarios reales, las consultas de los usuarios suelen estar relacionadas con textos mucho más largos: artículos, manuales, correos, informes, etc. Aquí surge una pregunta fundamental: ¿Cómo organizamos y estructuramos esa información para que sea útil en un sistema RAG? La respuesta está en una técnica clave: el chunking o segmentación de texto. ¿Qué es el chunking y por qué es tan importante? Cuando se trabaja con documentos extensos, no es eficiente ni recomendable tratarlos como una única unidad. En lugar de eso, se dividen en fragmentos más pequeños llamados chunks, que permiten: Reducir el coste de procesamiento: Solo se analizan los fragmentos relevantes en lugar de todo el documento. Mejorar la precisión: Los modelos generativos pueden enfocarse mejor en la parte del texto que realmente importa. Evitar ruido: Fragmentos bien definidos minimizan la inclusión de información irrelevante. Sin embargo, no se trata simplemente de cortar por cortar. La forma en que segmentamos los textos tiene un impacto directo en la calidad de las respuestas generadas. Estrategias de segmentación Existen dos métodos principales para dividir los textos: División por longitud (palabras o caracteres) Se fijan límites como 200 palabras o 1.000 caracteres por fragmento. —Es una técnica rápida y fácil de implementar, pero puede interrumpir frases o ideas a mitad de camino. División semántica Este enfoque utiliza modelos de IA que detectan cambios temáticos dentro del contenido y dividen el texto en secciones lógicas, lo que ayuda a preservar mejor el significado. —Aunque es más costoso en términos computacionales, este método permite una organización más precisa. Además, la división semántica no siempre depende de modelos avanzados de IA: también se puede realizar de manera más sencilla dividiendo el texto según los epígrafes o secciones, tal como ocurre en documentos de Word o PDF, donde las divisiones están predefinidas. ¿Cómo afecta la segmentación a la recuperación de información? Chunks demasiado grandes: Pueden contener información irrelevante, lo que reduce la precisión de la respuesta generada. Chunks demasiado pequeños: Pueden perder contexto y hacer que el sistema no encuentre la información relevante. Mejor enfoque: Combinar ambas estrategias para obtener fragmentos equilibrados que optimicen la recuperación semántica. Beneficios de implementar RAG con bases de datos vectoriales, embeddings y chunks bien diseñados La correcta implementación de estos elementos en un sistema RAG permite: Acceso a información actualizada y precisa sin necesidad de reentrenar el modelo generativo. Búsqueda semántica avanzada que mejora la relevancia de las respuestas. Optimización del almacenamiento y recuperación de datos, asegurando eficiencia y escalabilidad. Mejor experiencia de usuario al generar respuestas contextualizadas y coherentes. Conclusión La Recuperación Aumentada por Generación (RAG) representa un avance significativo en la inteligencia artificial, permitiendo que los modelos generativos accedan a información externa de manera eficiente y precisa. Como hemos visto, el éxito de estos sistemas depende de tres pilares fundamentales: la elección del modelo de embedding adecuado, la estructura óptima de la base de datos vectorial y una segmentación efectiva de los documentos. Con las herramientas y conceptos explicados en este artículo, ya cuentas con los conocimientos básicos para comenzar a implementar tus propios sistemas RAG. Si deseas explorar aplicaciones concretas que pueden beneficiar a tu empresa, te recomendamos nuestro artículo sobre IA creativa en la empresa. A medida que la IA continúa evolucionando, estas técnicas jugarán un papel cada vez más relevante en aplicaciones como asistentes virtuales, búsqueda inteligente de información y automatización de tareas cognitivas. Invertir en una estrategia sólida de RAG no solo mejora la precisión de los modelos generativos, sino que también permite un acceso más inteligente y contextualizado a la información, marcando el camino hacia una IA más útil, confiable y adaptada a las necesidades específicas de tu organización. ✅ ¿Estás listo para dar el siguiente paso en la implementación de sistemas RAG en tu empresa? IA & Data La tokenización y el caballero andante Don Quijote 22 de enero de 2025
6 de mayo de 2025