Agentic Systems

Agentic Orchestration

Twelve patterns for combining model calls, tools and code, and when each one earns its cost.

workflowsagentsguardrailsevaluation

Drawn from the Agentic Orchestration Playground · github.com/javiator/agentic-orchestration-play

The map

Workflows, agents, and what wraps them

Workflows code decides the steps

  • Prompt chain fixed steps + gates
  • Router one cheap decision
  • Consensus fan-out + judge
  • Reflection draft → critique loop

Agents a model decides the steps

  • Supervisor delegates turn by turn
  • Planner plans a graph, replans
  • Agentic RAG search as a tool
  • Code agent writes + runs Python

Around every pattern

  • Human-in-the-loop pause risky actions for approval
  • Guardrails layered input/output checks
  • Context management what the model gets to remember
  • Eval harness measure quality, latency and cost
Before the patterns

Three ideas to carry through

  1. Prefer the simplest pattern that works — a workflow before an agent.
  2. Every extra call buys something: check what, with an eval harness.
  3. The best way to learn a pattern is to break it: change a prompt, a model, a limit.
Part 1

Workflows

Code decides the steps. Predictable, cheap, easy to test.

Pattern 5 of 12

Prompt Chain vs Single Prompt

The same strict writing task two ways: one big prompt, or small steps with code checks between them.

workflowscode gatesparallel stepsstructured output

Problem

  • One prompt with many rules → some rules get dropped
  • You can't fix what you don't check

Use it when

  • The task decomposes into known steps
  • Output requirements can be checked by code
Pattern 5 of 12 · Prompt Chain vs Single Prompt

How it works

spec + topic ──▶ model ──▶ text                       (1 call)

topic ──▶ ① outline (JSON) ──▶ [gate: valid JSON, 3 sections?] ── no → retry once
                │
                ▼  ② write each section — in PARALLEL, one call each
          ┌─────┼─────┐
          ▼     ▼     ▼
        [code: assemble title + sections + takeaway]
                │
                ▼
         [gate: check the full spec]  ── fails → ③ targeted fix call
                │                              (only the failed checks)
                ▼
              text                            (~5–7 calls)

Takeaways

  1. When the steps are known, a workflow beats an agent: cheaper and predictable.
  2. Code gates are free, instant and exact — check everything you can in code.
  3. Fix only what failed: targeted repair beats regenerating.
Read the code →
Pattern 2 of 12

Router

A cheap model reads each request and picks the path — and the price — for it.

classificationmodel tiersescalationcost vs quality

Problem

  • Sending everything to the best model is simple — and pays top price for “hi”
  • One path can't be both cheap and capable

Use it when

  • Mixed traffic: many easy, some hard requests
  • Clear categories with different needs
Pattern 2 of 12 · Router

How it works

request ──▶ ROUTER (small model, one short call → JSON)
              │ route + confidence + reason
              ├── simple    ──▶ small model, one call        (cheap, fast)
              ├── reasoning ──▶ strong model, one call       (math, code, analysis)
              ├── research  ──▶ strong model + web tools     (fresh facts)
              └── decline   ──▶ canned reply, no model call  (out of scope)
              │
              └─ confidence < ROUTER_MIN_CONFIDENCE?  ESCALATE to the
                 safer, more capable path — a wrong cheap answer usually
                 costs more than the price difference.

Takeaways

  1. Most traffic is easy — one small call can save many big ones.
  2. Escalate when unsure: a wrong cheap answer costs more than the upgrade.
  3. Measure misroutes against “always strong” — the router is a model too.
Read the code →
Pattern 1 of 12

Multi-Model Research Consensus

One question → several models answer independently → a judge merges them and flags disagreements.

fan-outLLM judgeReAct toolsrebuttalmemory

Problem

  • One model can be confidently wrong
  • You can't see its blind spots from one answer

Use it when

  • High-stakes research questions
  • Facts that are contested or fast-moving
  • You want to know how sure to be
Pattern 1 of 12 · Multi-Model Research Consensus

How it works

              ┌──▶ agent 1 (model A) ──┐
   question ──┼──▶ agent 2 (model B) ──┼──▶ JUDGE (its own model) ──▶ merged answer
              └──▶ agent 3 (model C) ──┘            │                  + disagreements
                 in parallel, isolated              │
                 optional: web tools (ReAct)        ▼
                                          disagreements found?
                                                    │ yes (rebuttal on)
                                                    ▼
                          REBUTTAL: each agent sees the others' claims,
                          defends or revises ──▶ judge again (round 2)

   memory: every verdict is stored (SQLite); when on, related past
   findings are recalled into the shared prompt — "verify before relying".

Takeaways

  1. Fan-out is parallel: three models cost about the time of the slowest one.
  2. A separate judge synthesizes — and attributes every claim to a model.
  3. Disagreements are signal: they show exactly where to double-check.
Read the code →
Pattern 7 of 12

Reflection Loop

Draft, critique, revise — until it's good enough, stops improving, or runs out of budget.

self-critiqueiterative refinementstop conditionsdiminishing returns

Problem

  • First drafts miss constraints
  • Nobody checks the output before it ships

Use it when

  • Quality matters and is checkable
  • Clear criteria: length, format, audience
Pattern 7 of 12 · Reflection Loop

How it works

task ──▶ WRITER ──▶ draft v1
           ▲           │
           │           ▼
           │        CRITIC: score 1–10 + concrete issues (JSON)
           │           │
           │     stop? ├─ score ≥ target          → good enough
           │           ├─ no better than before   → plateau
           │           └─ rounds used up          → budget
           │           │ no
           └── revise ◀┘  (writer gets the draft + the issues)

result = the BEST-scoring version, not necessarily the last —
         a revision can make things worse.

Takeaways

  1. Most of the gain is in round one; later rounds cost the same and add little.
  2. Who critiques matters: self-critique is generous, an independent critic is stricter.
  3. Keep the best version — a revision can make things worse.
Read the code →
Part 2

Agents

A model decides the steps. Flexible, and you pay a model call for every decision.

Pattern 3 of 12

Supervisor & Specialists

A supervisor model decides, turn by turn, which specialist acts next — and when the job is done.

agents as toolsdynamic handoffshared scratchpadloop guards

Problem

  • The steps of the job aren't known in advance
  • Different sub-tasks need different skills

Use it when

  • Open-ended goals
  • Work that needs research, then analysis, then writing — adaptively
Pattern 3 of 12 · Supervisor & Specialists

How it works

            ┌──────────────────────────────────┐
goal ─────▶ │ SUPERVISOR  (a tool-calling LLM) │ ◀──────────────────┐
            └──────┬───────────────────┬───────┘                    │
    delegate(specialist, task)      finish(final_answer) ──▶ done   │
                   ▼                                                 │
            ┌──────────────┐  appends   ┌────────────┐              │
            │  SPECIALIST  │ ─────────▶ │ SCRATCHPAD │ shared state │
            │ (own model)  │ ◀───reads─ └────────────┘              │
            └──────┬───────┘                                        │
                   └── output returned as the tool result ──────────┘

Takeaways

  1. Dynamic handoff: a model decides who acts next, after seeing each result.
  2. Agents as tools: the supervisor's ReAct loop is the orchestrator.
  3. Turn caps and repeat guards keep a confused supervisor from spinning.
Read the code →
Pattern 4 of 12

Planner–Executor

Plan the whole job as a graph up front, run independent steps in parallel, replan when a step fails.

task graph (DAG)parallel wavesreplanningsynthesis

Problem

  • Deciding one step at a time is slow and sequential
  • You can't review the work before it runs

Use it when

  • Multi-part research or analysis
  • You want parallelism and a readable plan
Pattern 4 of 12 · Planner–Executor

How it works

goal ──▶ PLANNER (one call) ──▶ plan = steps + dependencies (a DAG)
                                 │   validated by code: ids, deps, no cycles
                                 ▼
          wave 1:  [s1 research]  [s2 research]     ← no deps: run in PARALLEL
          wave 2:        [s3 think: needs s1, s2]
          wave 3:        [s4 think: needs s3]
                                 │
                   a step FAILED? ──▶ REPLANNER: keeps finished work,
                                 │    plans only what's left (≤ MAX_REPLANS)
                                 ▼
                     SYNTHESIZER ──▶ final answer

Takeaways

  1. Planning up front means fewer decision calls — and parallel waves.
  2. Code validates the plan: dependencies, ids, no cycles.
  3. It commits early, so failures need an explicit replan that keeps finished work.
Read the code →
Pattern 6 of 12

Plain RAG vs Agentic RAG

Same question, model and documents: one fixed search, or an agent that searches like a researcher.

retrievalmulti-hopquery rewritinggrounding check

Problem

  • Answers need facts from several documents
  • The question's words don't match the documents

Use it when

  • Multi-hop questions
  • Messy wording, follow-the-lead lookups
Pattern 6 of 12 · Plain RAG vs Agentic RAG

How it works

question ──▶ search(question) ──▶ top-k chunks ──▶ model answers, citing chunks

question ──▶ ┌──────────────── agent loop (≤ RAG_MAX_STEPS) ───────────────┐
             │ model: what do I still need?                               │
             │   ├─ search_docs(query)  ← its own query: one fact at a    │
             │   │                        time, rephrased when it misses  │
             │   ├─ read_doc(doc_id)    ← whole document when a snippet   │
             │   │                        isn't enough                    │
             │   └─ answer (text)                                         │
             │        └─▶ GROUNDING CHECK: is every claim supported by    │
             │             what was retrieved? no → feedback, search more │
             └────────────────────────────────────────────────────────────┘

Takeaways

  1. Agency helps multi-hop: the agent follows the lead the first search revealed.
  2. It costs more: several times the calls and latency of plain RAG.
  3. Unanswerable questions need honesty — “the documents don't say” is a correct answer.
Read the code →
Pattern 8 of 12

Code-Executing Agent

The model writes Python, runs it, reads the output or traceback — and fixes its code.

code executionself-correctionsandboxingReAct

Problem

  • Models are unreliable at arithmetic, counting, reading tables
  • Plausible-looking numbers can be wrong

Use it when

  • Data questions over files
  • Exact computation, dates, counting
Pattern 8 of 12 · Code-Executing Agent

How it works

question ──▶ ┌──────────────────── loop (≤ CODE_MAX_STEPS) ───────────────────┐
             │ model ── run_python(code) ──▶ sandbox: fresh process          │
             │   ▲                              │                             │
             │   └── exit code + stdout/stderr ─┘  error? the model reads    │
             │                                     the traceback and fixes   │
             │ model ── text answer ──▶ done                                 │
             └───────────────────────────────────────────────────────────────┘

Takeaways

  1. Compute, don't guess: running code turns plausible into exact.
  2. Tracebacks are real feedback — far more useful than self-critique.
  3. This sandbox is a demo: real deployments need containers or VMs.
Read the code →
Part 3

Around every pattern

The controls that make any of the eight safe to run and worth their cost.

Pattern 9 of 12

Human-in-the-Loop

The agent works on its own — until an action is risky. Then it pauses for you.

approvalsrisk tiersinterrupt & resumefeedback

Problem

  • Full autonomy is dangerous for irreversible actions
  • Approving everything makes humans the bottleneck

Use it when

  • Money, external messages, deletions
  • Policies that need human judgement
Pattern 9 of 12 · Human-in-the-Loop

How it works

request ──▶ agent loop (tools over a fake shop)
              │ tool call
              ▼
        POLICY CHECK (code, see world.needs_approval)
          ├─ read / internal write / small refund ──▶ run it now
          └─ big refund / external email ──▶ PAUSE ⏸
                   │  the run's state (the conversation so far + the
                   │  proposed action) is held while a human decides:
                   ├─ approve           → run as proposed
                   ├─ edit + approve    → run with the human's arguments
                   └─ reject + feedback → NOT run; the agent is told why
                   ▼
             loop continues ──▶ final summary for the operator

Takeaways

  1. Gate by risk: routine actions run, irreversible ones wait for a human.
  2. Rejection feedback lets the agent adapt instead of retrying.
  3. Real systems checkpoint the paused state so a pause survives restarts.
Read the code →
Pattern 10 of 12

Guardrails

The same support bot with and without layered input and output checks — against real attacks.

prompt injectionPIIdefence in depthfalse positives

Problem

  • A prompt instruction is a request, not a control
  • Users paste personal data; attackers rephrase until it works

Use it when

  • Any bot facing untrusted input
  • Secrets, personal data, policy limits
Pattern 10 of 12 · Guardrails

How it works

user input ──▶ [1 PII redaction · code] ──▶ [2 injection patterns · code]
                 │ hit → BLOCK (no model call at all)
                 ▼
           [3 input classifier · small model] injection / harmful / off-topic → BLOCK
                 ▼
               BOT (same model + prompt as the unguarded bot)
                 ▼
           [4 secret-leak check · code] → BLOCK
           [5 PII in output · code]     → REDACT
           [6 output policy · small model] → BLOCK
                 ▼
              answer

Takeaways

  1. Instructions aren't controls: the unguarded bot leaks to a simple pretext.
  2. Layer cheap → expensive: code checks first, model checks only when needed.
  3. Every guard trades false positives against leaks — measure both.
Read the code →
Pattern 11 of 12

Context Management

One long conversation replayed four ways — then quizzed on what each strategy still remembers.

memorysummarizationcontext windowtoken cost

Problem

  • Conversations outgrow what's cheap — or possible — to send
  • Dropping history silently loses facts

Use it when

  • Long chats, assistants, agents with many steps
  • Facts that change over time
Pattern 11 of 12 · Context Management

How it works

FULL HISTORY   send everything.            Best recall; cost grows every
                                           turn, and long contexts dilute attention.
SLIDING WINDOW send the last N messages.   Cheap and flat; forgets anything
                                           older than the window, completely.
SUMMARY        every K messages, a model   Middle ground; summaries keep the
               call folds older messages   gist but drop specifics (numbers,
               into a running summary;     names) unless told to keep them.
               keep the last few raw.
NOTES          every K messages, a model   Precise on facts it decided to keep
               call updates a list of      (and can overwrite changed ones);
               durable facts; keep the     misses details nobody flagged as
               last few raw.               important. The idea behind "memory" features.

Takeaways

  1. Full history = best recall, at a cost that grows every turn.
  2. A window forgets everything outside it — completely.
  3. Notes keep specific facts, and can update a fact that changed.
Read the code →
Pattern 12 of 12

Eval Harness

Score single models and orchestration patterns on the same questions — quality, latency and cost.

evaluationLLM-as-judgebaselinescost vs quality

Problem

  • Eyeballing a few answers is how bad patterns ship
  • Extra calls must buy measurable quality

Use it when

  • Before adopting a pattern
  • When changing models, prompts or limits
Pattern 12 of 12 · Eval Harness

How it works

dataset (questions + expected answers / rubrics)
      │
      ▼            for every (target, question) pair, limited concurrency
┌───────────┐   ┌─────────────────────────────────────────────────────┐
│  TARGETS  │──▶│ run target → answer        (calls + tokens counted) │
│ single    │   │ exact-match check          (when `expected` given)  │
│ models,   │   │ LLM grader → 1–5 + reason  (rubric / reference)     │
│ exercises │   └─────────────────────────────────────────────────────┘
└───────────┘                       │
                                    ▼
           per-target summary: accuracy · grade · latency · cost

Takeaways

  1. Measure, don't eyeball: same questions, every target, side by side.
  2. The grader is a model with biases — read its reasons, not just its scores.
  3. Small sets are noisy: one question can swing the average.
Read the code →
Wrap-up

The right pattern is the cheapest one that passes your evals

Start with a workflow. Add agency where the steps cannot be known in advance. Wrap it in approvals, guardrails and context discipline. Measure before you believe it.

Run the exercises: github.com/javiator/agentic-orchestration-play