Agentic AI · Module 14 of 41 · 10 concepts · about 16 min

Agent Workflows

The standard shapes for arranging model calls and agents: sequential, parallel, branching and routing, loops, conditional steps, human approval and event-driven flows; and what an orchestrator does to run them reliably.

At work: The design vocabulary for most production 'agents', which are usually a fixed flow with one or two agent loops inside it, because that is what can be tested and trusted.

Workflows and orchestration

What it is

Two terms:

  • A workflow is a set of steps and the rules for moving between them. A step can be plain code, one model call, or a whole agent loop.
  • Orchestration is the job of running a workflow: starting steps in the right order, passing data between them, handling failures, and recording progress. The code that does it is the orchestrator.

A useful picture is a graph: steps are nodes, and the connections between them are edges.

Why it matters

Workflows put structure around model freedom.

  • You choose where the model may decide and where the path is fixed.
  • Fixed parts are predictable, testable and cheap.
  • Free parts handle the cases a fixed path cannot.
  • The most reliable systems are fixed on the outside and agentic only where needed.

In the real world: A claims system is a seven-step workflow in which only step four, 'investigate the claim', is an agent loop; the rest are fixed, and that is why it passed audit.

Visual example

Shapes

Each has a card below. Real systems combine several.

Eight workflow shapes at a glance
shapeideause when
SequentialA then B then CEach step needs the last one's output
ParallelA, B and C at once, then combineSteps are independent
RoutingClassify, then take one pathKinds of request need different handling
BranchingSplit on a conditionThe data decides the path
LoopRepeat until a test passesOutput can be checked and improved
ConditionalRun a step only if neededSome steps are often unnecessary
Human approvalPause for a personThe action is risky or irreversible
Event-drivenStart when something happensWork arrives unpredictably

Thinking of 'workflow' and 'agent' as competing choices. They nest. A workflow can contain agents as steps, and an agent can call a workflow as a tool.

Practise it: Design a Multi-Agent AI System, Design a Multi-Agent Incident Response System

Sequential workflows

What it is

A sequential workflow (also called prompt chaining) runs steps one after another, each taking the previous step's output:

  • extract the facts from an email;
  • check them against the order;
  • draft a reply;
  • check the reply.

Between steps you can add a gate: a check in code that stops the chain if the output is not good enough.

Why it matters

One large prompt asked to do four jobs does each less well than four prompts doing one job each.

  • Each step is small enough to prompt, test and debug alone.
  • A gate catches a bad intermediate result before more work is built on it.
  • The cost is latency: steps run one after another.

In the real world: A marketing team's 'write, translate, check tone' chain replaced one prompt that did all three badly; each step now has its own small test set.

def handle_email(email: str) -> str:
    facts = extract(email)                     # model call 1: structured output
    if facts.order_id is None:                 # gate, in code
        return ask_for_order_id()

    order = get_order(facts.order_id)          # plain code, no model
    decision = decide(facts, order)            # model call 2
    draft = write_reply(decision, order)       # model call 3
    return draft if passes_checks(draft, order) else hand_over(email, draft)

Chaining steps that could have been one. Each link adds latency and a place to fail. Split only where a step is genuinely different work or needs a gate.

Parallel workflows

What it is

A parallel workflow runs independent steps at the same time and then combines them. Two forms:

  • Sectioning (fan-out, fan-in): different sub-tasks at once. Check a document for legal, financial and style problems with three separate calls, then merge.
  • Voting: the same task several times, then take the majority or the best. Useful when one run is unreliable.

Why it matters

Parallelism buys speed and, with voting, reliability.

  • Three five-second steps in parallel take five seconds, not fifteen.
  • Each parallel call has a short, focused context.
  • Voting turns a 90 percent step into a much more reliable one, at three times the cost.
  • The combining step needs design: how are conflicting results reconciled?

In the real world: A due-diligence tool reads forty contracts in parallel and merges the findings; the sequential version took an hour, the parallel one takes four minutes.

Visual example

Parallel

The time taken is the slowest branch, not the sum.

Fan out, then fan in

  1. SplitOne document to three checkers
  2. at the same time
    Legal checkShort, focused prompt
    Finance checkShort, focused prompt
    Style checkShort, focused prompt
  3. CombineMerge reports; resolve conflicts
import asyncio

async def review(document: str) -> dict:
    legal, finance, style = await asyncio.gather(     # three calls at once
        check(document, LEGAL_PROMPT),
        check(document, FINANCE_PROMPT),
        check(document, STYLE_PROMPT),
    )
    return merge(legal, finance, style)               # fan-in: one combined report

async def classify_with_vote(text: str, n: int = 3) -> str:
    votes = await asyncio.gather(*[classify(text) for _ in range(n)])
    return max(set(votes), key=votes.count)           # majority wins

Running steps in parallel that are not independent. If the style check needs the legal check's rewrite, running both at once means one works on stale text.

Routing and branching workflows

What it is

Both send a request down one of several paths. They differ in who decides:

  • Routing: a model classifies the request ('billing', 'delivery') and the workflow follows that path. Each path has its own prompt, tools and sometimes its own model.
  • Branching (conditional edges): plain code decides from data. If the refund is over ₹500, go to approval; otherwise go straight to payment.

Why it matters

Different requests deserve different handling.

  • A specialised path has a shorter prompt and fewer tools, so it is more accurate and cheaper.
  • Easy requests can go to a small model and hard ones to a large one.
  • Where a rule decides the path, use code: it is free, instant and never wrong about a number.

In the real world: A support platform routes four in five messages to a small model with three tools; only the remainder reach the large model, and overall cost falls by more than half.

PATHS = {"billing": billing_agent, "delivery": delivery_agent,
         "account": account_agent, "human": hand_over}

def handle(message: str, user) -> str:
    route = classify(message)                      # small model, enum output
    return PATHS.get(route.category, hand_over)(message, user)

def after_decision(state) -> str:
    """A branch decided by code, from data."""
    if state.refund_amount == 0:
        return "reply"
    return "approval" if state.refund_amount > 500 else "pay"

Asking a model to make a decision that a comparison could make. 'Is 1,800 greater than 500?' does not need a language model, and a model will occasionally get it wrong.

Loops and conditional execution

What it is

Two ways a workflow departs from a straight line:

  • A loop repeats a step until a condition is met: generate, evaluate, revise, and again. Also called the evaluator-optimiser pattern.
  • Conditional execution runs a step only when needed: search the web only if the internal search found nothing; translate only if the message is not in English.

Why it matters

Loops add quality where output can be checked; conditions remove cost where steps are often unnecessary.

  • A loop needs an exit test and a maximum count, or it is a bill with no ceiling.
  • A condition that skips an expensive step for most requests is often the easiest saving in the system.
  • Both keep the model's freedom narrow: it improves or skips, it does not redesign the flow.

In the real world: A code-generation workflow loops 'write, run tests, fix' up to three times; 92 percent of tasks pass within the limit and the rest go to a person with the failing test attached.

def write_until_good(task: str, max_rounds: int = 3) -> str:
    draft = write(task)
    for _ in range(max_rounds):                        # the loop has a ceiling
        problems = evaluate(draft, task)               # a checklist-based critic
        if not problems:
            return draft
        draft = revise(draft, problems)
    return hand_over(task, draft)                      # did not converge: a person decides

def answer(question: str) -> str:
    passages = search_internal(question)
    if not passages:                                   # conditional step
        passages = search_web(question)
    return generate(question, passages)

A loop whose evaluator is the same prompt as the writer. It approves on round one, or disagrees for ever. The evaluator needs its own criteria and, ideally, real evidence such as test results.

Practise it: Design a Self-Correcting Code Agent

Human approval steps

What it is

A human approval step pauses the workflow until a person decides. The workflow:

  • reaches the step and saves its state;
  • notifies the person with what is proposed and why;
  • stops; nothing runs while it waits;
  • resumes from saved state when the decision arrives, taking the approved or declined path.

Why it matters

Some actions should not rest on a model's judgement alone.

  • Placed as a fixed step, approval cannot be skipped or argued away by the model.
  • Because state is saved, the wait can last minutes or days.
  • The step needs a path for 'declined' and for 'no answer in time', not only for 'approved'. Module 15 covers this in depth.

In the real world: A procurement workflow pauses on any purchase order above ₹1 lakh; the model can prepare the order but the 'send' step is only reachable through the approval node.

Implementing approval as an instruction: 'ask the user before refunding'. The model sometimes forgets. Approval must be a step in the workflow that the refund path cannot bypass.

Event-driven workflows

What it is

An event-driven workflow starts, or continues, when something happens, not when a user types. Typical events:

  • a new email, ticket or uploaded file;
  • a payment succeeding or failing;
  • a monitoring alert;
  • a timer: every night, or 24 hours after the last step;
  • another agent finishing its work.

Events usually arrive through a queue: a holding line that workers take jobs from, one at a time.

Why it matters

Much real work is not a chat.

  • Agents that react to events run in the background, with no one waiting.
  • A queue absorbs bursts: a thousand emails at 9 a.m. are worked through steadily instead of overwhelming the system.
  • Background runs can use slower, cheaper processing.
  • But no one is watching, so limits, logging and alerts matter more.

In the real world: An alert-triage agent wakes on each monitoring alert, gathers logs and posts a summary; duplicate alerts are dropped by an event id check that was added after it posted the same summary nine times.

Visual example

Event-driven

The queue absorbs bursts. The id check absorbs duplicates.

A workflow that nobody starts by hand

  1. EventNew ticket at 03:10
  2. QueueWaits for a free worker
  3. WorkerSkips duplicates by event id
  4. WorkflowTriage, investigate, draft
  5. Next eventApproval or timeout resumes it
def on_event(event: dict) -> None:
    """Called by a queue worker for each event."""
    key = event["id"]
    if already_processed(key):                 # the same event may be delivered twice
        return
    if event["type"] == "ticket.created":
        run_id = start_run("triage", payload=event["ticket"])
    elif event["type"] == "approval.decided":
        run_id = resume_run(event["run_id"], decision=event["decision"])
    elif event["type"] == "timer.fired":
        run_id = resume_run(event["run_id"], decision="timed_out")
    mark_processed(key, run_id)

Assuming each event arrives exactly once. Queues deliver 'at least once', so duplicates happen. Every handler must be safe to run twice for the same event.

What a workflow orchestrator must provide

What it is

Whatever shape the workflow has, the orchestrator running it needs six abilities:

  • Saved state after every step, so a run can resume (module 6).
  • Retries with backoff for steps that fail for passing reasons.
  • Timeouts on every step.
  • Safe repeats: a step run twice must not act twice (idempotency).
  • Limits: maximum steps, cost and duration per run.
  • Visibility: a record of every step's input, output and duration.

Why it matters

These are what turn a script into a service.

  • A workflow of ten steps that each work 99 percent of the time fails one run in ten without retries.
  • A long workflow will be interrupted by a deployment sooner or later.
  • A stuck step with no timeout holds a worker for ever.
  • You can write this yourself, use a graph framework, or use a durable-execution engine; the six needs are the same.

In the real world: A team's hand-rolled orchestrator worked for months until a deploy during a refund run paid a customer twice; they then adopted an engine that provided saved state and safe repeats by design.

Visual example

Orchestrator

If one is missing, the right-hand column is what eventually happens.

Six things every orchestrator needs
abilitywhat it doeswithout it
Saved stateResume from the last stepA crash loses the whole run
RetriesTry a failed step againOne hiccup fails the task
TimeoutsGive up on a stuck stepWorkers hang for ever
Safe repeatsA repeated step acts onceDouble refunds, double emails
LimitsCap steps, cost and timeRunaway cost
VisibilityRecord every stepFailures cannot be diagnosed

Building the happy path and adding these 'later'. Retrofitting saved state and safe repeats into a finished workflow usually means rewriting it.

Interview questions: agent workflows

What it is

The questions interviewers ask about agent workflows, from the first screening call to the senior round. Cover the answer, say yours aloud, then compare.

Why it matters

Reading an idea and explaining it are different skills.

  • Each answer below is the two or three sentences an interviewer is listening for.
  • The reasoning behind each one is in the cards above. If an answer surprises you, go back to that card.

In the real world: A candidate asked to design an 'invoice agent' draws a six-box workflow with one agent step and an approval node; the interviewer notes 'chose the simplest thing that works'.

Q: What is the difference between a workflow and an agent?

A workflow's steps and transitions are fixed by code; an agent's are chosen by the model. Workflows are predictable and testable, agents flexible. They nest: an agent loop can be one step in a workflow.

Q: Name the common workflow patterns.

Sequential chaining, parallel fan-out and fan-in, routing, conditional branching, evaluator-optimiser loops, human approval steps and event-driven triggers. Orchestrator-workers adds dynamic sub-tasks.

Q: When do you use parallel execution?

When steps are independent. It cuts latency to the slowest branch and keeps each context small. Voting runs the same step several times for reliability. The merge step must reconcile conflicts.

Q: Routing versus branching?

Routing uses a model to classify the request into a path. Branching uses code and data to choose. Use code whenever a rule or comparison decides.

Q: How do you stop a loop running for ever?

A pass condition from an independent evaluator, a maximum number of rounds, a stop when rounds no longer improve, and a hand-over when the cap is reached.

Q: How is a human approval step implemented?

As a workflow node: save state, notify, stop; resume from the saved state when a decision event arrives. It needs approve, decline and timeout paths, and must be the only route to the gated action.

Q: What is an event-driven agent?

One triggered by events such as a new ticket or a timer, usually via a queue. It runs in the background, must tolerate duplicate events, and needs strong limits and alerts because nobody is watching.

Q: What does an orchestrator provide?

Saved state, retries, timeouts, idempotent steps, run limits and a record of every step. These make long workflows survive failures and deployments.

Proposing a fully autonomous agent for a process that is the same five steps every time.

Exercise: build a workflow with routing, parallel steps and an approval

What it is

A short build that uses this module's ideas. Write it yourself before looking anything up; the checks at the end tell you whether it works.

Why it matters

An idea you have only read fades in a week.

  • Building it once, even in fifty lines, is what makes it yours.
  • Interviewers can tell the difference between someone who has read about a loop and someone who has debugged one.

In the real world: An operations team builds this in plain Python first, then ports it to a graph framework in a day because the shapes are already clear.

Your task. Build a small email-handling workflow in plain Python that uses four of the eight shapes and survives being stopped at the approval step.

Steps

  1. Write a router that classifies an email as refund, question or other with structured output.
  2. For question, run a sequential chain: retrieve a policy, draft, check.
  3. For refund, fetch the order and the policy in parallel, decide the amount, then branch in code: over ₹500 goes to approval, otherwise pay.
  4. Implement approval by saving the run's state to a file and exiting. A second script reads a decision and resumes.
  5. Wrap the drafting step in an evaluator loop capped at two rounds.
  6. Log each step's name, duration and output to a list and print it at the end.

You are done when

  • Three test emails take three different paths, visible in the step log.
  • The parallel step's duration is close to its slowest call, not the sum.
  • A ₹1,800 refund stops at approval; approving it from the second script completes the run without re-running earlier steps.
  • Declining it produces a polite refusal and no payment.

Stretch. Feed the workflow from a queue (a list will do) containing a duplicate event and show it is handled once.

Practise it: Design a Multi-Agent Incident Response System