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",
},
)
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.
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.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íntoma | Causa | Dónde mirar |
|---|---|---|
Edge mapping missing key | El router devolvió una etiqueta fuera del mapa | Todos los return de la función router |
| El grafo termina antes de tiempo | Un nodo no tiene arista de salida | El nodo destino de la rama que se cortó |
| Siempre se coge la misma rama | La clave que lee el router no la escribe nadie antes | El orden de los nodos previos |
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.
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í?
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.