Flujos
Un flujo es un procedimiento que tu agente sigue paso a paso: pedir un dato, consultar tu API, decidir con la respuesta, responder con una plantilla o pasar el caso a una persona. Los pasos los ejecuta código, así que el mismo caso recibe siempre el mismo tratamiento. El modelo solo interviene donde hay lenguaje de por medio: reconocer que un mensaje cae en el flujo, leer un valor en texto libre o reescribir una plantilla en tono natural.
Cuándo usar un flujo y cuándo una skill
Las skills son texto que el modelo lee e interpreta en cada turno. Sirven para procedimientos conversacionales, pero cada turno puede salir un poco distinto y cada uno cuesta varias llamadas al modelo.
Usa un flujo cuando:
- El caso necesita una llamada a tu API y la respuesta depende de lo que devuelve ("no tengo internet" → consultar la cuenta → facturas vencidas o problema técnico).
- La respuesta tiene que ser siempre la misma (un link de pago, un aviso legal).
- Necesitas una derivación garantizada con un motivo fijo ("pago duplicado" va a administración, siempre).
Usa una skill cuando el procedimiento es conversacional y no depende de datos externos (cómo atender un reclamo de cámaras, qué preguntar ante un cambio de domicilio). Las dos conviven en el mismo agente.
Cómo corre un flujo
- Llega un mensaje del cliente. Si la conversación ya tiene un flujo activo, se reanuda desde el paso donde quedó.
- Si no, el clasificador compara el mensaje con el "cuándo aplica" de cada flujo publicado y elige uno, o ninguno. No hay nada fijo: agregar un flujo agrega una intención, borrarlo la quita.
- El flujo avanza nodo a nodo hasta que uno espera al cliente (una pregunta, una respuesta) o termina el caso (fin, derivar, delegar).
- Las respuestas que produce un flujo son tus plantillas, así que no pasan por la verificación de fuentes. Las derivaciones llevan un motivo que tu equipo ve en el ticket.
Si ningún flujo aplica, el agente responde como siempre: conocimiento, skills, herramientas.
Las piezas
| Nodo | Qué hace | Salidas |
|---|---|---|
start | Dónde empieza el flujo. Exactamente uno por flujo. | next |
collect | Llena una variable. Si el cliente ya la dio en cualquier mensaje (ver Cómo entiende al cliente), está en su memoria o en la identidad del canal, no pregunta; si falta, pregunta y espera. Con ask el modelo redacta la pregunta con contexto; con prompt solo, la envía tal cual. Valida el valor (tipo, patrón) y repregunta hasta el tope configurado. | obtained, missing |
extract | Lee varios campos del último mensaje y sus adjuntos (el texto transcripto de una imagen o PDF, y los códigos de barras o QR que se leyeron). | next |
action | Llama a una de tus integraciones (herramienta HTTP) o consulta tus datos cargados. La respuesta se guarda en una variable. | ok, error |
condition | Evalúa ramas en orden sobre las variables (igual, mayor que, contiene, fechas, "algún elemento de la lista donde…"). Gana la primera verdadera; si ninguna, default. | una por rama, más default |
reply | Envía una plantilla con marcadores como {{customer.name}}, más filtros para contar, sumar o dar formato a listas (ejemplo abajo). Opcionalmente el modelo la reescribe en tono natural conservando todos los datos. | next |
escalate | Deriva a una persona con un motivo. El cliente recibe el mensaje del nodo o el mensaje de derivación del agente. Las variables que elijas se adjuntan para que el equipo las vea. | ninguna |
delegate | Termina el flujo y entrega el resto de la conversación a una skill. | ninguna |
end | Termina el flujo. Puede guardar variables en la memoria del cliente para no volver a pedirlas la próxima vez. | ninguna |
Las variables tienen tipo (text, number, date, document, email, phone, boolean, list, object). Las condiciones y plantillas llegan a datos anidados con puntos (customer.invoices). Una plantilla con filtros se ve así:
Hola {{customer.name}}. Tienes {{customer.invoices | where:status=overdue | count}} factura(s) vencida(s)
por ${{customer.invoices | where:status=overdue | sum:amount | money}}. Paga aquí: {{customer.pay_link}}.
Cómo entiende al cliente
Antes de dar cada paso, el motor lee los últimos mensajes de la conversación con el modelo y llena todas las variables del flujo que el cliente ya dio, sin importar cuál se estaba pidiendo: si pediste el DNI y responde con su nombre, el nombre queda guardado; si escribe nombre y dirección en el primer mensaje, quedan los dos; si manda la foto de una factura, lo que se lee ahí también cuenta. Un collect cuya variable ya está llena no pregunta. Por eso conviene escribir una buena descripción en cada variable: es lo que guía la lectura.
Ese mismo paso detecta cuando el cliente pregunta otra cosa ("¿pueden mandar un técnico?"): el agente responde esa pregunta con su conocimiento y el flujo sigue en el mismo mensaje. Si el cliente deja el trámite, el flujo termina en silencio y el agente responde como siempre.
En un collect, además del texto de la pregunta (prompt, que se envía tal cual), puedes escribir la intención del paso (ask): "pedir un dato que identifique la cuenta: DNI, número de socio o CUIT". Con ask, el modelo redacta la pregunta sabiendo lo que el cliente ya dio y lo que acaba de decir: no vuelve a pedir datos conocidos y reconoce lo que contó. prompt queda como respaldo.
Diseña los flujos como una política, no como un cuestionario con orden fijo: una condición al inicio que salte directo a la consulta cuando las variables que identifican al cliente ya se conocen ahorra preguntas.
Filtros de plantilla
Un marcador es {{variable}}. Puedes encadenar filtros con | para contar, sumar, dar formato o transformar el valor. Los mismos filtros sirven en las plantillas de respuesta y en los parámetros de una acción.
| Filtro | Qué hace |
|---|---|
count | Cuenta los elementos de una lista |
sum:campo | Suma un campo de una lista |
where:campo=valor | Filtra una lista por un campo |
first / last | Primer o último elemento |
join:separador | Une una lista en texto |
money | Formatea un número como importe |
date | Formatea una fecha |
upper / lower | Mayúsculas o minúsculas |
digits | Deja solo los dígitos |
slice:desde:hasta | Recorta el texto por posición |
replace:patron:reemplazo | Reemplazo por expresión regular (ver abajo) |
default:texto | Un texto cuando el valor está vacío |
Se encadenan de izquierda a derecha. Ejemplos:
{{invoices | count}}
{{invoices | where:status=overdue | sum:amount | money}}
{{phone | digits}}
{{name | default:cliente}}
Transformar un valor antes de enviarlo a una API
A veces el cliente escribe un dato en un formato y tu API espera otro. El filtro replace aplica una expresión regular al valor; si no coincide, lo deja igual. Se configura como replace:patron:reemplazo.
Ejemplo real: en Argentina el cliente suele escribir el CUIT completo (20-36647595-1), pero la API de clientes espera solo el DNI central (36647595). En el parámetro de la acción se pone:
{{documento | digits | replace:^(\d{2})(\d{8})(\d)$:$2}}
digits deja 20366475951, y replace toma el bloque central de 8 dígitos cuando son 11 (un CUIT); si el cliente escribió el DNI suelto de 8 dígitos, el patrón no coincide y el valor queda igual. Cada país arma su propio patrón: esto no está fijo en el producto, lo configuras en tu flujo.
Dos límites del filtro replace: el patrón no puede contener el carácter | (parte la sintaxis del marcador), y usa la sintaxis de expresiones regulares de JavaScript (\d dígito, {n} cantidad, ^ y $ inicio y fin, $1, $2 los grupos capturados).
Un ejemplo
"Sin internet o bloqueo", para un proveedor de internet:
collectel documento del titular. Si el cliente ya lo dio en un ticket anterior, la memoria lo completa y no se pregunta nada.actionconsulta la API de clientes del proveedor con ese documento.condition: no encontrado → derivar con motivocustomer_not_found; facturas vencidas → responder con el importe y el link de pago; en otro caso → preguntar qué pasa y pedir una foto de las luces del router, y derivar al equipo técnico con motivono_connection_account_ok.
Todos los textos que ve el cliente son tuyos, en tu idioma. Los identificadores (tipos de nodo, salidas, motivos) van en inglés por convención del producto.
Crear y probar flujos
Abre Flujos en la barra lateral. Un flujo se dibuja en un lienzo: eliges nodos de la paleta de la izquierda, conectas cada salida con el nodo siguiente y completas las propiedades del nodo seleccionado a la derecha (la pregunta a hacer, la herramienta a llamar y sus parámetros, las ramas de una condición, la plantilla de respuesta). Los problemas se listan en vivo: un nodo sin conexión de salida, una variable no declarada, una acción sin herramienta. Tres plantillas de inicio (enviar un link, derivar con motivo, consultar al cliente y decidir) te dan un flujo funcionando para adaptar.
También puedes crear y editar flujos desde el conector de Claude (MCP): describes el caso en lenguaje natural y Claude escribe la definición, la valida, la simula y la publica cuando se lo pides. Los dos caminos editan los mismos flujos.
- Borrador y publicado. Un flujo nuevo nace como borrador. Publicarlo lo valida y sube su versión; solo los publicados y vinculados a un agente se sirven.
- Simulación. El botón Simular corre el flujo, con los cambios sin guardar incluidos, sobre una lista de mensajes del cliente sin tocar conversaciones reales. Puedes simular las respuestas de la API para probar cada rama; los nodos recorridos se iluminan en el lienzo.
- Vínculo. Cada agente tiene su propio conjunto de flujos, elegidos en la pestaña Flujos del editor del agente, igual que las skills.
- Importar y exportar. Un flujo se exporta como JSON y se puede importar en otro workspace.
Leer qué pasó
En el panel "Qué pensó la IA" de la conversación, y en el chat de prueba, un turno que pasó por un flujo muestra qué flujo corrió, si empezó o continuó, y cada nodo con la salida que tomó (de dónde salió una variable, qué estado HTTP devolvió la API, qué rama coincidió).
Límites de seguridad
- Cada flujo tiene un tope de turnos (
maxTurns, 12 por defecto). Superado, el caso se deriva con motivomax_turns. - Si un flujo llega a un paso sin conexión (por ejemplo después de editar un flujo publicado), el caso se deriva con motivo
flow_dead_enden lugar de quedar colgado. - Mientras un flujo espera un valor, un mensaje que no viene al caso se trata como respuesta inválida: el flujo repregunta hasta su tope de reintentos y luego toma la salida
missing.