Saltar al contenido
arbelxez

7 min de lectura

Cómo se construye un agente que aguanta producción

Un chatbot contesta. Un agente toma pedidos, mueve plata y le escribe a un cliente de verdad. Esa distancia no la cubre un prompt más largo: la cubren herramientas acotadas, una condición de parada, un plan para cuando el modelo se equivoca y un presupuesto que alguien decidió antes de la primera factura.

01

Una herramienta por cada cosa que el agente puede hacer

Un chatbot tiene un prompt. Un agente tiene una superficie de acciones, y esa superficie es la decisión de diseño más cara del proyecto. En el canal de cliente de PÍDELO hay ocho herramientas y ninguna se llama procesarSolicitud: prepareOrder, createOrder, sendMenuImage, sendLocation, sendSchedule, sendWelcomeMessage, fetchKnowledgePackage y escalateToHumanAgent. El nombre es documentación que el modelo sí lee. Si yo no puedo decir en cinco palabras qué hace una herramienta, el modelo tampoco va a saber cuándo llamarla.

Acotar pesa tanto como nombrar. El canal administrativo es un segundo agente con tres herramientas de solo lectura —pedidos activos, reporte del negocio y desglose financiero— y con una prohibición escrita: por ahí no se toman pedidos. Separarlos no es purismo de arquitectura. El peor caso de un agente de consulta es un dato incompleto; el peor caso de un agente que escribe pedidos es un pedido que nadie hizo, y esos dos riesgos no se administran en el mismo lugar.

En Ch4t.ai Finance el catálogo es más grande: 18 herramientas de agente para crear transacciones, transferencias, categorías, presupuestos, inversiones, metas de ahorro, deudas y cobrables, más los listados, los reportes y el snapshot diario. Por eso el catálogo mismo se volvió contexto. Un servidor MCP propio expone 25 herramientas con autenticación híbrida y precarga las cuentas, las categorías y las deudas dentro de las descripciones de las herramientas. El modelo no adivina qué cuenta existe: lo lee en el mismo lugar donde ya está mirando.

Todo lo que sale del bucle se valida con Zod, y la base de conocimiento no se consulta con texto libre: el agente elige un tema de una lista cerrada. Es la misma idea repetida a tres alturas. Cuanto más estrecha es la puerta, menos maneras hay de que el modelo invente algo al cruzarla, y más fácil es leer después, en frío, qué hizo exactamente y con qué datos lo hizo.

02

El bucle tiene que saber cuándo parar

El bucle de tool-calling de PÍDELO va con el AI SDK de Vercel, con generateText y toolChoice en automático. Lo interesante no es que llame herramientas: es que la parada está declarada. stopWhen combina un tope de pasos con una condición de herramienta terminal, así que el bucle termina por una de dos razones que yo escribí, no porque el modelo se haya quedado sin cosas que decir. Un agente sin condición de parada no es un agente: es una factura abierta.

Parar también es una decisión de producto. En Finance, cuando una herramienta de escritura termina bien, el bucle se detiene ahí de forma obligatoria y el turno vuelve a la persona para que confirme. Es más lento y es correcto: nadie quiere que un agente encadene tres movimientos de plata en un mismo turno porque el mensaje era ambiguo. La velocidad se recupera en otro lado; un movimiento equivocado en la contabilidad de alguien, no.

Lo que el agente decide depende de lo que lee, así que el prompt no puede ser una cadena escondida en el código. En Finance el system prompt está en cinco capas: reglas de plataforma, persona según el rol, contexto de ejecución, formato de respuesta y catálogo de herramientas. En PÍDELO los prompts viven en un CMS versionado —borrador, publicado, archivado— con variantes y variables dinámicas. Cambiar el tono de un negocio deja de ser un despliegue, y lo que se publicó queda con fecha: eso es lo que permite discutir después por qué el agente contestó así.

03

El modelo se equivoca; el sistema no puede

Ningún mensaje sale hacia el cliente sin unas pasadas de calidad. Si el texto sale vacío, se sintetiza. Si trae markup o palabras escritas en otro alfabeto, se corrige. Si el flujo con herramientas falla, hay una recuperación sin herramientas que al menos deja al cliente con una respuesta escrita en vez de un silencio. Ninguna de las tres es elegante. Las tres existen porque el canal es WhatsApp y quien está del otro lado tiene hambre.

La conversación se guarda turno a turno en DynamoDB, incluidas las llamadas a herramientas con sus resultados, y se rehidrata entre reintentos. Esa parte se subestima siempre: si el reintento no ve lo que el intento anterior ya hizo, el agente repite acciones que tienen efecto en el mundo. La memoria no está ahí para que el agente parezca atento, sino para que no cree el mismo pedido dos veces.

Los proveedores también se caen. Cada modelo tiene su circuit breaker en Redis con scripts Lua atómicos: cerrado, abierto y medio abierto, con sondeo de recuperación y decaimiento exponencial del enfriamiento. Cuando uno se abre, la cadena de fallback multi-proveedor se lleva el tráfico al siguiente. Lo de atómico importa: son varios workers compitiendo por el mismo estado, y un breaker que se puede leer a medias es peor que no tener ninguno.

04

La salida al humano, la plata y el reloj

escalateToHumanAgent es una herramienta de primera clase, no un plan B. Tiene cuatro motivos tasados: que el cliente pida un humano, que repita una queja, que muestre frustración evidente o que la petición esté fuera de alcance. Cerrar esa lista hace dos cosas a la vez. El modelo sabe exactamente cuándo le está permitido rendirse, y el negocio puede medir por qué se rinde. Un agente que no sabe salirse no es autónomo: es terco.

El costo es un requisito, no una sorpresa de fin de mes. Los workers comparten presupuesto con un doble cubo, peticiones por minuto y tokens por minuto, así que la ráfaga de un negocio no se come la capacidad de los demás. Eso se decide antes de escribir el primer prompt, porque después ya es una decisión con clientes encima. La pregunta útil nunca fue cuánto cuesta un mensaje, sino cuánto puede llegar a costar el peor día del mes.

La latencia se administra con arquitectura, no con esperanza. El camino es webhook de Meta, SQS, BullMQ, worker, modelo, API de Meta y WebSocket, con locks distribuidos, deduplicación y una puerta de equidad entre chatbots. Las notas de voz se transcriben con Whisper y entran por ese mismo camino. Nada de eso lo nota el cliente, y esa es justamente la idea: lo único que debería notar es que le contestaron rápido y bien.

Y todo esto solo se sostiene si se puede mirar. El tracing va a Langfuse por OpenTelemetry, con tracers separados por canal para que el agente administrativo no ensucie la lectura del agente de cliente, y encima hay métricas propias de costo, tokens y errores por herramienta. Cuando alguien pregunta por qué el bot contestó eso a las once de la noche, la respuesta no es una teoría: es una traza.