Chatbot rápido con LangChain

La implementación de modelos de lenguaje conversacionales se puede agilizar de manera sencilla gracias a LangChain. Además, la capacidad de unir múltiples funcionalidades hace de este framework el preferido por los desarrolladores y científicos de datos.
Alberto Pérez Galende
Data Scientist & Desarrollador Python
Esta semana os compartimos en un post de Linkedin un framework ampliamente utilizado en python para implementar facil y rapido modelos de lenguaje en diferentes aplicaciones software. Langchain, lanzado en octubre de 2022, permite implementar modelos de lenguaje (LLM) en diferentes tareas como pueden ser Reality Augmented Generation (RAG), agentes, cadenas, etc. De esta manera, con pocas líneas de código, se puede crear una aplicación completa que tenga un chatbot incorporado capaz de consultar archivos personalizados para ofrecer las mejores respuestas posibles.
En este blog vamos a diseñar un pequeño chatbot capaz de acceder a una serie de CVs para poder preguntarle al modelo acerca de los candidatos registrados.
langchain3

ChatBot con LangChain y OpenAI

Requisitos

El Se usara Python en un Jupyter Notebook. Además, para usar el modelo, es necesario tener una cuenta de OpenAI y crear una API KEY para hacer las llamadas a su API. En cuanto a las dependencias a instalar con pip son:

  • Langchain: Librería principal de LangChain con todas las funcionalidades básicas.
  • Langchain-openai: Librería necesaria para hacer las llamadas a la API de OpenAI a través de LangChain
Y ya, no se necesitan más dependencias para replicar este cuaderno.

Inicio del cuaderno: Importaciones

Se comienza importando las clases y funciones necesarias para crear la memoria, la base de datos vectorial, el modelo, etc. Además, cargamos la API_KEY de Openai y el directorio donde vamos a guardar los CVs de la gente que queramos analizar.

import os
from dotenv import load_dotenv
 
from langchain.vectorstores import FAISS
from langchain_openai.chat_models import ChatOpenAI
from langchain_openai.embeddings import OpenAIEmbeddings
from langchain_community.document_loaders import PyPDFDirectoryLoader
from langchain.memory.buffer import ConversationBufferMemory
from langchain.chains.conversational_retrieval.base import ConversationalRetrievalChain
load_dotenv()
# Load openai API-KEY
API_KEY = os.environ[«OPENAI_API_KEY»]
# Load file directory
CV_path_directory = «./resources/»

Recursos para el chatbot

Una vez se han cargado las clases, funciones y variables necesarias es hora de empezar a crear las herramientas a las que el chatbot tendrá acceso a la hora de responder a las preguntas de los usuarios.
La primera parte, y la más importante en mi opinión, es la creación de una base de datos con los archivos deseados. Estos archivos se guardarán en una base de datos vectorial, FAISS, a través de unos embeddings creados gracias a el modelo _text-embedding-ada-002_ de openai.
loader = PyPDFDirectoryLoader(CV_path_directory)
pages = []
for page in loader.lazy_load():
    pages.append(page)
embeddings = OpenAIEmbeddings(api_key=API_KEY)
vectorstore = FAISS.from_documents(documents=pages, embedding=embeddings)
retriever = vectorstore.as_retriever()
Una vez tenemos la base de datos a la que se va a consultar, necesitamos un modelo de lenguaje. Para este blog se va a utilizar _gpt-4o-mini-2024-07-18_, un modelo relativamente pequeño y barato de openai, pero que para estas tareas concisas, que en este caso no va a tener un contexto excesivo, es más que suficiente.
llm = ChatOpenAI(model=«gpt-4o-mini-2024-07-18», api_key=API_KEY, temperature=0.1)
Por último, para transformar un simple modelo en un chatbot necesita memoria. Si no es capaz de recordar los mensajes anteriores, las llamadas serían independientes y cualquier instrucción o corrección se perdería por el camino.
memory = ConversationBufferMemory(memory_key=«chat_history», return_messages=True)
Y ya tenemos todas las herramientas para que este chatbot funcione, siendo capaz de acceder a dichos archivos para encontrar la información más relevante y crear respuestas adecuadas.

Cadena Conversacional

Ahora que ya tenemos todas las herramientas es hora de crear nuestro chatbot. Y aunque parezca una tarea compleja y costosa, gracias a LangChain, se convierte en algo sencillo e inmediato.
retrieval_chain = ConversationalRetrievalChain.from_llm(
    llm=llm,
    retriever=retriever,
    memory=memory,
)
Y listo, ya tenemos nuestro chatbot, con unas pocas líneas de código. Para hacer llamadas basta con usar la función _invoke_ y proporcionará la respuesta más adecuada.

Ejemplos

Los archivos usados han sido dos CVs, uno de Alberto Pérez Galende y otro de Juan Sánchez Blázquez. Al hacerle preguntas acerca de cualquiera de las dos personas el modelo es capaz de acceder al archivo correspondiente y responder con exactitud.
question_1 = «Who is Alberto Perez Galende?»
response = retrieval_chain.invoke({«question»: question_1})
response[«answer»]
«Alberto Perez Galende is a data scientist and Python developer based in Salamanca, Spain. He has a background in mathematics and physics and has experience in applying machine learning algorithms to various types of data. Currently, he works at Axpe Consulting as a data scientist and backend developer, focusing on computer vision processes, data extraction, and web app development using FastAPI and Docker. He holds a B.S. in Mathematics with a minor in Physics from Campbellsville University and a Master’s in Mathematical Research from the Polytechnic University of Valencia. He is also interested in improving his teamwork skills and learning more about supervised machine learning algorithms.»
Veamos ahora que ocurre al referirse a una pregunta o respuesta anterior. Al no proporcionar un nombre, y gracias a la memoria, el modelo deduce que esta pregunta va unida a la misma persona que la anterior.
question_2 = «What degree he studied?»
response_2 = retrieval_chain.invoke({«question»: question_2})
response_2[«answer»]
«He studied a B.S. major in Mathematics and a minor in Physics at Campbellsville University.»
Ahora preguntémosle algo relacionado con otro archivo.
question_3 = «Who is Juan Sanchez?»
response_3 = retrieval_chain.invoke({«question»: question_3})
response_3[«answer»]
«Juan Sánchez is a data scientist based in Salamanca, Spain, with a background in Mathematics. He has experience in data processing and analysis, visualization of results, and development of microservices in Python. His skills include Python, machine learning, deep learning, natural language processing, and working with relational databases. He is currently working as a Python developer at uXcale and has previously held a position as a data engineer at the same company. Juan is fluent in Spanish and English and has a B1 level in German. He is also pursuing a degree in Mathematics from the University of Salamanca.»
question_4 = «What degree he studied?»
response_4 = retrieval_chain.invoke({«question»: question_4})
response_4[«answer»]
«Juan Sánchez studied a degree in Mathematics at the Universidad de Salamanca.»

Conclusiones

Se puede ver que el modelo da respuestas concisas y fiables acerca de los archivos proporcionados, además de recordar los últimos mensajes que se han proporcionado. En este ejemplo se han usado cadenas, RAG, memoria y otras funcionalidades que, sin LangChain habría llevado días y varios archivos de código mucho más extensos. Sin embargo, gracias a este framework, esta implementación ha sido rápida y eficaz. Además de estas herramientas, LangChain proporciona soporte para agentes, cadenas mucho más complejas y otras funcionalidades, las cuales se pueden combinar, complementar y trabajar juntas para conseguir que la inteligencia artificial generativa sea lo más útil posible de la manera más sencilla.

¿Cómo de bien podría funcionar un equipo de agentes en el cual uno extrae información de una persona, otro agente analiza su rendimiento laboral, y un último, con la información de ambos, escribe un reporte acerca de dicho empleado?

LangChain ofrece oportunidades casi infinitas para interactuar con IA generativa y modelos de lenguaje. Y a ti, ¿qué casos de uso se te ocurren? ¿Has probado LangChain antes? ¡Cuéntanos tu experiencia y que nuevos casos de uso se te ocurren para usar este framework!