设计故事
在设计故事时,需要考虑两组对话交互:快乐路径和不快乐路径。快乐路径描述用户何时按照您的预期遵循对话流程,并在出现提示时始终提供必要的信息。然而,用户经常会因为问题、闲聊或其他问题而偏离愉快的道路。我们称这些为不幸的道路。
对你的机器人来说,优雅地处理不愉快的路径很重要,但也无法预测给定用户可能采取的路径。通常,开发人员在设计不愉快的路径时会尝试考虑所有可能的分歧路径。为状态机中的每个可能状态(其中许多永远不会达到)进行规划需要大量额外工作并显着增加训练时间。
相反,我们建议 在设计不愉快的路径时采用对话驱动的开发方法。对话驱动开发促进尽早与测试用户共享您的机器人,并收集真实的对话数据,这些数据可以准确地告诉您用户如何偏离快乐路径。从这些数据中,您可以创建故事来完成用户的请求,并开始思考如何引导他们回到快乐的道路上。
对于多回合交互,您应该定义一个故事,例如:
1 stories: 2 - story: Greeting and ask user how they're doing 3 steps: 4 - intent: greet 5 - action: utter_greet 6 - action: utter_ask_how_doing 7 - intent: doing_great 8 - action: utter_happy
管理对话流程
以下是管理故事中对话流程的一些技巧:
何时使用插槽来影响对话
插槽充当机器人的内存。定义槽时,您可以定义槽是否 应影响对话。属性influence_conversation
设置为 的插槽false
只能存储信息。属性influence_conversation
设置为 的插槽true
可以根据其中存储的信息影响对话流程。
需要将影响对话的插槽添加到您的故事或规则中。这也适用于插槽是由自定义操作设置的情况。例如,您可以使用由自定义操作设置的布尔槽来根据其值使用以下故事控制对话流:
1 stories: 2 - story: Welcome message, premium user 3 steps: 4 - intent: greet 5 - action: action_check_profile 6 - slot_was_set: 7 - premium_account: true 8 - action: utter_welcome_premium 9 10 - story: Welcome message, basic user 11 steps: 12 - intent: greet 13 - action: action_check_profile 14 - slot_was_set: 15 - premium_account: false 16 - action: utter_welcome_basic 17 - action: utter_ask_upgrade
如果您不希望槽影响对话流,则应将槽的属性设置influence_conversation
为false
。您不需要slot_was_set
在故事中包含不影响对话的插槽事件。
实现分支逻辑
在编写故事时,有时下一个操作将取决于您的自定义操作之一中返回的值。在这些情况下,重要的是在返回插槽和直接使用自定义操作代码来影响机器人接下来的操作之间找到正确的平衡。
如果某个值仅用于确定机器人的响应,请考虑将决策逻辑嵌入自定义操作中,而不是在您的故事中使用特征化槽。这有助于降低整体复杂性并使您的故事更易于管理。
例如,您可以转换这些故事:
1 stories: 2 - story: It's raining now 3 steps: 4 - intent: check_for_rain 5 - action: action_check_for_rain 6 - slot_was_set: 7 - raining: true 8 - action: utter_is_raining 9 - action: utter_bring_umbrella 10 11 - story: It isn't raining now 12 steps: 13 - intent: check_for_rain 14 - action: action_check_for_rain 15 - slot_was_set: 16 - raining: false 17 - action: utter_not_raining 18 - action: utter_no_umbrella_needed
合成一个故事是:
1 stories: 2 - story: check for rain 3 steps: 4 - intent: check_for_rain 5 - action: action_check_for_rain
在actions文件里定义:
1 def run(self, dispatcher, tracker, domain): 2 is_raining = check_rain() 3 if is_raining: 4 dispatcher.utter_message(template="utter_is_raining") 5 dispatcher.utter_message(template="utter_bring_umbrella") 6 else: 7 dispatcher.utter_message(template="utter_not_raining") 8 dispatcher.utter_message(template="utter_no_umbrella_needed") 9 return []
如果该值用于影响前进的动作流,请返回一个特征化槽来确定故事。例如,如果您想收集有关新用户的信息,但不收集回访用户的信息,您的故事可能如下所示:
1 stories: 2 - story: greet new user 3 steps: 4 - intent: greet 5 - action: check_user_status 6 - slot_was_set: 7 - new_user: true 8 - action: utter_greet 9 - action: new_user_form 10 - active_loop: new_user_form 11 - active_loop: null 12 13 - story: greet returning user 14 steps: 15 - intent: greet 16 - action: check_user_status 17 - slot_was_set: 18 - new_user: false 19 - action: utter_greet 20 - action: utter_how_can_help
使用 OR 语句和检查点
OR 语句和检查点 可用于减少您必须编写的故事数量。但是,应谨慎使用它们。过度使用 OR 语句或检查点会减慢训练速度,创建过多的检查点会使您的故事难以理解。
OR 语句
在机器人以相同方式处理不同意图的故事中,您可以使用 OR 语句作为创建新故事的替代方法。
例如,您可以合并这两个故事:
1 stories: 2 - story: newsletter signup 3 steps: 4 - intent: signup_newsletter 5 - action: utter_ask_confirm_signup 6 - intent: affirm 7 - action: action_signup_newsletter 8 9 - story: newsletter signup, confirm via thanks 10 steps: 11 - intent: signup_newsletter 12 - action: utter_ask_confirm_signup 13 - intent: thanks 14 - action: action_signup_newsletter
用 OR 语句合并成一个故事:
1 stories: 2 - story: newsletter signup with OR 3 steps: 4 - intent: signup_newsletter 5 - action: utter_ask_confirm_signup 6 - or: 7 - intent: affirm 8 - intent: thanks 9 - action: action_signup_newsletter
检查点
检查点对于将您的故事模块化为经常重复的单独块很有用。例如,如果您希望您的机器人在每个对话流程结束时询问用户反馈,您可以使用检查点来避免在每个故事结束时包含反馈交互:
1 stories: 2 - story: beginning of conversation 3 steps: 4 - intent: greet 5 - action: utter_greet 6 - intent: goodbye 7 - action: utter_goodbye 8 - checkpoint: ask_feedback 9 10 - story: user provides feedback 11 steps: 12 - checkpoint: ask_feedback 13 - action: utter_ask_feedback 14 - intent: inform 15 - action: utter_thank_you 16 - action: utter_anything_else 17 18 - story: user doesn't have feedback 19 steps: 20 - checkpoint: ask_feedback 21 - action: utter_ask_feedback 22 - intent: deny 23 - action: utter_no_problem 24 - action: utter_anything_else
检查点旨在使在许多不同的故事中重用某些对话部分变得更容易。强烈建议不要在现有检查点内使用检查点,因为这会显着增加训练时间并使故事难以理解。
在故事中创造逻辑中断
在设计对话流程时,通常很想创建长篇故事示例,以捕捉从头到尾的完整对话交互。在许多情况下,这将增加解释分支路径所需的训练故事的数量。相反,考虑将较长的故事分成处理子任务的较小对话块。
处理丢失信用卡的快乐路径故事可能如下所示:
stories: - story: Customer loses a credit card, reviews transactions, and gets a new card steps: - intent: card_lost - action: check_transactions - slot_was_set: - reviewed_transactions: ["starbucks"] - action: utter_ask_fraudulent_transactions - intent: inform - action: action_update_transactions - intent: affirm - action: utter_confirm_transaction_dispute - action: utter_replace_card - action: mailing_address_form - active_loop: mailing_address - active_loop: null - action: utter_sent_replacement - action: utter_anything_else - intent: affirm - action: utter_help
处理丢失的信用卡涉及一系列子任务,即检查欺诈交易的消费历史,确认更换卡的邮寄地址,然后跟进用户的任何额外请求。在此对话弧中,机器人会在多个位置提示用户输入,从而创建需要考虑的分支路径。
例如,当提示“utter_ask_fraudulent_transactions”时,如果没有任何适用,用户可能会以“拒绝”意图进行响应。当被问及机器人是否可以帮助他们做任何其他事情时,用户还可以选择以“拒绝”意图进行响应。
我们可以将这个长故事分成几个小故事:
1 stories: 2 - story: Customer loses a credit card 3 steps: 4 - intent: card_lost 5 - action: utter_card_locked 6 - action: spending_history_form 7 - active_loop: spending_history_form 8 - active_loop: null 9 - slot_was_set: 10 - reviewed_transactions: ["starbucks"] 11 - action: utter_ask_fraudulent_transactions 12 13 - story: Customer reviews transactions and gets a new card 14 steps: 15 - action: utter_ask_fraudulent_transactions 16 - intent: inform 17 - action: action_update_transactions 18 - slot_was_set: 19 - reviewed_transactions: ["target", "starbucks"] 20 - intent: affirm 21 - action: utter_confirm_transaction_dispute 22 - action: utter_replace_card 23 - action: mailing_address_form 24 - active_loop: mailing_address 25 - active_loop: null 26 - action: utter_sent_replacement 27 - action: utter_anything_else 28 29 - story: Customer has something else they need help with 30 steps: 31 - action: utter_anything_else 32 - intent: affirm 33 - action: utter_help