

终止支持通知：2025年9月15日， AWS 我们将停止对Amazon Lex V1的支持。2025 年 9 月 15 日之后，您将无法再访问 Amazon Lex V1 控制台或 Amazon Lex V1 资源。如果您使用的是 Amazon Lex V2，请改为参阅 [Amazon Lex V2 指南](https://docs.aws.amazon.com/lexv2/latest/dg/what-is.html)。

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

# 预订旅程
<a name="ex-book-trip"></a>

本示例介绍了如何创建可以支持多个目的的自动程序。本示例还介绍了如何使用会话属性实现跨目的信息共享。创建机器人后，您可以在 Amazon Lex 控制台中使用测试客户端来测试该机器人 (BookTrip)。客户端针对每个用户输入使用 [PostText](API_runtime_PostText.md) 运行时 API 操作向 Amazon Lex 发送请求。

本示例中的 BookTrip 机器人配置有两个意图（BookHotel 和 BookCar）。例如，假设用户首先预订酒店。在交互过程中，用户提供入住日期、地点和入住天数等信息。实现目的后，客户端可以使用会话属性保留这一信息。有关会话属性的更多信息，请参阅 [PostText](API_runtime_PostText.md)。

现在假设用户继续预订汽车。使用用户在之前的 BookHotel intent 中提供的信息（即目的地城市以及入住和退房日期），您配置为初始化和验证意图的代码挂钩（Lambda 函数）初始化 BookCar 意图的空位数据（即目的地、接送城市、提货日期和返回日期）。 BookCar 这一过程表明，跨目的信息共享让您可以构建能够与用户展开动态会话的自动程序。

在本示例中，我们使用以下会话属性。只有客户端和 Lambda 函数可以设置和更新会话属性。Amazon Lex 只在客户端和 Lambda 函数之间传递这些会话属性。Amazon Lex 不会保留或修改任何会话属性。
+ `currentReservation` — 包含正在进行的预订的插槽数据及其他相关信息。下面是从客户端发到 Amazon Lex 的一个示例请求。请求正文中包含 `currentReservation` 会话属性。

  ```
  POST /bot/BookTrip/alias/$LATEST/user/wch89kjqcpkds8seny7dly5x3otq68j3/text
  "Content-Type":"application/json"
  "Content-Encoding":"amz-1.0"
  
  {
     "inputText":"Chicago",
     "sessionAttributes":{
         "currentReservation":"{\"ReservationType\":\"Hotel\",
                                \"Location\":\"Moscow\",
                                \"RoomType\":null,
                                \"CheckInDate\":null,
                                \"Nights\":null}"
     }
  }
  ```

   
+ `lastConfirmedReservation` — 包含前一个意图的类似信息（如果有）。例如，如果用户预订了酒店，然后正在预订汽车，则此会话属性会存储先前 BookHotel 意图的车位数据。

   
+ `confirmationContext` — Lambda 函数在根据前一个预订的插槽数据（如果有）来预填充某些插槽数据时，会将本属性设置为 `AutoPopulate`。这可以实现跨目的信息共享。例如，如果用户之前预订了酒店，现在需要预订汽车，则 Amazon Lex 可以提示用户确认（或拒绝）在预订酒店的同一城市和相同日期预订汽车





在本练习中，您使用蓝图创建 Amazon Lex 机器人和 Lambda 函数。有关蓝图的更多信息，请参阅[Amazon Lex 和 AWS Lambda 蓝图](lex-lambda-blueprints.md)。





**下一个步骤**  
[步骤 1：查看本练习中使用的蓝图](ex-book-trip-blueprints.md)

# 步骤 1：查看本练习中使用的蓝图
<a name="ex-book-trip-blueprints"></a>

**Topics**
+ [机器人蓝图概述 (BookTrip)](#ex-book-trip-bp-summary-bot)
+ [Lambda 函数蓝图概述 () lex-book-trip-python](#ex-book-trip-summary-lambda)

## 机器人蓝图概述 (BookTrip)
<a name="ex-book-trip-bp-summary-bot"></a>

您用于创建自动程序的蓝图 (**BookTrip**) 提供以下预配置：
+ **槽类型** – 两种自定义槽类型：
  +  `RoomTypes`，使用枚举值 `king`、`queen` 和 `deluxe`，用于 `BookHotel` 目的。
  +  `CarTypes`，使用枚举值 `economy`、`standard`、`midsize`、`full size`、`luxury` 和 `minivan`，用于 `BookCar` 目的。

     
+ **意图 1 (BookHotel)** — 其预配置如下：
  + **预配置的槽** 
    + `RoomType`，属于 `RoomTypes` 自定义槽类型
    + `Location`，属于 `AMAZON.US_CITY` 内置槽类型
    + `CheckInDate`，属于 `AMAZON.DATE` 内置槽类型
    + `Nights`，属于 `AMAZON.NUMBER` 内置槽类型
  + **预配置的表达** 
    + “预订酒店”
    + “我想预订酒店” 
    + “在 \$1Location\$1 预订 \$1Nights\$1 晚”

    如果用户表达出上述任意一种说法，Amazon Lex 就会确定用户的意图是 `BookHotel`，然后提示用户提供插槽数据。
  + **预配置的提示** 
    + 针对 `Location` 槽的提示 –“您要住在哪个城市？”
    + 针对 `CheckInDate` 槽的提示 –“您想要在哪天入住？”
    + 针对 `Nights` 槽的提示 –“您要住几天？” 
    + 针对 `RoomType` 槽的提示 –“您想预订哪种类型的房间，双人床房、大床房还是豪华大床房？” 
    + 确认声明 — “好吧，我让你在 \$1Location\$1 住一晚 \$1Nights\$1 晚，从 \$1CheckInDate\$1 开始。是否要预订？” 
    + 拒绝 –“好的，已经取消了正在进行的预订。”

       
+ **意图 2 (BookCar)** — 其预配置如下：
  + **预配置的槽** 
    + `PickUpCity`，属于 `AMAZON.US_CITY` 内置类型
    + `PickUpDate`，属于 `AMAZON.DATE` 内置类型
    + `ReturnDate`，属于 `AMAZON.DATE` 内置类型
    + `DriverAge`，属于 `AMAZON.NUMBER` 内置类型
    + `CarType`，属于 `CarTypes` 自定义类型
  + **预配置的表达** 
    + “预订汽车”
    + “订一辆车” 
    + “办理汽车预订”

    如果用户说出其中任何一个，Amazon Lex 就会确定 BookCar 其意图，然后提示用户输入槽位数据。
  + **预配置的提示**
    + 针对 `PickUpCity` 槽的提示 –“您需要在哪座城市租赁汽车？”
    + 针对 `PickUpDate` 槽的提示 –“您想从哪天开始租赁汽车？”
    + 针对 `ReturnDate` 槽的提示 –“您想在哪天归还汽车？”
    + 针对 `DriverAge` 槽的提示 –“驾驶此次所租汽车的司机多大年龄？”
    + 针对 `CarType` 插槽的提示 —“您想要租哪种类型的汽车？ 我们最受欢迎的车型是经济型、中型和豪华型汽车”
    + 确认声明 — “好吧，我让你在 \$1CarType\$1 到 \$1PickUpCity\$1 租一套 \$1ReturnDate\$1。PickUpDate是否要预订？” 
    + 拒绝 –“好的，已经取消了正在进行的预订。”

## Lambda 函数蓝图概述 () lex-book-trip-python
<a name="ex-book-trip-summary-lambda"></a>

除了机器人蓝图外，还 AWS Lambda 提供了一个蓝图 (**lex-book-trip-python**)，您可以将其用作机器人蓝图的代码挂钩。关于机器人蓝图和相应 Lambda 函数蓝图的列表，请参阅[Amazon Lex 和 AWS Lambda 蓝图](lex-lambda-blueprints.md)。

使用 BookTrip 蓝图创建机器人时，您可以将此 Lambda 函数添加为用于 initialization/validation 用户数据输入BookCar 和意图实现的代码挂钩，从而更新意图（和 BookHotel）的配置。



提供的本 Lambda 函数展示了动态会话，该会话使用之前了解的用户信息 (保存在会话属性中) 来初始化目的的槽值。有关更多信息，请参阅 [管理对话上下文](context-mgmt.md)。

**下一个步骤**  
[步骤 2：创建 Amazon Lex 机器人](ex-book-trip-create-bot.md)

# 步骤 2：创建 Amazon Lex 机器人
<a name="ex-book-trip-create-bot"></a>

在本节中，您将创建一个 Amazon Lex 机器人 (BookTrip)。

1. 登录 AWS 管理控制台 并打开 Amazon Lex 控制台，网址为[https://console.aws.amazon.com/lex/](https://console.aws.amazon.com/lex/)。

1. 在 **Bots** 页面上，选择 **Create**。

1. 在 **Create your Lex bot** 页面上，
   + 选择 **BookTrip** 蓝图。
   + 保留默认的机器人名称 (BookTrip)。

1. 选择**创建**。控制台会向 Amazon Lex 发送一系列请求以便创建机器人。注意以下几点：

1. 控制台显示 BookTrip 机器人。在**编辑器**选项卡上，查看预配置意图的详细信息（BookCar 和）。 BookHotel

1. 在测试窗口中测试机器人。使用以下内容与您的自动程序进行测试会话：  
![\[与客服交谈，客服在对话中引发客户行程的城市、日期、晚数和房间类型。然后，客服确认预订。\]](http://docs.aws.amazon.com/zh_cn/lex/latest/dg/images/book-trip-no-lambda-10.png)

   根据用户的初始输入（“预订酒店”），Amazon Lex 推断出意图 (BookHotel)。然后，自动程序使用在本目的中预配置的提示来引导用户提供槽数据。用户提供所有插槽数据之后，Amazon Lex 会向客户端返回一条包含所有用户输入的消息作为响应。客户端会显示响应中的消息，如下所示。

   ```
   CheckInDate:2016-12-18 Location:Chicago Nights:5 RoomType:queen
   ```

   现在，您继续进行对话并尝试在接下来的对话中预订汽车。  
![\[与客服交谈，客服在对话中引发客户租车的城市、起始日期、归还日期、驾驶员年龄和汽车类型。然后，客服确认预订。\]](http://docs.aws.amazon.com/zh_cn/lex/latest/dg/images/book-trip-no-lambda-20.png)

   请注意,
   + 此时不进行用户数据验证。例如，您可以提供任何城市来预订酒店。
   + 您会再次提供一些相同的信息 (目的地、提车城市、提车日期及归还日期) 来预订汽车。在动态会话中，您的自动程序应该根据用户之前为预订酒店而提供的输入来初始化一些信息。

   在下一部分，您会创建一个 Lambda 函数，以便通过会话属性利用跨目的信息共享来进行一些用户数据验证和初始化工作。然后，您可以通过添加 Lambda 函数作为代码挂钩来更新意图配置，以执行 initialization/validation 用户输入和实现意图。

**下一个步骤**  
[步骤 3：创建 Lambda 函数](ex-book-trip-create-lambda-function.md)

# 步骤 3：创建 Lambda 函数
<a name="ex-book-trip-create-lambda-function"></a>

在本节中，您将使用控制台中提供的蓝图 (**lex-book-trip-python**) 创建 Lambda 函数。 AWS Lambda 您还可以使用控制台提供的示例事件数据来调用 Lambda 函数，从而对其进行测试。

此 Lambda 函数用 Python 编写。



1. 登录 AWS 管理控制台 并打开 AWS Lambda 控制台，网址为[https://console.aws.amazon.com/lambda/](https://console.aws.amazon.com/lambda/)。

1. 选择**创建函数**。

1. 选择**使用蓝图**。键入 **lex** 查找蓝图，选择 `lex-book-trip-python` 蓝图。

1. 选择**配置**，按如下方式配置 Lambda 函数。
   + 键入 Lambda 函数名称 (`BookTripCodeHook`)。
   + 对于角色，选择 **Create a new role from template(s)**，然后键入角色名称。
   + 保留其他默认值。

1. 选择**创建函数**。

1. 如果您使用的是英语 (美国) (en-US) 以外的区域设置，请按照[更新特定区域设置的蓝图](lex-lambda-blueprints.md#blueprint-update-locale)中所述更新意图名称。

1. 测试 Lambda 函数 您使用用于预订汽车和预订酒店的示例数据调用两次 Lambda 函数。

   1. 从**选择测试事件**下拉列表中，选择**配置测试事件**。

   1. 从**示例事件模板**列表中，选择 **Amazon Lex 预订酒店**。

      此示例事件与 Amazon Lex request/response 模型相匹配。有关更多信息，请参阅 [使用 Lambda 函数](using-lambda.md)。

   1. 选择**保存并测试**。

   1. 验证 Lambda 函数已成功执行。在此情况下，此响应与 Amazon Lex 响应模型相匹配。

   1. 重复这一步骤。这次从**示例事件模板**列表中选择 **Amazon Lex 预订汽车**。Lambda 函数会处理汽车预订工作。





**下一个步骤**  
[步骤 4：将 Lambda 函数添加为代码挂钩](ex-book-trip-create-integrate.md)

# 步骤 4：将 Lambda 函数添加为代码挂钩
<a name="ex-book-trip-create-integrate"></a>

在本节中，您将通过添加 Lambda 函数作为 BookCar 和配 BookHotel送活动的代码挂钩来更新和意图 initialization/validation 的配置。请确保您选择了 \$1LATEST 版本的意图，因为您只能更新 \$1LATEST 版本的 Amazon Lex 资源。



1. 在 Amazon Lex 控制台中，选择**BookTrip**机器人。

1. 在**编辑**器选项卡上，选择**BookHotel**意图。按以下方式更新意图配置：

   1. 确保意图版本 (意图名称旁边) 为 \$1LATEST。

   1. 按以下方式将 Lambda 函数添加为初始化和验证代码挂钩：
      + 在**选项**中，选择**初始化和验证代码挂钩**。
      + 从列表中选择您的 Lambda 函数。

   1. 按以下方式将 Lambda 函数添加为履行代码挂钩：
      + 在**履行**中，选择 **AWS Lambda 函数**。
      + 从列表中选择您的 Lambda 函数。
      + 选择 **Goodbye message** 并键入消息。

   1. 选择**保存**。

1. 在**编辑**器选项卡上，选择 BookCar 意图。按照之前的步骤将 Lambda 函数添加为验证和实现代码挂钩。

   

1. 选择**构建**。控制台会向 Amazon Lex 发送一系列请求以便保存配置。

1. 测试自动程序。有了能够执行初始化、用户数据验证和履行工作的 Lambda 函数，您就能在接下来的对话中看到用户交互中的差异：  
![\[与客服交谈，客服在对话中引发行程预订的城市、日期、晚数和房间类型，然后确认预订。\]](http://docs.aws.amazon.com/zh_cn/lex/latest/dg/images/book-trip-with-lambda-30.png)

   有关从客户端（控制台）到 Amazon Lex 以及从 Amazon Lex 到 Lambda 函数的数据流的更多信息，请参阅[数据流：预订酒店目的](book-trip-detail-flow.md#data-flow-book-hotel)。

1. 按照下图中所示继续进行对话并预订汽车：  
![\[与客服交谈，客服在对话中引发驾驶员的年龄和汽车类型，然后确认汽车预订。\]](http://docs.aws.amazon.com/zh_cn/lex/latest/dg/images/book-trip-with-lambda-40.png)

   当您选择预订汽车时，客户端（控制台）会向 Amazon Lex 发送包含会话属性的请求（来自之前的对话 BookHotel）。Amazon Lex 将此信息传递给 Lambda 函数，然后 Lambda 函数初始化（即预填充）一些 BookCar 槽位数据（即、、 PickUpDate和）。 ReturnDate PickUpCity
**注意**  
这体现了将会话属性用于跨目的保留背景信息的过程。控制台客户端在测试窗口中提供 **Clear** 链接，用户可以使用此链接清除之前的所有会话属性。

   有关从客户端（控制台）到 Amazon Lex 以及从 Amazon Lex 到 Lambda 函数的数据流的更多信息，请参阅[数据流：预订汽车目的](book-trip-detail-flow.md#data-flow-book-car)。

# 信息流的详细信息
<a name="book-trip-detail-flow"></a>

在本练习中，您使用 Amazon Lex 控制台中提供的测试窗口客户端与 Amazon Lex BookTrip 机器人进行了对话。本节介绍以下内容：
+ 客户端与 Amazon Lex 之间的数据流。

   

  本节假定客户端使用 `PostText` 运行时 API 向 Amazon Lex 发送请求，并显示相应的请求和响应详细信息。有关 `PostText` 运行时 API 的更多信息，请参阅 [PostText](API_runtime_PostText.md)。
**注意**  
有关客户端和 Amazon Lex（客户端在其中使用 `PostContent` API）之间的信息流示例，请参阅[步骤 2a (可选)：查看语音信息流的详细信息 (控制台)](gs-bp-details-postcontent-flow.md)。

   
+ Amazon Lex 与 Lambda 函数之间的数据流。有关更多信息，请参阅 [Lambda 函数输入事件和响应格式](lambda-input-response-format.md)。

**Topics**
+ [数据流：预订酒店目的](#data-flow-book-hotel)
+ [数据流：预订汽车目的](#data-flow-book-car)

## 数据流：预订酒店目的
<a name="data-flow-book-hotel"></a>

本部分介绍了获得每个用户输入后会发生的情况。

1. 用户：“book a hotel”

   1. 客户端 (控制台) 将向 Amazon Lex 发送以下 [PostText](API_runtime_PostText.md) 请求：

      ```
      POST /bot/BookTrip/alias/$LATEST/user/wch89kjqcpkds8seny7dly5x3otq68j3/text
      "Content-Type":"application/json"
      "Content-Encoding":"amz-1.0"
      
      {
         "inputText":"book a hotel",
         "sessionAttributes":{}
      }
      ```

      请求 URI 和正文都向 Amazon Lex 提供信息：
      + 请求 URI-提供机器人名称 (BookTrip)、机器人别名 (\$1LATEST) 和用户名。后面的 `text` 表示它是一个 `PostText` API 请求 (而不是 `PostContent`)。
      + 请求正文 – 包括用户输入 (`inputText`) 和空 `sessionAttributes`。最初这是一个空对象，Lambda 函数首先设置会话属性。

      

   1. 在 `inputText` 中，Amazon Lex 可检测意图 (BookHotel)。此意图配置有 Lambda 函数作为代码挂钩，以用于用户数据初始化/验证。因此，Amazon Lex 会通过传递以下信息作为事件参数来调用 Lambda 函数（请参阅[输入事件格式](lambda-input-response-format.md#using-lambda-input-event-format)）：

      ```
      {
         "messageVersion":"1.0",
         "invocationSource":"DialogCodeHook",
         "userId":"wch89kjqcpkds8seny7dly5x3otq68j3",
         "sessionAttributes":{
         },
         "bot":{
            "name":"BookTrip",
            "alias":null,
            "version":"$LATEST"
         },
         "outputDialogMode":"Text",
         "currentIntent":{
            "name":"BookHotel",
            "slots":{
               "RoomType":null,
               "CheckInDate":null,
               "Nights":null,
               "Location":null
            },
            "confirmationStatus":"None"
         }
      }
      ```

      除了客户端发送的信息以外，Amazon Lex 还包含以下额外数据：
      + `messageVersion` — Amazon Lex 当前只支持 1.0 版。
      + `invocationSource` — 表明 Lambda 函数调用的目的。在本示例中，它会执行用户数据初始化和验证（此时 Amazon Lex 知道用户尚未提供履行意图所需的所有插槽数据）。
      + `currentIntent` – 所有槽值均设置为空。

   1. 此时，所有槽值均为空值。Lambda 函数没有任何内容需要验证。Lambda 函数会向 Amazon Lex 返回以下响应。有关响应格式的信息，请参阅[响应格式](lambda-input-response-format.md#using-lambda-response-format)。

      ```
      {
         "sessionAttributes":{
            "currentReservation":"{\"ReservationType\":\"Hotel\",\"Location\":null,\"RoomType\":null,\"CheckInDate\":null,\"Nights\":null}"
         },
         "dialogAction":{
            "type":"Delegate",
            "slots":{
               "RoomType":null,
               "CheckInDate":null,
               "Nights":null,
               "Location":null
            }
         }
      }
      ```
**注意**  
`currentReservation` — Lambda 函数包含此会话属性。其值为当前槽信息和预订类型。  
只有 Lambda 函数和客户端可以更新这些会话属性。Amazon Lex 只是传递这些值。
`dialogAction.type` — 通过将此值设置为 `Delegate`，Lambda 函数将下一个操作的责任委派给 Amazon Lex。  
如果 Lambda 函数在用户数据验证过程中检测到任何内容，就会向 Amazon Lex 说明后续步骤。

   1. 根据 `dialogAction.type`，Amazon Lex 决定下一个操作（从用户获取 `Location` 插槽的数据）。它会根据目的配置针对这个槽选择一项提示消息（“您要住在哪座城市？”），然后向用户发送以下响应：  
![\[JSON 响应包含对话状态、意图名称、消息、响应卡、会话属性、要引发的插槽和其他插槽。\]](http://docs.aws.amazon.com/zh_cn/lex/latest/dg/images/book-hotel-10.png)

      这些会话属性会被传递到客户端。

      客户端读取响应并显示消息：“您要住在哪座城市？”

1. 用户：“Moscow”

   1. 客户端向 Amazon Lex 发送以下 `PostText` 请求（为便于阅读而添加了换行符）：

      ```
      POST /bot/BookTrip/alias/$LATEST/user/wch89kjqcpkds8seny7dly5x3otq68j3/text
      "Content-Type":"application/json"
      "Content-Encoding":"amz-1.0"
      
      {
         "inputText":"Moscow",
         "sessionAttributes":{
             "currentReservation":"{\"ReservationType\":\"Hotel\",
                                    \"Location\":null,
                                    \"RoomType\":null,
                                    \"CheckInDate\":null,
                                    \"Nights\":null}"
         }
      }
      ```

      除了 `inputText` 以外，客户端还会发送其收到的相同 `currentReservation` 会话属性。

   1. Amazon Lex 首先会根据当前意图来解读 `inputText`（服务记得它已经向特定用户询问了关于 `Location` 插槽的信息）。它会更新当前意图的插槽值并使用以下事件来调用 Lambda 函数：

      ```
      {
          "messageVersion": "1.0",
          "invocationSource": "DialogCodeHook",
          "userId": "wch89kjqcpkds8seny7dly5x3otq68j3",
          "sessionAttributes": {
              "currentReservation": "{\"ReservationType\":\"Hotel\",\"Location\":null,\"RoomType\":null,\"CheckInDate\":null,\"Nights\":null}"
          },
          "bot": {
              "name": "BookTrip",
              "alias": null,
              "version": "$LATEST"
          },
          "outputDialogMode": "Text",
          "currentIntent": {
              "name": "BookHotel",
              "slots": {
                  "RoomType": null,
                  "CheckInDate": null,
                  "Nights": null,
                  "Location": "Moscow"
              },
              "confirmationStatus": "None"
          }
      }
      ```
**注意**  
`invocationSource` 仍然是 `DialogCodeHook`。在此步骤中，我们只验证用户数据。
Amazon Lex 只是向 Lambda 函数传递会话属性。
对于 `currentIntent.slots`，Amazon Lex 已经将 `Location` 插槽更新为 `Moscow`。

   1. Lambda 函数执行用户数据验证，并确定 `Moscow` 是一个无效地点。
**注意**  
在本练习中，Lambda 函数具有一个简单的有效城市列表，而 `Moscow` 不在此列表中。在生产应用中，您可以使用后端数据库来获取这一信息。

      它会将插槽值重置回空值，并让 Amazon Lex 通过发送以下响应来再次提示用户提供另一个值：

      ```
      {
          "sessionAttributes": {
              "currentReservation": "{\"ReservationType\":\"Hotel\",\"Location\":\"Moscow\",\"RoomType\":null,\"CheckInDate\":null,\"Nights\":null}"
          },
          "dialogAction": {
              "type": "ElicitSlot",
              "intentName": "BookHotel",
              "slots": {
                  "RoomType": null,
                  "CheckInDate": null,
                  "Nights": null,
                  "Location": null
              },
              "slotToElicit": "Location",
              "message": {
                  "contentType": "PlainText",
                  "content": "We currently do not support Moscow as a valid destination.  Can you try a different city?"
              }
          }
      }
      ```
**注意**  
`currentIntent.slots.Location` 被重置为空值。
`dialogAction.type` 设置为 `ElicitSlot`，这会让 Amazon Lex 通过提供以下响应来再次提示用户：  
`dialogAction.slotToElicit` – 要将用户提供的数据用到的槽。
`dialogAction.message` - 传达给用户的 `message`。

   1. Amazon Lex 发现 `dialogAction.type` 并通过以下响应向客户端传递信息：  
![\[JSON 响应包含对话状态、意图名称、消息、响应卡、会话属性、要引发的插槽和其他插槽。\]](http://docs.aws.amazon.com/zh_cn/lex/latest/dg/images/book-hotel-20.png)

      客户端只是显示消息：“目前我们不支持莫斯科作为有效目的地，能否换一个城市？”

1. 用户：“Chicago”

   1. 客户端将向 Amazon Lex 发送以下 `PostText` 请求：

      ```
      POST /bot/BookTrip/alias/$LATEST/user/wch89kjqcpkds8seny7dly5x3otq68j3/text
      "Content-Type":"application/json"
      "Content-Encoding":"amz-1.0"
      
      {
         "inputText":"Chicago",
         "sessionAttributes":{
             "currentReservation":"{\"ReservationType\":\"Hotel\",
                                    \"Location\":\"Moscow\",
                                    \"RoomType\":null,
                                    \"CheckInDate\":null,
                                    \"Nights\":null}"
         }
      }
      ```

      

   1. Amazon Lex 知道上下文，即引发 `Location` 插槽的数据。在这个上下文中，它知道 `inputText` 值用于 `Location` 槽。然后，它通过发送以下事件来调用 Lambda 函数：

      ```
      {
          "messageVersion": "1.0",
          "invocationSource": "DialogCodeHook",
          "userId": "wch89kjqcpkds8seny7dly5x3otq68j3",
          "sessionAttributes": {
              "currentReservation": "{\"ReservationType\":\"Hotel\",\"Location\":Moscow,\"RoomType\":null,\"CheckInDate\":null,\"Nights\":null}"
          },
          "bot": {
              "name": "BookTrip",
              "alias": null,
              "version": "$LATEST"
          },
          "outputDialogMode": "Text",
          "currentIntent": {
              "name": "BookHotel",
              "slots": {
                  "RoomType": null,
                  "CheckInDate": null,
                  "Nights": null,
                  "Location": "Chicago"
              },
              "confirmationStatus": "None"
          }
      }
      ```

      Amazon Lex 通过将 `Location` 插槽设置为 `Chicago` 来更新 `currentIntent.slots`。

   1. 根据 `DialogCodeHook` 的 `invocationSource` 值，Lambda 函数会执行用户数据验证。它会将 `Chicago` 识别为有效的插槽值，相应更新会话属性，然后向 Amazon Lex 返回以下响应。

      ```
      {
          "sessionAttributes": {
              "currentReservation": "{\"ReservationType\":\"Hotel\",\"Location\":\"Chicago\",\"RoomType\":null,\"CheckInDate\":null,\"Nights\":null}"
          },
          "dialogAction": {
              "type": "Delegate",
              "slots": {
                  "RoomType": null,
                  "CheckInDate": null,
                  "Nights": null,
                  "Location": "Chicago"
              }
          }
      }
      ```
**注意**  
`currentReservation` — Lambda 函数通过将 `Location` 设置为 `Chicago` 来更新这一会话属性。
`dialogAction.type` – 被设置为 `Delegate`。用户数据有效，Lambda 函数指示 Amazon Lex 选择下一个操作。

       

   1. 根据 `dialogAction.type`，Amazon Lex 选择下一个操作。Amazon Lex 知道它需要更多插槽数据，因此会根据意图配置将下一个未填充的插槽 (`CheckInDate`) 设为最高优先级。它会根据目的配置针对这个槽选择一项提示消息（“您想要在哪天入住？”），然后向客户端发送回以下响应：  
![\[JSON 响应包含对话状态、意图名称、消息、响应卡、会话属性、要引发的插槽和其他插槽。位置插槽现在填充为“芝加哥”。\]](http://docs.aws.amazon.com/zh_cn/lex/latest/dg/images/book-hotel-30.png)

      客户端显示消息：“您想在哪天入住？” 

   

1. 用户交互继续进行（用户提供数据，Lambda 函数验证数据，然后将下一个操作委派给 Amazon Lex）。最后，用户提供所有插槽数据，Lambda 函数验证所有用户输入，然后 Amazon Lex 确定自己获得了所有插槽数据。
**注意**  
在本练习中，用户提供所有插槽数据之后，Lambda 函数会计算酒店的预订价格并将其作为另一个会话属性 (`currentReservationPrice`) 返回。

   此时，意图已准备就绪，但 BookHotel意图已配置为确认提示，要求用户确认后，Amazon Lex 才能实现意图。因此，在预订酒店之前，Amazon Lex 会向客户端发送以下消息来要求确认：  
![\[JSON 响应包含对话状态、意图名称、消息、响应卡、会话属性、要引发的插槽和其他插槽。现在，所有空插槽都已填充。\]](http://docs.aws.amazon.com/zh_cn/lex/latest/dg/images/book-hotel-40.png)

   客户端会显示消息：“好的，确定您要在芝加哥住 5 晚，入住日期是 2016-12-18。是否要预订？”

1. 用户：“yes”

   1. 客户端将向 Amazon Lex 发送以下 `PostText` 请求：

      ```
      POST /bot/BookTrip/alias/$LATEST/user/wch89kjqcpkds8seny7dly5x3otq68j3/text
      "Content-Type":"application/json"
      "Content-Encoding":"amz-1.0"
      
      {
         "inputText":"Yes",
         "sessionAttributes":{
             "currentReservation":"{\"ReservationType\":\"Hotel\",
                                    \"Location\":\"Chicago\",
                                    \"RoomType\":\"queen\",
                                    \"CheckInDate\":\"2016-12-18\",
                                    \"Nights\":\"5\"}",
            "currentReservationPrice":"1195"
         }
      }
      ```

   1. Amazon Lex 将解释确认当前意图的上下文中的 `inputText`。Amazon Lex 知道用户希望继续预订。此时 Amazon Lex 会通过发送以下事件来调用 Lambda 函数，从而履行意图。通过将事件中的 `invocationSource` 设置为 `FulfillmentCodeHook`，它向 Lambda 函数发送信息。Amazon Lex 也将 `confirmationStatus` 设置为 `Confirmed`。

      ```
      {
          "messageVersion": "1.0",
          "invocationSource": "FulfillmentCodeHook",
          "userId": "wch89kjqcpkds8seny7dly5x3otq68j3",
          "sessionAttributes": {
              "currentReservation": "{\"ReservationType\":\"Hotel\",\"Location\":\"Chicago\",\"RoomType\":\"queen\",\"CheckInDate\":\"2016-12-18\",\"Nights\":\"5\"}",
              "currentReservationPrice": "956"
          },
          "bot": {
              "name": "BookTrip",
              "alias": null,
              "version": "$LATEST"
          },
          "outputDialogMode": "Text",
          "currentIntent": {
              "name": "BookHotel",
              "slots": {
                  "RoomType": "queen",
                  "CheckInDate": "2016-12-18",
                  "Nights": "5",
                  "Location": "Chicago"
              },
              "confirmationStatus": "Confirmed"
          }
      }
      ```
**注意**  
`invocationSource` — 此时，Amazon Lex 将此值设置为 `FulfillmentCodeHook`，指示 Lambda 函数履行意图。
`confirmationStatus` – 被设置为 `Confirmed`。

   1. 这次，Lambda 函数实现了 BookHotel 意图，Amazon Lex 完成了预订，然后它会返回以下响应：

      ```
      {
          "sessionAttributes": {
              "lastConfirmedReservation": "{\"ReservationType\":\"Hotel\",\"Location\":\"Chicago\",\"RoomType\":\"queen\",\"CheckInDate\":\"2016-12-18\",\"Nights\":\"5\"}"
          },
          "dialogAction": {
              "type": "Close",
              "fulfillmentState": "Fulfilled",
              "message": {
                  "contentType": "PlainText",
                  "content": "Thanks, I have placed your reservation.   Please let me know if you would like to book a car rental, or another hotel."
              }
          }
      }
      ```
**注意**  
 `lastConfirmedReservation` — 是 Lambda 函数添加的新会话属性（不是 `currentReservation` 和 `currentReservationPrice`）。
`dialogAction.type` — Lambda 函数将此值设置为 `Close`，表示 Amazon Lex 不需要用户响应。
`dialogAction.fulfillmentState` – 被设置为 `Fulfilled` 并且包含要传达给用户的相应 `message`。

      

      

   1. Amazon Lex 查看 `fulfillmentState` 并向客户端发送以下响应：  
![\[JSON 响应包含对话状态、意图名称、消息、响应卡、会话属性、要引发的插槽和其他插槽。所有插槽都已填充，会话属性下最后确认的预订字段现已填充。\]](http://docs.aws.amazon.com/zh_cn/lex/latest/dg/images/book-hotel-60.png)
**注意**  
`dialogState` — Amazon Lex 将此值设置为 `Fulfilled`。
`message` — 与 Lambda 函数提供的消息相同。

       客户端将显示消息。

## 数据流：预订汽车目的
<a name="data-flow-book-car"></a>

本练习中的 BookTrip 机器人支持两种意图（BookHotel 和 BookCar）。预订酒店之后，用户可以继续进行对话以便预订汽车。只要会话未超时，客户端就会在每个后续请求中继续发送会话属性 (本示例中为 `lastConfirmedReservation`)。Lambda 函数可以使用此信息为意图初始化插槽数据。 BookCar 这体现了在跨目的数据共享中使用会话属性的过程。

具体而言，当用户选择 BookCar 意图时，Lambda 函数使用会话属性中的相关信息为意图预填充插槽（PickUpDate ReturnDate、和 PickUpCity）。 BookCar 

**注意**  
Amazon Lex 控制台提供**清除**链接，您可使用此链接清除之前的所有会话属性。

按照以下步骤继续进行对话。

1. 用户：“also book a car”

   1. 客户端将向 Amazon Lex 发送以下 `PostText` 请求：

      ```
      POST /bot/BookTrip/alias/$LATEST/user/wch89kjqcpkds8seny7dly5x3otq68j3/text
      "Content-Type":"application/json"
      "Content-Encoding":"amz-1.0"
      
      {
         "inputText":"also book a car",
         "sessionAttributes":{
             "lastConfirmedReservation":""{\"ReservationType\":\"Hotel\",
                                           \"Location\":\"Chicago\",
                                           \"RoomType\":\"queen\",
                                           \"CheckInDate\":\"2016-12-18\",
                                           \"Nights\":\"5\"}"
         }
      }
      ```

      客户端会发送 `lastConfirmedReservation` 会话属性。

   1. Amazon Lex 从中检测到意图 (BookCar) `inputText`。此意图也被配置为调用 Lambda 函数来执行初始化和用户数据验证。Amazon Lex 使用以下事件调用 Lambda 函数：

      ```
      {
          "messageVersion": "1.0",
          "invocationSource": "DialogCodeHook",
          "userId": "wch89kjqcpkds8seny7dly5x3otq68j3",
          "sessionAttributes": {
              "lastConfirmedReservation": "{\"ReservationType\":\"Hotel\",\"Location\":\"Chicago\",\"RoomType\":\"queen\",\"CheckInDate\":\"2016-12-18\",\"Nights\":\"5\"}"
          },
          "bot": {
              "name": "BookTrip",
              "alias": null,
              "version": "$LATEST"
          },
          "outputDialogMode": "Text",
          "currentIntent": {
              "name": "BookCar",
              "slots": {
                  "PickUpDate": null,
                  "ReturnDate": null,
                  "DriverAge": null,
                  "CarType": null,
                  "PickUpCity": null
              },
              "confirmationStatus": "None"
          }
      }
      ```
**注意**  
 `messageVersion` — Amazon Lex 当前只支持 1.0 版。
`invocationSource` – 表明调用的目的是执行初始化和用户数据验证。
`currentIntent` — 其中包括意图名称和插槽。此时，所有槽值均为空值。

      

   1. Lambda 函数发现所有插槽值均为空值，没有任何可以验证的内容。但是函数会使用会话属性来初始化一些槽值 (`PickUpDate`、`ReturnDate` 和 `PickUpCity`)，然后返回以下响应：

      ```
      {
          "sessionAttributes": {
              "lastConfirmedReservation": "{\"ReservationType\":\"Hotel\",\"Location\":\"Chicago\",\"RoomType\":\"queen\",\"CheckInDate\":\"2016-12-18\",\"Nights\":\"5\"}",
              "currentReservation": "{\"ReservationType\":\"Car\",\"PickUpCity\":null,\"PickUpDate\":null,\"ReturnDate\":null,\"CarType\":null}",
              "confirmationContext": "AutoPopulate"
          },
          "dialogAction": {
              "type": "ConfirmIntent",
              "intentName": "BookCar",
              "slots": {
                  "PickUpCity": "Chicago",
                  "PickUpDate": "2016-12-18",
                  "ReturnDate": "2016-12-22",
                  "CarType": null,
                  "DriverAge": null
              },
              "message": {
                  "contentType": "PlainText",
                  "content": "Is this car rental for your 5 night stay in Chicago on 2016-12-18?"
              }
          }
      }
      ```
**注意**  
除了 `lastConfirmedReservation` 以外，Lambda 函数中还包含更多会话属性（`currentReservation` 和 `confirmationContext`）。
`dialogAction.type`设置为`ConfirmIntent`，这会通知 Amazon Lex 需要用户回复 “是，否”（确认上下文设置为，Lambda 函数知道 yes/no 用户回复是 AutoPopulate为了让用户确认 Lambda 函数执行的初始化（自动填充的插槽数据）。  
   
Lambda 函数还在响应中包含一条 `dialogAction.message` 中的通知消息，供 Amazon Lex 将其返回客户端。  
`ConfirmIntent` (`dialogAction.type` 的值) 与所有自动程序目的都没有关系。在示例中，Lambda 函数使用此术语指示 Amazon Lex 获取 yes/no 用户的回复。

   1. 根据 `dialogAction.type`，Amazon Lex 向客户端返回以下响应：  
![\[JSON 响应包含对话状态、意图名称、消息、响应卡、会话属性、要引发的插槽和其他插槽。\]](http://docs.aws.amazon.com/zh_cn/lex/latest/dg/images/book-car-10.png)

      客户端显示消息：“您是否要从 2016-12-18 开始在芝加哥租用这辆汽车 5 天？”

1. 用户：“yes”

   1. 客户端将向 Amazon Lex 发送以下 `PostText` 请求：

      ```
      POST /bot/BookTrip/alias/$LATEST/user/wch89kjqcpkds8seny7dly5x3otq68j3/text
      "Content-Type":"application/json"
      "Content-Encoding":"amz-1.0"
      
      {
         "inputText":"yes",
         "sessionAttributes":{
            "confirmationContext":"AutoPopulate",
            "currentReservation":"{\"ReservationType\":\"Car\",
                                   \"PickUpCity\":null,
                                   \"PickUpDate\":null,
                                   \"ReturnDate\":null,
                                   \"CarType\":null}",
            "lastConfirmedReservation":"{\"ReservationType\":\"Hotel\",
                                         \"Location\":\"Chicago\",
                                         \"RoomType\":\"queen\",
                                         \"CheckInDate\":\"2016-12-18\",
                                         \"Nights\":\"5\"}"
         }
      }
      ```

   1. Amazon Lex 读取 `inputText` 并了解上下文（要求用户确认自动填充）。Amazon Lex 通过发送以下事件来调用 Lambda 函数：

      ```
      {
          "messageVersion": "1.0",
          "invocationSource": "DialogCodeHook",
          "userId": "wch89kjqcpkds8seny7dly5x3otq68j3",
          "sessionAttributes": {
              "confirmationContext": "AutoPopulate",
              "currentReservation": "{\"ReservationType\":\"Car\",\"PickUpCity\":null,\"PickUpDate\":null,\"ReturnDate\":null,\"CarType\":null}",
              "lastConfirmedReservation": "{\"ReservationType\":\"Hotel\",\"Location\":\"Chicago\",\"RoomType\":\"queen\",\"CheckInDate\":\"2016-12-18\",\"Nights\":\"5\"}"
          },
          "bot": {
              "name": "BookTrip",
              "alias": null,
              "version": "$LATEST"
          },
          "outputDialogMode": "Text",
          "currentIntent": {
              "name": "BookCar",
              "slots": {
                  "PickUpDate": "2016-12-18",
                  "ReturnDate": "2016-12-22",
                  "DriverAge": null,
                  "CarType": null,
                  "PickUpCity": "Chicago"
              },
              "confirmationStatus": "Confirmed"
          }
      }
      ```

      由于用户回复“是”，所以 Amazon Lex 将 `confirmationStatus` 设置为 `Confirmed`。

      

   1. 根据 `confirmationStatus`，Lambda 函数确定预填充的值正确无误。Lambda 函数执行以下操作：
      + 将 `currentReservation` 会话属性更新为已经预填充的槽值。
      + 将 `dialogAction.type` 设置为 `ElicitSlot`
      + 将 `slotToElicit` 值设置为 `DriverAge`。

      发送的响应如下：

      ```
      {
          "sessionAttributes": {
              "currentReservation": "{\"ReservationType\":\"Car\",\"PickUpCity\":\"Chicago\",\"PickUpDate\":\"2016-12-18\",\"ReturnDate\":\"2016-12-22\",\"CarType\":null}",
              "lastConfirmedReservation": "{\"ReservationType\":\"Hotel\",\"Location\":\"Chicago\",\"RoomType\":\"queen\",\"CheckInDate\":\"2016-12-18\",\"Nights\":\"5\"}"
          },
          "dialogAction": {
              "type": "ElicitSlot",
              "intentName": "BookCar",
              "slots": {
                  "PickUpDate": "2016-12-18",
                  "ReturnDate": "2016-12-22",
                  "DriverAge": null,
                  "CarType": null,
                  "PickUpCity": "Chicago"
              },
              "slotToElicit": "DriverAge",
              "message": {
                  "contentType": "PlainText",
                  "content": "How old is the driver of this car rental?"
              }
          }
      }
      ```

   1. Amazon Lex 返回以下响应：  
![\[JSON 响应显示了预订汽车的意图，并显示了一条引发“驾驶员年龄”插槽的消息。\]](http://docs.aws.amazon.com/zh_cn/lex/latest/dg/images/book-car-20.png)

      客户端显示消息“驾驶此次所租汽车的司机多大年龄？” 对话继续进行。