Artículo
· 14 oct, 2024 Lectura de 6 min

Modelos LLM y aplicaciones RAG paso a paso - Parte II - Creando el contexto

Continuamos con esta serie de artículos sobre LLM y aplicaciones RAG y en este artículo trataremos la parte recuadrada en rojo del siguiente diagrama:

En el proceso de creación de una aplicación RAG tan importante es la elección de un modelo de LLM adecuado a tus necesidades (entrenado en la temática correspondiente, costes del mismo, velocidad, etc) como el tener claro el contexto que queremos proporcionarle. Empecemos definiendo el término para tener claro a que nos referimos con contexto.

¿Qué es el contexto?

El contexto se refiere a la información adicional que se obtiene de una fuente externa, como una base de datos o un sistema de búsqueda, para complementar o mejorar las respuestas generadas por un modelo de lenguaje. El modelo de lenguaje utiliza esta información externa relevante para generar respuestas más precisas y detalladas en lugar de basarse únicamente en lo que ha aprendido durante su entrenamiento. El contexto ayuda a que las respuestas estén actualizadas y alineadas con el tema específico de la consulta.

Este contexto puede ser desde información almacenada en una base de datos con herramienta similares a la mostrada por nuestro querido miembro de la comunidad @José Pereira en este artículo o información no estructurada en forma de archivos de texto con los que alimentaremos el LLM, que será el caso que vamos a tratar aquí.

¿Cómo generar el contexto para nuestra aplicación RAG?

Lo primero y más indispensable es, obviamente, contar con toda la información que consideramos que puede ser relevante para las posibles consultas que se van a realizar contra nuestra aplicación. Una vez dispuesta dicha información de tal forma que sea accesible desde nuestra aplicación deberemos poder identificar cuales de todos los documentos disponibles para nuestro contexto se refieren a la pregunta específica realizada por el usuario. Para nuestro ejemplo contamos con una serie de documentos en PDF (prospectos de medicamentos) que vamos a querer utilizar como posible contexto ante las preguntas de los usuarios de nuestra aplicación.

Este punto es clave para el éxito de una aplicación RAG, tan malo es para la confianza de un usuario contestarle con generalizaciones y vaguedades típicas de un LLM como contestarle con un contexto totalmente equivocado. Es aquí donde entran nuestras queridas bases de datos vectoriales.

Bases de datos vectoriales

Seguramente ya habéis oído hablar antes de las "bases de datos vectoriales" como si estas fueran un nuevo tipo de base de datos como pueden ser las bases de datos relacionales o las documentales, nada más lejos de la realidad, estas bases de datos vectoriales son bases de datos al uso que soportan los tipos de datos vectoriales así como las operaciones relacionadas con los mismos. Veamos en el proyecto asociado al artículo como se representará ese tipo de datos:

Ahora echemos un vistazo a cómo se visualizaría un registro:

Bases de datos vectoriales...¿Para qué?

Como explicamos en el artículo anterior con los LLM la utilización de vectores es clave en los modelos de lenguaje, al poder representar en un espacio multidimensional los conceptos y las relaciones entre los mismos. Para el caso que nos atañe esta representación multidimensional será la clave para identificar cuales de los documentos de nuestro contexto serán relevantes para la pregunta realizada.

Perfecto, tenemos nuestra base de datos vectorial y los documentos que aportarán el contexto, ahora sólo necesitamos registrar el contenido de estos documentos dentro de nuestra base de datos, pero... ¿Con qué criterio?

Modelos para el vectorizado

¿Cómo? ¿Otro modelo? ¿No nos vale con el LLM? Pues...no es necesario molestar a nuestro LLM para que nos vectorice la información de nuestro contexto, podremos utilizar modelos más pequeños de lenguaje que se adecúen más a nuestras necesidades para esta tarea, como pueden ser los modelos entrenados para detectar similitudes entre frases. Podéis encontrar una miriada de los mismos en Hugging Face cada uno entrenado con un determinado conjunto de datos que nos permitirá mejorar la vectorización de nuestros datos.

Y si esto no os convence para utilizar uno de estos modelos para la vectorización sólo decir que por lo general este tipo de modelos...

Veamos en nuestro ejemplo como invocamos al modelo elegido para estas vectorizaciones:

if not os.path.isdir('/app/data/model/'):
    model = sentence_transformers.SentenceTransformer('sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2')            
    model.save('/app/data/model/')

Aquí estamos descargando en nuestro equipo local el modelo elegido para nuestro caso, este mini-LM es multiidioma por lo que podremos vectorizar tanto en español como en inglés sin problema.

Trozeado o "chunking"

Si ya habéis trasteado con modelos de lenguaje seguramente ya os hayáis enfrentado al reto del chunking. ¿Qué es este chunking? Muy sencillo, es la división del texto en fragmentos menores que puedan contener un significado relevante. Mediante este troceado de nuestro contexto podremos realizar consultas sobre nuestra base de datos vectorial que nos extraiga aquellos documentos de nuestro contexto que puedan ser relevantes en relación a la pregunta realizada.

¿Cuales son los criterios para este troceado? Pues realmente no hay un criterio mágico que nos permita saber cómo de largos tienen que ser nuestros trozos para que sean lo más precisos posibles. En nuestro ejemplo estamos utilizando una librería de Python proporcionada por langchain para realizar este troceado, aunque se podría utilizar cualquier otro método o librería para ello:

text_splitter = RecursiveCharacterTextSplitter(
    chunk_size = 700,
    chunk_overlap  = 50,
)
path = "/app/data"
loader = PyPDFDirectoryLoader(path)
docs_before_split = loader.load()
docs_after_split = text_splitter.split_documents(docs_before_split)

Como véis el tamaño elegido es de 700 caracteres, con un solape de 50 para evitar cortar palabras. Estos fragmentos extraidos de nuestros documentos serán los que vectorizaremos e insertaremos en nuestra base de datos.

Este proceso de troceado se puede optimizar tanto como se quiera mediante la "lematización", mediante el cual podemos transformar las palabras en su lema correspondiente (sin tiempos verbales, plurales, género, etc) y de tal forma eliminar cierto ruido de cara a la generación del vector, pero no vamos a entrar en ello, en esta página podéis ver una explicación más detallada.

Vectorización de fragmentos

Muy bien, tenemos nuestros fragmentos extraídos de cada uno de nuestros documentos, es el momento de vectorizar e insertar en nuestra base de datos, echemos un vistazo al código para entender como lo podríamos hacer.

for doc in docs_after_split:
    embeddings = model.encode(doc.page_content, normalize_embeddings=True)
    array = np.array(embeddings)
    formatted_array = np.vectorize('{:.12f}'.format)(array)
    parameters = []
    parameters.append(doc.metadata['source'])
    parameters.append(str(doc.page_content))
    parameters.append(str(','.join(formatted_array)))
    cursorIRIS.execute("INSERT INTO LLMRAG.DOCUMENTCHUNK (Document, Phrase, VectorizedPhrase) VALUES (?, ?, TO_VECTOR(?,DECIMAL))", parameters)
connectionIRIS.commit()

Como véis realizaremos los siguientes pasos: 

  1. Recorremos la lista de todos los trozos obtenidos de todos los documentos que van a formar nuestro contexto.
  2. Para cada fragmento vectorizamos el texto (utilizando la librería sentence_transformers). 
  3. Creamos un array utilizando la librería de numpy con el vector formateado y lo transformamos en un string.
  4. Registramos la información del documento con su vector asociado en nuestra base de datos. Si veis estamos ejecutando el comando TO_VECTOR que nos transformará el string del vector que le hemos pasado al formato adecuado.

Conclusión

En este artículo hemos podido ver la necesidad de disponer de una base de datos vectorial para la creación del contexto necesario en nuestra aplicación RAG, también hemos repasado como trocear y vectorizar la información de nuestro contexto para su registro en dicha base de datos.

En el próximo artículo veremos como consultar nuestra base de datos vectorial a partir de la pregunta que el usuario envíe al modelo de LLM y como, mediante la búsqueda de similitudes, montaremos el contexto que pasaremos al modelo. ¡No te lo pierdas!

Comentarios (0)1
Inicie sesión o regístrese para continuar