Routing inteligente con LLM para derivar conversaciones automáticamente
Clase 18 de 26 • Curso para Crear Agentes de AI con LangGraph
Resumen
Construye un agente que decide por sí mismo a qué nodo enviar cada turno. Con el patrón de routing en LangGraph y un structured output guiado por un language model, el flujo se deriva de forma fiable a conversation o booking. Verás cómo integrar un subgrafo React node, usar memoria compartida y depurar errores comunes sin añadir complejidad innecesaria.
¿Cómo implementar routing con structured output en LangGraph?
Para que el agente tome decisiones autónomas, se añade un router entre el extractor y los nodos finales. El router llama al LLM con un prompt breve y devuelve un esquema tipado que indica el siguiente paso: conversation o booking. Así, cada mensaje se encamina al nodo correcto.
¿Qué nodos y flujo define el grafo?
- Inicio, extractor y memoria compartida. El extractor guarda datos útiles del historial en el estado común.
- Intent route. Un nodo de enrutamiento que decide el destino con structured output.
- Conversation node. Maneja preguntas generales con respuesta directa o con RAG cuando aplica.
- Booking node. Agente con patrón React, representado como subgrafo con agent, tools y finalizar.
- End. Ambos caminos convergen al cierre del flujo.
¿Cómo se construye el intent route con un LLM?
- Se define un esquema tipado para el paso siguiente con Pydantic: conversation o booking.
- Se pasa al LLM el historial completo más un system prompt que explica cuándo ir a cada nodo.
- Se establece un valor por defecto: si no hay decisión clara, ir a conversation.
- Los nombres deben coincidir exactamente con los nodos del grafo: errores de nombre impiden el ruteo correcto.
Ejemplo ilustrativo en Python:
from typing import Literal
from pydantic import BaseModel
class IntentDecision(BaseModel):
step: Literal["conversation", "booking"] | None = None
SYSTEM_PROMPT = (
"Eres un asistente que enruta al paso adecuado: 'conversation' para preguntas generales, "
"'booking' si el usuario habla de citas o appointments."
)
def intent_route(messages, llm):
decision = llm.with_structured_output(schema=IntentDecision)(
[
{"role": "system", "content": SYSTEM_PROMPT},
*messages # historial completo
]
)
if decision is not None and decision.step is not None:
return decision.step
return "conversation" # por defecto
¿Cómo organizar el proyecto en nodes y routes?
- Carpeta nodes: define nodos como conversation, extractor y el booking node con patrón React.
- Carpeta routes: separa la lógica de enrutamiento. Incluye init.py, route.py y prompt.py para mantener el prompt del router y posibles tools.
- Ventajas: modularidad, claridad y posibilidad de evolucionar el router sin tocar los nodos.
¿Qué errores típicos se encontraron y cómo se corrigen?
Durante la integración surgieron fallos útiles para afinar el flujo. Identificarlos rápido evita diagnósticos erróneos del prompt o del modelo.
- Nombre del módulo mal escrito. Se intentó importar booking en lugar de booking node. Síntoma: “no puede importar ese módulo”. Solución: corregir el nombre exacto del nodo y evitar “refresh” innecesarios si la configuración de setapp-tools ya descubre módulos automáticamente.
- Condición lógica invertida. El chequeo usaba is none en vez de is not none, forzando el desvío a conversation aunque el LLM devolviera booking. Solución: validar que el esquema no sea nulo y devolver schema.step; si no existe, usar el valor por defecto conversation.
- Ajustes de prompt en el router. El clasificador debía contemplar variaciones como appointments, no solo “medical appointments”. Solución: afinar el lenguaje del system prompt con términos más generales.
- Falta de visibilidad al debug. No había impresiones del step devuelto. Solución: imprimir el esquema y usar un sistema de monitoring como LangSmith para inspeccionar decisiones y mejorar el prompt.
¿Cómo validar el agente con pruebas y buenas prácticas?
Probar con mensajes representativos confirma que el router toma decisiones correctas y que la memoria compartida da contexto a todos los nodos.
- Mensaje casual: “Hola, ¿cómo estás?”. Debe ir a conversation y responder con cortesía.
- Petición de cita: “Quiero una cita para mañana a las tres PM con el doctor Pérez”. Debe ir a booking; el extractor aporta nombre, fecha, hora y médico, y el agente React pregunta por datos faltantes si aplica.
- Disponibilidad y confirmación: el flujo de booking valida horarios y devuelve alternativas cuando no hay cupo, manteniendo la conversación en el historial compartido.
- Pregunta técnica general: “cómo mejorar el rendimiento de un website”. Debe ir a conversation y activar el RAG con la fuente disponible; conviene ajustar el prompt para respuestas concisas.
Buenas prácticas observadas: - Usar el historial completo en el router para mayor precisión; si el costo crece, evaluar un resumen previo o basarse solo en el último mensaje. - Incluir few-shot en el system prompt del router para desambiguar intenciones cercanas. - Escoger un modelo adecuado: para clasificar, un LLM no razonador puede bastar; para booking con React, uno con mejor razonamiento mejora la calidad. - Mantener consistencia de nombres de nodos y tipados en el structured output.
¿Te gustaría que preparemos ejemplos de few-shot para tu dominio o revisemos el prompt de tu router? Comparte tus dudas y casos en los comentarios.