intermediate45 minLección 1 de 5

Fundamentos de LangGraph y Grafos de Estado

Aprende qué es LangGraph, cómo StateGraph difiere de Graph y cómo definir estado, nodos, aristas, compilar y ejecutar un grafo de estado en Python.

Fundamentos de LangGraph y Grafos de Estado

LangGraph es un framework de LangChain para construir aplicaciones stateful multi-agente usando grafos como abstracción central. Cada nodo modifica un estado compartido y las aristas definen el flujo.


¿Qué es LangGraph?

LangGraph extiende LangChain modelando la lógica del agente como un grafo dirigido. El grafo transporta un objeto de estado tipado que persiste a través de los nodos, permitiendo loops complejos, ramificaciones y memoria.

Conceptos clave:

  • StateGraph: Clase recomendada para grafos con estado
  • Graph: Alternativa más simple, stateless
  • Nodos: Funciones Python que reciben y modifican el estado
  • Aristas: Conexiones dirigidas entre nodos
⚠️Warning

LangGraph no es una herramienta de DAG de workflow. Los nodos pueden ser revisitados, los loops pueden formarse y el estado se preserva entre ciclos. Esto es lo que lo hace adecuado para sistemas agenticos.


Mermaid: Ciclo de Ejecución Completo

100%

La fase de Definición construye la topología del grafo. La fase de Ejecución ejecuta nodos secuencialmente o en paralelo, cada uno leyendo y escribiendo en el estado compartido.


StateGraph vs Graph

CaracterísticaStateGraphGraph
Estado tipadoSí (TypedDict)No (valores simples)
Aristas condicionales
CheckpointingIntegrado (MemorySaver)No soportado
Ramificación paralelaLimitada
Nodos re-entrantesNo
Preparado para producciónAlto (PostgresSaver)Bajo
Soporte de loopsNo
Humano-en-el-bucleVia interrupt()No soportado
Composición de subgrafosNo
💡Tip

Siempre prefiere StateGraph a menos que tengas un pipeline stateless muy simple. La sobrecarga es mínima y obtienes checkpointing, ramificación y características de producción gratis.


Mermaid: Diagrama de Clase de la API StateGraph

100%

El patrón builder StateGraph colecciona nodos y aristas, luego .compile() produce un CompiledGraph que puede invocarse con estado y configuración.


Definiendo Estado con TypedDict

python
from typing import TypedDict, List from langgraph.graph import StateGraph # Define el esquema de estado compartido class AgentState(TypedDict): messages: List[str] # conversación hasta ahora next_step: str # qué nodo ejecutar a continuación metadata: dict # metadatos arbitrarios # Instancia un StateGraph con el esquema builder = StateGraph(AgentState)
ℹ️Note

StateGraph soporta tres enfoques de definición de esquema: TypedDict (ligero, sin validación), dataclass (mutable, Pythonico) y pydantic.BaseModel (validación, serialización). Elige BaseModel para producción cuando necesites verificación de tipos en tiempo de ejecución.

Comparación: Enfoques de Definición de Estado

EnfoqueValidaciónSerializaciónBoilerplateCaso de Uso
TypedDictNingunaManualMínimoPrototipado, agentes simples
dataclassNingunaVia dataclasses.asdict()BajoHerramientas internas
BaseModelValidación Pydantic completa.dict()/.json() integradoModeradoSistemas de producción

Nodos y Aristas

python
# Nodo: una función que recibe el estado y retorna actualizaciones def node_a(state: AgentState) -> dict: print("--- Nodo A ---") return {"messages": state["messages"] + ["Hola desde A"]} def node_b(state: AgentState) -> dict: print("--- Nodo B ---") return {"messages": state["messages"] + ["Hola desde B"]} # Registra nodos builder.add_node("a", node_a) builder.add_node("b", node_b) # Añade aristas: a -> b builder.add_edge("a", "b") # Define puntos de entrada y salida builder.set_entry_point("a") builder.set_finish_point("b")
💡Tip

Las funciones de nodo deben retornar un diccionario (o None). Los valores retornados se fusionan en el estado compartido mediante una actualización superficial. Las claves no retornadas mantienen su valor anterior — así es como el estado persiste entre nodos.

Ejecución Paralela de Nodos

python
def node_a(state: AgentState) -> dict: return {"messages": state["messages"] + ["A"]} def node_b(state: AgentState) -> dict: return {"messages": state["messages"] + ["B"]} def node_c(state: AgentState) -> dict: return {"messages": state["messages"] + ["C"]} builder = StateGraph(AgentState) builder.add_node("a", node_a) builder.add_node("b", node_b) builder.add_node("c", node_c) # Fan-out: a dispara b y c simultáneamente builder.add_edge(START, "a") builder.add_edge("a", "b") builder.add_edge("a", "c") builder.add_edge("b", END) builder.add_edge("c", END)

Cuando dos aristas salen del mismo nodo, ambos destinos ejecutan en paralelo usando threads de Python. Cada rama recibe una copia del estado y las escrituras se fusionan al completarse.

Manejo de Errores en Nodos

python
import traceback def safe_node(state: AgentState) -> dict: try: result = risky_operation(state["messages"][-1]) return {"messages": state["messages"] + [result]} except Exception as e: # Registra el error y continúa con fallback return { "messages": state["messages"] + [f"[ERROR]: {str(e)}"], "errors": state.get("errors", []) + [traceback.format_exc()] }

Envuelve la lógica de nodo propensa a fallos en try/except para evitar que todo el grafo se caiga. Almacena errores en el estado para manejo downstream o revisión humana.


Compilando y Ejecutando

python
# Compila el grafo en un objeto ejecutable app = builder.compile() # Invoca con estado inicial result = app.invoke({ "messages": [], "next_step": "start", "metadata": {} }) print(result["messages"]) # Salida: ['Hola desde A', 'Hola desde B']
📌Important

El método .compile() congela la definición del grafo. Después de la compilación, no puedes añadir nodos o aristas — debes reconstruir el builder. Para topologías dinámicas, ve la Lección 4 sobre actualizaciones dinámicas de grafo.

Streaming de Resultados

python
# Stream de actualizaciones conforme cada nodo completa for event in app.stream({"messages": [], "next_step": "start", "metadata": {}}): for node_name, output in event.items(): if node_name != "__end__": print(f"[{node_name}] -> {output}") # Salida: # [a] -> {'messages': ['Hola desde A']} # [b] -> {'messages': ['Hola desde A', 'Hola desde B']}

Usa .stream() en lugar de .invoke() cuando quieras observar estados intermedios. Cada evento emitido tiene como clave el nombre del nodo con la actualización parcial de estado.


Mermaid: Grafo de Estado Básico

100%

El estado fluye a través de las aristas; cada nodo puede leer y escribir en el AgentState compartido.


Mermaid: Diagrama de Estado del Ciclo de Vida del Nodo

100%

Cada nodo transiciona por leer → ejecutar → escribir. El grafo orquesta la secuencia, pasando estado a lo largo de las aristas.


Depurando Grafos con LangSmith

💡Tip

Cuando tu grafo se comporte inesperadamente, traza la ejecución con LangSmith. Establece LANGCHAIN_TRACING_V2=true y LANGCHAIN_API_KEY=your_key para obtener registros de traza completos mostrando entrada, salida y tiempo de cada nodo.

bash
# Habilita tracing de LangSmith export LANGCHAIN_TRACING_V2=true export LANGCHAIN_PROJECT=mi-agente

Practice Question

¿Qué clase deberías usar para un agente stateful con múltiples pasos?

Practice Question

¿Cómo se tipifica típicamente el estado en un StateGraph?

Practice Question

¿Qué recibe y retorna una función de nodo?

Practice Question

¿Cuál es el propósito de compile()?

Practice Question

¿Qué NO está soportado por la clase básica Graph?

Practice Question

Escenario: Estás construyendo un agente de producción que necesita checkpointing. ¿Qué clase elegir?


Success

Conclusiones Clave

  • LangGraph usa grafos dirigidos para representar lógica de agente stateful.
  • StateGraph es preferible a Graph cuando necesitas estado tipado y con checkpoint.
  • El estado se define con TypedDict y fluye a través de los nodos.
  • Los nodos son funciones Python que retornan actualizaciones parciales de estado.
  • El grafo se compila via .compile() y se invoca via .invoke().
  • Las aristas definen la topología; START y FINISH marcan puntos de entrada y salida.
  • StateGraph soporta loops, ramificaciones condicionales y persistencia.
  • Usa .stream() para observación en tiempo real de la salida de cada nodo.
  • Envuelve la lógica de nodo en try/except para manejar errores con gracia.
  • El tracing de LangSmith ayuda a depurar ejecuciones complejas de grafos.
Progreso20%