Index Ai Academy
Phase 1 · Building with LLMs · Tools & agents

Agent design patterns

Routing, orchestrator-workers and when not to build an agent.

About 30 minutes · A free account opens the whole lesson

Create a free account Try part of it here

Already have an account? Sign in to open this lesson

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

  1. Workflows and agents
  2. Routing in code
  3. When more agents don't help
  4. Voting with a safety rule
  5. Start with the simplest thing that works
  6. 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

PatternShapeMarketing example
Prompt chainingFixed sequence; each step's output feeds the next, with checks betweenBrief → outline → draft → brand check
RoutingSort the input, send it to a specialized prompt or modelInbound email → returns / wholesale / order status handler
Parallelization: sectioningIndependent subtasks run at the same time, then combineCheck one ad for brand voice, legal claims and SEO in three parallel calls
Parallelization: votingSame task several times; take the majority or flag disagreementAsk three times "does this ad make a health claim?"; escalate if any say yes
Orchestrator-workersA model splits the task into subtasks as it goes, and hands them out"Research our five competitors' pricing pages" → one worker per competitor
Evaluator-optimizerOne call drafts, another critiques against a checklist, repeat until it passesProduct description revised until it meets the voice guide
AgentThe 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.

Quick check
"Check one ad for brand voice, legal claims and SEO", each check independent of the others. Which pattern fits?
  1. An autonomous agent
  2. Voting: run the same check three times
  3. Parallelization (sectioning): three checks at the same time, then combine
  4. Prompt chaining: each check waits for the one before
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.

Try it now

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])
It runs right here in your browser, with nothing to install.

How it works:

  • classify checks the message for telltale words, in order, and returns a category.
  • HANDLERS maps each category to what happens next. A lambda is 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.

Quick check
What does this print?
routes = {"refund": "billing", "login": "support"}
topic = "refund"
print(routes.get(topic, "general"))
  1. support
  2. general
  3. refund
  4. billing
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.

Worked example

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")
In the lesson you can change this and run it.

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.

Quick check
Every weekday you turn a campaign export into a three-section summary, always the same sections. Which design fits best?
  1. A prompt chain (or one well-structured call): the steps are fixed
  2. Orchestrator-workers with one worker per section
  3. Voting across five models
  4. An autonomous agent with many tools
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.

Quick check
"Find out why our return on ad spend dropped last week" could involve any of a dozen data sources. Which design fits?
  1. A single prompt with no tools
  2. An agent: the steps depend on what each lookup finds
  3. Routing to one handler
  4. A fixed prompt chain
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:

  1. One prompt. Many features need nothing more.
  2. A fixed chain. If the steps are known, write them in code. It's cheaper, faster and far easier to debug.
  3. 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.
  4. 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

Create a free account

Try a quiz question

What's the key difference between a workflow and an agent?

  1. In a workflow your code fixes the steps; in an agent the model chooses them
  2. Agents can use tools, and workflows can only pass text between their steps
  3. Workflows make one model call, and agents make as many calls as they need
  4. Agents are always more accurate, because they can check their work and retry

Answer it at the end of the lesson to see if you're right, and why.

Before this lesson