

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 與 Amazon Bedrock 流程交談
<a name="flows-multi-turn-invocation"></a>

**注意**  
Amazon Bedrock Flows 多回合對話為 Amazon Bedrock 的預覽版本，可能會有所變更。

Amazon Bedrock Flows 多回合對話可在使用者與流程之間進行動態來回的對話，類似於自然對話。當代理程式節點需要釐清或其他內容時，它可以智慧地暫停流程的執行，並提示使用者提供特定資訊。這會建立更具互動性和內容感知的體驗，因為節點可以根據使用者回應調整其行為。例如，如果初始使用者查詢不明確或不完整，則節點可以提出後續問題來收集必要的詳細資訊。一旦使用者提供請求的資訊後，流程會順暢地使用豐富的輸入繼續執行，以確保更準確和相關的結果。對於單一互動可能不足以完全了解及解決使用者需求的複雜案例，此功能特別有用。

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

如需有關建立代理程式的詳細資訊，請參閱 [使用 AI 代理程式自動執行應用程式中的任務](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_tw/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_tw/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。

如需取得 ID 的相關資訊，請參閱 [檢視 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)})
```