Capítulo 4: Workflows Complejos con Múltiples Agentes
En los capítulos anteriores creamos agentes individuales y aprendimos a coordinarlos. Ahora vamos a construir workflows complejos que manejan procesos de negocio completos con múltiples pasos, validaciones, y flujos condicionales.
Imagínate que la Taquería Doña Carmen quiere implementar un sistema completo de pedidos a domicilio que incluya:
- Validación de zona de entrega
- Cálculo de costo de envío
- Asignación de repartidor
- Seguimiento en tiempo real
- Confirmación de entrega
- Sistema de calificaciones
¡Vamos a construir este sistema paso a paso!
El problema complejo que vamos a resolver
Un pedido a domicilio requiere muchos pasos coordinados:
1. Recibir pedido → 2. Validar zona → 3. Calcular envío → 4. Confirmar disponibilidad
↓
5. Asignar repartidor → 6. Preparar comida → 7. Enviar seguimiento → 8. Confirmar entrega
Cada paso puede fallar o requerir validaciones adicionales. Necesitamos un sistema robusto que maneje todas estas complejidades.
Diseñando el workflow complejo
Herramientas base para delivery
1import { agent, tool } from "llamaindex"; 2 3// Base de datos simulada de zonas de entrega 4const zonasEntrega = { 5 centro: { disponible: true, costo: 25, tiempoExtra: 10 }, 6 norte: { disponible: true, costo: 35, tiempoExtra: 15 }, 7 sur: { disponible: true, costo: 30, tiempoExtra: 12 }, 8 oriente: { disponible: false, costo: 0, tiempoExtra: 0 }, 9 poniente: { disponible: true, costo: 40, tiempoExtra: 20 }, 10}; 11 12// Repartidores disponibles 13let repartidores = [ 14 { 15 id: "REP001", 16 nombre: "Miguel", 17 disponible: true, 18 zona: "centro", 19 pedidosActivos: 0, 20 }, 21 { 22 id: "REP002", 23 nombre: "Carlos", 24 disponible: true, 25 zona: "norte", 26 pedidosActivos: 1, 27 }, 28 { 29 id: "REP003", 30 nombre: "Ana", 31 disponible: true, 32 zona: "sur", 33 pedidosActivos: 0, 34 }, 35 { 36 id: "REP004", 37 nombre: "Luis", 38 disponible: false, 39 zona: "poniente", 40 pedidosActivos: 2, 41 }, 42]; 43 44// Herramienta para validar zona de entrega 45const validarZonaEntrega = tool( 46 async ({ direccion }: { direccion: string }) => { 47 const texto = direccion.toLowerCase(); 48 49 // Detectar zona basada en palabras clave 50 let zonaDetectada = 'desconocida'; 51 52 if (texto.includes('centro') || texto.includes('zócalo') || texto.includes('catedral')) { 53 zonaDetectada = 'centro'; 54 } else if (texto.includes('norte') || texto.includes('satelite') || texto.includes('lindavista')) { 55 zonaDetectada = 'norte'; 56 } else if (texto.includes('sur') || texto.includes('coyoacán') || texto.includes('xochimilco')) { 57 zonaDetectada = 'sur'; 58 } else if (texto.includes('oriente') || texto.includes('iztapalapa') || texto.includes('nezahualcóyotl')) { 59 zonaDetectada = 'oriente'; 60 } else if (texto.includes('poniente') || texto.includes('santa fe') || texto.includes('polanco')) { 61 zonaDetectada = 'poniente'; 62 } 63 64 const infoZona = zonasEntrega[zonaDetectada] || { disponible: false, costo: 0, tiempoExtra: 0 }; 65 66 return { 67 zona: zonaDetectada, 68 disponible: infoZona.disponible, 69 costoEnvio: infoZona.costo, 70 tiempoExtra: infoZona.tiempoExtra, 71 mensaje: infoZona.disponible 72 ? `Entregamos en ${zonaDetectada}. Costo: $${infoZona.costo}, tiempo extra: ${infoZona.tiempoExtra} min` 73 : `Lo siento, no entregamos en ${zonaDetectada} por el momento` 74 }; 75 }, 76 { 77 name: "validar_zona_entrega", 78 description: "Valida si entregamos en una zona específica y calcula costo de envío" 79 } 80); 81 82// Herramienta para asignar repartidor 83const asignarRepartidor = tool( 84 async ({ zona, prioridad }: { zona: string; prioridad: 'normal' | 'alta' | 'urgente' }) => { 85 // Filtrar repartidores disponibles en la zona 86 const candidatos = repartidores.filter(r => 87 r.disponible && 88 (r.zona === zona || r.pedidosActivos === 0) // Puede ir a cualquier zona si no tiene pedidos 89 ); 90 91 if (candidatos.length === 0) { 92 return { 93 asignado: false, 94 mensaje: 'No hay repartidores disponibles en este momento', 95 tiempoEspera: 30 // minutos 96 }; 97 } 98 99 // Seleccionar el mejor repartidor 100 const mejorRepartidor = candidatos.sort((a, b) => { 101 // Priorizar por menos pedidos activos, luego por zona correcta 102 if (a.pedidosActivos !== b.pedidosActivos) { 103 return a.pedidosActivos - b.pedidosActivos; 104 } 105 return a.zona === zona ? -1 : 1; 106 })[0]; 107 108 // Asignar el pedido 109 mejorRepartidor.pedidosActivos += 1; 110 if (mejorRepartidor.pedidosActivos >= 2) { 111 mejorRepartidor.disponible = false; 112 } 113 114 return { 115 asignado: true, 116 repartidor: mejorRepartidor.nombre, 117 id: mejorRepartidor.id, 118 tiempoEstimado: zona === mejorRepartidor.zona ? 5 : 10, // minutos extra para llegar 119 mensaje: `Repartidor ${mejorRepartidor.nombre} asignado para zona ${zona}` 120 }; 121 }, 122 { 123 name: "asignar_repartidor", 124 description: "Asigna el mejor repartidor disponible según zona y prioridad" 125 } 126); 127 128// Herramienta para generar seguimiento 129const generarSeguimiento = tool( 130 async ({ 131 pedidoId, 132 tiempoPreparacion, 133 tiempoEntrega, 134 repartidor 135 }: { 136 pedidoId: string; 137 tiempoPreparacion: number; 138 tiempoEntrega: number; 139 repartidor: string; 140 }) => { 141 142 const ahora = new Date(); 143 const tiempoTotal = tiempoPreparacion + tiempoEntrega; 144 const horaEstimada = new Date(ahora.getTime() + tiempoTotal * 60000); 145 146 const seguimiento = { 147 pedidoId, 148 estado: 'confirmado', 149 tiempoEstimado: tiempoTotal, 150 horaEstimada: horaEstimada.toLocaleTimeString('es-MX', { 151 hour: '2-digit', 152 minute: '2-digit' 153 }), 154 repartidor, 155 pasos: [ 156 { paso: 'Pedido confirmado', completado: true, tiempo: 0 }, 157 { paso: 'Preparando comida', completado: false, tiempo: tiempoPreparacion }, 158 { paso: 'En camino', completado: false, tiempo: tiempoPreparacion + 5 }, 159 { paso: 'Entregado', completado: false, tiempo: tiempoTotal } 160 ] 161 }; 162 163 return { 164 seguimiento, 165 linkSeguimiento: `https://taqueria.com/seguimiento/${pedidoId}`, 166 mensaje: `Tu pedido ${pedidoId} llegará aproximadamente a las ${seguimiento.horaEstimada}` 167 }; 168 }, 169 { 170 name: "generar_seguimiento", 171 description: "Genera información de seguimiento en tiempo real para el pedido" 172 } 173); 174
Agente de Delivery Completo
Ahora vamos a crear el agente que maneja todo el proceso de delivery:
1// Importar herramientas de capítulos anteriores 2import { procesarPedido, verificarInventario, calcularPrecio } from './capitulo-02'; 3 4const agenteDelivery = agent({ 5 tools: [ 6 procesarPedido, 7 verificarInventario, 8 calcularPrecio, 9 validarZonaEntrega, 10 asignarRepartidor, 11 generarSeguimiento 12 ], 13 systemPrompt: ` 14 Eres el especialista en entregas a domicilio de Taquería Doña Carmen. 15 16 Tu proceso COMPLETO para pedidos a domicilio: 17 18 1. SALUDA y confirma que es pedido a domicilio 19 2. USA procesar_pedido para entender qué quiere 20 3. USA verificar_inventario para confirmar disponibilidad 21 4. PIDE la dirección de entrega 22 5. USA validar_zona_entrega para verificar si entregamos ahí 23 6. USA calcular_precio para obtener subtotal 24 7. AGREGA el costo de envío al total 25 8. PRESENTA resumen completo (comida + envío) 26 9. Si confirma, USA asignar_repartidor 27 10. USA generar_seguimiento para dar información de tracking 28 11. PROPORCIONA link de seguimiento y tiempo estimado 29 30 IMPORTANTE: 31 - Siempre pide la dirección DESPUÉS de confirmar disponibilidad 32 - Explica claramente los costos de envío 33 - Si no entregamos en la zona, sugiere recoger en local 34 - Proporciona información de seguimiento detallada 35 - Sé transparente sobre tiempos de entrega 36 37 FLUJO DE CONVERSACIÓN: 38 "¡Hola! ¿Es para entrega a domicilio? Perfecto. 39 [procesar pedido] 40 [verificar inventario] 41 ¿Cuál es tu dirección de entrega? 42 [validar zona] 43 [calcular precios] 44 Tu pedido sería: [resumen] + envío $X = Total $Y 45 ¿Confirmas? 46 [asignar repartidor] 47 [generar seguimiento] 48 ¡Listo! Tu pedido llegará a las X:XX" 49 ` 50}); 51
Workflow complejo en acción
Vamos a probar el sistema completo con diferentes escenarios:
1async function probarWorkflowComplejo() { 2 console.log("🚚 SISTEMA DE DELIVERY - TAQUERÍA DOÑA CARMEN"); 3 console.log("=".repeat(60)); 4 5 // Escenario 1: Pedido exitoso 6 console.log("\n📱 Escenario 1: Pedido a domicilio exitoso"); 7 console.log("-".repeat(40)); 8 9 const stream1 = await agenteDelivery.runStream({ 10 message: `Hola, quiero pedir a domicilio: 4 tacos de pastor, 2 quesadillas de queso y un agua de horchata. 11 Mi dirección es Av. Insurgentes 123, Colonia Centro`, 12 }); 13 14 for await (const chunk of stream1) { 15 process.stdout.write(chunk.delta); 16 } 17 18 console.log("\n" + "=".repeat(60)); 19 20 // Escenario 2: Zona no disponible 21 console.log("\n📱 Escenario 2: Zona no disponible para entrega"); 22 console.log("-".repeat(40)); 23 24 const stream2 = await agenteDelivery.runStream({ 25 message: `Buenos días, quiero 3 tacos de carnitas para entrega. 26 Vivo en Av. Oriente 456, Colonia Iztapalapa`, 27 }); 28 29 for await (const chunk of stream2) { 30 process.stdout.write(chunk.delta); 31 } 32 33 console.log("\n" + "=".repeat(60)); 34 35 // Escenario 3: Sin repartidores disponibles 36 console.log("\n📱 Escenario 3: Sin repartidores disponibles"); 37 console.log("-".repeat(40)); 38 39 // Simular que todos los repartidores están ocupados 40 repartidores.forEach((r) => (r.disponible = false)); 41 42 const stream3 = await agenteDelivery.runStream({ 43 message: `Quiero 2 tacos de suadero para entrega a Colonia Norte, Calle Reforma 789`, 44 }); 45 46 for await (const chunk of stream3) { 47 process.stdout.write(chunk.delta); 48 } 49} 50
Resultado esperado del workflow
🚚 SISTEMA DE DELIVERY - TAQUERÍA DOÑA CARMEN
============================================================
📱 Escenario 1: Pedido a domicilio exitoso
----------------------------------------
¡Hola! Veo que quieres pedir a domicilio. ¡Perfecto! 🚚
Tu pedido:
• 4 tacos de pastor - $60
• 2 quesadillas de queso - $50
• 1 agua de horchata - $20
✅ Todos los productos están disponibles.
Veo que tu dirección es en Colonia Centro. ¡Excelente! Sí entregamos ahí.
💰 Resumen de tu pedido:
Subtotal comida: $130
Costo de envío: $25
TOTAL: $155 pesos
⏱️ Tiempo estimado: 35 minutos (25 min preparación + 10 min entrega)
¿Confirmas tu pedido?
✅ ¡Pedido confirmado!
🚚 Repartidor Miguel asignado para tu entrega
📱 Link de seguimiento: https://taqueria.com/seguimiento/PED1234567890
🕐 Tu pedido llegará aproximadamente a las 15:35
¡Gracias por tu preferencia! Te mantendremos informado del progreso.
============================================================
📱 Escenario 2: Zona no disponible para entrega
----------------------------------------
¡Hola! Quieres 3 tacos de carnitas, ¡excelente elección! 🌮
✅ Los tacos de carnitas están disponibles - $45 total
Revisando tu dirección en Iztapalapa...
❌ Lo siento, actualmente no entregamos en esa zona.
Pero tienes estas opciones:
🏪 Puedes recoger en nuestro local (sin costo extra)
📍 Ubicación: Calle Principal 123, Centro
🕐 Horario: 9:00 AM - 9:00 PM
¿Te gustaría cambiar a pedido para recoger?
============================================================
📱 Escenario 3: Sin repartidores disponibles
----------------------------------------
¡Hola! Quieres 2 tacos de suadero, ¡excelente elección! 🌮
✅ Los tacos de suadero están disponibles - $30 total
Verificando tu dirección en Colonia Norte...
✅ Sí entregamos en esa zona - Costo de envío: $35
💰 Resumen:
Subtotal comida: $30
Costo de envío: $35
TOTAL: $65 pesos
⚠️ Lo siento, en este momento no tenemos repartidores disponibles.
Pero tienes estas opciones:
⏰ Podemos programar tu entrega para dentro de 30 minutos
🏪 Puedes recoger en nuestro local (sin costo de envío)
📞 Te avisamos cuando haya repartidores disponibles
¿Cuál opción prefieres?
============================================================
Ejecuta el código
Para probar este sistema completo, guarda el código en un archivo llamado delivery-workflow.ts y ejecuta:
1npx tsx delivery-workflow.ts 2
Asegúrate de tener instaladas las dependencias:
1npm install llamaindex @ai-sdk/openai 2
También necesitarás configurar tu API key de OpenAI:
1export OPENAI_API_KEY="tu-api-key-aqui" 2
Conceptos clave de workflows complejos
1. Coordinación de herramientas múltiples
En este capítulo integramos 6 herramientas diferentes que trabajan en secuencia:
procesarPedido→ Comprende la intención del clienteverificarInventario→ Valida disponibilidadvalidarZonaEntrega→ Verifica cobertura geográficacalcularPrecio→ Calcula costos totalesasignarRepartidor→ Gestiona recursos humanosgenerarSeguimiento→ Crea tracking en tiempo real
2. Manejo de estados complejos
El workflow mantiene estado a través de:
- Variables globales para repartidores y zonas
- Datos persistentes en cada herramienta
- Flujo condicional basado en disponibilidad
3. Validaciones en cascada
Cada paso valida el anterior antes de continuar:
Pedido válido → Inventario disponible → Zona cubierta → Repartidor libre → Seguimiento activo
4. Experiencia de usuario inteligente
El agente maneja 3 escenarios automáticamente:
- ✅ Éxito completo: Pedido procesado sin problemas
- ⚠️ Zona no disponible: Ofrece alternativas automáticamente
- 🚫 Sin repartidores: Propone opciones de reprogramación
¿Qué acabamos de lograr?
En este capítulo construiste un sistema de delivery completo que maneja:
✅ Funcionalidades empresariales
- Validación automática de pedidos y disponibilidad
- Cálculo dinámico de costos de envío por zona
- Asignación inteligente de repartidores
- Seguimiento en tiempo real con timestamps
- Manejo de excepciones con alternativas útiles
✅ Arquitectura robusta
- 6 herramientas especializadas trabajando en coordinación
- Flujo de decisiones complejas con múltiples validaciones
- Estado compartido entre herramientas
- Manejo de errores graceful con opciones al usuario
✅ Experiencia de usuario superior
- Comunicación clara en cada paso del proceso
- Transparencia total en costos y tiempos
- Alternativas automáticas cuando hay problemas
- Seguimiento profesional con links y estimaciones
✅ Escalabilidad real
- Fácil agregar nuevas zonas de entrega
- Simple modificar precios y tiempos
- Rápido integrar nuevos repartidores
- Directo conectar con sistemas externos (pagos, mapas, etc.)
🎯 Lo más importante
Has creado un agente que piensa como un gerente experimentado: evalúa, decide, actúa y comunica de forma profesional. Este no es solo código; es inteligencia de negocio automatizada.
Reflexión para desarrolladores
Este capítulo demuestra que los Agent Workflows pueden manejar procesos empresariales completos sin complejidad técnica excesiva. En menos de 300 líneas de TypeScript limpio y funcional:
- ✨ Automatizaste un proceso que normalmente requiere múltiples sistemas
- 🧠 Integraste lógica de negocio compleja con IA conversacional
- 🔄 Creaste flujos adaptativos que manejan excepciones inteligentemente
- 📱 Construiste una experiencia que mejora la satisfacción del cliente
En el próximo capítulo aprenderemos streaming en tiempo real para hacer estos workflows aún más interactivos y dinámicos.
¡Gracias por acompañarme en este viaje! 🌮✨ Abrazo. bliss. 🤓
