

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 与 Amazon Bedrock 流对话
<a name="flows-multi-turn-invocation"></a>

**注意**  
Amazon Bedrock 流多轮对话在 Amazon Bedrock 中为预览版，可能会有更改。

Amazon Bedrock Flows 多轮 back-and-forth对话支持用户和流程之间的动态对话，类似于自然对话。当代理节点需要澄清或更多上下文时，它可以智能地暂停流的执行并提示用户输入特定信息。这就创造了一种更具互动性和情境感知性的体验，因为节点可以根据用户的响应调整其行为。例如，如果初始用户查询不明确或不完整，节点可以提出后续问题以收集必要的详细信息。用户提供所请求的信息后，流将使用扩充后的输入无缝恢复执行，从而确保结果更加准确和相关。对于单次交互可能不足以完全理解和满足用户需求的复杂场景来说，此功能特别有用。

**Topics**
+ [如何在流中处理多轮对话](#flows-multi-turn-invocation-how)
+ [创建并运行示例流](#flows-multi-turn-invocation-example-flow)

## 如何在流中处理多轮对话
<a name="flows-multi-turn-invocation-how"></a>

要在流中使用多轮对话，您需要一个连接到 Amazon Bedrock 代理的[代理节点](flows-nodes.md#flows-nodes-agent)。运行流时，如果代理需要从用户处获得更多信息才能继续，就会发生多轮对话。此部分将介绍一个流，该流使用的代理遵循以下指令：

```
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.
```

有关创建代理的信息，请参阅[使用人工智能代理在应用程序中自动执行任务](agents.md)。

### 步骤 1：启动流
<a name="flows-multi-turn-invocation-start-flow"></a>

您可以通过调用[InvokeFlow](https://docs.aws.amazon.com/bedrock/latest/APIReference/API_agent-runtime_InvokeFlow.html)操作来启动流程。您需要添加要发送到流的初始内容。在以下示例中，`document` 字段包含*创建播放列表*的请求。每个对话都有一个唯一标识符（*执行 ID*），用于标识流中的对话。要获取执行 ID，您无需在首次调用 `InvokeFlow` 时发送 `executionID` 字段。来自 `InvokeFlow` 的响应包含执行 ID。在您的代码中，请使用标识符跟踪多个对话，并在后续调用 `InvokeFlow` 操作时标识一个对话。

以下是调用 `InvokeFlow` 的请求的示例 JSON。

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

### 步骤 2：检索代理请求
<a name="flows-multi-turn-invocation-retrieve-requests"></a>

如果流中的代理节点确定需要从用户处获得更多信息，来自 `InvokeFlow` 的响应流（`responseStream`）将包含一个 `FlowMultiTurnInputRequestEvent` 事件对象。该事件的 `content`（`FlowMultiTurnInputContent`）字段中包含要求提供的信息。在以下示例中，`document` 字段中的请求是获取有关播放列表的歌曲数量、音乐流派和主题的信息。在您的代码中，您随后需要从用户处获取这些信息。

以下是 `FlowMultiTurnInputRequestEvent` JSON 对象的示例：

```
{
    "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."
    }
}
```

由于在收到更多输入之前流无法继续，因此流还会发出一个 `FlowCompletionEvent` 事件。流总是在 `FlowCompletionEvent` 之前发出 `FlowMultiTurnInputRequestEvent`。如果 `FlowCompletionEvent` 事件中的 `completionReason` 的值为 `INPUT_REQUIRED`，则流需要更多信息才能继续。

以下是 `FlowCompletionEvent` JSON 对象的示例：

```
{
    "completionReason": "INPUT_REQUIRED"
}
```

### 步骤 3：将用户响应发送到流
<a name="flows-multi-turn-invocation-continue"></a>

再次调用 `InvokeFlow` 操作将用户响应发送回流。务必包含对话的 `executionId`。

以下是调用 `InvokeFlow` 的请求的示例 JSON。`document` 字段包含来自用户的响应。

```
{
  "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"
    }
  ]
}
```

如果流需要更多信息，流会创建更多 `FlowMultiTurnInputRequestEvent` 事件。

### 步骤 4：结束流
<a name="flows-multi-turn-invocation-end"></a>

当不需要更多信息时，流会发出一个包含最终响应的 `FlowOutputEvent` 事件。

以下是 `FlowOutputEvent` JSON 对象的示例：

```
{
    "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!"
     }
}
```

流还会发出一个 `FlowCompletionEvent` 事件。`completionReason` 的值为 `SUCCESS`。

以下是 `FlowCompletionEvent` JSON 对象的示例：

```
{
    "completionReason": "SUCCESS"
}
```

以下序列图显示了多轮流中的步骤。

![\[多轮对话的流步骤。\]](http://docs.aws.amazon.com/zh_cn/bedrock/latest/userguide/images/flows/flows-multi-turn-steps.png)


## 创建并运行示例流
<a name="flows-multi-turn-invocation-example-flow"></a>

在此示例中，您将创建一个使用代理为电台创建播放列表的流。代理要求澄清问题，以确定播放列表的歌曲数量、音乐流派和主题。

**创建流**

1. 按照[手动创建和配置代理](agents-create.md)中的说明在 Amazon Bedrock 控制台中创建代理。
   + 对于步骤 *2.d*，请输入 **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.**。
   + 对于步骤 *2.e*，请在**用户输入**中选择**已启用**。这样做可以让代理根据需求请求更多信息。

1. 按照[在 Amazon Bedrock 中创建和设计流](flows-create.md)中的说明创建流。确保流具有输入节点、代理节点和输出节点。

1. 将代理节点链接到您在步骤 1 中创建的代理。流应类似下图内容。  
![\[流多轮对话\]](http://docs.aws.amazon.com/zh_cn/bedrock/latest/userguide/images/flows/flows-multi-turn.png)

1. 在 Amazon Bedrock 控制台中运行流。在测试时，您可以跟踪流执行的步骤。有关更多信息，请参阅 [在 Amazon Bedrock 中测试流](flows-test.md)。

以下 Python 代码示例演示如何使用流。

要运行该代码，请指定以下内容：
+ `region_name`— 您运行流程的 AWS 区域。
+ `FLOW_ID` – 流的 ID。
+ `FLOW_ALIAS_ID` – 流的别名 ID。

有关获取的信息 IDs，请参阅[在 Amazon Bedrock 中查看有关流的信息](flows-view.md)。该代码会提示输入要向流发送的初始请求，然后根据流的需求请求更多输入。该代码不管理来自代理的其他请求，例如调用 AWS Lambda 函数的请求。有关更多信息，请参阅 [Amazon Bedrock 代理的工作原理](agents-how.md)。运行时，代码会生成 `FlowTraceEvent` 对象，您可以使用这些对象来跟踪从输入到流返回的响应的路径。有关更多信息，请参阅 [通过在 Amazon Bedrock 中查看流中每一步的跟踪记录来跟踪流中的每一步通过查看流中每一步的跟踪记录来跟踪流中的每一步](flows-trace.md)。

```
"""
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)})
```