AI Router
Route messages to named branches with an LLM.
The ai-router block asks an LLM to pick exactly one of several named,
described routes for each message. Use it where the routing decision needs
judgment (triaging tickets, classifying inbound email, dispatching webhooks by
intent) and a switch condition would be brittle.
A complete example
This flow triages support tickets to a team:
service:
name: ai-router
env:
- name: ANTHROPIC_API_KEY
required: true
connectors:
- name: claude
type: llm-anthropic
settings:
apiKey: ${ANTHROPIC_API_KEY}
flows:
- name: triage
process:
- type: ai-router
name: triage-ticket
connector: claude
prompt: >
Read the support ticket in the message body and route it to the team
best suited to handle it.
guardrail: >
If the ticket is ambiguous, spans multiple areas, or you are not
confident, take the default (human triage) path.
routes:
- name: billing
description: Payment failures, refunds, invoices, subscription changes.
process:
- type: set-payload
settings:
value: '{"team": "billing"}'
- name: technical
description: Bugs, outages, API errors, integration problems.
process:
- type: set-payload
settings:
value: '{"team": "technical"}'
default:
process:
- type: set-payload
settings:
value: '{"team": "human-triage"}'octo invoke --config samples/ai-router.yaml --flow triage \
--data '{"subject":"I was double charged","body":"Please refund the extra charge."}'
# -> {"event_id":"…","body":{"team":"billing"}}
Like ai-agent, ai-router is a composite: its keys sit at the top level
of the block.
How it decides
Each route's name and description are listed in the model's system prompt;
the description is the routing contract, so write it precisely. The model gets
read-only inspection tools (get_body, list_variables, get_variable) to
look at the message, then calls a select_route tool whose argument is
constrained to the configured route names. The chosen route's process chain
runs on the message. The decision loop is capped at 5 model calls; a model that
inspects without deciding falls through to the guardrail.
Guardrail and default
guardrail describes when the model should decline to pick a route;
default is the flow that runs when it does, or when it never decides. Give it
a real escape hatch such as a human-triage queue.
With no default configured, the guardrail passes the message through
unchanged, the same behavior as a switch with no default branch.
Choosing between switch, ai-router, and ai-agent
| Block | When |
|---|---|
switch | The condition is computable: a field value, a status code, a CEL expression. Deterministic, free, instant. Prefer it whenever you can write the condition. |
ai-router | The condition needs judgment over unstructured content, but the outcome is one decision: pick a branch, run it, done. |
ai-agent | The task needs multiple steps: gather data with tools, reason over results, produce an answer. An agent loops; a router decides once. |
A common composition is a router in front of agents: cheap single-decision triage first, and only the routes that need multi-step work pay for an agent. Full field tables: AI Blocks reference.