天天看點

Rasa使用——以星座運勢為case借助BotSociety設計storyrasa部分

經過兩周的摸索和實驗,今天終于把星座運勢推進到最後的測試階段。盡管跑通一個demo會覺得rasa非常簡單,但完成一個function,從分離不同的intent,對話架構設計,設定rasa pipeline,具體月份的讀取,考慮邊界和異常情況,才發現對rasa的了解僅限于冰山一角。

文章目錄

  • 借助BotSociety設計story
    • 圍繞API功能和使用者提問角度來寫story
  • rasa部分
    • 中文分詞問題
    • 清空slot的memory
    • 日期星座映射
    • 關鍵點設為entities
    • 合并intent
    • 合并path,用slot分流
    • Rasa測試

借助BotSociety設計story

圍繞API功能和使用者提問角度來寫story

API功能:

  • 查詢總體星座運勢
  • 查詢愛情指數
  • 查詢工作指數
  • 查詢财運指數
  • 查詢健康指數
  • 查詢幸運顔色
  • 查詢比對星座
  • 星座映射到日期
  • 日期映射到星座
  • 安慰等情緒響應

使用者角度:

  • 知道星座,明确提問
  • 不知道星座,模糊提問,日期映射
  • 檢視全部運勢
  • 檢視具體運勢

設計story:

Rasa使用——以星座運勢為case借助BotSociety設計storyrasa部分

rasa部分

中文分詞問題

問題描述:

Rasa使用——以星座運勢為case借助BotSociety設計storyrasa部分

在rasa train階段就出現了boundary的報錯

Rasa使用——以星座運勢為case借助BotSociety設計storyrasa部分

理想實體是

摩羯座

但是提取出來的是

摩羯

解決方案:

Rasa使用——以星座運勢為case借助BotSociety設計storyrasa部分

https://github.com/howl-anderson/rasa_chinese

清空slot的memory

問題描述:

Rasa使用——以星座運勢為case借助BotSociety設計storyrasa部分

上圖中,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使用——以星座運勢為case借助BotSociety設計storyrasa部分

Rasa測試

按照官方文檔https://rasa.com/docs/rasa/testing-your-assistant進行測試。

将nlu按照4:1切分成訓練集和測試集進行交叉驗證。

  • 檢視Data and Stories是否有效
  • 切分nlu
  • test nlu
  • 檢視intent/slot混淆矩陣
    Rasa使用——以星座運勢為case借助BotSociety設計storyrasa部分
Rasa使用——以星座運勢為case借助BotSociety設計storyrasa部分

由于這樣的測試資料集都來自寫好的nlu,是以還是需要在互動頁面中人工測試。

繼續閱讀