Exam Room · Advanced Generative AI Developer

Building Deterministic Pipelines With Bedrock Flows

July 29, 2026 · 28 min read

Generative AI Development · part of The Exam Room

The situation

A support team wants 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 the retrieval actually found something on topic, and then either draft an answer grounded in those passages 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 a Bedrock agent, because the model is doing the interesting part. That instinct is worth questioning. The sequence here is not something the model needs to discover; a person can draw it on a whiteboard in a minute, and it will look the same for every question. What the team wants is a predictable pipeline they can trace, version, and ship, with as little glue code as possible, and with the whole thing staying inside Bedrock next to the knowledge base and prompts it already uses.

The choice sits between three ways of assembling the steps: 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 for a known sequence that placement is the whole question.

What actually matters

The first thing to name is where the control flow is decided. In a Bedrock 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 earns its cost when the path genuinely cannot be known in advance. It is exactly what you do not want when the path is known, because model-chosen control flow is nondeterministic, harder to test, and costs a model call every time the model stops to decide what to do next. A Bedrock Flow inverts this: 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 it never chooses the order.

The second is how much of the work is Bedrock-native. This job is prompts, a knowledge base, and a condition; those are all first-class Bedrock building blocks. A Flow is built precisely for stitching those blocks together with the least assembly, and it keeps the whole pipeline in one place with the knowledge base and the prompts it calls. If instead 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 how much durability, error handling, and cross-service reach the run needs. A Flow executes a graph for a single invocation; it is not a durable, hours-long, resumable workflow engine with per-step retry policies and human-approval pauses. The support pipeline does not need those: it answers one question in one pass. When a job does need durable execution, exactly-once semantics, fan-out, or a human pause measured in days, that is Step Functions territory, and a Flow is not meant for it.

The fourth is safe deployment. The team wants to change a prompt without breaking what is live. Bedrock Flows are versioned, and you point traffic at an alias rather than at the mutable draft, so you can publish a new version and move the alias when you are ready, or roll it back by moving the alias. That is the difference between a graph you can iterate on and a graph you are afraid to touch.

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 control. For a pipeline whose steps you already know and whose blocks are Bedrock-native, the drawn graph is the cheaper, more predictable answer.

What we’ll filter on

  1. Is the sequence known ahead of time, or does the model need to discover it at run time?
  2. Are the building blocks Bedrock-native (prompts, knowledge bases, agents), or does the work spread across the wider AWS surface?
  3. How much durability, per-step retry, fan-out, and human-approval waiting does a single run need?
  4. How much assembly and glue code are you willing to own versus have the runtime provide?
  5. Does the workflow need clean versioning and a safe way to promote or roll back what is live?

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 for a known pipeline is that the control flow is nondeterministic, every decision point is another model call, and there is no drawn graph to trace or version as a fixed sequence.

A Bedrock Flow

A low-code visual builder and runtime, native to Bedrock, for a defined and mostly-deterministic workflow. You place nodes and connect them with data links: an input node and an output node at the edges; prompt nodes that run a prompt (inline or from Prompt Management); knowledge-base nodes that query a knowledge base; agent nodes that hand one step to an agent; Lambda nodes for custom code; condition nodes that branch on the data flowing through; iterator and collector nodes to loop over a set; and a Lex node to bring in an Amazon Lex bot.

Because you draw the links, the control flow is yours, designed ahead of time, not decided by a model at run time. Flows are versioned and deployed behind aliases.

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 are that it is Bedrock-centric rather than a general workflow engine, and it is not built 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: task states that call 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 durably for up to a year with exactly-once execution and a full history; Express workflows run up to five minutes for high-volume, short-lived work. Each state can carry its own retry and catch policy, and the callback pattern lets a run pause 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 a participant rather than the whole job. The sibling piece, when to orchestrate with Step Functions instead of an agent, walks that case in depth.

Layering them

You can also layer 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, and a Flow can drop in an agent node for one open-ended step. The engines are layers, not rivals; the question is which one owns the sequence for the job in front of you.

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
Low-code, visual build Configured, not drawn ✓ (drag-and-wire graph) ✓ (Workflow Studio)
Bedrock-native building blocks ✓ (prompts, KBs, agents, Lex) Via task integrations
Durable long-running execution ✓ (up to 1 year, Standard)
Built-in per-step retry and catch
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)
Versioned deployment Aliases ✓ (versions and 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 the model-driven agent is the wrong axis; the run is a single pass over Bedrock-native blocks with one branch, so the durability and cross-service reach of a state machine is more engine than the job needs; the Flow is the fit.

The solution

Build it as a Bedrock Flow. The sequence is known, the branch is a single condition, the building blocks are all Bedrock-native, and the team wants to stay next to the knowledge base and prompts they already run. That is the shape a Flow is for, and nothing in this job argues against it.

The pieces slot together directly. An input node hands the question in; a knowledge-base node retrieves the relevant passages; a condition node checks whether the retrieval cleared a relevance threshold; on the yes branch a prompt node drafts a grounded answer and hands it to the 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 needs the model to decide the order, so nothing spends a model call deciding it.

Deployment is disciplined in a way that matters for something subscribers touch: publish a version, point an alias at it, and move or roll back the alias to control what is live.

Keep the agent node in your pocket rather than in the graph. 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 the otherwise deterministic pipeline without handing the whole thing to the model. Today no step needs it.

The limit worth knowing before you commit: a Flow executes a graph for a single invocation. Hours-long runs, large fan-out with independent per-branch retries, and human-approval waits measured in days are not what the runtime carries. If the assistant grows a durable, cross-service spine, that is the signal to re-open the question rather than to bend the Flow around it.

Why not an agent. The model handles branching for free, which is worth its nondeterminism when the path truly varies. Here the path does not vary: a person can draw it on a whiteboard, and it looks the same for every question. Choosing an agent buys run-time flexibility nobody needs and pays for it with a model call at every decision point and a trace you cannot prove walks the required step. Reach for the agent when you cannot draw the sequence.

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 six nodes wired 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 passes back the retrieved passages along with their relevance scores. A condition node reads that output and branches: if the best score clears the threshold, control flows to a prompt node; if not, it flows to a Lambda node. The prompt node runs a grounded-answer prompt from Prompt Management, taking both the original question and the retrieved passages as inputs, and writes a drafted answer to the output node. The Lambda node, on the other branch, files a ticket with the question attached and writes a holding message to the output node instead. Every request walks one of those two branches, and which one is decided by the data, not by a model choosing what to do next.

Once it behaves, you 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; you 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. That is the shape a Flow is for, and it is the shape the support team already had in their heads.

Input question text Knowledge base retrieve passages and scores Relevant match? yes Prompt node draft grounded answer no Lambda node file ticket, holding message Output reply to caller designer draws every link; the model runs inside a node, never picks the order
A Flow is a graph you draw: nodes wired by data links, one fixed path per branch, the model working inside a node rather than choosing the sequence.

What’s worth remembering

  1. A Bedrock Flow is a graph of nodes connected by data links, so the control flow is designed by you ahead of time, not decided by a model at run time. That is the whole difference from an agent.
  2. 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.
  3. A Flow can still drop in an agent node for one open-ended step, so a mostly-deterministic graph can borrow model-driven judgement in exactly one place.
  4. A Flow executes a graph for a single invocation; it is not a durable, hours-long, resumable workflow engine, and it has no built-in per-step retry policy or human-approval pause.
  5. 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 with the model as one step, a state machine.

These posts are LLM-aided. Backbone, original writing, and structure by Craig. Research and editing by Craig + LLM. Proof-reading by Craig.