Rasa使用——以星座运势为case

经过两周的摸索和实验,今天终于把星座运势推进到最后的测试阶段。尽管跑通一个demo会觉得rasa非常简单,但完成一个function,从分离不同的intent,对话框架设计,设置rasa pipeline,具体月份的读取,考虑边界和异常情况,才发现对rasa的了解仅限于冰山一角。

借助BotSociety设计story

围绕API功能和用户提问角度来写story

API功能:

  • 查询总体星座运势
  • 查询爱情指数
  • 查询工作指数
  • 查询财运指数
  • 查询健康指数
  • 查询幸运颜色
  • 查询匹配星座
  • 星座映射到日期
  • 日期映射到星座
  • 安慰等情绪响应

用户角度:

  • 知道星座,明确提问
  • 不知道星座,模糊提问,日期映射
  • 查看全部运势
  • 查看具体运势

设计story:
botsociety

rasa部分

中文分词问题

问题描述:
在rasa train阶段就出现了boundary的报错

理想实体是摩羯座但是提取出来的是摩羯
解决方案:
请添加图片描述
https://github.com/howl-anderson/rasa_chinese

清空slot的memory

问题描述:
请添加图片描述
上图中,bot先询问了处女座的爱情指数,使starsign_type的槽位被填充入处女座,但是在新的一轮对话中,槽位没有被清空,影响了接下来的判断。

解决方案:
首先笔者在action中将槽位设为None,如下所示

class ResetAction(Action):
    def name(self) -> Text:
        return "action_reset"

    def run(self, dispatcher: CollectingDispatcher,
            tracker: Tracker,
            domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:

        return [SlotSet('starsign_type', None)]

然而,并没有起到清空的效果,而是采用AllSlotsReset()才能达到预期效果,使对话重新开始。经过实验发现slotset可以设当前slot为某一个值,但是设为None没反应。

# 正确方案:
        return [AllSlotsReset(), Restarted(), SlotSet('starsign_type', None)]

日期星座映射

问题描述:
由于一些用户不知道自己的星座,所以有必要在星座运势查询中设置星座日期映射的环节。用户的查询方式有多种,例如"7月2" “7 2” “七月二号” “7/2”
解决方案一:否定
用entities/slot(type = list)的方式将用户输入的信息中所有的数字提取出来,在action中进行星座匹配,再将结果返回给用户。
但是在实际操作中,无法将所有的数字提取出来,有些时候只能取到一个数字,非常不稳定,且中文数字提取不出来。
解决方案二:
猜想可能是entities的部分没有很好的提取到,虽然会共享一段数字(1-12,一-十二),但仍需要更明显的区分,于是用rasa中的role来区分。

我出生于[7]{"entity": "date", "role": "month"}[2]{"entity": "date", "role": "day"} .

不过,也没有什么用。叹气。

解决方案三:
我愿称之为,没有python扶不起的墙
思路是,把用户这句话读取,在action这个自由度很高的部分,利用python的正则来处理。题外话: 虽然rasa也有正则,但是总会出些bug,中文不适配等问题,所以选择熟练度和容易指数高的python好了。

class ReturnStarAction(Action):
    def name(self) -> Text:
        return "action_return_star"

    def checkdate(self, tracker):
        inp = tracker.latest_message['text']
        print(inp)
        number = re.compile(r'([一二三四五六七八九零十]+|[0-9]+)')
        pattern = re.compile(number)
        all = pattern.findall(inp)
        print(all)
        date_status = False
        date_accurate = False
        if len(all) != 2:
            return date_status, None, None, None
        else:
            date_status = True
            month = all[0]
            day = all[1]
            if not month.isdigit():
                month = pycnnum.cn2num(month)
            if int(month) > 0 and int(month) < 13:
                date_accurate = True
            if not day.isdigit():
                day = pycnnum.cn2num(day)
            if int(day) > 0 and int(day) < 32:
                date_accurate = True
            return date_status, date_accurate, month, day

    def findstar(self, month, day):
        daylist = [20, 19, 21, 20, 21, 22, 23, 23, 23, 24, 23, 22]
        starlist = ['摩羯座', '水瓶座', '双鱼座', '白羊座', '金牛座', '双子座',
                    '巨蟹座', '狮子座', '处女座', '天秤座', '天蝎座', '射手座']
        if int(day) < daylist[int(month) - 1]:
            return starlist[int(month) - 1]
        else:
            return starlist[int(month)]

    def run(self, dispatcher: CollectingDispatcher,
            tracker: Tracker,
            domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:
        date_status, date_accurate, month, day = self.checkdate(tracker)
        if not date_status or not date_accurate:
            dispatcher.utter_message(text=f'{"我寻思着这日期只应天上有,要不您说个靠谱的?"}')
            return []
        else:
            star = self.findstar(month, day)
            dispatcher.utter_message(text=f"原来你是{star}~!")
            return [SlotSet('starsign_type', star)]

解决方案四:
我愿称之为,逃避策略
当识别到intent是用户在询问星座日期,就可以直接返回一张图,让用户自行查看即可。

关键点设为entities

一开始我并没有把恋爱指数,工作指数,幸运色等作为关键词,而是普通的语料信息。修改后能够更好的提取到关键信息。

### 修改前
- intent: ask_horoscope
  examples: |
    - [白羊座](starsign_type)的爱情运势
    - [金牛座](starsign_type)的爱情
    - 我的桃花运咋样
    - 我的恋爱指数
### 修改后
- intent: ask_horoscope
  examples: |
    - [白羊座](starsign_type)的[爱情运势](love)
    - [金牛座](starsign_type)的[爱情](love)
    - 我的[桃花运](love)咋样
    - 我的[恋爱指数](love)

合并intent

合并相似度高的intent,intent变少了,命中正确率也相应提高。反之,细分如果太多,模型不够那么好,并不会达到预期效果,容易出现intent识别错位的情况。

合并path,用slot分流

因为合并了intent,那就意味着出现了公共path,path的一头是intent,一头是action,而决定走向哪一个action,就用slot槽位的填补来确定。这里遵循的原则是尽量走公共path,这也是出于对模型的适应,提高命中率,且用槽位判断可以更精准一些。
请添加图片描述

Rasa测试

按照官方文档https://rasa.com/docs/rasa/testing-your-assistant进行测试。
将nlu按照4:1切分成训练集和测试集进行交叉验证。

  • 查看Data and Stories是否有效
  • 切分nlu
  • test nlu
  • 查看intent/slot混淆矩阵
    请添加图片描述

请添加图片描述
由于这样的测试数据集都来自写好的nlu,所以还是需要在交互页面中人工测试。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值