Agent design patterns
Routing, orchestrator-workers and when not to build an agent.
Create a free account Try part of it here
Why it matters
"Let's build an agent" is often the wrong first move. Most successful AI features are a single well-written prompt, or a few prompts wired together in a fixed order. A handful of named patterns cover nearly every design. Knowing them lets you pick the simplest one that works. Simpler is cheaper, faster, easier to test, and easier to explain to the people who rely on it.
What you'll be able to do
- Tell workflows (code decides the steps) from agents (the model decides)
- Choose between chaining, routing, parallelization, orchestrator-workers and evaluator-optimizer
- Implement routing, voting and an evaluator-optimizer loop
- Argue for the simplest design that meets the goal
What it covers
- Workflows and agents
- Routing in code
- When more agents don't help
- Voting with a safety rule
- Start with the simplest thing that works
- Measure first
Workflows and agents
Think of a recipe versus a chef. A recipe lists the steps in order, and anyone can follow it. A chef looks in the fridge and decides what to cook. You want a chef for the unexpected. For your usual Tuesday dinner, the recipe is cheaper and more reliable.
Anthropic's engineering guide to building agents draws the same line:
- Workflows wire models and tools together along paths your code sets. You decide the steps, and the model does each one. That's the recipe.
- Agents let the model decide the steps, using tools in a loop until it's done. That's the chef.
Workflows are predictable and easy to test. Agents handle open-ended tasks whose steps can't be known in advance, but they cost more time, money and predictability. Start with the simplest option. Add complexity only when an eval shows it helps.
The patterns
| Pattern | Shape | Marketing example |
|---|---|---|
| Prompt chaining | Fixed sequence; each step's output feeds the next, with checks between | Brief → outline → draft → brand check |
| Routing | Sort the input, send it to a specialized prompt or model | Inbound email → returns / wholesale / order status handler |
| Parallelization: sectioning | Independent subtasks run at the same time, then combine | Check one ad for brand voice, legal claims and SEO in three parallel calls |
| Parallelization: voting | Same task several times; take the majority or flag disagreement | Ask three times "does this ad make a health claim?"; escalate if any say yes |
| Orchestrator-workers | A model splits the task into subtasks as it goes, and hands them out | "Research our five competitors' pricing pages" → one worker per competitor |
| Evaluator-optimizer | One call drafts, another critiques against a checklist, repeat until it passes | Product description revised until it meets the voice guide |
| Agent | The model picks tools in a loop | "Find out why return on ad spend dropped last week" |
Routing also saves money. Easy, high-volume categories can go to a small model, while hard ones go to a bigger one.
Show the answer
Parallelization (sectioning): three checks at the same time, then combine
The checks don't depend on each other, so running them side by side is faster than a chain, and simpler than an agent. Voting repeats one task; here there are three different tasks.
In a real system both functions call a model, and the critic uses the brand guide as its checklist. The loop stops when the critic has nothing to say, or after a fixed number of rounds. Here it prints 2 rounds: Stays dry on your commute.
Routing in code
A router is a classifier plus a dictionary of handlers. The classifier can be a keyword rule, a small model with structured output, or both: rules first, then the model for the rest.
import requests def classify(message): text = message.lower() if any(w in text for w in ["wholesale", "team", "units", "embroider", "stocking"]): return "wholesale" if any(w in text for w in ["return", "refund"]): return "returns" if any(w in text for w in ["arrived", "my order", "tracking"]): return "order_status" if any(w in text for w in ["ship", "deliver"]): return "shipping" return "other" HANDLERS = { "wholesale": lambda m: "→ sales team, with the wholesale price list", "returns": lambda m: "→ returns prompt, grounded in doc_returns", "order_status": lambda m: "→ order lookup tool", "shipping": lambda m: "→ shipping prompt, grounded in doc_shipping", "other": lambda m: "→ general assistant", } for lead in requests.get("https://api.gradient.test/v1/leads").json()["data"][:5]: category = classify(lead["message"]) print(f"{category:<13}", HANDLERS[category](lead["message"]), "|", lead["message"][:40])
How it works:
classifychecks the message for telltale words, in order, and returns a category.HANDLERSmaps each category to what happens next. Alambdais a tiny unnamed function written on one line.f"{category:<13}"pads the category to 13 characters, so the output lines up in columns.
Now every handler can have a short, focused prompt, instead of one giant prompt that tries to handle everything.
routes = {"refund": "billing", "login": "support"}
topic = "refund"
print(routes.get(topic, "general"))Show the answer
billing
"refund" is a key, so .get() returns its value, billing. The default, "general", only applies when the key is missing. Routing is often this simple: look up the category, with a safe default.
When more agents don't help
Multi-agent designs, with an orchestrator handing work to several workers, pay extra for planning, handoffs and merging results. They pay off when the job really splits into many independent pieces, especially more pieces than fit in one context window. When the work is one chain where each step depends on the last, or fits in one context, a single model usually does better for less.
A quick test: if you can't name what each worker does on its own, you don't need workers.
For marketers: describe the process the way you'd brief a team. "First this, then that, unless X" is a workflow, so build it as one. "Investigate and report back" is an agent.
Voting with a safety rule
You ask a model three times whether an ad makes a health claim. Two answers say no, one says yes. The majority says no. But for a risky question like this, one "yes" is enough to send it to a person.
votes = ["no", "no", "yes"] print(max(set(votes), key=votes.count)) print("escalate" if "yes" in votes else "ok")
It prints no (the most common answer), then escalate. For everyday questions you might go with the majority. For legal or health claims, any disagreement is a reason for a person to look. The rule you choose depends on which mistake costs more.
Show the answer
A prompt chain (or one well-structured call): the steps are fixed
Fixed, known steps are a workflow. An agent would add cost and unpredictability for nothing.
Show the answer
An agent: the steps depend on what each lookup finds
You can't list the steps in advance: each finding decides the next lookup. That open-endedness is what agents are for.
Start with the simplest thing that works
It's tempting to reach for an agent because agents sound capable. But every step the model decides for itself is a step you can't predict, test as easily, or cost in advance. So work up from the bottom:
- One prompt. Many features need nothing more.
- A fixed chain. If the steps are known, write them in code. It's cheaper, faster and far easier to debug.
- Routing. If requests fall into a few kinds, send each to a focused prompt. One giant prompt that handles everything tends to do each job a little worse.
- An agent. Use one only when the steps truly can't be known in advance.
Only move up when an eval shows the simpler version falling short. "It feels more advanced" isn't evidence, and a multi-agent system isn't automatically smarter. Each extra agent adds cost, delay and another place for errors to creep in. If each of three steps works 90% of the time, the chain works about 73% of the time. You'll measure that for yourself in a later phase.
Measure first
Add a step only when an eval shows that it helps.
Practice what you just read
- 2 code examples you can edit and run
- a practice exercise that checks your code
- a 5-question quiz
- 5 review cards for spaced repetition
Try a quiz question
What's the key difference between a workflow and an agent?