
🤖 Si tus agentes de IA son un simple loop de "LLM -> Herramienta -> LLM", estás construyendo un prototipo, no un sistema de producción.
Los agentes básicos que ofrecen frameworks como LangChain (con AgentExecutor) son excelentes para demos, pero fallan en el mundo real. Son una caja negra. No tienes control sobre el flujo, no puedes implementar retries de forma limpia, ni agregar pasos de validación humana. Cuando algo sale mal, todo el proceso se rompe sin un estado claro de dónde o por qué.
Este enfoque no escala. Para tareas complejas que requieren lógica condicional, múltiples agentes colaborando o la capacidad de recuperarse de errores, necesitas una estructura que te dé control explícito. Necesitas poder definir el flujo de trabajo como un ingeniero, no como alguien que espera que la magia del LLM lo resuelva todo.
La Solución: Pensar en Grafos, no en Loops ⚙️
LangGraph te obliga a dejar de pensar en loops y empezar a pensar en grafos de estado. Es una extensión de LangChain que te permite construir agentes y aplicaciones multi-agente como un grafo cíclico. Cada nodo en el grafo es una función (una llamada a un LLM, una ejecución de herramienta) y cada arista es una transición que tú defines explícitamente.
En resumen: LangGraph te devuelve el control.
¿LangGraph vs. Agentes Nativos de Claude? Los agentes de Claude 3 son potentes y su uso de herramientas es de primera clase, pero es un sistema cerrado. Funciona de maravilla hasta que deja de hacerlo, y ahí no tienes dónde meter mano. Estás atado a la lógica de Anthropic.
LangGraph es agnóstico al modelo y de código abierto. Te da los bloques para construir tu propia lógica de enrutamiento. Puedes usar Claude, GPT-4, Llama 3 o un modelo local. Tú decides si después de una llamada a una herramienta se reintenta, se escala a un humano o se pasa a otro agente especializado. Es más trabajo de setup, pero es la única forma de construir algo robusto y mantenible.
Implementación: De un Loop a un Grafo Controlado 💻
Vamos a construir un agente simple que puede buscar información y decidir si la respuesta es suficiente o si necesita seguir investigando.
Prerrequisitos: Instala las librerías necesarias.
pip install langchain langchain_openai langgraph langchainhub beautifulsoup4
Necesitarás una API key de OpenAI (OPENAI_API_KEY) en tus variables de entorno.
1. Definir el Estado del Agente
El estado es un diccionario que se pasa entre los nodos. Contiene toda la información que el agente necesita para tomar decisiones. Usamos TypedDict para mantenerlo ordenado.
from typing import TypedDict, Annotated, List
from langchain_core.messages import BaseMessage
import operator
class AgentState(TypedDict):
# La lista de mensajes se acumula con el tiempo
messages: Annotated[List[BaseMessage], operator.add]
Este bloque define AgentState. El campo messages es una lista de mensajes (Human, AI, Tool) que se irá actualizando en cada paso del grafo. operator.add asegura que los nuevos mensajes se añadan a la lista en lugar de sobreescribirla.
2. Crear Nodos y el Grafo Ahora definimos los nodos (funciones Python) y los conectamos. Un nodo llamará al agente, otro ejecutará las herramientas. Una arista condicional decidirá qué hacer a continuación.
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_community.tools.tavily_search import TavilySearchResults
from langgraph.prebuilt import ToolExecutor
from langgraph.graph import StateGraph, END
# Herramientas y LLM
tools = [TavilySearchResults(max_results=1)]
tool_executor = ToolExecutor(tools)
model = ChatOpenAI(temperature=0, streaming=True)
# Lógica de los nodos
def call_model(state):
"""Invoca al LLM con el estado actual."""
messages = state['messages']
response = model.invoke(messages)
return {"messages": [response]}
def call_tool(state):
"""Ejecuta la herramienta llamada por el LLM."""
last_message = state['messages'][-1]
tool_calls = last_message.tool_calls
tool_names = [call['name'] for call in tool_calls]
# Aquí podrías agregar lógica de routing si tuvieras múltiples herramientas
action = ToolInvocation(tool=tool_names[0], tool_input=tool_calls[0]['args'])
response = tool_executor.invoke(action)
# Devolvemos la respuesta de la herramienta como un ToolMessage
tool_message = ToolMessage(content=str(response), tool_call_id=tool_calls[0]['id'])
return {"messages": [tool_message]}
# Arista condicional
def should_continue(state):
"""Decide si continuar o finalizar."""
last_message = state['messages'][-1]
if not last_message.tool_calls:
return "end" # No hay llamadas a herramientas, terminamos
else:
return "continue" # Hay llamadas a herramientas, continuamos
# Construcción del grafo
workflow = StateGraph(AgentState)
workflow.add_node("agent", call_model)
workflow.add_node("action", call_tool)
workflow.set_entry_point("agent")
# Definimos las aristas
workflow.add_conditional_edges(
"agent",
should_continue,
{
"continue": "action",
"end": END,
},
)
workflow.add_edge("action", "agent")
# Compilamos el grafo para obtener un objeto ejecutable
app = workflow.compile()
# Ejecutarlo
inputs = {"messages": [("user", "what is the weather in buenos aires")]}
for output in app.stream(inputs):
for key, value in output.items():
print(f"Output from node '{key}':")
print("---")
print(value)
print("\n---\n")
Este segundo bloque es el corazón del sistema:
1. Herramientas y Modelo: Definimos un buscador (TavilySearchResults) y el LLM.
2. Nodos call_model y call_tool: Son funciones simples que toman el estado y retornan una actualización. Una llama al LLM, la otra a la herramienta.
3. Arista should_continue: Esta función es clave. Inspecciona el último mensaje. Si el LLM llamó a una herramienta, devuelve "continue". Si no, devuelve "end".
4. StateGraph: Aquí ensamblamos todo. add_node registra las funciones. set_entry_point define dónde empezar. add_conditional_edges implementa nuestra lógica de enrutamiento. add_edge crea una transición fija (después de la acción, siempre volvemos al agente).
5. compile(): Crea el objeto app que podemos ejecutar.
Caso Real: Monitoreo de Infraestructura en DevopsTechIA ⚡
Usamos LangGraph para un agente de diagnóstico de alertas de Prometheus. Antes, un script de Python recibía la alerta y ejecutaba una serie de if/elif/else para decidir qué hacer. Era frágil y difícil de extender.
Ahora, la alerta dispara un workflow de LangGraph:
1. Nodo Triage: Un LLM recibe el JSON de la alerta y lo clasifica (e.g., DB_HIGH_LATENCY, POD_CRASH_LOOP).
2. Arista Condicional: El grafo enruta a un nodo específico según la clasificación.
3. Nodo Check_Postgres: Si es un problema de DB, este nodo ejecuta una herramienta que corre pg_stat_activity en la base de datos afectada.
4. Nodo Check_Kubernetes: Si es un pod, ejecuta kubectl describe pod y kubectl logs.
5. Nodo Synthesize: Recibe los resultados de los nodos de herramientas y usa un LLM para generar un resumen accionable que se postea en un canal de Slack.
El beneficio es claro: control y extensibilidad. Añadir un nuevo tipo de alerta es tan simple como agregar un nuevo nodo y una nueva arista condicional. No tocamos el resto del flujo. Podemos agregar un nodo de Human-in-the-loop para que un ingeniero apruebe acciones destructivas, como reiniciar un pod.
Limitaciones: No es para Todo 📌
Seamos honestos, LangGraph tiene una curva de aprendizaje y es más verboso que un agente simple.
- No es para scripts rápidos: Si solo necesitas una respuesta de un LLM con una herramienta,
AgentExecutoro una llamada directa a la API de Claude es más rápido de implementar. LangGraph es para sistemas persistentes y complejos. - Requiere pensar en estado: Tienes que diseñar tu
AgentStatecuidadosamente. Si el estado se vuelve un monolito inmanejable, la depuración se convierte en un infierno. - La visualización es básica: Aunque puedes imprimir el grafo en ASCII, depurar flujos complejos visualmente todavía es un desafío. Necesitas logs claros en cada nodo.
Conclusión: El Paso Necesario para la IA en Producción
LangGraph no es una herramienta más, es un cambio de paradigma para construir agentes de IA. Te obliga a aplicar principios de ingeniería de software (estado explícito, modularidad, control de flujo) a un campo que a menudo se siente como magia negra.
En una línea: LangGraph te da el andamiaje para construir agentes que sobreviven al contacto con la realidad de producción.
Próximo paso: Intenta modificar el grafo de ejemplo para incluir un segundo tool. Agrega lógica a la arista condicional para enrutar al tool correcto según el nombre de la herramienta que el LLM decida usar.