Multi-agent
Router
One call picks the specialist; only that one runs.
A router reads the request once and sends it down exactly one branch. The specialists never see requests that are not theirs, and the branches that are not chosen cost nothing.
The choice can be a model call, as here, or plain code (keywords, a classifier). Either way the paths are fixed in the graph, so the run is easy to predict and test.
- Use it when
- Clear categories of request
- Specialists with different tools or permissions
- Predictable cost: one routing call plus one branch
- Skip it when
- A request needs several specialists (Supervisor)
- Categories overlap heavily
Run it
Scripted model · no key needed · CriogenAI engine in your browserThe runmodel 0 · tools 0
- Press Run to watch the pattern work, step by step.
Try it with your own key optional: a real model makes the decisions; the tools stay simulated
- Your key stays in this tab's memory: not saved, not in cookies or the address bar. Reload or close the tab and it is gone.
- Your browser calls OpenAI directly. Nothing passes through criogenai.com, and nothing is logged.
- Each run makes at most 16 short model calls, billed to your account. Tools, data and side effects are simulated.
This run is the TypeScript code below, running on the CriogenAI engine in your browser (WebAssembly). Without a key, a scripted model stands in for MODEL; with your key, your provider answers, called from this tab. The tools return made-up data.
Build it with CriogenAI
Built from primitives:Workflow.routeclass Route(BaseModel):
team: str # "billing" | "technical" | "sales"
classify = Agent(MODEL, instructions="Classify the request: billing, technical or sales.", output=Route)
teams = {name: Agent(MODEL, instructions=f"You are the {name} support specialist.") for name in ("billing", "technical", "sales")}
async def route(state: Dict[str, Any]) -> Dict[str, Any]:
return {"team": (await classify.run(state["input"])).output.team}
wf = Workflow()
wf.add_node("route", route)
for name, agent in teams.items():
wf.add_node(name, agent) # an agent node reads and writes `messages`
wf.edge(name, END)
wf.start("route").route("route", lambda s: s["team"], {n: n for n in teams})
result = await wf.compile().run({"input": "I was charged twice", "messages": [{"role": "user", "content": [{"type": "text", "text": "I was charged twice"}]}]})const teams = ["billing", "technical", "sales"] as const;
const classify = new Agent<{ team: (typeof teams)[number] }>({
model: MODEL,
instructions: "Classify the request: billing, technical or sales.",
output: { type: "object", properties: { team: { enum: [...teams] } }, required: ["team"] },
});
const wf = new Workflow().node("route", async (state) => ({ team: (await classify.run(String(state.input))).output?.team }));
for (const name of teams) {
wf.addNode(name, new Agent({ model: MODEL, instructions: `You are the ${name} support specialist.` })); // reads and writes `messages`
wf.edge(name, END);
}
wf.start("route").route("route", (s) => String(s.team), Object.fromEntries(teams.map((n) => [n, n])));
const result = await wf.compile().run({ input: task, messages: [{ role: "user", content: [{ type: "text", text: task }] }] });