Skip to content

5 Design Patterns for Building AI Agents (And When to Use Each)

ReAct, Plan-and-Execute, Reflection, Tool Use, and Multi-Agent — what each AI agent pattern looks like, when it fits, where it bites, plus a starter checklist for a typical project.

From ReAct to multi-agent: what each pattern looks like, where it fits, and where it bites.

Ask someone to write their first agent and you'll usually get the same thing: a while loop. Send the question to the model, take the answer, feed it back in, repeat until the model says "done."

Five rounds later it's still going in circles.

That's not a coding problem. It's that nobody told them agents already have established skeletons — the same way someone who's never met a design pattern can ship working business logic that falls apart the moment it gets complicated.

Five patterns cover most of what you'll actually build. Here's what each one looks like, when it fits, and where it bites.


1. ReAct: think a step, do a step

In one line: think, act, look at the result, think again. Not all the thinking up front, and not head-down execution either.

Each pass through the loop produces three things:

  • Thought — what I know now, what to do next
  • Action — which tool, with what arguments
  • Observation — what the tool actually returned
while not done and step < max_steps:
    thought = llm.think(history)     # what should happen next
    action  = llm.decide(thought)    # pick a tool + fill args
    obs     = run_tool(action)       # actually run it
    history.append(thought, action, obs)

Where it fits: questions the model can't answer from memory and has to look up across several steps. "Who were our three highest-paying customers last month, and when do their contracts renew?" The model doesn't know. It has to go find out.

Where it bites: it gets stuck in loops. Hand it an error it hasn't seen and it will retry the same action until the tokens run out. max_steps isn't optional. And feed the Observation back raw — if you pre-process it, the model stops seeing what actually happened.


2. Plan-and-Execute: make the list first

The move: split planning from execution. Have the model break the task into steps, then walk them one at a time.

plan = planner.decompose(task)      # ["read the code", "change the signature", "add tests", "run lint"]
for step in plan:
    result = executor.run(step, context)
    context.update(result)
    if result.failed:
        plan = planner.replan(plan, step, result)   # drifted? re-plan

Where it fits: long tasks with many steps and dependencies between them. Refactoring a module, batch-editing a set of files, migrating data across systems.

A side benefit: it's cheaper. Planning needs your strongest model. Each execution step is simple enough for a cheap one.

Where it bites: if the plan drifts, plain Plan-and-Execute won't correct itself. That replan call above looks like a nice-to-have. It isn't.


3. Reflection: make it fix its own work

The move: generate → critique → revise, a few rounds. Let the model review its own draft until it holds up.

draft = generator.write(task)
for round in range(3):
    critique = critic.review(draft, rubric)   # find faults against the standard
    if critique.is_good_enough:
        break
    draft = generator.revise(draft, critique)

Where it fits: tasks where the output has a clear standard. Writing code (does it compile, do tests pass), writing copy (does it hit forbidden phrases), translating (are the terms right).

Where it bites: with no objective standard, the model drifts into self-congratulation — revising until it's more convinced than ever that the first draft was fine. So rubric has to be something verifiable: run the tests, run the linter, check the glossary. Let a machine give the feedback; don't let the model grade itself.


4. Tool Use: move capability outside the model

The point: the model doesn't answer directly. It says "call this function with these arguments," and your code does the actual work.

tools = [{
    "name": "query_order",
    "description": "Look up an order by phone number. Use when the user asks about order status; do NOT use for refund policy questions.",
    "parameters": {...}
}]

You need this almost everywhere: live data, deterministic math, touching external systems. Don't let it do arithmetic in its head. Don't let it guess the weather.

An easy detail to miss: the tool description is the prompt, and it's the part most often written badly. Describing when to use a tool isn't enough — describe when not to. The second half of that description above kills a large share of misfired calls.

Where it bites: accuracy drops as the tool count grows. Past about ten it gets noticeably worse — mount tools per scenario instead of passing everything in at once.


5. Multi-Agent: divide the work, don't make one agent do everything

The idea: instead of one agent carrying the whole job, split it into roles that coordinate through messages. Planner + executor + reviewer is the usual shape.

Where it fits: work that splits cleanly into specialties, or that benefits from different perspectives pushing back on each other. A research report: one agent searches, one writes, one looks for holes.

Where it bites, and I'll be blunt: token cost typically runs 3–10× a single agent, and debugging difficulty is exponential. When two agents start blaming each other, you can't tell which one is broken.

My rule of thumb: if one agent with a good prompt can do it, don't build a multi-agent system. Most projects that claim to need one just have a lazy prompt.


How to choose

Your situationUse
Answer needs multi-step lookup, path is uncertainReAct
Long task, many steps, dependencies between themPlan-and-Execute
Output has an objective standard, worth polishingReflection
Needs live data or touches external systemsTool Use
Work splits cleanly into specialtiesMulti-Agent

In practice these stack. A support agent runs Tool Use at the bottom, ReAct as the main loop, a Reflection pass after the draft, and switches to Plan-and-Execute when a ticket gets complicated.


Appendix: the agent checklist for a typical project

Patterns covered. Now the question nobody answers: what does my project actually need? Here's a checklist you can copy.

Start with these, nothing more

  • One agent + a ReAct loop — don't split into multiple agents on day one
  • 3 to 5 tools — each description says when not to use it
  • A hard max_steps cap — stops spinning, stops burning tokens
  • Structured output — constrain with JSON Schema or Pydantic; don't parse free text
  • Full-trace logging — record the Thought / Action / Observation of every step

Picking an SDK or harness

First, the distinction: an SDK is a library you embed in your own product; a harness is a runtime that already handles files, terminals, and permissions. Start with an SDK for a typical project. If what you want is the latter, these three are worth a look in 2026.

SDKs (embed in your product — pick by your main model)

  • OpenAI Agents SDK — four primitives: agents, handoffs, guardrails, tracing, with sessions managing history automatically. Still 0.x (0.18, July 2026) but shipping constantly; since April 2026 it has native sandbox execution and enforced structured output. Despite the name it reaches 100+ non-OpenAI models through LiteLLM, and there's a separate JS/TS version.
  • Claude Agent SDK — this packages the same runtime that powers Claude Code, so you get an agent loop that's already been hardened in production as a library: hooks to intercept points in the loop, in-process MCP so tools don't need subprocesses, and granular tool permissions. Python 3.10+ and TypeScript.

Harnesses (runtimes that work out of the box)

  • Eve (Vercel) — "a folder is an agent": instructions.md for the system prompt, tools/ for TypeScript tools, skills/ loaded on demand. It checkpoints every step, so a crash or redeploy resumes where it left off; approval gates, Slack/Discord/GitHub channels, and cron schedules are all built in. Apache 2.0, released June 2026. The tradeoff: durable execution and sandboxing are tied most tightly to Vercel's platform.
  • Pi — a deliberately minimal agent harness from Earendil (Mario Zechner), TypeScript + MIT, at pi.dev. The position is extreme: ship primitives, you assemble the features. The docs list what they didn't build — no sub-agents, no plan mode, no permission popups, no built-in todos, no background bash, and not even MCP. Want one? Write a TypeScript extension, or pi install someone's package. The system prompt is minimal too, with AGENTS.md / SYSTEM.md and on-demand skills for context management. 15+ providers, switchable mid-session; sessions are trees you can branch from any point. Four ways to use it: interactive TUI, pi -p for scripts, RPC, or as an SDK inside your own app — OpenClaw runs on it. (Careful: this is not Inflection's chatbot Pi. Same name, different thing.)
  • DeepSeek Harness (dsh) — open-sourced by DeepSeek in August 2026, MIT, command is dsh. Underneath is the Cordis plugin framework and a strict "everything is a plugin" rule: models, tools, skills, sessions, sandboxes, storage, and the agent loop itself are all swappable. Since rc.8 it can drive Codex and Claude Code as sub-agents.

One warning: all three are young — Eve is in public beta, Pi moves fast, and dsh is a developer preview (0.1.0-rc, session format still at v0, so old sessions won't read after an upgrade). Fine to try; put them on a non-critical path before you trust them in production.

Before you ship, check these

  • Does every tool description say when not to use it?
  • Single steps retry; total failure has a fallback (hand off to a human or return a safe answer)
  • Each session has a token/cost ceiling
  • No dead history piling up in the context
  • You can explain how this result was reached

Two last things

Patterns are skeletons, not silver bullets. What actually decides whether an agent is good is usually boring: are the tool descriptions precise, is there a fallback when things fail, is the context full of junk.

If an agent you're running doesn't behave, don't reach for more complexity first. Step back and look at which problem it is — no skeleton at all, or a skeleton that's built but not finished.

Those two need completely different fixes.


*What's the deepest hole you've fallen into building an agent? *