Skip to main content

Agent node recipes

Almost every Agent node you build is one of two things: a step that works out where the conversation goes, or a step that collects something and moves on. Both are below in full - what to set, what to write, and how each finishes - followed by the two wired together and what to do when neither fits.

They're examples to copy rather than a catalogue to search. Start from the closest one and change what doesn't fit. For what an individual setting does: the prompt, capabilities, exits, settings.

What you write, and where

A node's behaviour comes from three fields, answering three different questions:

FieldAnswersKeep it
GoalWhat does done look like? The outcome, not the procedureUnder 500 characters
InstructionsHow does it get there?As short as the job allows
Exits (drawer)What are the ways out, and what does each mean?Two to five branches

Exits appear twice in each recipe below, and that's deliberate rather than duplication: the drawer holds each branch's name and description; the Instructions hold the sentence that causes it. A branch configured in the drawer with nothing in the prompt pointing at it never fires - which is why max_retry so often does nothing.

How to structure the instructions

Two headings do the work, and a third only when the order is genuinely fixed:

HeadingWhat belongs there
## RulesYour business constraints, and how to use each tool
## ExitsEach branch, and the sentence that causes it
## StepsOnly when the order can't move - and numbering them Step 1, Step 2 switches the node into sequential execution

The full rules - including what the platform already put in your prompt, and the three levels of step numbering - are in Writing instructions. The two recipes below demonstrate both sides: Clarify and branch has no Steps section because its order is conditional, and Collect and validate numbers its steps deliberately.

Four rules behind both recipes

  • Every exit needs a sentence that reaches it. Walk your exits list and find the instruction that causes each one. max_retry is usually the orphan.
  • Tell the node whether to speak on the way out. Most steps should exit silently so the next one opens cleanly; the exceptions are the ones whose job is to say something.
  • Write the failure path. The happy path is easy to imagine and easy to test. The tool-is-down path is neither, and it needs a branch of its own.
  • One job per node. If you find yourself combining both recipes, that's two nodes.

Clarify and branch

Use when the flow needs to know which way to go, and the customer's first message might not settle it.

This is the step that asks a question only if it has to, optionally looks something up, and then hands off. It resolves nothing itself.

Setting
Rich mediaQuick replies
ToolsA lookup, if the decision depends on one
VariablesNone
BehaviourExit without a reply on

Goal

Establish whether the customer's issue is about billing or about the product
not working, so the conversation reaches the right team.

Instructions

## Rules
- If it's already clear which exit fits, finish on it without asking anything.
- If it's ambiguous between two, ask one short question that separates them and
offer @Quick Replies with those options.
- If they mention a specific charge or invoice, call @Look Up Account first -
which exit is right depends on what it returns.
- One question per turn, and never more than two in total.
- Report only what @Look Up Account returned. Never guess what the account holds.
- Do not try to resolve the issue. Your job ends once you know where it goes.
- Send no message on the turn you exit.

## Exits
- Finish on `billing` for a charge, an invoice, or a refund.
- Finish on `technical` when the product or app isn't working.
- If the request is about neither, finish on `out_of_scope` - don't try to help
with it.
- If two questions still haven't settled it, finish on `unclear` rather than
guessing.

Exits

BranchDescription
billinga charge, an invoice, or a refund
technicalthe product or app isn't working
out_of_scopethe request is about neither
uncleartwo questions haven't settled which it is
on_erroralready present - wire it to a handover

Why it works. No variable is written, because the decision is the exit - each branch already leads to the node that knows what to do, so storing it duplicates the wiring. Exiting silently lets the next node open cleanly.

The "do not try to resolve the issue" line is doing more work than it looks. Without it a helpful model starts answering the billing question itself, and the node quietly becomes two nodes.

Watch out for. Exit descriptions that overlap - that's what makes this kind of node feel random. And unclear needs its instruction as well as its branch, or it can never fire.


Collect and validate

Use when the flow needs two or three specific values, and a wrong one is worse than none.

Setting
ToolsThe validating lookup
VariablesEach value (Agent fills this, with a description)
BehaviourExit without a reply on

Goal

Confirm the customer's identity from their policy number and registered mobile
number, so a claim can be registered against the right policy.

Instructions

## Steps
- Step 1. Ask for the policy number. It must be 10 digits.
- Step 2. Ask for the registered mobile number.
- Step 3. Call @Verify Policy with both. It returns the policy holder's name,
or no match.
- Step 4. Read the name back and ask them to confirm it's them.

## Rules
- One question per turn. Don't ask for both numbers together.
- If a number is the wrong length, say which part is wrong and ask again - do
not call the tool with it.
- Write policy_number and mobile_number only once they've passed validation.
- If @Verify Policy returns no match, say the details didn't match and ask them
to re-check the policy number. Don't imply they gave you false details.
- If @Verify Policy fails to respond or returns an error, that is not a failed
check. Say you can't verify right now, and finish on
`verification_unavailable`. Never count it as one of their attempts.

## Exits
- Finish on `verified` once @Verify Policy has returned a name and they've
confirmed it.
- After three failed attempts at either number, or two genuine no-match
results, finish on `max_retry`.

Exits

BranchDescription
verifiedthe policy holder's name was returned and confirmed
max_retry3 failed attempts at a number, or 2 no-match results
verification_unavailable@Verify Policy could not be reached
on_erroralready present - wire it to a handover

Why it works. The steps are numbered because the order genuinely can't move - you can't verify before you've collected. That numbering also turns on sequential execution, which is working with this node rather than against it.

Validation happens twice, at two different costs: format is checked before the tool call (a 9-digit number never reaches @Verify Policy), and identity is checked by the tool. Getting that order wrong means paying for a call you already knew would fail.

A tool failing is not a negative result. "No match" and "the service is down" look identical to a prompt that doesn't separate them - and conflating them tells a customer with perfectly valid details that their details are wrong, then spends their retry budget proving it. That's why verification_unavailable is a third branch rather than a rule. Note you have to write it: a tool erroring does not route to on_error - the agent is told and carries on inside the step - so a system-failure path exists only if you create one.

Each variable's description is what the agent uses to decide what counts as a valid value - "the 10-digit policy number printed at the top of the schedule" does real work there.

Watch out for. Leaving a variable read-only. Nothing is written, nothing warns you, and the failure surfaces in a later node - the single most common mistake with variables. The limit is five writable per node, and a node collecting five separate things is usually several nodes.

And note the retry budget is one sentence covering the whole node. Two or three separate counts in prose is the signal that this should be two or three nodes.


The two, wired together

The pair covers most flows between them: work out where this is going, then collect what that path needs.

Two things worth noticing. triage-issue writes no variable - its exit carries the decision. verify-identity writes two, because the billing flow downstream needs the policy number, and an exit can't carry a value.

That's the rule of thumb for the whole flow: anything a later node needs is a variable; anything only this node's routing depends on is an exit.

Notice too that three different endings all land on the same handover. That's fine - separate branches that share a destination still tell you from the logs which one happened, and you can split them later without rewriting the node.

When neither fits

Most nodes that match neither recipe turn out to be one of three things:

  • Two nodes. If you're deciding and collecting in one step, that's usually why it feels hard to write. Split it and each half becomes one of the recipes above.
  • Not an Agent node at all. If there's no conversation - a lookup, a calculation, a record update - an Execute Workflow node is cheaper and can't drift. If the whole job is handing over, that's Transfer to Agent.
  • A step whose only job is to say one thing. Give it a response exit and no branches. If you're building a node with a single branch called done, this is what you wanted.

A good test for the second one: if you can't name what the agent would say, it probably isn't an Agent node.

Variations

Changes you make to either recipe above.

Run one cheaply

Use when a narrow, high-volume step doesn't need your strongest model.

Setting
Model configurationOverride on, a smaller model
BehaviourConversation history off
VariablesNone

Take Clarify and branch, then change those two things.

Why it works. A step choosing between two or three clearly-different outcomes is the cheapest thing a model does. On a step every conversation passes through, that saving is real. Turning conversation history off makes it cheaper still and more repeatable, since the step only needs the current message.

Watch out for. The failure mode disguises itself. A weaker model on nuanced branch descriptions starts picking wrong, and the symptom is bad routing - which looks like your descriptions are wrong. You can lose an afternoon rewriting prompts to fix a model change.

Change the model on its own, test that node's routing specifically, and treat new flakiness as caused by the change until proven otherwise. Two obvious branches tolerate a small model; four subtle ones often don't. Note also that the override isn't versioned, so there's no record of when it changed.


Make one voice-safe

Use when the same flow serves chat and phone calls.

Setting
Channel overridesEnd-of-turn silence raised, keypad capture on, boost phrases
Rich mediaAttach if you like - it does nothing on voice
First responseUseful here, for a scripted opener

Take Collect and validate - digits are where voice actually breaks - and add to its Rules:

## Rules (voice)
- Read digits back in groups of three or four, then ask them to confirm.
- If they spell something out, confirm it letter by letter using common words.
- Never read more than three options aloud.
- On chat, offer @Quick Replies where there's a shortlist to choose from.

Why it works. The instructions stand on their own without the buttons, so the chat customer taps and the caller hears the options. Rich media is skipped entirely on voice - it doesn't fail, it just silently doesn't happen - so a step designed around chips degrades to a step that talks.

The channel overrides earn their place here specifically: a longer end-of-turn silence, because people pause while reading digits off a card; keypad capture, so they can key the number instead of saying it; and boost phrases for any product names in the exchange.

Watch out for. Writing "tap the button below" into instructions shared with voice. Nothing warns you, and the caller is told to tap something that isn't there.


Read next: The Agent node · Exits · Test a multi agent