Contenido del curso

Introducción a LangChain

Chats y memoria con LangChain

Chatbot QA con LangChain y ChromaDB

Resumen

Construir un chatbot que responda preguntas sobre documentación técnica requiere conectar un modelo de lenguaje con una base de datos vectorial. Aquí verás cómo integrar ChatOpenAI con ChromaDB usando LangChain para crear un sistema de preguntas y respuestas sobre documentación de Hugging Face, ideal para desarrolladores que exploran Retrieval Augmented Generation (RAG).

Cómo inicializar el modelo de chat con LangChain

El primer paso es importar la clase que conecta tu aplicación con OpenAI. Desde langchain.chat_models traes ChatOpenAI y creas una instancia llamada llm, que es la convención para referirse a un Large Language Model.

python from langchain.chat_models import ChatOpenAI

llm = ChatOpenAI( model_name="gpt-3.5-turbo", temperature=0.2, max_tokens=1000 )

Cada parámetro tiene un propósito específico que afecta el comportamiento del chatbot:

  • model_name: define qué modelo de OpenAI usarás. gpt-3.5-turbo es una opción equilibrada entre costo y calidad.
  • temperature: controla la creatividad de las respuestas. Un valor de 0.2 hace que el modelo sea sobrio y predecible.
  • max_tokens: limita la longitud de la respuesta. 1000 tokens permite respuestas amplias sin escatimar contexto.

¿Qué hace el parámetro temperature en un modelo de lenguaje? Controla la aleatoriedad de las respuestas. Valores bajos (0.2) generan respuestas más consistentes y técnicas; valores altos (0.8) producen salidas más creativas y variables.

Por qué convertir un vector store en retriever

Una base de datos vectorial almacena embeddings, pero el modelo necesita un componente que recupere los fragmentos relevantes. Ese componente es el retriever, y se obtiene con el método as_retriever() sobre la instancia de Chroma.

python retriever = vector_store.as_retriever(search_kwargs={"k": 2})

El parámetro k define cuántos fragmentos similares regresa el retriever por consulta. Con k=2 obtienes los dos pasajes más parecidos a la pregunta. Puedes subirlo a 3 o 4 si necesitas más contexto, pero ten cuidado: cada fragmento adicional aumenta los tokens del prompt y, por lo tanto, el costo de la llamada.

¿Cuál es el valor mínimo recomendado para k en un retriever? Dos fragmentos. Con uno solo rara vez hay contexto suficiente para responder bien una pregunta, así que dos es el piso práctico.

Cómo diseñar la función run_conversation

La función run_conversation orquesta toda la interacción. Recibe el vector store y un chat_type que define el comportamiento, en este caso "QA" para preguntas y respuestas sin memoria.

python def run_conversation(vector_store, chat_type, llm): console.print("Hola, ¿quieres preguntarme sobre transformers e inteligencia artificial?", style="blue")

if chat_type == "QA": console.print("Estás utilizando el chatbot en modo preguntas y respuestas...", style="green") retriever = vector_store.as_retriever(search_kwargs={"k": 2}) while True: console.print("Tú:", style="blue") query = get_query_from_user() if query.lower() == "salir": break if chat_type == "QA": response = process_qa_query(query, retriever, llm) console.print(f"IA: {response}", style="red")

Qué diferencia hay entre un chat con memoria y uno sin memoria

La variable chat_type abre la puerta a dos comportamientos distintos. En modo QA, cada pregunta se resuelve de forma aislada: el modelo no recuerda lo que preguntaste antes. Esto es útil cuando consultas documentación puntual y no necesitas hilar respuestas.

Un chat con memoria, en cambio, conserva el historial y permite hacer preguntas de seguimiento como “¿y eso cómo se aplica al ejemplo anterior?”. Aquí se implementa solo el modo Question Answering para mantener el flujo simple.

Cómo manejar el loop de conversación con el usuario

Un while True simula la experiencia continua de un chat. Dentro del loop, la función get_query_from_user (definida en utils) captura el texto que escribe la persona en la consola.

El criterio de salida es sencillo: si la query convertida a minúsculas es igual a "salir", el loop se rompe con break. Convertir a minúsculas evita que la persona tenga que escribir exactamente como esperas.

Cómo se procesa una pregunta con process_qa_query

Cuando la query no es un comando de salida y el chat_type es QA, la función delega el trabajo a process_qa_query. Esta recibe tres argumentos:

  1. La query del usuario.
  2. El retriever que busca en ChromaDB los fragmentos relevantes.
  3. El llm que genera la respuesta final.

El modelo llm no estaba definido dentro de run_conversation originalmente, así que se pasa como argumento desde main. Esta separación mantiene la función desacoplada y reutilizable: puedes cambiar el modelo sin tocar la lógica de conversación.

La respuesta se imprime con el prefijo IA: en color rojo, distinguiendo visualmente quién habla en cada turno. Esa pequeña decisión de diseño hace que la consola se sienta como una conversación real, no como un volcado de logs.

¿Vas a ajustar los hiperparámetros como temperature, max_tokens o k en tu propio proyecto? Cuéntame en los comentarios qué combinación te funcionó mejor.