MÓDULO 5 · LANGGRAPH · LECCIÓN 02 · 35 MIN

Aristas condicionales: separar decidir de hacer

Una arista condicional no conecta dos nodos. Conecta un nodo con una función que devuelve una etiqueta, y un mapa que traduce esa etiqueta al nodo real. La lógica de control («a dónde voy») queda fuera de la lógica de trabajo («qué hago»).
01 — La firma
Origen, router, mapa
builder.add_conditional_edges(
    "contar",          # nodo del que salimos
    decidir_camino,    # función router: state -> str
    {                  # mapa etiqueta -> nodo
        "es_largo": "final_largo",
        "es_corto": "final_corto",
    },
)
contar→ decidir_camino()→ final_largo  /  final_corto

El tercer argumento es opcional: si lo omites, LangGraph interpreta el valor devuelto como el nombre del nodo destino. Ahorra tres líneas y te ata a que los nombres de nodo sean también tu vocabulario de decisiones. Con mapa, puedes renombrar un nodo sin tocar el router.

02 — La restricción que no es opcional
El router no toca el estado
def decidir_camino(state: Estado) -> str:
    return "es_largo" if state["longitud"] > 10 else "es_corto"

La guía dice que el router «no debe» modificar el estado. Es más fuerte que eso: no puede. LangGraph usa el valor devuelto como etiqueta de enrutado y no lo fusiona en el estado. Si devuelves un diccionario esperando actualizar algo, no actualizas nada y además rompes el mapa.

// si para decidir hace falta trabajo — una API, un LLM, una consulta — hazlo en un nodo previo, guárdalo en el estado, y deja que el router solo lea.
03 — El fallo que vas a ver
El mapa tiene que ser exhaustivo
ValueError: Edge mapping missing key

Significa que el router devolvió una etiqueta que no está en el mapa. Con un if sobre un entero es difícil que pase. Con un router que devuelve texto de un LLM, pasa el primer día. Dos defensas: tipar el retorno con Literal["es_largo", "es_corto"] para que el editor te avise, y añadir una etiqueta de descarte mapeada a un nodo de fallback en vez de confiar en que el else cubra todo.

SíntomaCausaDónde mirar
Edge mapping missing keyEl router devolvió una etiqueta fuera del mapaTodos los return de la función router
El grafo termina antes de tiempoUn nodo no tiene arista de salidaEl nodo destino de la rama que se cortó
Siempre se coge la misma ramaLa clave que lee el router no la escribe nadie antesEl orden de los nodos previos
04 — Límite del patrón
Ramificar no es paralelizar

Una arista condicional elige un camino. Si lo que quieres es que dos nodos se ejecuten a la vez a partir del mismo punto, eso es fan-out: se hace con varias aristas normales desde el mismo origen, no con add_conditional_edges. Y en cuanto dos ramas escriben la misma clave del estado, necesitas un reducer.

Condicional
contar → una de las ramas
el estado lo escribe un solo nodo
Fan-out
contar → todas las ramas
varias escrituras que hay que fusionar
Auditoría

El ejemplo de la guía calcula longitud después de pasar el texto a mayúsculas, y el router decide con un umbral de 10 caracteres. En ese caso concreto da igual, porque .upper() no cambia la longitud en ASCII.

Pero la pregunta es de diseño: si mañana el nodo previo recorta, normaliza o traduce el texto, ¿el router sigue decidiendo sobre lo que crees? Formúlalo así: ¿el estado que lee el router describe la entrada del usuario, o el resultado del último nodo que pasó por ahí?

05 — Ahora tú
Provoca el error de mapa

Haz que decidir_camino devuelva "medio" cuando la longitud esté entre 5 y 10, sin tocar el mapa. Ejecútalo y copia el mensaje de error exacto.

Luego decide dónde prefieres cubrirlo — en el mapa, o con un nodo de fallback — y justifica cuál de los dos aguanta mejor un router que use un LLM.