LangGraph: grafos de estados para agentes más robustos

Diagrama de flujo con nodos y conexiones sobre fondo oscuro representando grafo de estados

Los agents basados en LLM que solo usan el patrón “while tool_call: execute” funcionan para tareas simples pero se desmoronan en flujos complejos: pierden contexto, hacen loops infinitos, no se pueden reanudar tras fallo. LangGraph (del equipo LangChain) propone modelar agentes como grafos de estados explícitos: nodos que hacen trabajo, edges condicionales que deciden siguiente paso, estado persistente que se puede inspeccionar y replay.

El problema con agents “simples”

Un agente básico:

while True:
    response = llm.invoke(messages + [prompt])
    if tool_call in response:
        result = execute_tool(tool_call)
        messages.append(result)
    else:
        return response

Problemas:

  • Loops infinitos si el LLM insiste en el mismo tool.
  • Sin persistencia: si falla, empiezas de cero.
  • No hay control fino: no sabes en qué “paso” estás.
  • Difícil de testear: caja negra.

Para flujos complejos (customer support, investigación multi-paso, procesos ETL con IA), esto escala mal.

El modelo LangGraph

LangGraph modela el agente como:

  • State: objeto TypedDict con todo el contexto.
  • Nodes: funciones que toman state y devuelven update parcial.
  • Edges: conexiones entre nodos, con lógica condicional.
  • Graph: compilación de nodos + edges.
from langgraph.graph import StateGraph, END
from typing import TypedDict

class AgentState(TypedDict):
    messages: list
    next_step: str

def classify(state: AgentState) -> AgentState:
    # Clasificar intent
    return {"next_step": "search" if needs_search else "respond"}

def search(state: AgentState) -> AgentState:
    # Hacer búsqueda
    return {"messages": state["messages"] + [search_result]}

def respond(state: AgentState) -> AgentState:
    # Generar respuesta final
    return {"messages": state["messages"] + [response]}

graph = StateGraph(AgentState)
graph.add_node("classify", classify)
graph.add_node("search", search)
graph.add_node("respond", respond)
graph.set_entry_point("classify")
graph.add_conditional_edges("classify", lambda s: s["next_step"])
graph.add_edge("search", "respond")
graph.add_edge("respond", END)

app = graph.compile()
result = app.invoke({"messages": [user_msg]})

Cada paso es explícito, testeable, observable.

Features clave

Persistent state (checkpointing)

LangGraph puede persistir el estado del grafo en cada paso a SQLite, Postgres, Redis:

from langgraph.checkpoint.postgres import PostgresSaver

checkpointer = PostgresSaver.from_conn_string("postgres://...")
app = graph.compile(checkpointer=checkpointer)

# Ejecutar con thread_id para estado persistente
config = {"configurable": {"thread_id": "user-123"}}
result = app.invoke(state, config=config)

# Luego reanudar
result = app.invoke(None, config=config)  # Continúa desde último paso

Esto permite:

  • Agentes de larga duración (días, semanas).
  • Chat con memoria real entre sesiones.
  • Recovery tras fallo.
  • Human-in-the-loop: agente pausa para aprobación humana.

Streaming por paso

for event in app.stream(state, config=config):
    print(event)

Obtienes updates en tiempo real de qué nodo se está ejecutando y qué devuelve. Útil para UIs interactivas.

Loops con condiciones

graph.add_conditional_edges(
    "react_step",
    lambda s: "continue" if not s["done"] else "END",
    {"continue": "react_step", "END": END}
)

Loops explícitos con condición de parada clara.

Subgraphs

Grafos complejos pueden construirse componiendo subgrafos — reusabilidad y modularidad.

Patterns comunes

ReAct pattern clásico

graph = StateGraph(...)
graph.add_node("agent", agent_node)
graph.add_node("tool_executor", execute_tools)

def should_continue(state):
    if state["messages"][-1].tool_calls:
        return "continue"
    return "end"

graph.add_conditional_edges("agent", should_continue, {
    "continue": "tool_executor",
    "end": END
})
graph.add_edge("tool_executor", "agent")

ReAct estándar pero con estado explícito y checkpointing.

Human-in-the-loop

graph.add_node("human_approval", lambda s: interrupt("Aprobar?"))

# Ejecución pausa en interrupt
# Operator aprueba/rechaza via API
app.update_state(config, {"approved": True})
app.invoke(None, config=config)  # Continúa

Crítico para agentes que ejecutan acciones reales (envíos de email, transacciones bancarias).

Multi-agent colaboration

Varios grafos cooperando, cada uno con su especialidad, coordinados por un supervisor agent.

Comparación con alternativas

Aspecto LangGraph LangChain AgentExecutor CrewAI AutoGen
Modelo Grafo de estados Loop simple Roles de equipo Conversaciones
Persistencia Nativa No Manual Limitada
Streaming
Debuggability Alta Baja Media Media
Curva aprendizaje Media Baja Media Media

LangGraph es más complejo pero más robusto para producción.

Integración con LangSmith

LangSmith (observability de LangChain) visualiza runs de LangGraph:

  • Ver cada nodo ejecutado.
  • Input/output por paso.
  • Latencias y tokens.
  • Replay y debug.

Para desarrollo iterativo de agentes complejos, es prácticamente imprescindible.

Cuándo LangGraph vale la pena

Encaja en:

  • Workflows multi-paso con lógica condicional compleja.
  • Agentes de larga duración (minutos+).
  • Human-in-the-loop (approval flows).
  • Multi-agent systems.
  • Production observability importante.

No encaja en:

  • Chatbot simple de 1-turno.
  • Tool calling sencillo (un solo round).
  • Prototipos rápidos donde setup de grafo es overkill.

Limitaciones

  • Learning curve: entender state + nodes + edges toma tiempo.
  • Dependencia de LangChain: sigues en ecosystem LangChain (pros y cons).
  • Maduración: API sigue cambiando (aunque estabilizándose).
  • Python only (JS/TS tiene versión pero menos madura).

Alternativas a evaluar

  • LlamaIndex Workflows: similar enfoque de workflows.
  • Haystack pipelines: modelado de pipelines.
  • Flowise: visual low-code para builds similares.
  • Propio framework: para casos muy específicos, roll-your-own tiene sentido.

Conclusión

LangGraph es una evolución importante en cómo construir agentes LLM productivos. Su modelo explícito de estado y flujo soluciona muchos problemas que agents naïve tenían. Para producción seria con flujos complejos, human-in-the-loop, o multi-agent, es de las opciones más maduras. Para casos simples, el overhead no compensa. La integración con LangSmith para observability lo hace el pack más completo actualmente. Con el ritmo de evolución, próximas releases cerrarán las pocas asperezas actuales.

Síguenos en jacar.es para más sobre agents LLM, LangChain y arquitecturas IA.

Entradas relacionadas