美文网首页rasa
(一)Rasa学习笔记——详解FormAction中的reque

(一)Rasa学习笔记——详解FormAction中的reque

作者: 博士伦2014 | 来源:发表于2020-10-13 19:47 被阅读0次

    1. 先解释一下FormAction

    FormAction:在Rasa Core中,当我们执行一个action需要同时填充多个slot时,可以使用FormAction来实现,因为FormAction会遍历监管的所有slot,当发现相关的slot未被填充时,就会向用户主动发起询问,直到所有slot被填充完毕,才会执行接下来的业务逻辑。

    2. 下面介绍Form Action的实现

    Form Action的实现主要包含四步

    • 构造story
    • 添加form字段到Domain
    • 配置FormPolicy
    • Form Action 函数的具实现

    前面三步请移步官网这篇文章, 我这里提到这些主要是为讲解后面的request_next_slot()函数做铺垫。
    以官网中实现的restaurant_form为例,restaurant_form是我们要实现的 form action 的名字,要实现一个完整的 form action 我们至少需要定义以下三个函数:

    • name: action 的名字
    • required_slots: 要使Submit方法起作用,需要填充的slots列表。
    • submit: 填充完所有的slots后,在form末尾需要做的事情。
    def name(self) -> Text:
        """Unique identifier of the form"""
    
        return "restaurant_form"
    
    @staticmethod
    def required_slots(tracker: Tracker) -> List[Text]:
        """A list of required slots that the form has to fill"""
    
        return ["cuisine", "num_people", "outdoor_seating", "preferences", "feedback"]
    
    def submit(
        self,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: Dict[Text, Any],
    ) -> List[Dict]:
        """Define what the form has to do
            after all required slots are filled"""
    
        # utter submit template
        dispatcher.utter_message(template="utter_submit")
        return []
    

    对于我们要实现的restaurant_form来说:

    class RestaurantForm(FormAction):
        """Example of a custom form action."""
    
        def name(self) -> Text:
            """Unique identifier of the form."""
    
            return "restaurant_form"
    
        @staticmethod
        def required_slots(tracker: Tracker) -> List[Text]:
            """A list of required slots that the form has to fill."""
    
            return ["cuisine", "num_people", "outdoor_seating", "preferences", "feedback"]
    
        def submit(
            self,
            dispatcher: CollectingDispatcher,
            tracker: Tracker,
            domain: Dict[Text, Any],
        ) -> List[Dict]:
            """Define what the form has to do after all required slots are filled."""
            # utter submit template
            dispatcher.utter_message(template="utter_submit")
            return []
    
    

    class RestaurantForm继承了rasa中的FormAction这个类,因此如果我们想要实现一些复杂功能和逻辑,就可以重写父类FormAction中的某些方法,比如validate_{slot-name}, slot_mappings等,这其中当然也包括我们要讲的request_next_slot()函数, (终于到重点了),那么request_next_slot()函数是用来干嘛的呢?
    官网是这么说的

    如果slots中充满了你确定无法处理的东西,并且你想直接停用表单(deactivate the form),那么可以重写request_next_slot()方法。

    下面还是以restaurant_formcuisine slot 为例进行解释,但是我们可以使用任何想要触发停用的逻辑(trigger deactivation):

    def request_next_slot(
        self,
        dispatcher: "CollectingDispatcher",
        tracker: "Tracker",
        domain: Dict[Text, Any],
    ) -> Optional[List[EventType]]:
        """Request the next slot and utter template if needed,
            else return None"""
        for slot in self.required_slots(tracker):
            if self._should_request_slot(tracker, slot):
    
                ## Condition of validated slot that triggers deactivation:触发停用的条件
                if slot == "cuisine" and tracker.get_slot("cuisine") == "caribbean":
                    dispatcher.utter_message(text="Sorry, I can't help you with that")
                    return self.deactivate()
    
                ## For all other slots, continue as usual
                logger.debug(f"Request next slot '{slot}'")
                dispatcher.utter_message(
                    template=f"utter_ask_{slot}", **tracker.slots
                )
                return [SlotSet(REQUESTED_SLOT, slot)]
        return None
    

    在父类FormAction中,request_next_slot()方法是这样的:

    # noinspection PyUnusedLocal
        def request_next_slot(
            self,
            dispatcher: "CollectingDispatcher",
            tracker: "Tracker",
            domain: Dict[Text, Any],
        ) -> Optional[List[EventType]]:
            """Request the next slot and utter template if needed,
                else return None"""
    
            for slot in self.required_slots(tracker):
                if self._should_request_slot(tracker, slot):
                    logger.debug(f"Request next slot '{slot}'")
                    dispatcher.utter_message(template=f"utter_ask_{slot}", **tracker.slots)
                    return [SlotSet(REQUESTED_SLOT, slot)]
    
            # no more required slots to fill
            return None
    

    两者的区别之处在于restaurant_form中增加了一个判断cuisine是否等于caribbean逻辑
    我写这个是因为我在项目中遇到了一个这样的逻辑:在反问用户填充槽位时,如果某个槽位三次都没有填对,那么就结束本次对话,并向用户发出提示信息重新开始对话。
    很明显只要在

    ...
    # 触发停用的经过验证的插槽的条件
    
    ....
    

    之下加上自己的判断逻辑就好了,具体怎么加有一定的小技巧,我暂时先不放出代码,但是整个问题的解决思路已经很清晰了。

    以上~

    参考:

    1. Forms
    2. Rasa中文聊天机器人开发指南(3):Core篇

    相关文章

      网友评论

        本文标题:(一)Rasa学习笔记——详解FormAction中的reque

        本文链接:https://www.haomeiwen.com/subject/uwfbpktx.html