Skip to lesson

AWSAWS Certified Generative AI Developer - Professional2026-101.6 Implement prompt engineering strategies and governance for FM interactions

Route flow branches through validated processing

Completed by the knowledge check

Learning objective

Implement conditional Prompt Flow branches, reusable nodes, and pre/postprocessing steps.

AWS documentation uses the name Amazon Bedrock Flows for the capability that the objective calls Prompt Flow. This lesson uses the documented name.

Core idea

A conditional flow should branch on explicit, typed values rather than on an application’s interpretation of unconstrained prose. Amazon Bedrock Flows provides Condition nodes for routing and Lambda function nodes for code-based processing. Prompt nodes can reference saved Prompt management resources, giving different flows a shared instruction artifact.

The architectural decision is which work belongs to generation, deterministic processing, or routing. A model can interpret a request; code can validate the resulting category; a Condition node can select the appropriate path. Combining all three responsibilities inside a prompt hides decisions that the graph should expose.

Reuse means sharing an explicit resource and its contract, not assuming every flow node is a callable subflow. This Bite uses saved prompt references and Lambda function references as the concrete reuse mechanisms. Sequential wiring, draft preparation, and versioned invocation remain the concern of 1.6.8.

How it works

Produce typed branch inputs

A Condition node can accept multiple inputs; define a named, typed input for each value your comparisons need. Apply the expression and prompt-output contracts in 1.6.8, including explicit parsing before using generated JSON as an object.

Choose branch fields that represent meaningful decisions. A validated category can select a specialized prompt. A missing-field flag can select clarification. A verified policy restriction can select a safe terminal response. Do not let a model-generated confidence number act as an authorization grant; permission checking belongs to trusted application logic.

Define ordered conditions and a default

Condition expressions reference input names, not the input-extraction path. After defining an input named route, a condition can compare route == "support". Numeric comparisons use operators such as >, >=, <, and <=. Logical expressions use and, or, and not; parentheses make grouping explicit. Equality also requires matching data types, so the number 1 and the string "1" are different values.

Conditions are evaluated in order. If multiple conditions match, the earlier condition takes precedence. Put a narrow, consequential restriction before a broad category match when the restriction must win. Test the overlap deliberately rather than relying on a diagram’s visual position.

Provide a default outcome for unmatched values. In the API, the Condition node uses configuration.condition.conditions; branch connections have type Conditional and identify the condition through configuration.conditional.condition. The default connection uses default. Bedrock’s flow testing checks that valid condition expressions and a default outcome exist.

Keep branch selection separate from payload movement. Condition nodes do not have outputs. Conditional connections select downstream execution, while Data connections supply the downstream inputs. AWS’s condition-flow example connects the Flow input output directly to each Flow output node’s document input, alongside the conditional connections. Routing alone does not define the receiving prompt’s variable values.

Reuse resources with a stable contract

A Prompt node can use a saved prompt through sourceConfiguration.resource.promptArn instead of duplicating inline instructions. Different node instances can reference the same prompt while supplying different variable values. Use an approved version-qualified reference and the governance in 1.6.2 and 1.6.3 when the instruction artifact must remain reproducible.

A Lambda function node selects a function through configuration.lambdaFunction.lambdaArn. You can use that processing resource in multiple graphs, but each node still needs correctly configured input and output types. Shared code does not remove the obligation to test each graph’s mappings.

Define a narrow function contract, such as “parse and validate the route envelope” or “validate and format the final response.” Avoid a catch-all function that interprets arbitrary upstream outputs and hides routing policy inside code. Keep branch policy visible in the Condition node when deterministic comparisons can express it.

Implement pre/postprocessing at explicit boundaries

An Inline code node is another processing option. AWS states: “Inline code node is in preview release for Amazon Bedrock and is subject to change.” It supports only Python 3.12 (Python_3), with up to five inline code nodes per flow, and is not supported in asynchronous flow execution. Inputs become Python variables with the exact node-input names; response contains the result of the last executed line. The isolated execution environment has no internet access. Use it for bounded local transformations when that preview scope is acceptable; use a Lambda resource when processing needs an external function or shared function contract.

For preprocessing, a Lambda node can normalize accepted input, validate required business fields, or produce a typed record for downstream prompts. Bedrock sends an event containing messageVersion, flow, and node. Within node.inputs, each configured input includes its name, type, expression, and resolved value. Read that event contract rather than assuming the Lambda receives the application’s original request unchanged.

The function’s response appears at the node’s functionResponse output. Configure its type to match the value returned. If later expressions select $.data.route, return an object with that field rather than a serialized object string.

For postprocessing, parse generated content, verify business constraints and evidence identifiers, and construct the response envelope the application accepts. If validation fails, return an explicit status and route it through another Condition node to a controlled outcome. Do not turn an invalid model response into an apparently valid answer by filling missing facts with defaults.

Transformation and validation are different operations. Normalizing harmless whitespace can preserve meaning. Changing a product identifier or inventing a missing evidence reference changes meaning. Define which transformations are allowed and retain enough original data to diagnose errors.

Test the routing contract

ValidateFlowDefinition validates a proposed graph definition and returns validations, an array of identified errors. A successful HTTP response alone does not mean that array is empty. Use graph validation to catch structural defects, then run behavioral cases with InvokeFlow and enableTrace set to true to inspect node inputs and outputs.

Include every named branch, the default, overlapping conditions, wrong types, malformed generated JSON, and processing failures. Verify that the chosen output is appropriate and that each downstream node receives the intended payload. Reuse the deployment mechanisms from 1.6.8 after branch behavior passes the regression requirements in 1.6.6.

Key distinctions and trade-offs

Condition versus classification: The model can generate a category. The Condition node compares a supplied value with explicit rules. Validation connects those responsibilities safely.

Conditional versus Data connection: One selects a route; the other carries a value. A correct branch with a missing data connection is still a defective graph.

Input expression versus processing code: $.data expressions extract values. Lambda code parses, normalizes, and validates them. Do not expect extraction syntax to perform arbitrary transformations.

Resource reuse versus identical behavior: A saved prompt or function can be shared, but different variable mappings and surrounding branches can produce different outcomes. Test the integration in every consuming flow.

Architecture / decision scenario

A service desk receives requests about troubleshooting, billing, and unsupported topics. A preprocessing Lambda validates the request envelope and preserves the original text. A classification prompt returns a route proposal; a second Lambda parses it into an object and marks missing information.

The Condition node evaluates a missing-information rule before the support and billing rules. Conditional connections select clarification or a specialized prompt, while Data connections supply the validated request. Unknown categories take the default path to a controlled unsupported response. Both specialized paths reference approved saved prompts and share a postprocessing Lambda contract.

Postprocessing rejects unsupported evidence identifiers and emits a validation status. A final condition returns either the accepted response or a safe failure envelope. Tests cover every route, missing information that overlaps a supported category, malformed classifier output, and invalid final evidence. Trace inspection confirms both branch selection and the data each chosen prompt consumed.

Common exam traps

  • Treating condition order as irrelevant when rules overlap.
  • Omitting a default outcome for unexpected categories.
  • Expecting a Condition node to emit a payload through an output port.
  • Confusing a conditional connection with a data connection.
  • Passing generated JSON text to an Object input without parsing it.
  • Assuming shared prompt or Lambda resources eliminate integration testing.

What to remember

  • Validate typed values before using them for consequential branching.
  • Conditions use named inputs, ordered comparisons, and a default outcome.
  • Wire branch selection and branch data separately.
  • Reuse saved prompt ARNs and Lambda resources through explicit contracts.
  • Test pre/postprocessing and every route with observable intermediate values.

Knowledge check

References