The pattern catalog
Before the end-to-end builds, one reference: every agentic pattern in one place, each with a diagram, a one-line "when," and a pointer to where the book uses it. The topology chapter covered multi-agent shapes; this catalog is broader, it includes the single-agent reasoning patterns, the reliability patterns, and the retrieval patterns too, so that the four capstone builds that follow can say "this uses reflection plus map-reduce plus a verifier panel" and you can look each up. Think of it as the vocabulary of agentic design; the builds are sentences in it.
Lab 14.1 implements the seven core control-flow patterns as runnable skeletons; the catalog below is the full set, families and all.
Family 1: single-agent reasoning
How one agent structures its own thinking.
ReAct (reason + act). The base loop: the model reasons, acts (calls a tool), observes the result, and repeats. Every agent in this book is ReAct at bottom (Chapter 7).
reason -> act(tool) -> observe -> reason -> ... -> answer
Reflection (self-critique). Generate a draft, critique it, revise. Cheap quality lift for a single agent; the seed of verification.
draft -> critique -> revise -> (repeat) -> output
Plan-and-execute. Plan the whole sequence first, then execute the steps. More token-efficient than re-deciding each step; good when the shape is knowable up front (the workflow end of the spectrum).
plan[s1,s2,s3] -> exec s1 -> exec s2 -> exec s3 -> done
Evaluator-optimizer. Generate, score against a bar, and if it falls short, retry with the score as feedback, looping until good enough. The single-agent cousin of the verification mesh.
generate -> score --below bar--> generate(+feedback) -> score --ok--> accept
Family 2: multi-agent orchestration
How several agents divide work. These are the topologies and the three idioms.
Orchestrator-workers (map-reduce). Split the task into independent units, run workers in parallel, merge. The workhorse; Capstones A, C, D.
orchestrator
/ | \
worker worker worker
\ | /
merge
Pipeline (crew). Role-specialists in sequence, each consuming the last one's output. Capstone C's extract-then-judge.
extract -> judge -> route -> ...
Handoff. An agent transfers control to a specialist it selects. Capstone B's triage.
triage --hands off--> specialist -> answer
Debate / judge panel (ensemble-vote). N agents attempt or critique the same item; a majority or judge decides. The verification mesh (Chapter 26); Capstones A and D.
finder --> [refuter, refuter, refuter] --majority--> keep / kill
Hierarchical delegation. Workers spawn sub-workers, recursively, under the parent's budget. For dynamically-decomposing problems (Chapter 22).
Blackboard. Agents react to a shared workspace rather than a coordinator. For coordination data (dedup indexes, claim registries), not control (Chapter 27).
Family 3: retrieval and knowledge
How an agent brings in information.
RAG (retrieve-augment-generate). Retrieve chunks, stuff them into the prompt, answer. The chat-shaped one-shot (Chapter 34).
Agentic retrieval. Retrieval as an iterating tool: search, reformulate, search again, switch between vector and keyword per sub-question. The agent-shaped one (Chapter 34).
search -> (weak) -> reformulate -> search -> grep(exact) -> read -> answer
Memory-augmented. Consult a durable memory of past runs before acting; write learnings after (Chapter 35).
Family 4: reliability and control
How an agent stays safe, bounded, and correct.
Guardrail. A filter on text crossing a boundary, at the tool boundary for injected content (Chapter 13, Chapter 37).
Human-in-the-loop (approval gate). A durable pause for a human decision on a consequential action (Chapter 38); Capstone B.
...propose effect -> [PARK for human] --approve--> execute
--deny-----> revise
Budget-bounded (admission control). Admit work only if the budget covers it; land as a clean partial when exhausted (Chapter 23); Capstone D's per-request budget.
Checkpoint-resume. Persist progress so a crash resumes the failed slice, not the whole run (Chapter 25).
Router. Classify the request and dispatch to the right handler, model, or agent. A cost lever (small model routes, big model works) and an organizing pattern.
request -> classify -> {perf | data | security} handler
The lab
Seven of these run as deterministic skeletons, so the shapes are concrete before any framework:
python3 patterns.py
ReAct answer: latency rose ~13x (from 2 reason/act steps)
Reflection draft -> critique('too vague: name the mechanism and the evidence') -> revised: v841 shrank the payments-db pool 50->10 at 01:55; logs show pool exhaustion at 02:03; p99 rose 14x. Roll back v841.
Plan-and-execute plan=pull metrics -> list deploys -> search logs -> conclude | executed 4
Router routed 'checkout latency spike' -> perf -> PERF handler: check latency + deploys
Evaluator-optimizer accepted after 3 tries (score 0.4, score 0.7, score 0.95): v841 shrank the payments-db pool 50->10;...
Map-reduce mapped 6 shards -> 6 findings -> 1 merged report
Ensemble-vote votes=['v841', 'v841', 'network', 'v841', 'v840'] -> majority 'v841' (3/5)
The closing line is the catalog's real lesson: patterns compose. A production system is rarely one pattern; it is several nested. The capstones that follow are each a specific composition, and the "patterns used" box in each names them, so you can read a real build as an assembly of catalog entries.
Don't be confused: a pattern vs a framework. A pattern is a shape of control flow (ReAct, map-reduce, reflection); a framework is a library that makes some patterns easy to express (LangGraph makes graphs easy, CrewAI makes crews easy). You choose patterns by the problem and a framework by which patterns it expresses well, and the same pattern runs in any framework or none, which is why this catalog is framework-neutral and the idioms lab showed three of them in plain Python. Learn the patterns; the frameworks are how you type them faster.
Full source
"""Lab 14.1: the agentic pattern catalog, runnable.
Every agentic system is built from a small set of recurring patterns.
This lab implements the core ones as tiny, deterministic skeletons over
a trivial model stand-in, so the SHAPE of each is visible and runnable
before you dress it in a framework:
1. ReAct reason -> act -> observe, loop until done
2. Reflection draft -> self-critique -> revise
3. Plan-and-execute plan the steps, then run each
4. Router classify the request, dispatch to a specialist
5. Evaluator-optimizer generate -> score -> retry with feedback until good
6. Map-reduce fan out over items, then merge
7. Ensemble-vote N attempts, majority wins
The real systems add a real model, real tools, and a framework; the
control-flow idea is exactly what you see here. Standard library only.
Deterministic.
"""
from __future__ import annotations
from collections import Counter
# --- 1. ReAct: reason, act, observe, loop -----------------------------------
def react(task: str) -> str:
tools = {"search": lambda q: f"[3 hits for {q!r}]",
"calc": lambda e: str(eval(e, {"__builtins__": {}}))}
scratch, steps = [], [("search", "checkout errors"), ("calc", "2930/210")]
for name, arg in steps: # a real model picks these
obs = tools[name](arg)
scratch.append(f"thought: need {name}; act: {name}({arg}); obs: {obs}")
return f"answer: latency rose ~{tools['calc']('2930//210')}x " \
f"(from {len(scratch)} reason/act steps)"
# --- 2. Reflection: draft, critique, revise ---------------------------------
def reflect(task: str) -> str:
draft = "v841 caused it." # thin first pass
critique = "too vague: name the mechanism and the evidence"
revised = ("v841 shrank the payments-db pool 50->10 at 01:55; logs show "
"pool exhaustion at 02:03; p99 rose 14x. Roll back v841.")
return f"draft -> critique({critique!r}) -> revised: {revised}"
# --- 3. Plan-and-execute: plan then run each step ---------------------------
def plan_execute(task: str) -> str:
plan = ["pull metrics", "list deploys", "search logs", "conclude"]
done = [f"[{i+1}/{len(plan)}] {s}: ok" for i, s in enumerate(plan)]
return "plan=" + " -> ".join(plan) + " | executed " + str(len(done))
# --- 4. Router: classify, then dispatch to a specialist ---------------------
def route(request: str) -> str:
def perf(r): return "PERF handler: check latency + deploys"
def data(r): return "DATA handler: check schema + freshness"
def sec(r): return "SEC handler: check auth + injection"
label = ("perf" if any(w in request for w in ("latency", "slow", "spike"))
else "sec" if "auth" in request or "attack" in request
else "data")
return f"routed {request!r} -> {label} -> " + \
{"perf": perf, "data": data, "sec": sec}[label](request)
# --- 5. Evaluator-optimizer: generate, score, retry with feedback -----------
def evaluator_optimizer(task: str, bar: float = 0.9) -> str:
attempts = [("v841 broke it", 0.4),
("v841 shrank the db pool", 0.7),
("v841 shrank the payments-db pool 50->10; logs confirm; "
"p99 14x; roll back", 0.95)] # each retry uses feedback
trace = []
for text, score in attempts:
trace.append(f"score {score}")
if score >= bar:
return f"accepted after {len(trace)} tries ({', '.join(trace)}): " \
f"{text[:40]}..."
return "gave up (max tries)"
# --- 6. Map-reduce: fan out over items, then merge --------------------------
def map_reduce(items: list[str]) -> str:
mapped = [(it, len(it) % 3) for it in items] # a per-item finding count
total = sum(n for _, n in mapped)
return f"mapped {len(items)} shards -> {total} findings -> 1 merged report"
# --- 7. Ensemble-vote: N attempts, majority wins ----------------------------
def ensemble(task: str) -> str:
votes = ["v841", "v841", "network", "v841", "v840"] # 5 finders
winner, n = Counter(votes).most_common(1)[0]
return f"votes={votes} -> majority {winner!r} ({n}/{len(votes)})"
if __name__ == "__main__":
task = "why did checkout p99 spike overnight?"
demos = [
("ReAct ", react(task)),
("Reflection ", reflect(task)),
("Plan-and-execute ", plan_execute(task)),
("Router ", route("checkout latency spike")),
("Evaluator-optimizer ", evaluator_optimizer(task)),
("Map-reduce ", map_reduce([f"shard-{i}" for i in range(6)])),
("Ensemble-vote ", ensemble(task)),
]
for name, out in demos:
print(f"{name} {out}")
print("\nseven patterns, one primitive: a step that transforms state. "
"Real agentic systems compose these (a swarm is map-reduce + "
"ensemble-vote; a research agent is plan-execute + reflection + "
"evaluator-optimizer) over a real model and real tools.")
👉 Next: Capstone A, built end to end, the repository-audit fleet from project kickoff through validation and troubleshooting, on Bedrock with an open-source framework and every pattern this catalog just named.