The situation
An overnight job takes a batch of a few thousand supplier documents, extracts structured fields from each with a foundation model, validates the extraction against a schema, writes the clean records to a data store, and, when a document fails validation twice, routes it to a human reviewer before carrying on. Some of those steps are a model call. Most of them are not. The whole thing has to run to completion even when a single model invocation throttles, a Lambda times out, or a reviewer takes two days to respond, and the operations team wants to be able to open a run afterwards and see exactly which documents took which path.
The first instinct is to reach for a Bedrock agent, because the model is doing the interesting work. That instinct is worth questioning. The model is one participant in a workflow that is mostly known in advance, mostly deterministic, and mostly about moving data reliably between AWS services with retries and a human pause in the middle.
The choice sits between three orchestration engines: a model-driven Bedrock agent, a visually-defined Bedrock Flow, and an AWS Step Functions state machine. Each puts the decision about what happens next in a different place, and that placement is the whole question.
What actually matters
The first thing to name is where the control flow is decided. In an agent the foundation model decides the sequence at run time: it reads the request, picks a tool or a knowledge base, observes the result, and chooses the next step, looping until it is done. That is the right tool when the path genuinely cannot be known in advance. It is also precisely what you do not want when the path is known, because model-chosen control flow is nondeterministic, harder to test, and spends an extra model call every time the model stops to decide what to do next. A Bedrock Flow and a Step Functions state machine both invert this: a person draws the sequence, and the runtime walks the graph. The model still does the work inside a node, but it does not choose the order.
The second is durability and failure handling. A batch that runs for hours across thousands of documents will hit throttling, transient errors, and slow dependencies. Step Functions Standard workflows are durable: an execution can run for up to a year, each state can carry its own retry policy with backoff and its own catch handler for specific errors, and the service persists execution state so a long-running run survives without you holding it open in your own process. A Bedrock agent has no equivalent durable-execution model; if you want a retried, resumable, auditable long-running process, you are rebuilding a workflow engine around it.
The third is reach across AWS services and shape of the work. The document job is mostly not model calls: it is reads and writes to a data store, schema validation, fan-out across many records, and a human approval pause. Step Functions integrates directly with a large number of AWS services and can fan work out with its Map state, run branches in parallel, wait on a callback token for a human decision, and invoke Bedrock as an optimised integration for the steps that are model calls. When the GenAI work is one step inside a larger business process, the orchestrator that reaches furthest across the rest of AWS wins.
The fourth is auditability. When a run has to be defensible, which document was refunded, which was escalated, which field was overwritten, model-chosen control flow is a liability because it is hard to prove the model always took the required step. A Step Functions execution gives you a full execution history you can inspect state by state, and a Flow gives you a fixed graph you can trace node by node. The more the outcome has to be provable, the more the drawn sequence is worth.
Underneath all of it: reach for the model-driven agent only when the value it adds, discovering a path you could not draw, outweighs what it costs in determinism and operational control. For a workflow whose steps you already know, the agent is the expensive answer to a question you were not asking.
What we’ll filter on
- Who decides the control flow, the model at run time or a designer ahead of time?
- Does the run need durable, long-running, resumable execution with per-step retries and error handling?
- How much does the job reach beyond the model into other AWS services, fan-out, parallelism, and human-approval waits?
- How provable and auditable does each run need to be?
- Is the GenAI work the whole job, or one step inside a larger process?
The landscape
An agent
An instruction prompt, a set of tools, and optional knowledge bases, with the foundation model running the reason-act-observe loop and choosing each step. On Bedrock that is an agent hosted on AgentCore, reaching its tools through a gateway.
Good when the path varies request to request and cannot be drawn in advance, and when the whole job is essentially reasoning with tools. Its ceiling is that the control flow is nondeterministic, every decision point is another model call, and there is no built-in durable execution, retry policy, or human-pause primitive; you would build those yourself around it.
The sibling piece on orchestrating multiple agents covers the multi-agent extension of this shape.
A Bedrock Flow
A visual builder and runtime for a mostly-deterministic pipeline. You place nodes, prompt nodes, knowledge-base nodes, agent nodes, Lambda nodes, condition nodes, iterators, input and output, and wire the data between them. The graph is fixed; the model runs inside nodes but never chooses the order.
Good when the sequence is known, stays close to Bedrock-native building blocks (prompts, knowledge bases, agents), and you want predictability and traceability with low assembly effort. A Flow can still drop in an agent node for one open-ended step.
Its limits are that it is oriented around Bedrock primitives rather than the whole AWS surface, and it is not the tool for hours-long durable runs, large fan-out, or human-approval waits.
An AWS Step Functions state machine
A general-purpose, durable workflow orchestrator. You define states in a state machine: task states that call a service or a Lambda or Bedrock, choice states that branch, parallel states, a Map state that fans out across a collection, wait states, and success or failure states.
Standard workflows run up to a year with exactly-once execution and full history; Express workflows run up to five minutes for high-volume, short-lived work. Each state can carry retry and catch policies, and the callback pattern lets a run pause on a task token until a human or external system responds. It integrates directly with a large range of AWS services and invokes Bedrock as one step among many.
It is the right home when durability, retries, fan-out, cross-service reach, or human pauses dominate, and the model is a participant rather than the conductor. The cost is that you design and maintain the state machine, and for a job that is purely model reasoning it is more scaffolding than you need.
Combining them
You can also combine them rather than choosing once. A Step Functions state machine can invoke a Bedrock model, an agent, or a Flow as a single task state, so a durable, auditable outer workflow can wrap a model-driven inner step exactly where run-time flexibility matters. The engines are layers, not rivals.
Evaluation
Side by side
| Property | Bedrock agent | Bedrock Flow | Step Functions |
|---|---|---|---|
| Control flow decided by | Model, at run time | Designer, ahead of time | Designer, ahead of time |
| Deterministic / testable | ✗ | ✓ | ✓ |
| Durable long-running execution | ✗ | ✗ | ✓ (up to 1 year, Standard) |
| Built-in per-step retry and catch | ✗ | Limited | ✓ |
| Fan-out and parallelism | ✗ | Iterator over a set | ✓ (Map, Parallel) |
| Human-approval pause | Build it yourself | ✗ | ✓ (callback task token) |
| Reach across AWS services | Via action-group Lambdas | Bedrock-centric plus Lambda | ✓ (broad direct integrations) |
| Auditable per-run trace | Trace of model reasoning | Node-by-node graph | ✓ (full execution history) |
| Best when | Path must be discovered at run time | Known Bedrock-native pipeline | Durable cross-service process, model as one step |
Reading it for the document job: the sequence is known, so the model-driven agent is the wrong axis; the run is long, retry-heavy, fans out over thousands of records, and pauses for a human, which is more than a Flow is built to carry; the state machine is the fit.
How to route it
The solution
Build it as a Step Functions state machine, with Bedrock as one task among many. Everything the job actually demands, surviving a throttle, surviving a Lambda timeout, waiting two days on a reviewer, and being auditable document by document afterwards, is a first-class primitive there and code you would otherwise write and operate.
Model the document job directly. A Map state fans out across the batch. For each document, a task state invokes Bedrock to extract the fields, a choice state checks the validation result, a retry policy on the extraction state handles throttling with exponential backoff, and a catch handler routes a repeat failure to a wait-for-callback task that pauses on a task token until a reviewer decides. Success and failure states close each item out.
Pick the workflow type on run length. Standard gives durable execution up to a year with a full history you can inspect state by state, which is what the operations team is asking for when they want to open a run and see which documents took which path. Express suits short, high-volume runs and does not carry that history, so it is the wrong half of the choice here.
The cost is honest: you design and maintain the state machine. That is effort worth spending when the workflow is the product and the model is a participant, and effort wasted on a job that is purely model reasoning.
Why not an agent. The model handles branching for free, and that is worth its nondeterminism when the path has to be discovered. This path is known in advance. Asking an agent to carry it means asking it to be a durable workflow engine, and it is not one: building retries, resumability, a two-day human pause, and an audit trail around an agent is rebuilding Step Functions by hand, with none of the guarantees.
Why not a Flow. A Flow draws a fixed graph with little assembly and traces node by node, which suits a single-pass, Bedrock-native pipeline well. This job is none of those things. It runs for hours, fans out across thousands of records with independent per-item retry, and waits on a human. That is the state machine’s territory, not the Flow’s.
Where they combine. The engines layer, and the answer here stays a state machine because of it. A Step Functions task state can invoke a Bedrock model, an agent, or a Flow, so when one step in this spine later needs the model to choose its own path, that step becomes an agent invocation inside the state machine rather than a reason to abandon it.
Worked example
The job: a few thousand supplier documents, extract fields, validate, store, escalate two-time failures to a human.
Framed as an agent. One agent per document reads the file, calls an extract tool, checks the schema, and on a second failure calls a tool that notifies a reviewer. It works for a single document in isolation, but the batch has no home: nothing durably tracks three thousand in-flight runs, nothing retries a throttled model call with backoff for you, and nothing pauses cleanly for a two-day human response. You would wrap the agent in your own queue, retry logic, and state store, which is a workflow engine you are now maintaining.
Framed as a Flow. A Flow expresses the per-document happy path well: input, extract via a prompt or agent node, condition on validity, branch to store or to a notify Lambda. It falls short on the batch shape. Fanning out over thousands of records with independent retry policies, running branches in parallel, and pausing days for a reviewer are past what the Flow runtime is meant to carry.
Framed as a state machine. A Map state iterates the batch. Per document: a task state invokes Bedrock to extract, with a retry policy for throttling and a catch for hard errors; a choice state branches on the validation outcome; a failed document goes to a wait-for-callback state that holds on a task token until a reviewer resolves it, then rejoins; a clean document writes to the store. The run is durable across the whole night, every document has an inspectable history, and the model call is one state among many. This is the framing that fits the job; the other two were rebuilding a workflow engine that already exists.
What’s worth remembering
- The first question is who decides the control flow: the model at run time (an agent) or a designer ahead of time (a Flow or a state machine). A known sequence does not need a model choosing its order.
- A Bedrock agent has no built-in durable execution, retry policy, or human-pause primitive. Wanting those around an agent is a sign the job is really a workflow.
- Map and Parallel states give fan-out and parallelism; the callback task-token pattern gives a durable human-approval pause. None of these is native to an agent.
- The engines combine. A Step Functions state machine can invoke a model, an agent, or a Flow as a task, so a durable outer workflow can wrap a model-driven inner step where flexibility pays off.
- Match the engine to the job: path the model must discover, an agent; known Bedrock-native pipeline, a Flow; durable, retryable, cross-service process with the model as one step, a state machine.