Agent Patterns Cheat Sheet
A one-page reference for the architectural patterns covered in this course. Keep it open while you build. For deeper treatment see Agent Architectures and Building Your First Agent.
Vocabulary
| Term | Meaning |
|---|---|
| Step / turn | One model call plus any tool execution it triggers |
| Trajectory | The full sequence of steps from goal to final answer |
| Tool call | The model's request to run a named function with arguments |
| Observation | The result of a tool call, fed back to the model |
| Stop condition | Rule that ends the loop (final answer, budget hit, error cap) |
The Canonical Agent Loop
Every architecture below is a variation on one core loop: think, act, observe, repeat until done. In compact pseudocode:
function run_agent(goal, tools, max_steps):
history = [system_prompt, goal]
for step in 1..max_steps:
response = model.call(history, tools)
if response.has_tool_calls():
for call in response.tool_calls:
result = execute(call.name, call.args) # may raise
history.append(tool_result(call.id, result))
else:
return response.text # final answer
if over_budget() or too_many_errors():
return abort("stop condition hit")
return abort("max_steps exceeded")
The differences between patterns are where the reasoning happens and whether the agent revisits its own work.
Pattern Comparison
| ReAct | Plan-and-Execute | Reflexion | |
|---|---|---|---|
| Shape | Interleave reason + act each step | Plan all steps up front, then execute | Act, then self-critique, then retry |
| Reasoning | Inline, one step at a time | Front-loaded into a static plan | After-the-fact on a failed/weak result |
| Best for | Open-ended, exploratory tasks | Multi-step tasks with clear structure | Tasks with a checkable success signal |
| Latency | Low per step, can run long | Higher up front, fast execution | Highest (extra critique passes) |
| Token cost | Moderate | Moderate, predictable | High (repeated attempts) |
| Pros | Simple, adaptive, easy to debug | Parallelisable steps, fewer dead ends | Recovers from mistakes, higher quality |
| Cons | Can loop or wander | Brittle if the world changes mid-plan | Slow and expensive; needs an evaluator |
| Failure mode | Gets stuck repeating an action | Executes a plan that no longer fits | Critiques without improving (thrash) |
When to pick which
| Situation | Pattern |
|---|---|
| "Find X by exploring tools/data" | ReAct |
| "Do these N known steps in order" | Plan-and-Execute |
| "Get it right; we can verify the result" | Reflexion |
| Long task whose steps depend on findings | ReAct, or Plan-and-Execute with re-planning |
| Cost-sensitive, latency-sensitive | ReAct (cap max_steps tightly) |
ReAct in One Block
Reasoning and acting interleaved. The model emits a thought, takes one action, sees the observation, then repeats. With native tool use the "thought" lives in the model's text and the "action" is a tool call.
loop until final answer or budget hit:
thought = model reasons about what to do next
action = model calls one tool
observation = execute(action)
append (thought, action, observation) to history
Plan-and-Execute in One Block
Separate the planner (one call that decomposes the goal into ordered sub-tasks) from the executor (a small ReAct loop per sub-task). Re-plan only when a step fails.
plan = planner.call(goal) # -> ["step 1", "step 2", ...]
results = []
for step in plan:
r = execute_subtask(step, tools) # mini agent loop
results.append(r)
if r.failed:
plan = planner.replan(goal, results) # optional recovery
synthesize(results) -> final answer
Reflexion in One Block
Add an evaluator and a memory of past attempts. The agent tries, gets scored or critiqued, writes a lesson to memory, and retries with that lesson in context.
for attempt in 1..max_retries:
result = base_agent.run(goal, reflections)
verdict = evaluator(result) # pass/fail + critique
if verdict.passed:
return result
reflections.append(verdict.critique) # carried into next attempt
return best_so_far(results)
Minimal Tool Definition (Claude Tool Use)
A tool is a name, a description the model reads to decide when to use it, and a JSON Schema for its arguments. Write descriptions for the model, not for humans — they are prompt.
weather_tool = {
"name": "get_weather",
"description": (
"Get the current weather for a city. "
"Use when the user asks about temperature, rain, or conditions. "
"Returns temperature in Celsius and a short summary."
),
"input_schema": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "City name, e.g. 'Berlin' or 'Tokyo'.",
},
},
"required": ["city"],
},
}
Wire it into a request and dispatch the tool call:
import anthropic
client = anthropic.Anthropic()
resp = client.messages.create(
model="claude-sonnet-latest",
max_tokens=1024,
tools=[weather_tool],
messages=[{"role": "user", "content": "What's the weather in Berlin?"}],
)
if resp.stop_reason == "tool_use":
for block in resp.content:
if block.type == "tool_use":
result = get_weather(**block.input) # your function
# Send the result back as a tool_result block to continue the loop
Tool Design Checklist
| Rule | Why |
|---|---|
| One clear job per tool | The model picks better between focused tools |
| Description states when to use it | The description is the selection prompt |
| Type and constrain every argument | Schema validation catches bad calls early |
| Return structured, compact results | Saves context; easier to reason over |
| Return errors as data, not exceptions | Lets the agent recover instead of crashing |
Stop Conditions (always set these)
| Guard | Typical default |
|---|---|
max_steps |
10-25 per task |
| Token / cost budget | Hard cap per run |
| Wall-clock timeout | Per run and per tool call |
| Repeated-action detector | Abort if same call repeats N times |
| Consecutive-error cap | Abort after 3 failed tool calls |
See Also
- Tool Reference — full schemas and MCP details
- Glossary — terms used across the course
- Troubleshooting — common loop and tool-call failures
- Agentic AI course home — all lessons