El entusiasmo con los agentes LLM del último año se ha topado con una pared incómoda: el patrón clásico de bucle —invocar al modelo, mirar si pide una herramienta, ejecutarla y repetir— funciona bien en demos y se desmorona en cuanto la tarea tiene tres pasos y una condición. Los agentes pierden contexto, entran en bucles infinitos sobre la misma herramienta, no se pueden reanudar tras un fallo y, cuando algo sale mal, el operador se queda mirando un log plano preguntándose por qué el modelo decidió lo que decidió. LangGraph, publicado por el equipo de LangChain a principios de 2024, aborda ese problema tratando al agente como un grafo de estados explícito en lugar de una caja negra conversacional.
Por qué los agentes “simples” se rompen
El agente tipo ReAct escrito a mano es siempre la misma plantilla: un bucle que llama al LLM con el historial de mensajes, comprueba si la respuesta contiene una llamada a herramienta, la ejecuta, concatena el resultado al historial y vuelve a empezar. Termina cuando el modelo responde sin pedir herramientas. Esa forma es elegante sobre papel pero tiene cuatro problemas que escalan mal. Primero, no hay límite natural: si el modelo se obsesiona con la misma herramienta, giras indefinidamente hasta agotar tokens. Segundo, no hay persistencia: un corte de red, un timeout o un reinicio del contenedor te devuelven al punto de partida. Tercero, no hay observabilidad: el “paso” en el que estás es implícito, existe solo en la longitud del historial de mensajes. Cuarto, es imposible de testear por piezas, porque toda la lógica vive dentro del mismo bucle.
Cuando el flujo es “pregunta al usuario, clasifica intención, consulta base de datos si procede, responde”, estos problemas se notan poco. Cuando el flujo es “agente de soporte que escala a humano, investigación multipaso sobre varias fuentes, proceso ETL con validaciones intermedias”, los notas desde la primera semana.
El modelo mental de LangGraph
LangGraph cambia la unidad de composición. En vez de un bucle que encadena llamadas, defines cuatro cosas: un estado, unos nodos, unas aristas y un grafo. El estado es un diccionario tipado que representa todo lo que el agente sabe en un momento dado: la conversación, variables intermedias, banderas de control. Los nodos son funciones puras que reciben el estado y devuelven una actualización parcial del mismo. Las aristas conectan nodos y pueden ser incondicionales (tras el nodo A siempre pasa a B) o condicionales (tras el nodo A, si la función de routing devuelve “buscar” pasa a B, si devuelve “responder” pasa a C). El grafo es la compilación de todo eso en un objeto ejecutable.
La consecuencia práctica es que cada paso del agente es ahora una función independiente, con un contrato claro de entrada y salida, testeable en aislamiento y observable desde fuera. Un flujo típico de clasificar-y-responder se modela declarando tres nodos (clasificador, buscador, redactor), una arista condicional desde el clasificador que decide si hay que buscar, una arista directa del buscador al redactor y una arista del redactor al nodo terminal. El grafo compilado expone un invoke que acepta el estado inicial y un stream que emite eventos por cada transición.
from langgraph.graph import StateGraph, END
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", route_from_classify)
graph.add_edge("search", "respond")
graph.add_edge("respond", END)
app = graph.compile()
Las tres funciones que hacen el trabajo
Tres características hacen que LangGraph pague el coste de aprenderlo frente a un bucle casero o a AgentExecutor de LangChain.
La primera es el checkpointing. LangGraph puede persistir el estado del grafo en cada transición sobre SQLite, Postgres o Redis. Al compilar el grafo con un checkpointer y ejecutar con un thread_id, cada paso queda guardado. Una invocación posterior con el mismo thread_id y entrada nula continúa desde el último punto. Esto habilita agentes de larga duración medidos en horas o días, chats con memoria real entre sesiones, recuperación ante fallos del proceso y, sobre todo, el patrón de humano en el bucle: el grafo se detiene en un nodo de aprobación, un operador revisa mediante una API, actualiza el estado con la decisión y el grafo retoma. Sin esto, los agentes que ejecutan acciones con efectos reales —envíos de correo, pagos, modificaciones en CRM— son irresponsables en producción.
La segunda es el streaming por paso. El método stream emite un evento por cada nodo ejecutado con la actualización parcial del estado. Las interfaces pueden mostrar al usuario qué está haciendo el agente en cada momento sin esperar al resultado final, y los sistemas de observabilidad pueden medir latencia por nodo en vez de solo latencia total.
La tercera son los bucles explícitos con condición de salida. Un nodo puede apuntar hacia sí mismo a través de una arista condicional que distingue entre “sigue” y “termina”. Es el patrón ReAct de toda la vida, pero con la condición de parada declarada en un solo sitio en vez de enterrada dentro del cuerpo del bucle.
Comparativa rápida con lo que había antes
Frente al AgentExecutor de LangChain, LangGraph gana en persistencia nativa, en facilidad de depuración y en capacidad para modelar lógica condicional no trivial; pierde en curva de aprendizaje y en sencillez para casos de un solo turno. Frente a los frameworks orientados a múltiples agentes como CrewAI o AutoGen, LangGraph es más bajo nivel: no te da un modelo predefinido de roles o conversaciones, te da primitivas para construir el tuyo. La integración con LangSmith para observabilidad —ver cada nodo ejecutado, sus entradas y salidas, tokens consumidos, latencias, reproducción de trazas— es lo que inclina la balanza para equipos que ya están en el ecosistema LangChain. Además, LangGraph se compone bien con LCEL (LangChain Expression Language), así que los Runnable que ya tienes encajan como nodos sin tocar nada.
Cuándo compensa y cuándo no
LangGraph paga su coste cuando el flujo tiene lógica condicional no trivial, cuando la duración del agente supera el minuto, cuando necesitas intervención humana o cuando la observabilidad en producción es un requisito. No compensa para un chatbot de un turno, para una llamada única a una herramienta o para prototipos exploratorios donde montar el grafo es más ceremonia que producto. La heurística útil: si tu agente cabe en quince líneas de bucle y nunca va a ejecutarse más de diez segundos, no lo metas en un grafo.
Mi lectura
LangGraph es una de esas bibliotecas que parecen un rodeo hasta que te enfrentas al segundo agente serio en producción, y entonces se vuelve difícil volver atrás. El argumento de fondo no es técnico sino organizativo: el bucle ReAct casero obliga a que la lógica del flujo, el control de errores, la persistencia y la observabilidad convivan en el mismo cuerpo de código, y eso envejece mal. Un grafo de estados separa esas capas casi por diseño. La API sigue moviéndose —hay renombramientos y patrones que cambian entre releases— y eso es una fricción real, pero la apuesta conceptual es sólida y se alinea con décadas de literatura sobre máquinas de estado y BPM. Para quien ya vive dentro de LangChain, es la evolución natural. Para quien parte de cero, el coste de aprenderlo es razonable si el agente va a tocar producción. Para todos los demás, un bucle bien escrito sigue siendo suficiente.