Converse with an Amazon Bedrock flow - Amazon Bedrock

Converse with an Amazon Bedrock flow

Note

Amazon Bedrock Flows multi-turn conversation is in preview release for Amazon Bedrock and is subject to change.

Amazon Bedrock Flows multi-turn conversation enables dynamic, back-and-forth conversations between users and flows, similar to a natural dialogue. When an agent node requires clarification or additional context, it can intelligently pause the flow's execution and prompt the user for specific information. This creates a more interactive and context-aware experience, as the node can adapt its behavior based on user responses. For example, if an initial user query is ambiguous or incomplete, the node can ask follow-up questions to gather the necessary details. Once the user provides the requested information, the flow seamlessly resumes execution with the enriched input, ensuring more accurate and relevant results. This capability is particularly valuable for complex scenarios where a single interaction may not be sufficient to fully understand and address the user's needs.

How to process a multi-turn conversation in a flow

To use a multi-turn conversation in a flow, you need an agent node connected to an Amazon Bedrock agent. When you run the flow, a multi-turn conversation happens when the agent needs further information from the user before it can continue. This section describes a flow that uses an agent with the following instructions:

You are a playlist creator for a radio station. When asked to create a playlist, ask for the number of songs, the genre of music, and a theme for the playlist.

For information about creating an agent see Automate tasks in your application using AI agents.

Step 1: Start the flow

You start a flow by calling the InvokeFlow operation. You include the initial content that you want to send to the flow. In the following example, the document field contains a request to Create a playlist. Each conversation has a unique identifer (execution ID) that identifies the conversation within the flow. To get the execution ID, you don't send theexecutionID field in your first call to InvokeFlow. The response from InvokeFlow includes the execution ID. In your code, use the identifer to track multiple conversations and identify a conversation in further calls to the InvokeFlow operation.

The following is example JSON for a request to InvokeFlow.

{ "flowIdentifier": "XXXXXXXXXX", "flowAliasIdentifier": "YYYYYYYYYY", "inputs": [ { "content": { "document": "Create a playlist." }, "nodeName": "FlowInputNode", "nodeOutputName": "document" } ] }

Step 2: Retrieve agent requests

If the agent node in the flow decides that it needs more information from the user, the response stream (responseStream) from InvokeFlow includes an FlowMultiTurnInputRequestEvent event object. The event has the requested information in the content (FlowMultiTurnInputContent) field. In the following example, the request in the document field is for information about the number of songs, genre of music, and theme for the playlist. In your code, you then need to get that information from the user.

The following is an example FlowMultiTurnInputRequestEvent JSON object.

{ "nodeName": "AgentsNode_1", "nodeType": "AgentNode", "content": { "document": "Certainly! I'd be happy to create a playlist for you. To make sure it's tailored to your preferences, could you please provide me with the following information: 1. How many songs would you like in the playlist? 2. What genre of music do you prefer? 3. Is there a specific theme or mood you'd like for the playlist? Once you provide these details, I'll be able to create a customized playlist just for you." } }

Since the flow cannot continue until more input is received, the flow also emits a FlowCompletionEvent event. A flow always emits the FlowMultiTurnInputRequestEvent before the FlowCompletionEvent. If the value of completionReason in the FlowCompletionEvent event is INPUT_REQUIRED, the flow need more information before it can continue.

The following is an example FlowCompletionEvent JSON object.

{ "completionReason": "INPUT_REQUIRED" }

Step 3: Send the user response to the flow

Send the user response back to the flow by calling the InvokeFlow operation again. Be sure to include the executionIdfor the conversation.

The following is example JSON for the request to InvokeFlow. The document field contains the response from the user.

{ "flowIdentifier": "AUS7BMHXBE", "flowAliasIdentifier": "4KUDB8VBEF", "executionId": "b6450554-f8cc-4934-bf46-f66ed89b60a0", "inputs": [ { "content": { "document": "1. 5 songs 2. Welsh rock music 3. Castles" }, "nodeName": "AgentsNode_1", "nodeInputName": "agentInputText" } ] }

If the flow needs more information, the flow creates further FlowMultiTurnInputRequestEvent events.

Step 4: End the flow

When no more information is needed, the flow emits a FlowOutputEvent event which contains the final response.

The following is an example FlowOutputEvent JSON object.

{ "nodeName": "FlowOutputNode", "content": { "document": "Great news! I've created a 5-song Welsh rock playlist centered around the theme of castles. Here's the playlist I've put together for you: Playlist Name: Welsh Rock Castle Anthems Description: A 5-song Welsh rock playlist featuring songs about castles Songs: 1. Castell y Bere - Super Furry Animals 2. The Castle - Manic Street Preachers 3. Caerdydd (Cardiff Castle) - Stereophonics 4. Castell Coch - Catatonia 5. Chepstow Castle - Feeder This playlist combines Welsh rock bands with songs that reference castles or specific Welsh castles. Enjoy your castle-themed Welsh rock music experience!" } }

The flow also emits a FlowCompletionEvent event. The value of completionReason is SUCCESS.

The following is an example FlowCompletionEvent JSON object.

{ "completionReason": "SUCCESS" }

The following sequence diagram shows the steps in a multi-turn flow.

Flow steps for a multi-turn conversation.

Creating and running an example flow

In this example, you create a flow that uses an agent to create playlists for a radio station. The agent asks clarifying questions to determine the number of songs, the genre of music, and the theme for the playlist.

To create the flow
  1. Create an agent in the Amazon Bedrock console by following the instructions at Create and configure agent manually.

    • For step 2.d, enter You are a playlist creator for a radio station. When asked to create a playlist, ask for the number of songs, the genre of music, and a theme for the playlist..

    • For step 2.e, in User input, choose Enabled. Doing this lets the agent request more information, as needed.

  2. Create the flow by following the instructions at Create a flow in Amazon Bedrock. Make sure the flow has an input node, an agents node, and an output node.

  3. Link the agent node to the agent that you created in step 1. The flow should look like the following image.

    Flow multi-turn conversation
  4. Run the flow in the Amazon Bedrock console. For testing you can trace the steps that the flow makes. For more information, see Test a flow in Amazon Bedrock.

The following Python code example shows how use the flow.

To run the code, specify the following:

  • region_name – The AWS Region in which you are running the flow.

  • FLOW_ID – The ID of the flow.

  • FLOW_ALIAS_ID – The alias ID of the flow.

For information about getting the IDs, see View information about flows in Amazon Bedrock. The code prompts for an initial request to send to the flow and requests more input as needed by the flow. The code doesn't manage other requests from the agent, such as requests to call AWS Lambda functions. For more information, see How Amazon Bedrock Agents works. While running, the code generates FlowTraceEvent objects that you can use to track the path from the input to the response that flow returns. For more information, see Track each step in your flow by viewing its trace in Amazon Bedrock.

""" Runs an Amazon Bedrock flow and handles muli-turn interaction for a single conversation. """ import logging import boto3 import botocore import botocore.exceptions logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) def invoke_flow(client, flow_id, flow_alias_id, input_data, execution_id): """ Invoke an Amazon Bedrock flow and handle the response stream. Args: client: Boto3 client for Amazon Bedrock agent runtime flow_id: The ID of the flow to invoke flow_alias_id: The alias ID of the flow input_data: Input data for the flow execution_id: Execution ID for continuing a flow. Use the value None on first run. Returns: Dict containing flow_complete status, input_required info, and execution_id """ response = None request_params = None if execution_id is None: # Don't pass execution ID for first run. request_params = { "flowIdentifier": flow_id, "flowAliasIdentifier": flow_alias_id, "inputs": [input_data], "enableTrace": True } else: request_params = { "flowIdentifier": flow_id, "flowAliasIdentifier": flow_alias_id, "executionId": execution_id, "inputs": [input_data], "enableTrace": True } response = client.invoke_flow(**request_params) if "executionId" not in request_params: execution_id = response['executionId'] input_required = None flow_status = "" # Process the streaming response for event in response['responseStream']: # Check if flow is complete. if 'flowCompletionEvent' in event: flow_status = event['flowCompletionEvent']['completionReason'] # Check if more input us needed from user. elif 'flowMultiTurnInputRequestEvent' in event: input_required = event # Print the model output. elif 'flowOutputEvent' in event: print(event['flowOutputEvent']['content']['document']) elif 'flowTraceEvent' in event: logger.info("Flow trace: %s", event['flowTraceEvent']) return { "flow_status": flow_status, "input_required": input_required, "execution_id": execution_id } if __name__ == "__main__": session = boto3.Session(profile_name='default', region_name='YOUR_FLOW_REGION') bedrock_agent_client = session.client('bedrock-agent-runtime') # Replace these with your actual flow ID and alias ID FLOW_ID = 'YOUR_FLOW_ID' FLOW_ALIAS_ID = 'YOUR_FLOW_ALIAS_ID' flow_execution_id = None finished = False # Get the intial prompt from the user. user_input = input("Enter input: ") flow_input_data = { "content": { "document": user_input }, "nodeName": "FlowInputNode", "nodeOutputName": "document" } logger.info("Starting flow %s", FLOW_ID) try: while not finished: # Invoke the flow until successfully finished. result = invoke_flow( bedrock_agent_client, FLOW_ID, FLOW_ALIAS_ID, flow_input_data, flow_execution_id) status = result['flow_status'] flow_execution_id = result['execution_id'] more_input = result['input_required'] if status == "INPUT_REQUIRED": # The flow needs more information from the user. logger.info("The flow %s requires more input", FLOW_ID) user_input = input( more_input['flowMultiTurnInputRequestEvent']['content']['document'] + ": ") flow_input_data = { "content": { "document": user_input }, "nodeName": more_input['flowMultiTurnInputRequestEvent']['nodeName'], "nodeInputName": "agentInputText" } elif status == "SUCCESS": # The flow completed successfully. finished = True logger.info("The flow %s successfully completed.", FLOW_ID) except botocore.exceptions.ClientError as e: print(f"Client error: {str(e)}") logger.error("Client error: %s", {str(e)}) except Exception as e: print(f"An error occurred: {str(e)}") logger.error("An error occurred: %s", {str(e)}) logger.error("Error type: %s", {type(e)})