On this page
Guides / Architecture: when a flow, when a Met

Architecture: when a flow, when a Met

The ladder from a template to an autonomous Met, what each rung costs, how flows and Mets combine in both directions, and an end-to-end example.

Updated View .md

Build an AI agent sets out the core decision: an agent decides the sequence on every run; a flow has it decided by whoever builds it. This guide goes one step further, because in practice almost nothing good is only one of the two. What works in production is a flow that calls a Met only at the step that needs judgment, or a Met that calls a flow for what cannot be improvised.

The reason is twofold. Every AI step spends Energy and can get it wrong; every fixed step spends nothing and always does the same thing. The fewer steps depend on the model, the cheaper and more predictable the process.

The ladder

Ordered from the cheapest, most controllable rung to the most expensive and open-ended:

what it isspends Energyuse it when
1. Template, rule or codefixed text, flow.condition, data.code, buttons with channel.ask_optionsnothe answer is known in advance or can be computed
2. One bounded callan AI Field or an isolated Run (tool_policy: "none")one callyou need to read or write language, but the task is a single one and needs no tools
3. Ask a Metthe agent.ask node inside a flowthat stepone step needs a Met's judgment or writing; the rest of the process stays fixed
4. A Met that conversesthe agent.handoff node: from there on the Met handles the contactevery turnthe conversation cannot be predicted; the Met calls Functions for what cannot be improvised

Start at the bottom and climb only when the rung below falls short. The signals to climb:

And the signals to step down, which are the ones that save the most: a Met that always does the same steps in the same order is a flow or a Function; a Met that picks between three fixed options is a button menu; a Met that only writes one sentence does not need its ninety tools.

Rung 1: template, rule and code

Everything that does not go through a model:

Rung 2: one bounded call

When you need language but not an agent:

const run = await met.runs.create({
  met: 'Extractor',
  tool_policy: 'none',
  input: 'Return only the tax ID and the total from this text, as JSON: ...',
});

Rung 3: Ask a Met (agent.ask)

The agent.ask node ("Pedirle a Met") hands a task to a Met in the workspace with two fields: the Met (met_id) and the instruction (prompt), which can carry references to earlier nodes. The answer lands in @{node:<id>.text}.

Two things worth knowing before you use it:

Rung 4: a Met that converses

The agent.handoff node binds a Met to the conversation: from there on that Met answers the contact. It is the right rung for handling people, and the worst one for running procedures: anything with fixed steps —charging, booking, logging an order— goes in a Function that the Met calls, with parameters the Function validates.

Both directions of the combination

directionhowwhen
flow → Metagent.ask for one step; agent.handoff to hand over the conversationthe process is fixed and one of its steps needs judgment or writing
Met → flowan AI Function with an HTTP handler or with flow_id; the flow returns its result with the function.result nodethe Met converses and, at some point, has to run something it cannot improvise

In the second direction, the Function's parameters are the contract: with enum_values the Met can only send one of the values you allowed, and what happens next is decided by your flow or your backend, not by the model.

What each thing costs

Logic, data and messaging nodes spend no Energy. Conditions, code, buttons, templates, waits, loops and CRM reads or writes run without a model. The nodes that spend are the ones that invoke AI: agent.ask, agent.handoff, agent.nudge, image.generate, image.edit, voice.generate, video.generate, and a flow.action node when one of its actions puts a Met to work. An mcp.call node does not go through a model, but the tool it calls may have its own cost, for example one that generates images.

What makes a Met expensive is not just its level. Every call to the model carries its instructions and the definition of all its active tools, even when the turn is trivial: a Met with a long prompt and dozens of tools pays for that context to write one sentence. The part of the context that repeats is charged less when it comes from cache, but it is not free. And the level multiplies all of the above.

Routing costs too. A Run without met is handled by the workspace's main Met, which can delegate to another Met: two executions where one would do. With met, the Run goes straight to that Met, without going through the orchestrator.

How to measure it: GET /billing/executions filters by met_id and by run_id, and totals adds up the whole filter (What each call costs). There is no per-flow cost in the API today, so use a trick: give your flow's AI step its own Met. Filtering by that met_id tells you exactly what that step costs, run by run.

Levels

Each Met has a level, chosen with model when you create or edit it (Mets and their tools):

modelfor what
agilfast and the one that spends the least Energy per answer: classifying, extracting, writing a short sentence, answering what is already in its instructions
brillantethe everyday one: handling people, combining data, writing with judgment
genioreasons more and spends more: decisions with many variables, long and delicate texts
await met.agents.update(writerId, { model: 'agil' });

The practical rule: agile for bounded tasks. If the task fits in a two-line instruction and a one-sentence answer, raising its level does not make it better; it only makes it more expensive. The image and video nodes in a flow pick their own level; agent.ask uses the Met's.

Bounded context

The less context a Met loads, the less each turn costs and the fewer ways it has to drift:

Control the output

A model can return something reasonable but wrong. Before its output reaches a customer, a flow checks it without AI:

  1. Validate with code. flow.condition compares values but does not measure lengths or look for patterns, so the validation goes in a data.code that returns a yes or a no, and the condition reads it:

js // Input data: {"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 };

Then, a flow.condition with @{node:validar.result.ok} equal to true.

  1. Keep a fixed fallback. The "Si no" (else) branch sends text you wrote. If the model fails, the contact gets something correct instead of nothing or something odd.
  2. Whatever publishes, charges or sends goes through a person. When a Met asks to post on social media, charge, invoice, spend ad budget or send a template that Meta bills, the action can wait for someone in the business to approve it (Human approvals). A flow has no approval node: what it sends on its own goes out unreviewed, which is why it has to be fixed text or validated output.
  3. Narrow what the Met can ask for. In a Function, enum_values and required parameters make what reaches your backend have the shape you expect.

End-to-end example: replying to comments

This is the pattern Meteor uses to reply to comments on its own posts: when someone comments the keyword, they get the information by private message, a short public reply and a "Like". Only one of the six steps uses AI.

stepnodewhat it doesspends Energy
1trigger.start with the social.comment_received triggerstarts on a new comment on the chosen account that contains the keyword (contains, case-insensitive)no
2mcp.call → meta_reply_to_comment_privatesends a fixed private text with the information and the linkno
3mcp.call → meta_like_commentlikes the comment (Facebook only; skipped on Instagram)no
4agent.askasks the writer Met for one sentence to reply in publicyes
5data.code + flow.conditionvalidates the sentence: that it exists, that it is at most 120 characters and that it has no linksno
6mcp.call → meta_reply_to_commentposts the validated sentence or, through the "Si no" (else) branch, a fixed fallback textno

The comment's data arrives in the trigger: @{trigger.payload.comment_id}, @{trigger.payload.comment_text}, @{trigger.payload.platform} and @{trigger.payload.account_id}. Each comment is claimed before the flow runs, so the same comment never triggers it twice.

The instruction for step 4 fits in three lines:

Write a public reply of a single warm sentence, at most 120 characters,
with no links or contact details, for this comment: @{trigger.payload.comment_text}

The writer Met runs on agil, with brief instructions about the brand's tone and its tools switched off with disabled_tools. What is at stake with AI is small —one sentence— and even so it does not go out without passing validation.

Routines are this same pattern

Met's Routines —create and post on social media, advertise what you sell, follow up with your customers— are built this way inside:

FAQ

Does a flow with no AI steps spend Energy?

No. Logic, data and messaging nodes do not invoke a model. Watch out for what does cost outside of Energy: a WhatsApp template outside the 24-hour window is billed by Meta.

Can I choose the level of an agent.ask node?

Not per node: the step uses the level of the Met you pick. If you need one step on agile and another on brilliant, use two Mets.

When is an isolated Run better than agent.ask?

When you call from your backend and the task is a single extraction or classification over a text or a document. The isolated Run loads no tools or context; agent.ask runs inside a flow and the Met does it with everything it has.