hub.gazar.dev · cheat sheet← all cheat sheets

Week 1 · Foundations

Workflow patterns cheat sheet.

Everything from Session 1 on one page: workflow vs agent, the five workflow patterns with code, how to gate and compose them, the three-gate decision map, the guardrails an agent needs, the cost and latency math, the observability minimum, and the antipatterns. Skim it before you reach for an agent.

Why demos die Workflow vs agent The autonomy ladder The five patterns Gates between steps Composing patterns Graduating to an agent Agent guardrails Cost & latency Observability Antipatterns Quick reference
01

Four ways a demo dies in production

A demo runs once, on a happy path, with you watching. Production runs a million times, on inputs you never imagined, while you sleep. Each failure mode has a defence, so name it before you ship.

💸 Cost spirals

Every token is a line item. A chatty agent loop burns 20× a single call. Price the worst case, not the happy one.

Guard: per-request token budget, cheap-model routing, caching, hard loop caps.

🐢 Latency balloons

Each sequential hop waits on the model. A 5-step chain feels broken. You are graded at p95/p99, not the average.

Guard: parallelise independent hops, stream tokens, set timeouts, cache hot paths.

🤥 Confidently wrong

A probabilistic service in a deterministic-looking API. A wrong answer arrives with the same tone as a right one. Air Canada was held liable for one.

Guard: ground answers in retrieval, validate outputs, gate with a judge, cite sources.

🕶️ Flying blind

No evals to catch it, no traces to debug it. You learn it broke from a viral screenshot (see: Chevy, DPD).

Guard: trace every step, run evals in CI, sample live traffic, alert on drift.

02

Workflow vs agent: who drives?

One question separates them: are the steps fixed in code, or does the model choose them at run time?

flowchart LR
  subgraph WF["WORKFLOW · you drive"]
    direction LR
    A1["Step 1"] --> A2["Step 2"] --> A3["Output"]
  end
  subgraph AG["AGENT · the model drives"]
    direction LR
    M{"Model picks
next step + tool"} M --> T["Tool"] --> O["Observe"] --> M M -.-> DONE["Done"] end classDef wf fill:#D6F5E3,stroke:#1F2937,color:#0E1726; classDef ag fill:#EEE6FF,stroke:#1F2937,color:#0E1726; class A1,A2,A3 wf; class M,T,O,DONE ag;
DimensionWorkflowAgent
Control flowfixed in codechosen by the model at run time
Token costpredictableunbounded without a cap
Latencyyou can bound itgrows with every turn
Debuggingreplay the stepsreconstruct a trajectory
Testingunit-testableneeds eval sets and trajectory checks
Reach for italmost alwayslast resort, and only when gated
Anthropic's finding: the most reliable production systems are workflows, not autonomous agents. Agency costs tokens, latency, and blast radius. Buy it only when the task genuinely cannot be scripted.
03

The autonomy ladder

Ordered simplest to most dynamic. Reach left first; every rung right is a cost you take only when forced. The line between workflow and agent is where the model, not you, starts picking the steps.

flowchart LR
  A["1 call"] --> B["Chain"] --> C["Router"] --> D["Parallelize"] --> E["Orchestrator"] --> F["Agent"]
  classDef s fill:#D6F5E3,stroke:#1F2937,color:#0E1726;
  classDef m fill:#DCEBFE,stroke:#1F2937,color:#0E1726;
  classDef a fill:#EEE6FF,stroke:#1F2937,color:#0E1726;
  class A,B s; class C,D,E m; class F a;
    
RungWho picks the stepYou gainYou pay
1 callyou (fixed)simplest, cheapest, testableno adaptivity
Chainyou (fixed order)quality via gating between stepsmore latency per hop
Routeryou (branch set is fixed)right-sized cost per requesta classifier to build and watch
Parallelizeyou (branch set is fixed)latency down, quality up via votingN× the tokens
Orchestratorthe model (branches)handles structure unknown up frontrun-time nondeterminism
Agentthe model (everything)open-ended, looping taskscost, latency, blast radius
04

The five workflow patterns

These cover most real work before you ever need an agent. Each is a handful of lines; the skill is knowing which one the task wants, and where it breaks.

1 · chaining

Prompt chaining

Split a task into ordered steps and gate between them. Validate the outline before you spend tokens writing the essay.

Use when the task has clean, checkable sub-steps and each step's output is the next step's input.

Breaks when steps are actually independent (parallelise instead) or the shape is unknown up front (orchestrate).

Cost: N sequential calls; latency adds up, so keep the chain short.

# gate between steps: fail early and cheap
outline = llm("draft an outline", brief)
if not valid(outline):        # deterministic check
    return reject(outline)
draft = llm("write from outline", outline)
return llm("tighten and proof", draft)
2 · routing

Routing

Classify first, then dispatch: cheap model for easy, big model for hard, a dedicated flow for refunds. Saves money on day one.

Use when inputs fall into distinct kinds that each want different handling or a different model tier.

Breaks when the classifier is wrong: a misroute sends a hard case to the cheap path. Measure routing accuracy.

Cost: one small classifier call plus the chosen flow; usually a net saving.

# classify once, dispatch to the right-sized flow
kind = classify(request)      # small, fast model
match kind:
    case "faq":    return haiku(request)
    case "refund": return refund_flow(request)
    case _:        return opus(request)
3 · parallel

Parallelization

Fan out independent work and aggregate. Two flavours: sectioning (split one job into parts) and voting (run the same job N times and take the consensus). Faster, and often better.

Use when subtasks don't depend on each other, or when independent votes raise reliability on a hard call.

Breaks when branches secretly depend on one another, or the merge/vote logic is naive and hides disagreement.

Cost: N× tokens, but roughly 1× latency because the calls run concurrently.

# fan out independent work, then aggregate
parts = gather(
    llm("summarise", doc),
    llm("extract risks", doc),
    llm("list next actions", doc),
)
return merge(parts)   # or majority vote
4 · orchestrator

Orchestrator–workers

A planner splits work it cannot know up front, spawns workers per subtask, then synthesizes. The branches are decided at run time: the first real taste of agency.

Use when the number and shape of subtasks depend on the input (multi-file edits, research over an unknown set of sources).

Breaks when the plan runs away: no cap on subtasks, or the synthesis step drowns in worker output.

Cost: a planner call, N worker calls, a synthesis call; bound N.

# the planner decides the branches at run time
plan = orchestrator(task)   # -> list of subtasks
assert len(plan) <= MAX_SUBTASKS
results = gather(*[worker(s) for s in plan])
return synthesise(task, results)
5 · evaluator

Evaluator–optimizer

Generate, critique against a rubric, revise, loop until it passes. Quality without a human in every turn. Always cap the loop, or a $5 task becomes $50.

Use when there is a clear rubric and revision reliably improves the draft (translation, code that must pass tests, structured extraction).

Breaks when the evaluator can't tell better from worse, or the loop has no cap and thrashes forever.

Cost: 2 calls per round × rounds; the cap is the budget.

# generate, critique, revise; ALWAYS cap
draft = generate(task)
for _ in range(MAX_ROUNDS):
    v = evaluate(draft, rubric)
    if v.passed: break
    draft = revise(draft, v.feedback)
return draft
05

Gates: what goes between the steps

A pattern is only as good as its gates. A gate is the check that decides whether output moves forward, gets revised, or gets rejected. Reach for the cheapest gate that actually catches the failure.

~free

Deterministic check

Schema, type, regex, range, required fields, does-it-parse. No model call. Catches malformed and out-of-bounds output instantly.

1 call

LLM-as-judge

A model scores the output against a rubric: faithfulness, tone, completeness. Use for quality you can't express as a rule.

retrieval

Ground-truth compare

Check the answer against a source document or a golden set. The main defence against confidently-wrong output.

human

Human-in-the-loop

A person approves before the action commits. Reserve for irreversible or high-stakes steps; it costs latency and attention.

Order of escalation: deterministic first (free, instant), then a judge (cheap), then ground-truth (needs a source), then a human (expensive). Every gate you push right costs money or time, so only escalate when the cheaper gate can't catch the failure.
06

Composing patterns

Real systems are not one pattern; they are trees of them. A router picks a branch, a branch is a chain, a chain fans out in parallel, the result passes an evaluator before it ships. Each node stays independently testable.

flowchart TB
  IN(["request"]) --> R{"Router"}
  R -- simple --> C1["1 call"]
  R -- structured --> CH["Chain w/ gates"]
  R -- research --> O["Orchestrator"]
  O --> P[["Parallel workers"]]
  C1 --> EV{"Evaluator"}
  CH --> EV
  P --> EV
  EV -- fail --> CH
  EV -- pass --> OUT(["response"])
  classDef s fill:#D6F5E3,stroke:#1F2937,color:#0E1726;
  classDef m fill:#DCEBFE,stroke:#1F2937,color:#0E1726;
  classDef a fill:#EEE6FF,stroke:#1F2937,color:#0E1726;
  class C1,CH s; class R,O,P m; class EV,OUT a; class IN s;
    
The rule: build with the smallest composition that clears the task, and keep each node isolated enough to unit-test on its own. Complexity you can't test in pieces is complexity you can't debug in production.
07

When do you graduate to an agent?

Three gates. An agent has to clear all three. Most features stop at the first, and that is a good thing.

flowchart TB
  START(["A task to build"]) --> Q1{"Steps known
in advance?"} Q1 -- yes --> WF["Use a WORKFLOW"] Q1 -- "no, open-ended" --> Q2{"Must it loop:
act, observe, decide?"} Q2 -- no --> WF Q2 -- yes --> Q3{"Worth the cost,
latency and risk?"} Q3 -- "not yet" --> WF Q3 -- yes --> AG["Use an AGENT
with guardrails + evals"] classDef wf fill:#D6F5E3,stroke:#1F2937,color:#0E1726; classDef ag fill:#EEE6FF,stroke:#1F2937,color:#0E1726; class WF wf; class AG ag;

Gate 1 · Unknowable steps

Can you write the steps in code ahead of time? If yes, a workflow wins. Agency only earns its keep when the path genuinely can't be scripted.

Gate 2 · Needs a loop

Does the task have to act, observe the result, and decide the next move on the fly? A one-shot or fixed chain that would do means you don't need an agent.

Gate 3 · Worth the risk

Is the value worth the extra tokens, latency, and blast radius, and can you afford the guardrails and evals it demands? If not yet, stay on a workflow.

08

If you must ship an agent: bound every axis

An unguarded agent is the demo that dies in every one of the four ways at once. Before it touches production, put a ceiling on each axis it can run away on.

AxisGuardrail
Iterationshard max-steps; break on no-progress
Budgettoken/$ ceiling per request; kill on breach
Toolsallow-list, least privilege; no raw shell
Irreversible actshuman approval or dry-run first
Timeper-tool and per-request timeouts
I/Ostructured tool schemas; validate every arg
Failuretyped fallback path; never a raw stack trace to the user
# the model drives; bound every axis
for step in range(MAX_STEPS):     # 1. iteration cap
    if spend > BUDGET: break       # 2. $ ceiling
    act = model(state, TOOLS)       # 3. allow-list
    if act.risky:
        require_human(act)          # 4. approval
    state = execute(act, timeout=30) # 5. sandbox+TO
    if act.done: break
09

Cost & latency: napkin math

Order-of-magnitude, not benchmarks. The point is the shape: an agent's worst case is "it never stops", which is why every rung right on the ladder is a bill you sign up for.

ShapeModel callsRel. tokensRel. p95 latencyBlast radius
Single call1tiny
3-step chain3~3×~3×small, bounded
Router + flow2~1–2×~1.5×small
Parallel (×4)4~4×~1× (concurrent)medium cost
Agent (~10 turns)10–30+10–30×10×+large, unbounded
Price the worst case, not the happy path. Multiply the token cost of a single turn by your loop cap, and that is the number to put in the budget. If you can't say what the cap is, you don't have a budget, you have a leak.
10

Make it observable, or ship blind

You can't debug what you can't replay, and you can't improve what you don't measure. Two flying-blind failure modes above have the same cure: traces and evals from day one.

Traces

One span per step and per tool call, with inputs, outputs, tokens, and latency. When it breaks, you replay the trajectory instead of guessing.

Offline evals

A fixed test set scored in CI on every change. Catches regressions before they ship, not after a screenshot.

Online evals

Sample live traffic, score with a judge or human labels, and watch for quality drift as inputs shift under you.

Metrics that matter

Task success, faithfulness/groundedness, p95 latency, cost per request, and refusal/error rate. Alert on each.

The bar: no traces and no evals means you learn about breakage from users, not dashboards. Instrument before you scale, not after the incident.
11

Six antipatterns

Monolithic agent

One giant loop with 30 tools doing everything. Impossible to test, reason about, or bound.

Over-engineered planning

Multi-agent choreography for a job a three-step chain would nail.

Missing observability

Shipped with no traces or evals, so you learn it is broken from users, not dashboards.

Premature agency

An agent where a router or chain would do. You bought nondeterminism you didn't need and now have to guard.

Unbounded loop

A generate-critique or agent loop with no cap. A $5 task quietly bills $50 the day inputs get weird.

No fallback path

One bad model call and the raw error reaches the user. No retry, no default, no graceful degrade.

The cure for all six: start simple, make it observable, cap every loop, and add agency only when a gate demands it.
12

Quick reference: pick the pattern

If the task is…Reach forBecause
Ordered steps, each checkableChaininggate between steps, fail early and cheap
Different inputs need different handlingRoutingright-size the model per request
Independent subtasks, known up frontParallelizationlatency down, quality up via voting
Subtasks unknowable until run timeOrchestratorthe planner decides the branches
Quality needs iteration to a barEvaluator–optimizercritique-and-revise loop, capped
Open-ended, must loop, worth the riskAgentonly after all three gates clear