Compilar un flujo en una Historia
Convierte un proceso de varios pasos en un grafo dirigido con estado: crea, valida y publica.
create_storylinevalidate_storylinepublish_storylinelist_storylinesupdate_storylineUna Storyline es un grafo dirigido adjunto a un agente: convierte "responder una pregunta" en "llevar a cabo toda una tarea de principio a fin" (recolección de datos, tutoría, coaching…). Los nodos son pasos (cada uno con su propia tarea, habilidades, base de conocimientos y herramientas, además de dimensiones de perfil modificables); las salidas llevan condiciones (ai / user_choice / rule / callback / goto_storyline). El tiempo de ejecución nunca edita el alma ni el límite de seguridad del agente — es constante desde el primer nodo hasta el último, lo cual es exactamente lo que necesita un producto regulado o dirigido a menores.
Crear un borrador
create_storyline(
agent_name="Support", key="loan-intake", name="Loan intake",
profile_schema={"docs_ready": {"type": "bool"}}, # dims that accumulate across nodes
graph={"nodes": [
{"node_key": "n1", "title": "Understand need", "flags": {"is_entry": True},
"on_enter_opening": "Hi — which kind of loan are you applying for?",
"exits": [{"kind": "ai", "label": "need clear", "to_node_key": "n2",
"ai_criteria": "the user stated the loan type and rough amount"}]},
{"node_key": "n2", "title": "Collect documents",
"task": "Collect the checklist items; chase missing ones across turns.",
"exits": [{"kind": "user_choice", "label": "documents ready", "to_node_key": "n3",
"user_choice": {"button_text": "I've uploaded everything"},
"writes": [{"ref": "dim", "key": "docs_ready", "op": "set", "value": True}]}]},
{"node_key": "n3", "title": "Hand off", "task": "Summarise the case and hand off to a human.",
"flags": {"is_terminal": True}, "exits": []}
]},
allow_agent_enroll=True,
enroll_trigger="the visitor says they want to apply for a loan",
)★ Validar, luego publicar ★
validate_storyline(storyline_id="…") # → {"ok": true} is required to publish
publish_storyline(storyline_id="…") # freezes an immutable version and goes liveInscripción — quién entra y cuándo (requiere publicación)
is_default=True— uno por agente; inscripción automática en la primera conversación.allow_agent_enroll=True+enroll_trigger— el agente inscribe al usuario cuando juzga que se cumple el desencadenante.entry="user"(o"both") — el flujo aparece en el menú de flujos guiados del widget de chat y en el menú desplegable de nueva conversación, por lo que el usuario lo inicia deliberadamente (un botón, no un juicio del modelo). Asigna undisplay_namey unadescriptionde una línea — eso es lo que muestra el menú. Combínalo conconcurrency="session"para flujos de "un caso por conversación": cada selección abre un caso nuevo.- Asignación manual en la consola.
Lo que ve el usuario — visibilidad, banner y el mapa de solo lectura
user_visibility controla la presentación al usuario final de un flujo en ejecución (por defecto invisible):
invisible— ninguna interfaz de usuario; el flujo se ejecuta en silencio (comportamiento anterior).named— un banner delgado sobre el chat muestra el nombre del flujo. Nada más.trail— banner + un botón View que abre un mapa de solo lectura: los pasos ya realizados llevan sus títulos; las ramas no realizadas y los pasos futuros son bloques grises anónimos (ocultos en el servidor — el usuario ve lo largo que es el flujo, no qué hay dentro).full— banner con pasox / y+ el mapa completo: cada paso con nombre, codificado por colores según hecho / actual / próximo.
Extras: allow_exit=True añade un botón Salir al banner (un flujo salido no se vuelve a inscribir automáticamente en esa conversación; un flujo seleccionado por el usuario puede volver a entrarse desde el menú, manteniendo el progreso). show_profile=True lista los valores actuales de las dimensiones de perfil debajo del mapa (números como barras de progreso cuando el esquema declara min/max). Por nodo, rewind: "reset" | "keep" permite al usuario hacer clic en un paso realizado en el mapa completo y volver a él — reset restaura la instantánea del perfil tomada al llegar, keep mantiene los datos recopilados (flujos de estudio/revisión). Los efectos secundarios del mundo real (registros archivados, documentos enviados) nunca se revierten, así que marca solo los pasos sin efectos secundarios. En canales IM (Telegram/WhatsApp) el comando /storyline informa del flujo actual y, para trail/full, devuelve un enlace firmado de corta duración al mismo mapa de solo lectura.
El nombre del parámetro heredado learner_visibility y sus valores hidden / completed_only siguen siendo aceptados (mapean a invisible / trail) pero están obsoletos — usa user_visibility.
Concurrencia — ¿sigue el progreso a la persona o al caso?
concurrency decide cuántas ejecuciones puede tener un mismo usuario en esta línea:
"user"(por defecto) — una ejecución por persona; cada conversación continúa el mismo progreso. Adecuado para currículos, incorporación, KYC: "hasta dónde ha llegado esta persona"."session"— una ejecución por conversación; un nuevo chat inicia un caso nuevo e independiente. Adecuado para solicitudes de licencia, tickets de soporte, flujos por producto: "hasta dónde ha llegado este caso". El mismo usuario puede ejecutar tres solicitudes de producto en tres chats, cada uno con su propio progreso y pizarra.
Coloca el estado donde corresponde: estado del caso en la pizarra (vive y muere con la ejecución — el nombre del producto, la lista de documentos de esta solicitud), hechos sobre la persona en las dimensiones de perfil (siguen al usuario entre ejecuciones y storylines — detalles de la empresa, identidad verificada). Un caso por conversación es deliberado: para abrir otro caso, abre otro chat. Cambiar concurrency afecta solo a las inscripciones futuras; las ejecuciones ya en curso mantienen su clave.
Listas de verificación, decisiones condicionadas, archivos y acciones deterministas
Cuatro capacidades a nivel de nodo convierten "la IA decide cuándo hemos terminado" en un estado acumulado y determinista:
checklist—[{key, label}, …]en un nodo. Cada turno la plataforma marca los elementos como completados según lo que el visitante proporciona realmente (subidas, o descripciones con detalles concretos — las promesas no cuentan), y una regla de salida{"op": ">=", "left": {"ref": "checklist"}, "right": {"value": 1}}avanza cuando todo está marcado. El mapa de solo lectura muestra al usuario una lista viva ✓/○. Esta es la forma adecuada para flujos de solicitud/aprobación: el paso 1 anuncia lo que se necesita, el paso 2 recopila elemento por elemento mediante la lista de verificación.choices_offer: "on_ready"— ritmo estilo juego para los botones de elección: permanecen ocultos (y la coincidencia por texto está desactivada — no se puede saltar escribiendo la palabra del botón) hasta que el paso esté completo — lista de verificación terminada, o se juzga verdadero unchoices_ready_criteriaque proporciones. Usauser_choicepara decisiones genuinas entre alternativas; un único botón "continuar" es una señal de alerta.{"ref": "files"}en reglas de salida — el número de archivos/imágenes subidas mientras se está en este nodo (se reinicia en la transición).files >= 2es un umbral completamente determinista de "documentos recibidos".questions— chips de rompehielos por nodo (máx. 6): las preguntas que el usuario probablemente haría en este paso, mostradas como sugerencias seleccionables mientras está en él. Combínalo conon_enter_openingpara que cada paso se presente y ofrezca una vía de entrada — un usuario nunca debería preguntarse "qué se supone que debo hacer aquí".on_enter_actions/on_complete_actions—[{tool, args}]la plataforma ejecuta de forma determinista cuando se entra en el paso / se completa el flujo (p. ej. archivar el lead conmcp__agent4__submit_leaden el paso terminal). Los argumentos de cadena interpolan claves de dimensión y pizarra con plantillas de llaves. Los errores se registran y nunca rompen el chat.
El contexto se mantiene plano sin importar lo larga que sea la storyline: cada turno inyecta solo el nodo actual (tarea, recursos, opciones), las dimensiones de perfil y una pizarra de tamaño limitado — nunca el grafo completo ni los pasos anteriores. Los viajes largos (un año escolar, un arco de juego de toda la temporada) deben encadenarse como storylines (on_complete: goto_next): la pizarra de cada línea comienza de nuevo mientras las dimensiones de perfil se mantienen, lo cual es exactamente "resumir el pasado, mantener el presente tal cual".
El juez de salida ahora ve una ventana de conversación reciente y el estado recopilado, no solo el último mensaje — pero mantén ai_criteria sobre lo que el visitante dijo o hizo; el mecanismo de lista de verificación anterior sigue siendo más fuerte que cualquier criterio textual.
Errores de diseño — cada uno de estos ha producido un flujo atascado en producción
Tú (el que construye el agente) eres el autor más probable de estos errores. Comprueba cada uno antes de publicar:
- Una salida
rulenecesita un escritor.readiness >= 100es un callejón sin salida a menos que algo escriba realmentereadiness: unawritesde la salida (determinista — preferido),profile_writesde un nodo consource: "ai"(puntuado a partir de la conversación), otra storyline o ediciones manuales en la consola.validate_storylineahora marca esto comowarn.rule_unwritten_dim— trata esa advertencia como un error a menos que sepas que existe un escritor externo. Este error exacto se envió una vez: una recolección de datos de tres pasos cuyo segundo paso condicionaba en una dimensión que nadie escribía; los usuarios nunca podían superarlo. - Las dimensiones puntuadas por IA casi nunca alcanzan límites exactos. Si la dimensión es puntuada por el modelo,
>= 100(o== max) prácticamente nunca se dispara — los modelos puntúan de forma conservadora. Condiciona en un umbral realista (>= 70), o haz que la finalización del paso sea unauser_choicey usa laswritesde la salida para establecer el valor de forma determinista. user_choicecoincide exactamente con el texto del botón — y la etiqueta debe decir qué hace. El mensaje del visitante debe ser igual abutton_text. En las líneas visibles el widget renderiza estos como botones reales, así que escribe frases verbales completas y precisas — "Start document collection", no "Start" (¿comenzar qué? — feedback real de las pruebas). Mantenlos distintos y en el lenguaje de la audiencia. En las líneasinvisibleno hay botones — repite las opciones en lataskdel nodo. Prefiereuser_choicepara decisiones genuinas (qué rama, enviar vs. seguir editando); "he terminado este paso" es trabajo de las salidas de IA/reglas, no de un botón.- Publicar no toca las ejecuciones ya en curso. Las inscripciones se fijan a la revisión en la que comenzaron — una publicación de corrección de errores solo llega a las ejecuciones nuevas. Para mover a los usuarios existentes, llama a
POST /storylines/{id}/enrollments/migrate(resetde vuelta a la entrada omovea un nodo — ambas vuelven a fijar la ejecución a la revisión publicada actual). - Recorre la línea como usuario antes de entregarla. Abre la página
/s/del enlace compartido, entra en el flujo, haz clic en cada botón y rama hasta el final. La simulación de ejecución del editor simula el grafo; solo la página real ejerce los mensajes de apertura, botones, visibilidad y finalización juntos.
Las salidas están ordenadas por prioridad (orden de la lista): las deterministas rule / user_choice / callback se juzgan primero, ai al final. Construye if/else, bucles de reintento y uniones AND a partir de salidas deterministas — no apuestes por el LLM. Edita un borrador con update_storyline (semántica PUT; mantén cada node_key estable, ya que las salidas y el embudo lo referencian).
Informa de vuelta. Devuelve el enlace de consola de la Storyline publicada —
https://console.agent4.io/#/storylines/<id>(el id decreate_storyline) — con un resumen de una línea del flujo y cómo un usuario entra en él.