The situation
A support team needs an assistant that answers policy questions from subscribers. The shape is fixed and everyone already knows it. Take the question, pull the relevant passages from a knowledge base built on the policy documents, check whether retrieval found something on topic, then either draft a grounded answer or hand the question to a fallback that files a ticket for a human. Every request walks the same path. The only variation is the branch on whether the knowledge base returned anything useful.
The first instinct is to build an agent, because the model does the interesting part. That instinct is worth questioning. The sequence is not something the model has to discover. A person can draw it on a whiteboard in a minute, and it looks the same for every question. What the team needs is a predictable pipeline they can trace, version and ship, with as little glue code as possible, sitting inside Bedrock next to the knowledge base and prompts they already run.
So the choice sits between three ways of assembling the steps: a model-driven agent, a visually defined Amazon Bedrock Flow, and an AWS Step Functions state machine. Each puts the decision about what happens next in a different place.
What actually matters
The first thing to name is where control flow is decided. In a model-driven agent the foundation model produces the sequence at run time. It reads the request, emits a tool or knowledge-base call, takes the result back, and emits the next call, looping until it returns a final answer. That behaviour helps when the path genuinely cannot be known in advance. It works against you when the path is known, because a model-produced sequence is nondeterministic, harder to test, and adds a model call at every decision point. A Flow inverts that. A designer places the nodes and draws the links, and the runtime walks the graph in the order you wired it. The model still runs inside a prompt node or an agent node, but the order comes from the links.
The second is how much of the work is Bedrock-native. This job is prompts, a knowledge base, and a condition, all first-class Bedrock building blocks. A Flow is built for stitching those together with the least assembly, and it keeps the pipeline in one place with the knowledge base and prompts it calls. If the job were mostly reads and writes to other AWS services, fan-out across thousands of records, and long durable runs, the centre of gravity would move outside Bedrock and a Flow would be the wrong shape.
The third is durability, error handling and cross-service reach. A synchronous InvokeFlow call runs until the graph finishes or times out at one hour, and there is no per-step retry policy and no multi-day approval pause. The support pipeline answers one question in one pass, so none of that is missing. When a job needs exactly-once semantics, per-state retries, fan-out, or a human pause measured in days, that is Step Functions territory.
There is also the shape of the bill and the latency. A Flow adds no orchestration charge of its own; you pay for the model invocations, the knowledge-base queries, the Lambda calls and anything else the nodes touch. Each node is another hop, so latency is roughly the sum of the steps on the branch taken. A drawn graph with one model call per request costs less and finishes sooner than a reason-act-observe loop that makes several, and the drawing tells you by how much.
The fourth is safe deployment. A prompt change should not break what is live. Flows are versioned, and you point traffic at an alias rather than at the mutable working draft. So you publish a new version, move the alias, and move it back if the new one regresses. That is the difference between a graph the team iterates on and a graph the team leaves alone.
What we’ll filter on
- Is the sequence known ahead of time, or does the model have to discover it at run time?
- Are the building blocks Bedrock-native (prompts, knowledge bases, agents), or does the work spread across the wider AWS surface?
- How much durability, per-step retry, fan-out and human-approval waiting does one run need?
- How much assembly and glue code are you willing to own rather than have the runtime provide?
- Does the workflow need clean versioning and a safe way to promote or roll back what is live?
The landscape
A model-driven agent
An instruction prompt, a set of tools, and optional knowledge bases, with the foundation model running the reason-act-observe loop and emitting each step. On AWS that used to mean Amazon Bedrock Agents. Since 30 July 2026 that service is Amazon Bedrock Agents Classic, in maintenance mode and closed to accounts with no prior usage. Existing agents keep running and their APIs stay available, but the model catalogue there is frozen and no new features are planned. New agent work goes to Amazon Bedrock AgentCore, where action groups become MCP tools behind AgentCore Gateway.
Good when the path varies request to request and cannot be drawn in advance, and the job is essentially reasoning with tools. Its ceiling for a known pipeline: the sequence is nondeterministic, every decision point is another model call, and there is no drawn graph to trace or version.
An Amazon Bedrock Flow
Amazon Bedrock Flows, renamed from Prompt Flows when it reached general availability in November 2024, is a low-code visual builder and runtime for a defined, mostly deterministic workflow. You place nodes and connect them with data links. A flow has exactly one input node and up to twenty output nodes. In between: prompt nodes running a prompt inline or from Prompt management; knowledge-base nodes; agent nodes handing one step to an agent alias; Lambda function nodes and inline code nodes (preview, Python 3.12 only) for custom code; condition nodes that branch on the data; iterator, collector and DoWhile loop nodes for repetition; S3 retrieval and storage nodes; and a Lex node for an Amazon Lex bot.
Because you draw the links, control flow is designed ahead of time. Flows are versioned and deployed behind aliases. The quotas are tight enough to check before you design: 40 nodes per flow, 5 condition nodes carrying 5 conditions each, 10 versions and 10 aliases per flow, and 100 flows per account.
The canvas also changes who can own the pipeline. The graph is drawn and republished in the console, so a support lead or a policy owner can add a node, rewire a link and publish a version without an application deployment. That argument is separate from determinism, and for some teams it is the stronger one.
Good when the sequence is known, the blocks are Bedrock-native, and you want predictability and traceability with less code than wiring it by hand. Its limits: it is Bedrock-centric rather than a general workflow engine, with no per-step retry policy and no parallel fan-out.
An AWS Step Functions state machine
A general-purpose, durable workflow orchestrator. You define states: task states calling a service, 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 for up to a year with exactly-once execution, and their history stays retrievable for 90 days after a run completes. Express workflows run up to five minutes for high-volume, short-lived work, at-least-once when started asynchronously. Each state carries its own retry and catch policy, and the callback pattern holds a run on a task token until a human or external system responds. It integrates directly with a broad range of AWS services and invokes Bedrock as one step among many.
The right home when durability, retries, fan-out, cross-service reach or human pauses dominate, and the model is one participant rather than the whole job.
Layering them
You can layer them rather than choosing once. A state machine can invoke a Bedrock model, an agent or a Flow as a single task state, and a Flow can drop in an agent node for one open-ended step. The engines stack; the question is which one owns the sequence for the job in front of you.
Evaluation
Side by side
| Property | Model-driven agent | Bedrock Flow | Step Functions |
|---|---|---|---|
| Control flow decided by | Model output, at run time | Designer, ahead of time | Designer, ahead of time |
| Deterministic / testable | ✗ | ✓ | ✓ |
| Low-code, visual build | Configured, not drawn | ✓ (drag-and-wire graph) | ✓ (Workflow Studio) |
| Bedrock-native building blocks | ✓ | ✓ (prompts, KBs, Lex; agent node needs a Classic agent) | Via task integrations |
| Durable long-running execution | ✗ | 1 hour sync, 24 hours async (preview) | ✓ (up to 1 year, Standard) |
| Built-in per-step retry and catch | ✗ | ✗ | ✓ |
| Fan-out and parallelism | ✗ | Iterator, one item at a time | ✓ (Map, Parallel) |
| Human-in-the-loop pause | Return of control | Agent-node multi-turn (preview, Classic agent only) | ✓ (callback task token) |
| Reach across AWS services | Gateway tools and Lambdas | Bedrock-centric plus Lambda | ✓ (broad direct integrations) |
| Versioned deployment | Versions and aliases | ✓ (10 versions, 10 aliases) | ✓ (versions and aliases) |
| Best when | Path must be discovered at run time | Known Bedrock-native pipeline | Durable cross-service process |
Reading it for the support pipeline: the sequence is known, so a model-driven agent is the wrong axis. The run is a single pass over Bedrock-native blocks with one branch, so a state machine is more engine than the job needs. The Flow fits.
The solution
Build it as an Amazon Bedrock Flow. The sequence is known, the branch is a single condition, the building blocks are all Bedrock-native, and the team stays next to the knowledge base and prompts they already run.
The pieces slot together directly. An input node hands the question in. A knowledge-base node retrieves passages, each carrying a relevance score. A condition node compares the top score against a threshold. On the yes branch a prompt node drafts a grounded answer and hands it to an output node; on the no branch a Lambda node files a ticket. Every run walks the same path and traces node by node. Nothing here calls a model to settle the order.
Condition nodes are narrower than code, and that narrowness is what makes them reproducible. A condition compares named inputs to each other, or to a constant, using the six relational operators: equal, not equal, and the four greater-than and less-than comparisons. Combine them with and, or and not. The operands are strings, numbers and booleans, nothing richer. Conditions are evaluated in order and the earlier match takes precedence, so put the specific case above the general one and wire a default branch. The same scores take the same path every time.
Sequential prompt chains are what the graph gives you beyond that branch. A prompt node holds a prompt and its model configuration, and its modelCompletion output becomes an input variable of the next node. Draft-then-critique-then-rewrite is three nodes on one canvas rather than three application calls with your own orchestration between them. The cost is linear in the links: a four-step chain is four model invocations, four lots of latency, and four chances for the output to drift from what you evaluated. Chain when a step needs its own prompt and model configuration, not because the canvas makes adding one easy.
Reusable prompt components keep the wording out of the graph. A prompt node can reference a prompt ARN from Bedrock Prompt management instead of carrying inline text, so several Flows share one governed prompt and a wording fix lands everywhere at once. Inline text is quicker to draw and slower to live with. Prompt nodes and knowledge-base nodes both take a guardrail identifier and version too, so the policy travels with the node.
Pre-processing and post-processing belong in Lambda function nodes at either end of the model nodes. Strip the caller’s formatting on the way in, check the drafted answer carries a citation on the way out, reject a payload that will not parse. Work with one right answer belongs in code rather than in a prompt.
Tracing is how you check, after the fact, which path a request took. Set enableTrace to true on InvokeFlow and every flowOutputEvent comes back alongside a flowTraceEvent. A nodeInputTrace and a nodeOutputTrace carry the fields going into and out of each node with a timestamp, and a conditionNodeOutputTrace names the conditions that were satisfied, so the record shows which branch fired and on what data. The console test window shows the same per-node inputs and outputs behind Show trace. Asynchronous runs expose the equivalent through ListFlowExecutionEvents. When a subscriber complains about an answer, that is the evidence.
The iterator and collector nodes cover the batch case without a state machine. An iterator takes an array and emits its items one at a time, downstream nodes run per item, and a collector gathers the results back into an array. The items are processed in sequence, not in parallel, so a hundred policy questions run a hundred times slower than one. A flow gets one iterator and one collector, which caps how far that pattern stretches. Genuine fan-out is a Map state.
Deployment is where the discipline shows, and subscribers see the output of this one. A Flow has a working draft and immutable published versions behind an alias, the same shape a prompt version and a guardrail version have, and the three only make sense promoted together. A Flow version pointing at a prompt draft cannot be rolled back, because the thing that changed underneath it has no version to return to. Put the Flow version, the prompt version and the pinned model ID in one release bundle and move them as a unit. Ten versions and ten aliases per flow is the ceiling, so prune as you go.
Leave the agent node out until a step needs it. A Flow is not all-or-nothing about flexibility, so if one step later turns out to need open-ended reasoning, an agent node drops a model-driven step into an otherwise deterministic pipeline. Check what that node points at first. Its configuration takes the alias ARN of a Bedrock Agents Classic agent, which an account with no prior Agents usage can no longer create, so new work of that kind goes to AgentCore.
The limits worth knowing before you commit: a synchronous InvokeFlow runs for at most an hour. Asynchronous flow executions, still in preview, stretch a run to 24 hours with each node capped at five minutes, but inline code nodes are unsupported there and a timed-out run does not resume. There is no per-step retry, no parallel fan-out, and no approval wait measured in days. If the assistant grows a durable cross-service spine, re-open the question rather than bending the Flow around it.
Why not an agent. A model-driven loop handles branching without anyone drawing it, which is worth the nondeterminism when the path truly varies. Here it does not vary. An agent adds run-time flexibility nobody needs, a model call at every decision point, and a trace you cannot check against a required step. It also means Agents Classic, closed to new accounts, or a move onto AgentCore for a sequence a person can draw in a minute.
Why not Step Functions. Retries, parallelism, fan-out and human pauses are first-class there rather than code you write and operate, and none of those is what this job asks for. The run is one pass over Bedrock blocks, so the state machine is more engine than the work requires, and you would maintain it for capabilities the pipeline never exercises.
Worked example
The job: answer a subscriber policy question from a knowledge base, or escalate to a human when retrieval comes up short. Drawn as a Flow, it is seven nodes in a fixed order.
The input node receives the question text. Its output link feeds a knowledge-base node, which queries the policy knowledge base and returns retrievalResults, an array of passages with their relevance scores. A condition node reads the top score through an expression and branches. Above the threshold, control flows to a prompt node; otherwise, to a Lambda node. The prompt node runs a grounded-answer prompt from Prompt management, taking both the question and the retrieved passages as input variables, and writes a drafted answer to an output node. The Lambda node files a ticket with the question attached and writes a holding message to a second output node. Each branch ends in its own output node, and the data fixes which branch a request takes.
Once it behaves, publish a version and point the production alias at it. A later change, a tighter grounding prompt or a different relevance threshold, becomes a new version. Move the alias when it is ready, or move it back if it regresses. The graph is small, deterministic, entirely inside Bedrock, and traceable node by node. It is also the shape the support team already had in their heads.
What’s worth remembering
- Amazon Bedrock Flows gives you a graph of nodes connected by data links, so control flow is designed ahead of time instead of produced by a model at run time.
- Reach for a Flow when the sequence is known, the blocks are Bedrock-native, and you want predictability and traceability with less code than wiring it by hand.
- Publish immutable versions and point an alias at one, and promote the Flow version, the prompt version and the pinned model ID together; a Flow version pointing at a prompt draft cannot be rolled back.
- A synchronous
InvokeFlowcaps at one hour and asynchronous flow executions at 24 hours in preview, with no per-step retry, no parallel fan-out, and no multi-day approval pause. - Amazon Bedrock Agents is now Agents Classic, closed since 30 July 2026 to accounts without prior usage, so a Flow’s agent node and any new model-driven work point at AgentCore.
- Match the assembler to the job: a path the model must discover, an agent; a known Bedrock-native pipeline you draw and version, a Flow; a durable cross-service process, a state machine.