# Arquitectura: cuándo flujo y cuándo Met

[Cómo construir un agente](construir-un-agente.html) plantea la decisión de fondo: el agente decide la secuencia en cada ejecución; el flujo la decide quien lo construye. Esta guía va un paso más allá, porque en la práctica casi nada bueno es solo una de las dos cosas. Lo que funciona en producción es **un flujo que llama a un Met solo en el paso que necesita juicio**, o **un Met que llama a un flujo para lo que no admite improvisación**.

La razón es doble. Cada paso con IA gasta Energía y puede equivocarse; cada paso fijo no gasta y hace siempre lo mismo. Mientras menos pasos dependan del modelo, más barato y más predecible es el proceso.

## La escalera

Ordenada del escalón más barato y controlable al más caro y libre:

| | qué es | gasta Energía | úsalo cuando |
|---|---|---|---|
| **1. Plantilla, regla o código** | texto fijo, `flow.condition`, `data.code`, botones con `channel.ask_options` | no | la respuesta se conoce de antemano o se puede calcular |
| **2. Una llamada acotada** | un [Campo IA](campo-ia.html) o un Run aislado (`tool_policy: "none"`) | una llamada | hay que leer o escribir lenguaje, pero la tarea es una sola y no necesita herramientas |
| **3. Pedirle a Met** | el nodo `agent.ask` dentro de un flujo | ese paso | un paso necesita el criterio o la redacción de un Met; el resto del proceso sigue fijo |
| **4. Un Met que conversa** | el nodo `agent.handoff`: desde ahí el Met atiende al contacto | cada turno | la conversación no se puede prever; el Met llama [Funciones](funciones-y-flujos.html) para lo que no admite improvisación |

**Empieza abajo y sube solo cuando el escalón de abajo no alcanza.** Las señales para subir:

- **Del 1 al 2:** la entrada es texto libre y la regla se volvió una lista de palabras que nunca termina.
- **Del 2 al 3:** la tarea necesita el tono, los datos o las herramientas de un Met en particular.
- **Del 3 al 4:** no sabes cuántas vueltas va a dar la conversación ni en qué orden.

Y las señales para bajar, que son las que más ahorran: un Met que hace siempre los mismos pasos en el mismo orden es un flujo o una Función; un Met que elige entre tres opciones fijas es un menú de botones; un Met que solo escribe una frase no necesita sus noventa herramientas.

### Escalón 1: plantilla, regla y código

Todo lo que no pasa por un modelo:

- **`flow.condition`** bifurca el flujo por grupos de condiciones (todas o cualquiera). Compara con `eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `contains`, `starts_with`, `in`, `not_in`, `has_any`, `has_none`, `is_set` e `is_empty`, y con `matches_term`, que busca palabras completas sin distinguir mayúsculas, tildes ni puntuación. Si ningún grupo coincide, sale por «Si no».
- **`data.code`** transforma datos con JavaScript: recibe `entrada` y lo que retornes queda en `@{node:<id>.result}`. Corre aislado, sin internet, archivos ni módulos, con 1 segundo, 64 MB de memoria y un resultado de hasta 256 KB. Las referencias `@{...}` van en sus datos de entrada, no dentro del código.
- **`channel.ask_options`** le hace una pregunta al contacto y espera su elección con botones o respuestas rápidas, sin gastar Energía del Met. Es la forma de clasificar cuando las opciones son pocas y conocidas: que la persona elija cuesta menos y se equivoca menos que adivinar lo que quiso decir.
- **Plantillas y mensajes fijos**: los nodos de mensajería envían un texto que escribiste tú, con referencias a los datos del disparador.

### Escalón 2: una llamada acotada

Cuando hace falta lenguaje pero no un agente:

- Un **[Campo IA](campo-ia.html)** llena una celda de una colección con el prompt del campo: clasificar un lead, resumir una nota, sacar la ciudad de una dirección.
- Un **Run aislado** ejecuta un Met con `tool_policy: "none"`: trabaja solo con el `input`, sus adjuntos (PDF e imágenes) y las instrucciones del Met. No carga habilidades, integraciones, historial, variables ni contexto del workspace, y si el modelo intenta usar una herramienta la ejecución se detiene sin despacharla. Detalle en [Ejecutar Mets](ejecutar-agentes.html#run-aislado-sin-herramientas-ni-contexto).

```ts
const run = await met.runs.create({
  met: 'Extractor',
  tool_policy: 'none',
  input: 'Devuelve solo el NIT y el total de este texto, en JSON: ...',
});
```

### Escalón 3: Pedirle a Met (`agent.ask`)

El nodo `agent.ask` («Pedirle a Met») le encarga una tarea a un Met del workspace con dos campos: el Met (`met_id`) y la instrucción (`prompt`), que puede llevar referencias a nodos anteriores. La respuesta queda en `@{node:<id>.text}`.

Dos cosas que conviene saber antes de usarlo:

- **El Met corre completo**, con sus instrucciones, habilidades y herramientas. El nodo no tiene nivel propio: usa el del Met. Por eso el Met que eliges para un paso acotado define el costo del paso. Para una frase corta, usa un Met especializado en nivel ágil, con instrucciones breves y sus herramientas apagadas (más abajo, [contexto acotado](#contexto-acotado)).
- **La respuesta es texto libre**, sin esquema. Si va a salir hacia afuera, valídala antes (más abajo, [controlar la salida](#controlar-la-salida)).

### Escalón 4: un Met que conversa

El nodo `agent.handoff` vincula un Met a la conversación: a partir de ahí ese Met le responde al contacto. Es el escalón correcto para atender, y el peor para ejecutar procedimientos: lo que tiene pasos fijos —cobrar, agendar, registrar un pedido— va en una [Función](funciones-y-flujos.html) que el Met llama, con parámetros que la Función valida.

## Los dos sentidos de la combinación

| sentido | cómo | cuándo |
|---|---|---|
| **flujo → Met** | `agent.ask` para un paso; `agent.handoff` para entregarle la conversación | el proceso es fijo y uno de sus pasos necesita juicio o redacción |
| **Met → flujo** | una [Función IA](funciones-y-flujos.html) con handler HTTP o con `flow_id`; el flujo devuelve su resultado con el nodo `function.result` | el Met conversa y, en algún momento, tiene que ejecutar algo que no puede improvisar |

En el segundo sentido, los parámetros de la Función son el contrato: con `enum_values` el Met solo puede mandar uno de los valores que permitiste, y lo que pasa después lo decide tu flujo o tu backend, no el modelo.

## Lo que cuesta cada cosa

**Los nodos de lógica, datos y mensajería no gastan Energía.** Condiciones, código, botones, plantillas, esperas, bucles y lecturas o escrituras del CRM corren sin modelo. Gastan los nodos que invocan IA: `agent.ask`, `agent.handoff`, `agent.nudge`, `image.generate`, `image.edit`, `voice.generate`, `video.generate`, y un nodo `flow.action` cuando una de sus acciones pone a trabajar a un Met. Un nodo `mcp.call` no pasa por un modelo, pero la herramienta que llama puede tener su propio costo, por ejemplo una que genere imágenes.

**Lo que encarece un Met no es solo su nivel.** En cada llamada al modelo viajan sus instrucciones y la definición de todas sus herramientas activas, aunque el turno sea trivial: un Met con un prompt largo y decenas de herramientas paga ese contexto para escribir una frase. La parte del contexto que se repite se cobra más barata cuando sale de caché, pero no es gratis. Y el nivel multiplica todo lo anterior.

**Rutear también cuesta.** Un Run sin `met` lo atiende el Met principal del workspace, que puede delegar en otro Met: son dos ejecuciones donde una alcanzaba. Con `met`, el Run va directo a ese Met, sin pasar por el orquestador.

**Cómo medirlo:** `GET /billing/executions` filtra por `met_id` y por `run_id`, y `totals` suma todo el filtro ([Cuánto cuesta cada llamada](costo-por-llamada.html)). Hoy no hay un costo por flujo en la API, así que usa un truco: dale al paso de IA de tu flujo **su propio Met**. Filtrando por ese `met_id` sabes exactamente cuánto cuesta ese paso, corrida por corrida.

## Niveles

Cada Met tiene un nivel, que se elige con `model` al crearlo o editarlo ([Mets y sus herramientas](mets-y-herramientas.html)):

| `model` | para qué |
|---|---|
| `agil` | rápido y el que menos Energía gasta por respuesta: clasificar, extraer, escribir una frase corta, responder lo que ya está en sus instrucciones |
| `brillante` | el de todos los días: atender, combinar datos, redactar con criterio |
| `genio` | razona más y gasta más: decisiones con muchas variables, textos largos y delicados |

```ts
await met.agents.update(redactorId, { model: 'agil' });
```

La regla práctica: **ágil para tareas acotadas**. Si la tarea cabe en una instrucción de dos líneas y una respuesta de una frase, subirla de nivel no la mejora; solo la encarece. Los nodos de imagen y video de un flujo eligen su propio nivel; `agent.ask` usa el del Met.

## Contexto acotado

Mientras menos contexto cargue un Met, menos cuesta cada turno y menos formas tiene de desviarse:

- **Apaga lo que no usa** con `disabled_tools`. Los nombres válidos salen de `met.agents.tools(id)` ([Mets y sus herramientas](mets-y-herramientas.html#apagar-herramientas-por-met)).
- **Oculta las colecciones** que no le tocan con `expose_to_agent: false`.
- **Prefiere varios Mets especializados** a uno que lo sabe todo. Un Met redactor con cinco líneas de instrucciones y sus herramientas apagadas es el Met correcto para un `agent.ask` que escribe una frase.
- **Para extraer o clasificar una sola cosa, usa un Run aislado** (`tool_policy: "none"`): ni siquiera carga el historial.

## Controlar la salida

Un modelo puede devolver algo razonable pero equivocado. Antes de que su salida llegue a un cliente, un flujo la revisa sin IA:

1. **Valida con código.** `flow.condition` compara valores pero no mide largos ni busca patrones, así que la validación va en un `data.code` que devuelve un sí o un no, y la condición lo lee:

   ```js
   // Datos de entrada: {"texto": "@{node:redactar.text}"}
   const t = String(entrada.texto || '').trim();
   const ok = t.length > 0 && t.length <= 120 && !/https?:\/\/|www\./i.test(t);
   return { ok, texto: t };
   ```

   Después, un `flow.condition` con `@{node:validar.result.ok}` igual a `true`.
2. **Ten un respaldo fijo.** La rama «Si no» envía un texto que escribiste tú. Si el modelo falla, el contacto recibe algo correcto en vez de nada o de algo raro.
3. **Lo que publica, cobra o envía pasa por una persona.** Cuando un Met pide publicar en redes, cobrar, facturar, gastar pauta o enviar una plantilla que Meta cobra, la acción puede quedar esperando la aprobación de alguien del negocio ([Aprobaciones humanas](aprobaciones-humanas.html)). Un flujo no tiene un nodo de aprobación: lo que envía por su cuenta sale sin revisión, y por eso tiene que ser texto fijo o una salida validada.
4. **Acota lo que el Met puede pedir.** En una Función, `enum_values` y los parámetros obligatorios hacen que lo que llega a tu backend tenga la forma que esperas.

## Ejemplo de punta a punta: responder comentarios

Es el patrón con el que Meteor responde los comentarios de sus propias publicaciones: cuando alguien comenta la palabra clave, recibe la información por mensaje privado, una respuesta pública corta y un «Me gusta». Solo un paso de los seis usa IA.

| paso | nodo | qué hace | gasta Energía |
|---|---|---|---|
| 1 | `trigger.start` con el disparador `social.comment_received` | arranca con un comentario nuevo de la cuenta elegida que contiene la palabra clave (`contains`, sin distinguir mayúsculas) | no |
| 2 | `mcp.call` → `meta_reply_to_comment_private` | manda por privado un texto fijo con la información y el enlace | no |
| 3 | `mcp.call` → `meta_like_comment` | le da «Me gusta» al comentario (solo en Facebook; en Instagram se omite) | no |
| 4 | `agent.ask` | le pide al Met redactor una frase para responder en público | **sí** |
| 5 | `data.code` + `flow.condition` | valida la frase: que exista, que no pase de 120 caracteres y que no tenga enlaces | no |
| 6 | `mcp.call` → `meta_reply_to_comment` | publica la frase validada o, por la rama «Si no», un texto fijo de respaldo | no |

Los datos del comentario llegan en el disparador: `@{trigger.payload.comment_id}`, `@{trigger.payload.comment_text}`, `@{trigger.payload.platform}` y `@{trigger.payload.account_id}`. Cada comentario se reserva antes de correr el flujo, así que un mismo comentario no lo dispara dos veces.

La instrucción del paso 4 cabe en tres líneas:

```text
Escribe una respuesta pública de una sola frase, cálida y de máximo 120 caracteres,
sin enlaces ni datos de contacto, para este comentario: @{trigger.payload.comment_text}
```

El Met redactor va en `agil`, con instrucciones breves sobre el tono de la marca y sus herramientas apagadas con `disabled_tools`. Lo que se pone en riesgo con la IA es poco —una frase— y aun así no sale sin pasar por la validación.

## Las Rutinas son este mismo patrón

Las [Rutinas](rutinas-y-grupos.html) de Met —crear y publicar en redes, anunciar lo que vendes, hacer seguimiento a tus clientes— están construidas así por dentro:

- **Elegir es un botón.** En cada paso la persona elige un camino, y elegirlo no llama a ningún modelo.
- **El encargo es una plantilla.** Lo que se le pide al Met del camino se arma con texto fijo y los datos del negocio.
- **Una delegación por paso.** Cada paso con IA es un solo encargo a un solo Met. Los pasos que no necesitan IA —calcular a quién hacerle seguimiento con los pedidos, por ejemplo— los hace el servidor.
- **La salida se valida.** El Met cierra con un bloque de datos estructurados que se lee, se acota y se normaliza; si no llega o no se entiende, el paso queda con su texto y sin cifras: nunca se inventan.
- **Lo que publica pasa por aprobación.** Durante una rutina, las acciones que publican o gastan pauta quedan siempre esperando a una persona.
- **El costo se mide por corrida.** Cada paso es un turno con su Energía, y al cerrar la rutina se ve cuánto gastó toda la corrida.

## Preguntas frecuentes

### ¿Un flujo sin pasos de IA consume Energía?

No. Los nodos de lógica, datos y mensajería no invocan un modelo. Ojo con lo que sí tiene costo fuera de la Energía: una plantilla de WhatsApp fuera de la ventana de 24 horas la cobra Meta.

### ¿Puedo elegir el nivel de un nodo `agent.ask`?

No por nodo: el paso usa el nivel del Met que eliges. Si necesitas un paso en ágil y otro en brillante, usa dos Mets.

### ¿Cuándo conviene un Run aislado en vez de `agent.ask`?

Cuando llamas desde tu backend y la tarea es una sola extracción o clasificación sobre un texto o un documento. El Run aislado no carga herramientas ni contexto; `agent.ask` corre dentro de un flujo y el Met lo hace con todo lo que tiene.
