LangChain + Streamlit + Llama Llevando la IA Conversacional a tu Máquina Local
LangChain + Streamlit + Llama Bringing Conversational AI to Your Local Machine
En los últimos meses, los Modelos de Lenguaje Grandes (LLMs) han ganado una atención significativa, capturando el interés de desarrolladores en todo el planeta. Estos modelos han creado perspectivas emocionantes, especialmente para los desarrolladores que trabajan en chatbots, asistentes personales y creación de contenido. Las posibilidades que los LLMs aportan han generado una ola de entusiasmo en la comunidad de Desarrolladores | IA | PNL.
¿Qué son los LLMs?
Los Modelos de Lenguaje Grandes (LLMs) se refieren a modelos de aprendizaje automático capaces de producir texto que se asemeja estrechamente al lenguaje humano y de comprender comandos de manera natural. Estos modelos se entrenan utilizando conjuntos de datos extensos que incluyen libros, artículos, sitios web y otras fuentes. Al analizar los patrones estadísticos dentro de los datos, los LLMs predicen las palabras o frases más probables que deben seguir a una entrada dada.
- Potenciando la excelencia operativa a través de la minería de proce...
- La Efectividad Irrebatible del Aprendizaje por Transferencia
- Cómo los modelos de aprendizaje automático pueden amplificar las in...
Al utilizar los Modelos de Lenguaje Grandes (LLMs), podemos incorporar datos específicos del dominio para abordar consultas de manera efectiva. Esto se vuelve especialmente ventajoso cuando se trata de información a la que el modelo no tuvo acceso durante su entrenamiento inicial, como la documentación interna de una empresa o su repositorio de conocimientos.
La arquitectura utilizada para este propósito se conoce como Retrieval Augmentation Generation o, menos comúnmente, Generative Question Answering.
¿Qué es LangChain?
LangChain es un impresionante y gratuito marco de trabajo meticulosamente diseñado para potenciar a los desarrolladores en la creación de aplicaciones impulsadas por el poder de los modelos de lenguaje, en particular los modelos de lenguaje grandes (LLMs).
LangChain revoluciona el proceso de desarrollo de una amplia gama de aplicaciones, incluidos chatbots, preguntas y respuestas generativas (GQA) y resúmenes. Al combinar de manera fluida componentes provenientes de múltiples módulos, LangChain permite la creación de aplicaciones excepcionales adaptadas al poder de los LLMs.
Leer más: Documentación oficial
¿Motivación?
En este artículo, demostraré el proceso de creación de tu propio Asistente de Documentos desde cero, utilizando LLaMA 7b y Langchain, una biblioteca de código abierto desarrollada específicamente para integración sin problemas con LLMs.
Aquí tienes un resumen de la estructura del blog, que detalla las secciones específicas que proporcionarán un desglose detallado del proceso:
Configurar el entorno virtual y crear la estructura de archivos
Obtener LLM en tu máquina local
Integrar LLM con LangChain y personalizar PromptTemplate
Recuperación de documentos y generación de respuestas
Crear una aplicación usando Streamlit
Sección 1: Configurar el entorno virtual y crear la estructura de archivos
Configurar un entorno virtual proporciona un entorno controlado y aislado para ejecutar la aplicación, asegurando que sus dependencias estén separadas de otros paquetes de todo el sistema. Este enfoque simplifica la gestión de dependencias y ayuda a mantener la consistencia en diferentes entornos.
Para configurar el entorno virtual para esta aplicación, proporcionaré el archivo pip en mi repositorio de GitHub. Primero, creemos la estructura de archivos necesaria como se muestra en la figura. Alternativamente, puedes simplemente clonar el repositorio para obtener los archivos necesarios.
Dentro de la carpeta de modelos, almacenaremos los LLMs que descargaremos, mientras que el archivo pip se ubicará en el directorio raíz.
Para crear el entorno virtual e instalar todas las dependencias dentro de él, podemos utilizar el comando pipenv install
desde el mismo directorio o simplemente ejecutar el archivo por lotes setup_env.bat
. Esto instalará todas las dependencias del pipfile
. Esto asegurará que todos los paquetes y bibliotecas necesarios se instalen en el entorno virtual. Una vez que las dependencias se instalen correctamente, podemos proceder al siguiente paso, que implica descargar los modelos deseados. Aquí está el repositorio.
Sección 2: Obtener LLaMA en tu máquina local
¿Qué es LLaMA?
LLaMA es un nuevo modelo de lenguaje grande diseñado por Meta AI, que es la empresa matriz de Facebook. Con una colección diversa de modelos que van desde 7 mil millones hasta 65 mil millones de parámetros, LLaMA se destaca como uno de los modelos de lenguaje más completos disponibles. El 24 de febrero de 2023, Meta lanzó el modelo LLaMA al público, demostrando su dedicación a la ciencia abierta.
Teniendo en cuenta las notables capacidades de LLaMA, hemos decidido utilizar este potente modelo de lenguaje para nuestros propósitos. Específicamente, utilizaremos la versión más pequeña de LLaMA, conocida como LLaMA 7B. Incluso a este tamaño reducido, LLaMA 7B ofrece importantes capacidades de procesamiento de lenguaje, lo que nos permite lograr nuestros resultados deseados de manera eficiente y efectiva.
Artículo de investigación oficial:
LLaMA: Modelos de lenguaje de base abierta y eficientes
Para ejecutar el LLM en una CPU local, necesitamos un modelo local en formato GGML. Varios métodos pueden lograr esto, pero el enfoque más sencillo es descargar el archivo bin directamente desde el repositorio de modelos de Hugging Face. En nuestro caso, descargaremos el modelo Llama 7B. Estos modelos son de código abierto y están disponibles para su descarga de forma gratuita.
Si buscas ahorrar tiempo y esfuerzo, no te preocupes, ¡te tengo cubierto! Aquí tienes el enlace directo para descargar los modelos ?. Simplemente descarga cualquier versión y luego mueve el archivo al directorio de modelos dentro de nuestro directorio raíz. De esta manera, tendrás el modelo convenientemente accesible para su uso.
¿Qué es GGML? ¿Por qué GGML? ¿Cómo GGML? LLaMA CPP
GGML es una biblioteca de tensores para aprendizaje automático, es solo una biblioteca de C++ que te permite ejecutar LLMs solo en la CPU o CPU + GPU. Define un formato binario para distribuir modelos de lenguaje grandes (LLMs). GGML utiliza una técnica llamada cuantización que permite que los modelos de lenguaje grandes se ejecuten en hardware de consumo.
Ahora, ¿qué es la cuantización?
Los pesos del LLM son números de punto flotante (decimales). Al igual que se requiere más espacio para representar un número entero grande (por ejemplo, 1000) en comparación con un número entero pequeño (por ejemplo, 1), se requiere más espacio para representar un número de punto flotante de alta precisión (por ejemplo, 0.0001) en comparación con un número de punto flotante de baja precisión (por ejemplo, 0.1). El proceso de cuantizar un modelo de lenguaje grande implica reducir la precisión con la que se representan los pesos para reducir los recursos necesarios para usar el modelo. GGML admite varias estrategias de cuantización diferentes (por ejemplo, cuantización de 4 bits, 5 bits y 8 bits), cada una de las cuales ofrece diferentes compensaciones entre eficiencia y rendimiento.
Para utilizar eficazmente los modelos, es esencial tener en cuenta los requisitos de memoria y disco. Dado que los modelos se cargan completamente en la memoria actualmente, necesitarás suficiente espacio en disco para almacenarlos y suficiente RAM para cargarlos durante la ejecución. En el caso del modelo de 65B, incluso después de la cuantización, se recomienda tener al menos 40 gigabytes de RAM disponibles. Vale la pena señalar que los requisitos de memoria y disco son actualmente equivalentes.
La cuantización juega un papel crucial en el manejo de estas demandas de recursos. A menos que tengas acceso a recursos computacionales excepcionales
Al reducir la precisión de los parámetros del modelo y optimizar el uso de memoria, la cuantización permite que los modelos se utilicen en configuraciones de hardware más modestas. Esto garantiza que la ejecución de los modelos siga siendo factible y eficiente para una gama más amplia de configuraciones.
¿Cómo lo utilizamos en Python si es una biblioteca de C++?
Es ahí donde entran en juego los binding de Python. El binding se refiere al proceso de crear un puente o interfaz entre dos lenguajes, en este caso Python y C++. Utilizaremos llama-cpp-python
que es un binding de Python para llama.cpp
que actúa como una inferencia del modelo LLaMA en C/C++ puro. El objetivo principal de llama.cpp
es ejecutar el modelo LLaMA utilizando cuantización de enteros de 4 bits. Esta integración nos permite utilizar eficazmente el modelo LLaMA, aprovechando las ventajas de la implementación en C/C++ y los beneficios de la cuantización de enteros de 4 bits.
Con el modelo GGML preparado y todas nuestras dependencias en su lugar (gracias al pipfile), es hora de embarcarnos en nuestro viaje con LangChain. Pero antes de sumergirnos en el emocionante mundo de LangChain, comencemos con el ritual habitual de “Hola Mundo”, una tradición que seguimos siempre que exploramos un nuevo lenguaje o framework, después de todo, LLM también es un modelo de lenguaje.
Image By Author: Interacción con LLM en la CPU
¡¡¡Voilà!!! Hemos ejecutado con éxito nuestro primer LLM en la CPU, completamente fuera de línea y de manera completamente aleatoria (puedes jugar con el hiperparámetro temperature).
Con este emocionante hito logrado, ahora estamos listos para embarcarnos en nuestro objetivo principal: responder preguntas de texto personalizado utilizando el framework LangChain.
Sección 3: Primeros pasos con LLM – Integración de LangChain
En la última sección, inicializamos LLM utilizando llama cpp. Ahora, vamos a aprovechar el framework LangChain para desarrollar aplicaciones utilizando LLMs. La interfaz principal a través de la cual puedes interactuar con ellos es a través de texto. Como simplificación excesiva, muchos modelos son texto de entrada, texto de salida. Por lo tanto, muchas de las interfaces en LangChain se centran en el texto.
El surgimiento del Ingeniería de Prompts
En el campo en constante evolución de la programación ha surgido un paradigma fascinante: el Prompting. El Prompting implica proporcionar una entrada específica a un modelo de lenguaje para obtener una respuesta deseada. Este enfoque innovador nos permite dar forma a la salida del modelo en función de la entrada que proporcionamos.
Es sorprendente cómo los matices en la forma en que redactamos un prompt pueden tener un impacto significativo en la naturaleza y el contenido de la respuesta del modelo. El resultado puede variar fundamentalmente según la redacción, lo que resalta la importancia de una cuidadosa consideración al formular los prompts.
Para proporcionar una interacción fluida con LLMs, LangChain proporciona varias clases y funciones para facilitar la construcción y el trabajo con prompts utilizando una plantilla de prompt. Es una manera reproducible de generar un prompt. Contiene una cadena de texto la plantilla, que puede tomar un conjunto de parámetros del usuario final y generar un prompt. Veamos algunos ejemplos.
Image By Author: Prompt sin Variables de Entrada
Image By Author: Prompt con una Variable de Entrada
Image By Author: Prompt con Múltiples Variables de Entrada
Espero que la explicación anterior haya proporcionado una comprensión más clara del concepto de prompting. Ahora, procedamos a hacer un prompt al LLM.
Imagen por Autor: Guiando a través de Langchain LLM
Esto funcionó perfectamente bien, pero no es la utilización óptima de LangChain. Hasta ahora hemos utilizado componentes individuales. Tomamos la plantilla de indicación formateada, luego tomamos el llm, y luego pasamos esos parámetros dentro del llm para generar la respuesta. El uso de un LLM de forma aislada es adecuado para aplicaciones simples, pero las aplicaciones más complejas requieren encadenar LLMs, ya sea entre sí o con otros componentes.
LangChain proporciona la interfaz Chain para este tipo de aplicaciones encadenadas. Definimos una cadena de forma muy genérica como una secuencia de llamadas a componentes, que pueden incluir otras cadenas. Las cadenas nos permiten combinar múltiples componentes para crear una aplicación única y coherente. Por ejemplo, podemos crear una cadena que tome la entrada del usuario, la formatee con una plantilla de indicación y luego pase la respuesta formateada a un LLM. Podemos construir cadenas más complejas combinando múltiples cadenas juntas o combinando cadenas con otros componentes.
Para entenderlo mejor, creemos una cadena muy simple que tomará la entrada del usuario, formateará la indicación con ella y luego la enviará al LLM utilizando los componentes individuales mencionados anteriormente que ya hemos creado.
Imagen por Autor: Encadenamiento en LangChain
Cuando se trata de múltiples variables, tienes la opción de ingresarlas de forma colectiva utilizando un diccionario. Esto concluye esta sección. Ahora, adentrémonos en la parte principal donde incorporaremos texto externo como un recuperador para fines de pregunta-respuesta.
Sección 4: Generación de Incrustaciones y Almacenamiento de Vectores para Pregunta-Respuesta
En numerosas aplicaciones de LLM, hay una necesidad de datos específicos del usuario que no están incluidos en el conjunto de entrenamiento del modelo. LangChain te proporciona los componentes esenciales para cargar, transformar, almacenar y consultar tus datos.
Conexión de Datos en LangChain: Fuente
Las cinco etapas son:
- Cargador de Documentos: Se utiliza para cargar datos como documentos.
- Transformador de Documentos: Divide el documento en fragmentos más pequeños.
- Incrustaciones: Transforma los fragmentos en representaciones vectoriales, también conocidas como incrustaciones.
- Almacenes de Vectores: Se utiliza para almacenar los vectores de fragmentos mencionados anteriormente en una base de datos de vectores.
- Recuperadores: Se utiliza para recuperar un conjunto o conjuntos de vectores que son más similares a una consulta en forma de vector que está incrustado en el mismo espacio latente.
Ciclo de Recuperación de Documentos / Pregunta-Respuesta
Ahora, vamos a recorrer cada una de las cinco etapas para realizar una recuperación de fragmentos de documentos que son más similares a la consulta. Después de eso, podemos generar una respuesta basada en el fragmento de vector recuperado, como se ilustra en la imagen proporcionada.
Sin embargo, antes de continuar, necesitaremos preparar un texto para ejecutar las tareas mencionadas anteriormente. Para fines de esta prueba ficticia, he copiado un texto de Wikipedia sobre algunos superhéroes populares de DC. Aquí está el texto:
Imagen por Autor: Texto en Bruto para Pruebas
Cargando y Transformando Documentos
Para empezar, creemos un objeto de documento. En este ejemplo, utilizaremos el cargador de texto. Sin embargo, Lang chain ofrece soporte para múltiples documentos, por lo que dependiendo de tu documento específico, puedes utilizar diferentes cargadores. A continuación, utilizaremos el método load
para recuperar datos y cargarlos como documentos desde una fuente preconfigurada.
Una vez que el documento se carga, podemos proceder con el proceso de transformación dividiéndolo en fragmentos más pequeños. Para lograr esto, utilizaremos el TextSplitter. Por defecto, el separador divide el documento en el separador ‘\n\n’. Sin embargo, si establece el separador como nulo y define un tamaño de fragmento específico, cada fragmento tendrá esa longitud especificada. En consecuencia, la longitud de la lista resultante será igual a la longitud del documento dividido por el tamaño del fragmento. En resumen, se parecerá a algo como esto: longitud de la lista = longitud del documento / tamaño del fragmento
. Vamos a ponerlo en práctica.
Imagen por Autor: Cargando y Transformando el Documento
Parte del viaje son los Embeddings !!!
Este es el paso más importante. Los embeddings generan una representación vectorizada del contenido textual. Esto tiene un significado práctico ya que nos permite conceptualizar el texto dentro de un espacio vectorial.
El embedding de palabras es simplemente una representación vectorial de una palabra, con el vector que contiene números reales. Dado que los idiomas típicamente contienen al menos decenas de miles de palabras, los vectores de palabras binarios simples pueden volverse poco prácticos debido a un alto número de dimensiones. Los embeddings de palabras resuelven este problema al proporcionar representaciones densas de palabras en un espacio vectorial de baja dimensión.
Cuando hablamos de recuperación, nos referimos a recuperar un conjunto de vectores que son más similares a una consulta en forma de un vector que está incrustado en el mismo espacio latente.
La clase base Embeddings en LangChain expone dos métodos: uno para incrustar documentos y otro para incrustar una consulta. El primero toma como entrada varios textos, mientras que el último toma un solo texto.
Imagen por Autor: Embeddings
Para comprender completamente los embeddings, recomiendo encarecidamente adentrarse en los fundamentos, ya que forman el núcleo de cómo las redes neuronales manejan los datos textuales. He cubierto extensamente este tema en uno de mis blogs utilizando TensorFlow. Aquí está el enlace.
Word Embeddings – Representación de Texto para Redes Neuronales
Creando Vector Store y Recuperando Documentos
Un vector store administra eficientemente el almacenamiento de datos incrustados y facilita las operaciones de búsqueda de vectores en su nombre. La incrustación y el almacenamiento de los vectores incrustados resultantes es un método prevalente para almacenar y buscar datos no estructurados. Durante el tiempo de consulta, la consulta no estructurada también se incrusta y se recuperan los vectores de incrustación que exhiben la mayor similitud con la consulta incrustada. Este enfoque permite la recuperación efectiva de información relevante del vector store.
Aquí, utilizaremos Chroma, una base de datos de incrustaciones y un vector store especialmente diseñado para simplificar el desarrollo de aplicaciones de IA que incorporan embeddings. Ofrece una suite completa de herramientas y funcionalidades integradas para facilitar su configuración inicial, todas las cuales se pueden instalar fácilmente en su máquina local ejecutando un simple comando pip install chromadb
.
Imagen por Autor: Creando Vector Store
Hasta ahora, hemos presenciado la notable capacidad de los embeddings y los vector stores para recuperar fragmentos relevantes de colecciones extensas de documentos. Ahora, ha llegado el momento de presentar este fragmento recuperado como un contexto junto con nuestra consulta, al LLM. Con un movimiento de su varita mágica, suplicaremos al LLM que genere una respuesta basada en la información que le proporcionamos. La parte importante es la estructura de la consulta.
Sin prolongar la espera más, procedamos ahora a la fase final y descubramos si nuestro LLM es capaz de generar una respuesta convincente. Ha llegado el momento de presenciar la culminación de nuestros esfuerzos y revelar el resultado. ¡Aquí vamos!
Imagen por Autor: Preguntas y Respuestas con el Documento
¡Este es el momento que estábamos esperando! ¡Lo hemos logrado! Acabamos de construir nuestro propio bot de preguntas y respuestas utilizando el LLM ejecutándose localmente.
Sección 5: Encadenar todo usando Streamlit
Esta sección es completamente opcional ya que no sirve como una guía completa de Streamlit. No profundizaré en esta parte, en su lugar, presentaré una aplicación básica que permite a los usuarios cargar cualquier documento de texto. Luego tendrán la opción de hacer preguntas a través de una entrada de texto. En segundo plano, la funcionalidad se mantendrá consistente con lo que cubrimos en la sección anterior.
Sin embargo, hay un inconveniente cuando se trata de cargar archivos en Streamlit. Para evitar posibles errores de falta de memoria, considerando especialmente la naturaleza intensiva en memoria de los LLM, simplemente leeré el documento y lo escribiré en la carpeta temporal dentro de nuestra estructura de archivos, nombrándolo raw.txt.
De esta manera, independientemente del nombre original del documento, Textloader lo procesará sin problemas en el futuro.
Actualmente, la aplicación está diseñada para archivos de texto, pero puedes adaptarla para PDF, CSV u otros formatos. El concepto subyacente sigue siendo el mismo, ya que los LLM están diseñados principalmente para entrada y salida de texto. Además, puedes experimentar con diferentes LLM compatibles con las bibliotecas C++ de Llama.
Sin profundizar más en los detalles intrincados, presento el código de la aplicación. Siéntete libre de personalizarlo según tus necesidades específicas.
Así es como se verá la aplicación de streamlit.
Esta vez alimenté la trama de The Dark Knight copiada de Wiki y simplemente pregunté ¿De quién es la cara gravemente quemada? y el LLM respondió: Harvey Dent.
¡Muy bien, muy bien, muy bien! Con esto, llegamos al final de este blog.
¡Espero que hayas disfrutado este artículo y lo hayas encontrado informativo y cautivador! Puedes seguirme, Afaque Umer, para leer más artículos como este.
Intentaré presentar más conceptos de aprendizaje automático / ciencia de datos y trataré de explicar términos y conceptos que suenan complicados de manera más sencilla.
Afaque Umer es un apasionado Ingeniero de Aprendizaje Automático. Le encanta enfrentar nuevos desafíos utilizando las últimas tecnologías para encontrar soluciones eficientes. ¡Empujemos juntos los límites de la IA!
Original. Repostado con permiso.