5. Los Agentes en LangChain#
Los Agentes son una pieza importante y potente de LangChain. Dentro de este apartado, vamos a ver los siguientes aspectos:
¿Qué son los agentes y su funcionamiento? ¿Cómo crear agentes asistidos con motores de búsqueda? ¿Cómo crear agentes programadores de código y conversacionales? ¿Cómo usar herramientas personalizadas por los agentes? ¿Cómo crear potentes agentes reales?
Los agentes son una de las partes más novedosas de LangChain , pero ofrecen un enorme potencial para aplicaciones basadas en LLM, y además de una manera muy sencilla.
Al combinar lo que ya aprendimos sobre Model IO, conexiones de datos y cadenas, ya hemos abordado aplicaciones similares a agentes, pero los agentes facilitan la creación de estas aplicaciones siendo además más robustas.
Básicamente, los agentes permiten a los LLM conectarse a herramientas (por ejemplo, Wikipedia, Calculadora, Búsqueda de Google, etc.) y llevar a cabo un enfoque estructurado para completar una tarea basada en ReAct (razonamiento y actuación).
ReAct es un enfoque de inteligencia artificial que combina razonamiento (Reasoning) y acción (Acting) para mejorar la toma de decisiones y la interacción con el entorno. Se utiliza en modelos de lenguaje y agentes de IA para mejorar su capacidad de resolver problemas de manera más eficiente.
5.1. ¿Cómo funciona ReAct?#
El enfoque ReAct permite a un modelo de IA no solo generar respuestas, sino también razonar sobre ellas y actuar en consecuencia. Se basa en un ciclo de:
Pensamiento: El modelo analiza la situación y razona sobre los pasos a seguir.
Acción: Toma decisiones o consulta herramientas externas para obtener más información.
Observación: Analiza los resultados de la acción y ajusta su razonamiento.
5.2. ¿Para qué se usa?#
ReAct se usa en:
Agentes conversacionales avanzados (como asistentes inteligentes que pueden planificar y razonar).
Sistemas de búsqueda y recuperación de información (como IA que consulta bases de datos o la web).
Juegos y simulaciones (donde los agentes de IA deben tomar decisiones en entornos dinámicos).
Al Agente se le asigna una tarea y puede razonar qué herramientas son apropiadas para usar y luego puede utilizar esos resultados para continuar a través de una cadena interna hasta que resuelva la tarea.
Los agentes pueden ser extremadamente poderosos, especialmente si los combinamos con nuestras propias herramientas personalizadas.
Imagina un Agente con acceso a documentos corporativos internos y la capacidad de realizar búsquedas relevantes externas, de repente, tendrás un asistente corporativo muy poderoso con información interna y externa para responder preguntas (de clientes, de personal interno,…).
Ver el siguiente enlace:
https://python.langchain.com/v0.1/docs/modules/agents/agent_types/
Una lista de herramientas disponibles, se pueden encontrar en:
https://python.langchain.com/v0.1/docs/integrations/tools/
NOTA: 👌 💖 Existe el frimware denominado CrewaAI que nos permite crear agentes de una forma fácil y eficiente.
5.3. Primer caso de uso de los agentes Langchain#
Vamos a instalar primero la siguiente librería de Python
#!pip install -U langchain-community
import langchain
from langchain_openai import ChatOpenAI
from langchain.prompts import PromptTemplate, SystemMessagePromptTemplate,ChatPromptTemplate, HumanMessagePromptTemplate
llm = ChatOpenAI(
model="llama3.2",
base_url = 'http://localhost:11434/v1',
api_key='ollama', # required, but unused,
temperature = 0
)
#Recomendable temperatura a 0 para que el LLM no sea muy creativo, vamos a tener muchas herramientas a nuestra disposición y queremos que
#sea más determinista
NOTA: según la documentación de LangChain, Al compilar con LangChain, todos los pasos se rastrearán automáticamente en LangSmith. Para configurar LangSmith, solo necesitamos configurar las siguientes variables de entorno:
export LANGCHAIN_TRACING_V2="true"
export LANGCHAIN_API_KEY="<your-api-key>"
Para el siguiente agente se necesita tener instalada la siguiente librería
#!pip install numexpr
A continuación definimos la herramientas a las que tiene accesos el agente. En este caso le estamos dando la herramienta de llm-math, que es una herramienta para el cálculo matemático.
from langchain.agents import load_tools,initialize_agent,AgentType,create_react_agent,AgentExecutor
# llm-math es una herramienta para el cálculo matemático
tools = load_tools(["llm-math",],llm=llm)
#Lista de herramientas disponibles: https://python.langchain.com/v0.1/docs/integrations/tools/
Podemos ver todos los tipos de agentes de los que podemos disponer, de la siguiente forma:
#dir(AgentType) #Vemos los diferentes tipos de agente a usar
Ahora ya creamos el agente
agent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,verbose=True,handle_parsing_errors=True)
#Usamos el Zero Shot porque no estamos dando ningún ejemplo, solo pidiendo al agente hacer una tarea sin ejemplos previos
resultado = agent.run("Dime cuánto es 1598 multiplicado por 1983 y después sumas 1000")
Otra forma de utilizar un agente es mediante create_react_agent.
template = '''Responde lo mejor que puedas usando tu conocimiento como LLM o bien las siguientes herramientas:
{tools}
Utiliza el siguiente formato:
Pregunta: la pregunta de entrada que debes responder
Pensamiento: siempre debes pensar en qué hacer
Acción: la acción a realizar debe ser una de [{tool_names}]
Entrada de acción: la entrada a la acción.
Observación: el resultado de la acción.
... (este Pensamiento/Acción/Introducción de Acción/Observación puede repetirse N veces,si no consigues el resultado tras 5 intentos, para la ejecución)
Pensamiento: ahora sé la respuesta final
Respuesta final: la respuesta final a la pregunta de entrada original
¡Comenzar! Recuerda que no siempre es necesario usar las herramientas
Pregunta: {input}
Pensamiento:{agent_scratchpad}'''
#agent_scratchpad: El agente no llama a una herramienta solo una vez para obtener la respuesta deseada, sino que tiene una estructura que llama a las
#herramientas repetidamente hasta obtener la respuesta deseada. Cada vez que llama a una herramienta, en este campo se almacena cómo fue la
#llamada anterior, información sobre la llamada anterior y el resultado.
prompt = PromptTemplate.from_template(template)
agente = create_react_agent(llm,tools,prompt)
agent_executor = AgentExecutor(
agent=agente,
tools=tools,
verbose=True,
return_intermediate_steps=True,
handle_parsing_errors=True
)
respuesta = agent_executor.invoke({"input": "Dime cuánto es 1598 multiplicado por 1983"})
print(respuesta)
5.4. Crear agente potenciado motor búsqueda.#
Ver el apéndice de este tema, para conocer los servicios que nos ofrece esta herramienta. Para poder utilizarla se necesita primero bajar la librería. Lo hacemos de la siguiente manera:
#!pip install google-search-results
Utilizando este procedimiento tendremos acceso a motores de búsqueda que serán mucho más potentes que solo disponer de la información del LLM.
from langchain_openai import ChatOpenAI
from langchain.prompts import PromptTemplate, SystemMessagePromptTemplate,ChatPromptTemplate, HumanMessagePromptTemplate
from langchain.agents import load_tools,initialize_agent,AgentType,create_react_agent,AgentExecutor
llm = ChatOpenAI(
model="llama3.2",
base_url = 'http://localhost:11434/v1',
api_key='ollama', # required, but unused,
)
# leemos la api key para serpapi
f = open('../SERPAPIKey.txt')
serp_api_key = f.read()
#Definir variable de entorno para que funcione correctamente:
import os
os.environ["SERPAPI_API_KEY"]=serp_api_key #Si no está definida el error nos dará el nombre de la variable de entorno que espera
Definimos las herramientas a las que el agente tendrá acceso
# Le indicamos qu eutilice la herramienta serpapi, que ya tenemos conexión pues hemos indicado nuestra api-key
tools = load_tools(["serpapi","llm-math",],llm=llm)
agent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,verbose=True)
agent.invoke("¿En qué año nació Einstein? ¿Cuál es el resultado de ese año multiplicado por 3?")
5.5. Creación de un agente programador de código.#
En este apartado vamos a crear un agente que genere código python para la tarea que nosotros le solicitemos.
from langchain_openai import ChatOpenAI
from langchain.prompts import PromptTemplate, SystemMessagePromptTemplate,ChatPromptTemplate, HumanMessagePromptTemplate
from langchain.agents import load_tools,initialize_agent,AgentType,create_react_agent,AgentExecutor
llm = ChatOpenAI(
model="llama3.2",
base_url = 'http://localhost:11434/v1',
api_key='ollama', # required, but unused,
temperature = 0
)
#Recomendable temperatura a 0 para que el LLM no sea muy creativo, vamos a tener muchas herramientas a nuestra disposición y queremos que
#sea más determinista
Importamos las siguientes librerías concretas para realizar estos trabajos
#!pip install langchain_experimental
from langchain_experimental.agents.agent_toolkits import create_python_agent # agente para crear código python
from langchain_experimental.tools.python.tool import PythonREPLTool
# creamos el agente
agent = create_python_agent(tool=PythonREPLTool(),
llm=llm,
agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION)
# Tenemos la siguiente lista de python desordenada con la que vamos a trabajar después
lista_ejemplo = [3,1,5,3,5,6,7,3,5,10]
# hacemos trabajar al agente
agent.invoke(f'''ordena la lista {lista_ejemplo}''')
La salida anterior ha generado una salida nula debido a que se ha excedido el tiempo de ejecución. Ello es debido a las limitaciones del equipo local con el que se está trabajando.
Ahora vamos a ver otro ejemplo pero utilizando un dataframe
#!pip install openpyxl
import pandas as pd
df = pd.read_excel('datos_ventas_small.xlsx')
df.head()
agent.invoke(f'''¿Qué sentencias de código tendría que ejecutar para obtener la suma de venta total agregada por Línea de Producto? Este sería el dataframe {df}, no tienes que ejecutar la sentencia, solo pasarme el código a ejecutar''')
df.groupby('Línea Producto')['Venta total'].sum()
Como sugerencia, es mejor pedir la instrucción de python para conseguir el objetivo, que no que te de directamente el resultado.
agent.invoke(f'''¿Qué sentencias de código tendría que ejecutar para tener una visualización con la librería Seaborn que agregue a nivel de Línea de Producto el total de venta? Este sería el dataframe {df}, recuerda que no tienes que ejecutar la sentencia, solo pasarme el código a ejecutar''')
#!pip install seaborn
import seaborn as sns
sns.barplot(x='ID', y='Venta total', data=df)
5.6. Crear herramientas personalizadas.#
Podemos definir nuestras propias herramientas ( tools ) para ser usadas por el agente.
Es muy importante definir bien el docstring (descripción de la función) puesto que en base a ello el agente seleccionará o no esa herramienta.
El uso de herramientas personalizadas expande el uso de los agentes, podríamos incluso definir herramientas que conecten con APIs internas de nuestra empresa para determinadas tareas.
from langchain_openai import ChatOpenAI
from langchain.prompts import PromptTemplate, SystemMessagePromptTemplate,ChatPromptTemplate, HumanMessagePromptTemplate
from langchain.agents import load_tools,initialize_agent,AgentType,create_react_agent,AgentExecutor
llm = ChatOpenAI(
model="llama3.2",
base_url = 'http://localhost:11434/v1',
api_key='ollama', # required, but unused,
temperature = 0
)
#Recomendable temperatura a 0 para que el LLM no sea muy creativo, vamos a tener muchas herramientas a nuestra disposición y queremos que
#sea más determinista
# Creamos nuestra herramienta personalizada
from langchain.agents import tool
Definimos la función que implementa la herramienta que va a utilizar el agente.
@tool
def persona_amable (text: str) -> str:
'''Retorna la persona más amable. Se espera que la entrada esté vacía ""
y retorna la persona más amable del universo'''
return "Miguel Celebres"
El LLM va a consultar del docstring de la función anterior, por si necesita utilizar esa herramienta personalizada para construir su respuesta.
Primero vamos a realizar el ejemplo, sin utilizar esa herramienta personalizada
tools = load_tools(["wikipedia","llm-math",],llm=llm)
agent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,verbose=True)
agent.invoke("¿Quién es la persona más amable del universo?")
Ahora vamos a indicar que utilice la herramienta personalziada que hemos construido anteriormente
tools = tools + [persona_amable]
agent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,verbose=True)
agent.invoke("¿Quién es la persona más amable del universo?")
Ahora vamos a ver otro ejemplo. En este caso, como nos podemos conectar a una determinada API interna
@tool
def nombre_api_interna(text: str) -> str:
'''Conecta a la API_xx que realiza la tarea xx, debes usar esta API Key'''
##Definir conexión a la API interna y devolver un resultado
return resultado
Supongamos que queremso consultar la hora actual sin más.
# Solicitud con las herramientas actuales no proporciona el resultado que queremos
agent.invoke("¿Cuál es la hora actual?")
Lo que vamos a hacer es definir una herramienta personalizada que nos resuelva este problema
from datetime import datetime
@tool
def hora_actual(text: str)->str:
'''Retorna la hora actual, debes usar esta función para cualquier consulta sobre la hora actual. Para fechas que no sean
la hora actual, debes usar otra herramienta. La entrada está vacía y la salida retorna una string'''
return str(datetime.now())
tools = tools + [hora_actual]
agent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,verbose=True, handle_parsing_errors=True)
# Solicitud con las herramientas actuales SÍ proporciona el resultado que queremos
agent.invoke("¿Cuál es la hora actual?")
5.7. Agentes conversacionales con memoria.#
from langchain_openai import ChatOpenAI
from langchain.prompts import PromptTemplate, SystemMessagePromptTemplate,ChatPromptTemplate, HumanMessagePromptTemplate
from langchain.agents import load_tools,initialize_agent,AgentType,create_react_agent,AgentExecutor
llm = ChatOpenAI(
model="llama3.2",
base_url = 'http://localhost:11434/v1',
api_key='ollama', # required, but unused,
temperature = 0
)
#Recomendable temperatura a 0 para que el LLM no sea muy creativo, vamos a tener muchas herramientas a nuestra disposición y queremos que
#sea más determinista
from langchain.memory import ConversationBufferMemory
memory = ConversationBufferMemory(memory_key="chat_history") #ponemos una denominada clave a la memoria "chat_history"
tools = load_tools(["wikipedia","llm-math",],llm=llm)
agent = initialize_agent(tools, llm, agent=AgentType.CONVERSATIONAL_REACT_DESCRIPTION,memory=memory,verbose=True)
agent.invoke("Dime 5 productos esenciales para el mantenimiento del vehículo.")
# Vamos a poner a prueba la memoria
agent.invoke("Necesito la respuesta anterior en castellano")
5.8. Cración Agente Chatbot con memoria.#
Vamos acrear un Agente Chatbot con memoria a partir de sistema RAG con nuestra base de datos vectorial. Este agente va a combinar el potencial del BD vectorizadas con nuestros propios documentos y el resto de herramientas.
El agente debe verificar si la herramienta apropiada es la personalizada que creemos que obtendrá datos de la BBDD Vectorial o, sin embargo, debe usar otras herramientas como Wikipedia para consultar información o bien el propio conocimiento del LLM.
from langchain_openai import ChatOpenAI
from langchain.prompts import PromptTemplate, SystemMessagePromptTemplate,ChatPromptTemplate, HumanMessagePromptTemplate
from langchain.agents import load_tools,initialize_agent,AgentType,create_react_agent,AgentExecutor
llm = ChatOpenAI(
model="llama3.2",
base_url = 'http://localhost:11434/v1',
api_key='ollama', # required, but unused,
temperature = 0
)
#Recomendable temperatura a 0 para que el LLM no sea muy creativo, vamos a tener muchas herramientas a nuestra disposición y queremos que
#sea más determinista
#Podríamos establecer que tuviera memoria
from langchain.memory import ConversationBufferMemory
memory = ConversationBufferMemory(memory_key="chat_history") #ponemos una denominada clave a la memoria "chat_history"
from langchain_community.vectorstores import SKLearnVectorStore
from langchain_openai import OpenAIEmbeddings
from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import LLMChainExtractor
# Caragamos nuestros datos de una BD vectorial
#funcion_embedding = OpenAIEmbeddings(openai_api_key=api_key)
from langchain_ollama import OllamaEmbeddings
funcion_embedding = OllamaEmbeddings(model="llama3.2")
persist_path="BD/ejemplosk_embedding_db"
vector_store_connection = SKLearnVectorStore(embedding=funcion_embedding, persist_path=persist_path, serializer="parquet")
compressor = LLMChainExtractor.from_llm(llm)
compression_retriever = ContextualCompressionRetriever(base_compressor=compressor, base_retriever=vector_store_connection.as_retriever())
Ahora vamos a definir una herramienta personalizada apoyada en la base de datos vectorial, de tal manera que el agente pueda utilizar esta herramienta que hemos definido.
from langchain.agents import tool
@tool
def consulta_interna(text: str) -> str:
'''Retorna respuestas sobre la historia de España. Se espera que la entrada sea una cadena de texto
y retorna una cadena con el resultado más relevante. Si la respuesta con esta herramienta es relevante,
no debes usar ninguna herramienta más ni tu propio conocimiento como LLM'''
compressed_docs = compression_retriever.invoke(text)
resultado = compressed_docs[0].page_content
return resultado
tools = load_tools(["wikipedia","llm-math"],llm=llm)
tools=tools+[consulta_interna]
#ahora ya tenemos nuestra herramienta
Ahora ya estamos en condiciones de crear el agente y lo utilizamos.
agent = initialize_agent(tools, llm, agent=AgentType.CONVERSATIONAL_REACT_DESCRIPTION,memory=memory,verbose=True)
# esto lo debería coger de nuestra herramienta personalizada
agent.invoke("¿Qué periodo abarca cronológicamente en España el siglo de oro?")
agent.invoke("¿Qué pasó durante la misma etapa en Francia?") #Gracias a tener memoria compara en esas fechas qué ocurrió en Francia
agent.invoke("¿Cuáles son las marcas de vehículos más famosas hoy en día?") #Pregunta que no podemos responder con nuestra BD Vectorial
NOTA: 🙋♂️😅 Como puede verse, los resultados que obtenemos no son los que buscamos, pero ello es debido a las limitaciones computacionales con las que estamos trabajando, por lo que este método es más bien didáctico y se expone para su conocimiento. En un mundo real, se debe utilizar un sistema computacional mucho más potente para obtener resultados acorde con lo que buscamos.
5.9. Agente para análisis automático de SQL.#
En este apartado vamos a crear un agente que haga consultas SQL a la base de datos, pero las consultas se las pedimos en lenguaje natural, no SQL. 😲🤑. En concreto lo que vamos a pedir es lo siguiente: ¿Cuántas ventas ha habido en el primer trimestre del 2025?, que equivale a la siguiente consulta:
SELECT SUM(ventas) AS total_ventas
FROM ventas
WHERE fecha >= '2025_01-01' AND fecha < '2025-04-01';
from langchain_openai import ChatOpenAI
from langchain.prompts import PromptTemplate, SystemMessagePromptTemplate,ChatPromptTemplate, HumanMessagePromptTemplate
from langchain.agents import load_tools,initialize_agent,AgentType,create_react_agent,AgentExecutor
llm = ChatOpenAI(
model="llama3.2",
base_url = 'http://localhost:11434/v1',
api_key='ollama', # required, but unused,
temperature = 0
)
#Recomendable temperatura a 0 para que el LLM no sea muy creativo, vamos a tener muchas herramientas a nuestra disposición y queremos que
#sea más determinista
#!pip install mysql-connector-python
import mysql.connector #pip install mysql-connector-python
Para desarrollar y ejecutar este caso de uso, se neceita tener isntalado en nuestro equipo un servidor de base de datos MySql. Como no es el caso, nos vamos a limitar a mostrar el código, ya que todos los conceptos que en él se desarrollan, ya se han expuestos en capítulos anteriores.
f = open('../password_sql.txt')
pass_sql = f.read()
# Configuración de la conexión a la base de datos
config = {
'user': 'root',
'password': pass_sql,
'host': '127.0.0.1',
'database': 'world'
}
# Conectar a la base de datos
conn = mysql.connector.connect(**config)
cursor = conn.cursor()
# Definir la consulta manualmente: tengo una base de datos mysql en mi computadora local denominada "world" y una tabla "Country"
#sobre la que quiero hacer la suma de la población en la columna "Population" para el continente Asia (columna "Continent")
query = """
SELECT SUM(Population)
FROM Country
WHERE Continent = 'Asia';
"""
# Ejecutar la consulta
cursor.execute(query)
result = cursor.fetchone()
suma_poblacion = result[0] if result[0] is not None else 0
print(f"La suma de la población del continente Asia es: {suma_poblacion}")
# Creamos el agente SQL
from langchain_community.agent_toolkits import create_sql_agent
from langchain.sql_database import SQLDatabase
# Crear una cadena de conexión a la base de datos MySQL
connection_string = f"mysql+mysqlconnector://{config['user']}:{config['password']}@{config['host']}/{config['database']}"
# Crear una instancia de la base de datos SQL
db = SQLDatabase.from_uri(connection_string)
agent = create_sql_agent(
llm,
db=db,
verbose=True
)
agent.invoke("Dime la población total de Asia")
result = agent.invoke("Dime el promedio de la esperanza de vida por cada una de las regiones ordenadas de mayor a menor")
# Mostrar el resultado
print(result["output"])
# Para utilizar few-shoots para las consultas SQL: https://python.langchain.com/v0.1/docs/use_cases/sql/agents/
5.10. Apéndice.#
5.10.1. Serpapi.#
SerpApi es una API que permite extraer datos de los resultados de búsqueda de Google y otros motores de búsqueda sin necesidad de realizar scraping manualmente. Facilita la obtención de resultados de Google Search, Google Images, Google News, Google Maps, Google Shopping, YouTube y más, de una manera estructurada y libre de bloqueos.
5.10.1.1. ¿Por qué usar SerpApi?#
Evita bloqueos: Google implementa restricciones y CAPTCHA para prevenir el scraping, pero SerpApi maneja esto automáticamente.
Datos estructurados: Los resultados se devuelven en formato JSON, lo que facilita su procesamiento.
Compatibilidad con múltiples motores de búsqueda: Además de Google, soporta Bing, DuckDuckGo, Yahoo, entre otros.
Alta velocidad y escalabilidad: Permite realizar múltiples solicitudes de búsqueda de forma eficiente.
5.10.1.2. ¿Cómo funciona?#
Para usar SerpApi, necesitas:
Crear una cuenta en SerpApi.
Obtener una API Key para autenticar solicitudes.
Realizar peticiones HTTP al endpoint de búsqueda con los parámetros deseados.
5.10.1.3. Ejemplo en Python#
Aquí tienes un ejemplo de cómo hacer una búsqueda en Google usando la API de SerpApi con Python:
import requests
params = {
"q": "ChatGPT",
"hl": "es",
"gl": "es",
"api_key": "TU_API_KEY"
}
response = requests.get("https://serpapi.com/search", params=params)
data = response.json()
print(data)
Este código devuelve los resultados de búsqueda de Google en JSON.
5.10.1.4. Casos de uso#
Monitoreo de rankings en SEO.
Seguimiento de precios en Google Shopping.
Extracción de datos de Google Maps para negocios locales.
Automatización de investigaciones en Google News.
NOTA: 👍 👌 Esta herramienta es de pago pero en el momento de redactar estas líneas, existe una versión gratuita que permite hacer 100 búsquedas al mes sin tener que pagar.
5.10.2. Artículo muy interesante.#
A continuación se indica un enlace para ver un artículo muy interesante sobre los agentes de LangChain