[TOC]
Rasa學(xué)習(xí)筆記2--Rasa Core
1. 概念介紹
首先引出Rasa的設(shè)計理念:
Learning from real conversations is more important than designing hypothetical ones饭玲,我覺得這是非常重要的事情塘雳,我們在構(gòu)建自己的bot的時候 钞啸,我們往往想絞盡腦汁來排列組合出各種意圖的story培漏,但是在實際應(yīng)用中蚯姆,我們發(fā)現(xiàn)不管我們的story庫有多豐富沧侥,還是會有大量的unhappy path無法處理瞎疼,所以我們應(yīng)該想方設(shè)法從真實的對話中來抽象sotry工窍。
1.1 Stories
sotry就是Rasa用來訓(xùn)練對話管理模型的數(shù)據(jù)集割卖。格式如下:*開頭的表示某一輪用戶輸入的intent和slot信息。-開頭的表示分配給bot對應(yīng)的action患雏。
## greet + location/price + cuisine + num people <!-- name of the story - just for debugging -->
* greet
- action_ask_howcanhelp
* inform{"location": "rome", "price": "cheap"} <!-- user utterance, in format intent{entities} -->
- action_on_it
- action_ask_cuisine
* inform{"cuisine": "spanish"}
- action_ask_numpeople <!-- action that the bot should execute -->
* inform{"people": "six"}
- action_ack_dosearch
1.2 Domains
定義了整個系統(tǒng)需要操作的所有元素鹏溯,包括:intent,slot,entity,template,actions。
1.3 Actions
定了了bot具體執(zhí)行動作纵苛。在Rasa中定了四種action剿涮,包括:
- Utterance actions,直接返回template中定義的話術(shù)攻人。
- Retrieval actions取试,閑聊(small talk)和FAQ(small questions)的方式。
- Custom actions怀吻,用戶自定義瞬浓。用戶自定義的action,需要發(fā)布action server,然后通過HTTP請求來獲取執(zhí)行action的答案蓬坡。
- Defailt actions,比如:action_listen, action_restart, action_default_fallback等
1.4 Policies
所謂policy就是bot在對話中的每一步?jīng)Q定要執(zhí)行哪一個action猿棉。我們可以在config.yml中配置多個policies磅叛,Agent會根據(jù)policy的執(zhí)行優(yōu)先級來選擇最終的action。
Max_history 萨赁,bot再決定action時會向前考慮的對話輪數(shù)弊琴。
Data Augmentation, 在訓(xùn)練模型是杖爽,Rasa會從stories.md中隨機取出sotry拼接一起看作一個story敲董,用來做數(shù)據(jù)擴(kuò)充。
agent決定action的一般原則是選擇這些policy給的得分最大的action慰安,但是當(dāng)兩個policy給出了相同的最高得分腋寨,這時候就需要根據(jù)policy的priority來下決定采取哪一個policy的結(jié)果。在Rasa中推薦的設(shè)置是:
5. FormPolicy
4. FallbackPolicy and TwoStageFallbackPolicy
3. MemoizationPolicy and AugmentedMemoizationPolicy
2. MappingPolicy
1. EmbeddingPolicy, KerasPolicy, and SklearnPolicy
1.4.1 KarasPolicy
構(gòu)造訓(xùn)練數(shù)據(jù)和模型輸入:
對于每個story化焕,會先封裝成一個TrackerWithCachedStates對象實例萄窜,里面包括:
sender_id: story標(biāo)識
_states: 這個story可以生成的所有對話狀態(tài)的組合,內(nèi)容是[最大max_history的狀態(tài)+一下個狀態(tài)]
domain
slots,此story包含的slots和值
latest_message撒桨,
latest_action_name查刻,
latest_bot_utterance,
event,包括ActionExcuted,UserUttered,SlotSet等,封裝domain中的所有內(nèi)容
等-
構(gòu)造對話狀態(tài)與預(yù)測action
分別是:trackers_as_states和trackers_as_actions元莫,他們是一一對應(yīng)的關(guān)系赖阻,去重之后會有n個組合。其中:
trackers_as_states踱蠢,所有max_history狀態(tài)的組合火欧,比如:
trackers_as_actions,預(yù)測的action茎截,比如對應(yīng)上面005:
將上述結(jié)果編碼苇侵,構(gòu)造模型輸入X,Y
X:shape(n, max_history, feature_num),其中feature_num=envent的數(shù)量企锌,使用one-hot編碼榆浓,為1的位置,表示當(dāng)前state的Event撕攒。因為Event的定義就是用來描述對話中的所有內(nèi)容陡鹃。
Y: shape(n, actins_num),因為policy只預(yù)測action抖坪,所以Y的one-hot用來表示預(yù)測的actin來萍鲸。
1.4.2 Embedding Policy (Transformer Embedding Dialogue Policy)
1.5 Forms
現(xiàn)看一個使用Form實現(xiàn)的對話情形:
所謂form就是slot filling擦俐,是我們在實現(xiàn)任務(wù)型對話的一般思路,及:首先定義一些必須槽位,每個槽位會構(gòu)建一個反問話術(shù)品擎,然后bot會順序反問用戶,收集信息备徐,直到填滿所有槽位萄传。FormAction就是來實現(xiàn)這個功能蜜猾。
名詞解釋:happy path,就是指你問用戶什么信息瓣铣,用戶就配個回答給bot這個信息。
比如下面這個happy path:
## happy path
* greet
- utter_greet
* request_restaurant
- restaurant_form
- form{"name": "restaurant_form"}
- form{"name": null}
- utter_slots_values
* thankyou
- utter_noworries
當(dāng)用戶意圖是request_restaurant贷揽,bot會接著執(zhí)行restaurant_form action棠笑。form{"name": "restaurant_form"}會激活這個form禽绪,form{"name": null}會關(guān)閉這個form。對于unhappy path的情形循捺,bot可以執(zhí)行任意其他的action雄人,只要這個form還是active的。
我們可以使用Rasa提供的sdk來定制自己的FormAction础钠,需要實現(xiàn)下面三個方法:
- name(),aciton的名字
- required_slots()旗吁,列出來所有必須的槽位
- submit()方法,當(dāng)所有槽位被填充很钓,此action產(chǎn)生的結(jié)果或者執(zhí)行的動作。
一旦form action被激活企孩,FormPolicy會對應(yīng)的被激活叹洲,FormPolicy非常簡單,它預(yù)測的一下個動作永遠(yuǎn)還是form action蝗柔。
定制化slot mapping
有時候我們填充槽位不一定只是用抽取到的slot value,也可以是多種形式的回答槽畔。比如當(dāng)bot問:"您是要坐在外面嗎?"胁编,用戶可能的回答有:“是的”/"不是"/“我更喜歡坐在里面”。這幾個回答都是不同的意圖或者是相同實體中的其他value早直,但卻都是正確的回答市框,所以,我們要將這些答案mapping到這一輪的槽位上喻圃。
FormAction可以支持將yes/no以或者自由文本映射到slot中,只需要實現(xiàn)slot_mappings()方法粪滤。
def slot_mappings(self):
# type: () -> Dict[Text: Union[Dict, List[Dict]]]
return { "outdoor_seating": [self.from_entity(entity="seating"),
self.from_intent(intent='affirm', value=True),
self.from_intent(intent='deny', value=False)]}
如上所示,我們將所有mapping策略函數(shù)封裝在list中肆汹,賦值給目的槽位"outdoor_seating"予权。詳細(xì)來講:
- from_entity,將抽取出來的"seating"(seating表示實體)的value填充到outdoor_seating
- from_intent硼啤,如果識別的意圖是affirm斧账,True填充到outdoor_seating,反之嗓袱,F(xiàn)alse填充到outdoor_seating习绢。
還有其他的復(fù)制策略函數(shù)蝙昙,from_trigger_intent梧却,from_text放航。
slot value validation
有時候我們需要對用戶輸入的slot value進(jìn)行個性化的確認(rèn),我們可以在FormAction中使用 validate_{slot-name} 方法來實現(xiàn)荆几。當(dāng)然赊时,我們也可以在validate的過程中來終止form,即放validate方法返回self.deactivate()焊傅,或者重新反問狈涮。
處理unhappy path
在FormAction執(zhí)行過程中鸭栖,如果用戶不配合,比如:問其他問題松却、閑聊或者改變了主意溅话,這時候form會引起ActionExecutionRejection,所以砚哆,你需要采取措施不讓這種情形產(chǎn)生屑墨。比如,
處理閑聊情形的story如下:
## chitchat
* request_restaurant
- restaurant_form
- form{"name": "restaurant_form"}
* chitchat
- utter_chitchat
- restaurant_form
- form{"name": null}
當(dāng)用戶改變注意战转,不在詢問最初的需求以躯,這時候bot就不能繼續(xù)詢問最初form的槽位。便可以使用action_deactivate_form來關(guān)閉此form:
## chitchat
* request_restaurant
- restaurant_form
- form{"name": "restaurant_form"}
* stop
- utter_ask_continue
* deny
- action_deactivate_form
- form{"name": null}
處理待條件的slot的邏輯
這個功能是為了讓對話更加靈活和有個性化刁标,比如某個人回答要吃希臘菜命雀,bot可以反問他是不是需要露天的座位±羯埃可以在FormAction中通過required_slots()來實現(xiàn):
@staticmethod
def required_slots(tracker) -> List[Text]:
"""A list of required slots that the form has to fill"""
if tracker.get_slot('cuisine') == 'greek':
return ["cuisine", "num_people", "outdoor_seating",
"preferences", "feedback"]
else:
return ["cuisine", "num_people",
"preferences", "feedback"]
1.6 檢索動作(retrieval action)
這個是Rasa在實驗的新功能狐血,主要作用是為了在解決閑聊(small talk)和Faq(simple question)問題時,可以簡化構(gòu)建story浪默,因為這些都是單輪的對話缀匕,可以嘗試通過一個aciton解決掉。
比如阔加,我們可以不在使用下面這些story:
## weather
* ask_weather
- utter_ask_weather
## introduction
* ask_name
- utter_introduce_myself
...
而是用一個chitchat
意圖來將上面所有意圖包裝起來:
## chitchat
* chitchat
- respond_chitchat
然后retrival action使用NLU組件中的response selector模型來學(xué)習(xí)和預(yù)測結(jié)果满钟。
訓(xùn)練數(shù)據(jù)
準(zhǔn)備NLU訓(xùn)練數(shù)據(jù):
## intent: chitchat/ask_name
- what's your name
- who are you?
- what are you called?
## intent: chitchat/ask_weather
- how's weather?
- is it sunny where you are?
首先所有上面的sample將被放在一起用來訓(xùn)練意圖識別模型用來預(yù)測chitchat類別湃番。然后通過一個'/'符號來分隔出來的后綴就是對應(yīng)的答案,將作為訓(xùn)練模型的label吠撮,這其實就是一個問題-答案的qq模型。
然后泥兰,在另外一個response.md
文件中準(zhǔn)備response語料:
## ask name
* chitchat/ask_name
- my name is Sara, Rasa's documentation bot!
## ask weather
* chitchat/ask_weather
- it's always sunny where I live
1.7 interactive actions
1.8 Fallback Action
當(dāng)NLU得分低于某個閾值或者policy預(yù)測低于某個閾值逾条,需要進(jìn)行對話回退,也就是嘗試讓用戶重新表達(dá)师脂。有下面兩種用法:
- 使用
FallbackPolicy
:
policies:
- name: "FallbackPolicy"
nlu_threshold: 0.4
core_threshold: 0.3
fallback_action_name: "action_default_fallback"
action_default_fallback
這個action會對應(yīng)執(zhí)行模板中定義的utter_default
來反問客戶。
- 使用
TwoStageFallbackPolicy
:
policies:
- name: TwoStageFallbackPolicy
nlu_threshold: 0.3
core_threshold: 0.3
fallback_core_action_name: "action_default_fallback"
fallback_nlu_action_name: "action_default_fallback"
deny_suggestion_intent_name: "out_of_scope"
當(dāng)用戶輸入低于nlu閾值啄育,TwoStageFallbackPolicy
會采用多個階段來處理:
- 如果用戶輸入低于nlu閾值拌消,bot執(zhí)行
action_default_ask_affirmation
讓用戶確認(rèn)輸入: 如果用戶說yes,則把輸入看作大于閾值的輸入, sotry繼續(xù)氓英。如果用戶否認(rèn)鹦筹,讓用戶重新輸入。 - 執(zhí)行
action_default_ask_rephrase
讓用戶重新輸入:如果用戶用戶重新輸入的句子大于閾值徘键,則sotry繼續(xù)遍蟋。如果用戶輸入再一次低于閾值,再次讓用戶確定意圖它呀。 - 執(zhí)行
action_default_ask_affirmation
讓用戶二次確認(rèn):如果用戶確認(rèn)挟憔,則story繼續(xù)烟号。如果用戶否認(rèn)汪拥,用戶輸入會被認(rèn)定為'deny_suggestion_intent_name',就會執(zhí)行最終的召回動作fallback_nlu_action_name
(比如轉(zhuǎn)人工)。
1.8 Knowledge Base Actions
目前Rasa使用這個action主要解決兩個問題:
- 當(dāng)用戶需要具體問某個實體的信息和屬性
-
解決指代問題
如下面這個例子:
1.8.1 Knowledge Base
rasa_sdk中提供數(shù)據(jù)庫加載的抽象類:InMemoryKnowledgeBase宪赶,直接:knowledge_base = InMemoryKnowledgeBase("knowledge_base_data.json")
來構(gòu)造實例脯燃。文檔中提供的一個數(shù)據(jù)庫例子如下:
{
"restaurant": [
{
"id": 0,
"name": "Donath",
"cuisine": "Italian",
"outside-seating": true,
"price-range": "mid-range"
},
{
"id": 1,
"name": "Berlin Burrito Company",
"cuisine": "Mexican",
"outside-seating": false,
"price-range": "cheap"
},
{
"id": 2,
"name": "I due forni",
"cuisine": "Italian",
"outside-seating": true,
"price-range": "mid-range"
}
],
"hotel": [
{
"id": 0,
"name": "Hilton",
"price-range": "expensive",
"breakfast-included": true,
"city": "Berlin",
"free-wifi": true,
"star-rating": 5,
"swimming-pool": true
},
{
"id": 1,
"name": "Hilton",
"price-range": "expensive",
"breakfast-included": true,
"city": "Frankfurt am Main",
"free-wifi": true,
"star-rating": 4,
"swimming-pool": false
},
{
"id": 2,
"name": "B&B",
"price-range": "mid-range",
"breakfast-included": false,
"city": "Berlin",
"free-wifi": false,
"star-rating": 1,
"swimming-pool": false
},
]}
這是一個餐館的數(shù)據(jù)辕棚,其中id和name一般都是要配置的邓厕。當(dāng)然我們也可以定制自己的數(shù)據(jù)庫扁瓢。
1.8.2 準(zhǔn)備NLU data
首先定義一個新的意圖query_knowledge_base
來表示“查詢數(shù)據(jù)庫”的用戶意圖引几,然后bot對應(yīng)的執(zhí)行``ActionQueryKnowledgeBase `動作,目前rasa中可以解決的兩種分類是:1. 列舉出用戶指定屬性的所有對象敞掘。2. 用戶想知道某個對象的某個屬性贿讹。對于上述的餐館領(lǐng)域,可以構(gòu)造如下的nlu數(shù)據(jù):
## intent:query_knowledge_base
- what [restaurants](object_type:restaurant) can you recommend?
- list some [restaurants](object_type:restaurant)
- can you name some [restaurants](object_type:restaurant) please?
- can you show me some [restaurant](object_type:restaurant) options
- list [German](cuisine) [restaurants](object_type:restaurant)
- do you have any [mexican](cuisine) [restaurants](object_type:restaurant)?
- do you know the [price range](attribute:price-range) of [that one](mention)?
- what [cuisine](attribute) is [it](mention)?
- do you know what [cuisine](attribute) the [last one](mention:LAST) has?
- does the [first one](mention:1) have [outside seating](attribute:outside-seating)?
- what is the [price range](attribute:price-range) of [Berlin Burrito Company](restaurant)?
- what about [I due forni](restaurant)?
- can you tell me the [price range](attribute) of [that restaurant](mention)?
- what [cuisine](attribute) do [they](mention) have?
...
其中:
object_type: 標(biāo)注數(shù)據(jù)庫中的某個實體茄菊。
mention: 標(biāo)注指代赊堪。
attribute: 數(shù)據(jù)庫中包含的屬性哭廉。
另外,使用synonyms
來將數(shù)據(jù)中標(biāo)記的單詞映射到數(shù)據(jù)庫中使用的標(biāo)準(zhǔn)格式遵绰,比如:'restaurants'->'restaurant'椿访。
上面有提到目前rasa可以解決的兩種情景:
- 從數(shù)據(jù)庫中查詢用戶指定屬性的所有對象。
當(dāng)用戶想要從數(shù)據(jù)庫中查詢對象成玫,問句中必須包含某個對象哭当,即'object_type',同時需要指定某些屬性钦勘。
比如:
What Italian restaurant options in Berlin do I have?
用戶想得到'object_type'='restaurant'彻采, 條件是{'cuisine'='Italian'朵栖,'city'='Berlin'}柴梆,然后action就通過這兩個條件來篩選符合的對象。
當(dāng)然想要解析上面的問句需要如下的標(biāo)注:
What [Italian](cuisine) [restaurant](object_type) options in [Berlin](city) do I have?.
- 用戶想知道某個對象的某個屬性门扇。
這種情形偿渡,比如:
What is the cuisine of Berlin Burrito Company?
用戶想知道'Berlin Burrito Company'的'cuisine'溜宽。需要的標(biāo)注如下:
What is the [cuisine](attribute) of [Berlin Burrito Company](restaurant)?
1.8.3 解決指代
rasa中定義兩種指代,1. 順序指代(ordinal mentions),比如:'the first one'适揉,2. 普通指代嫉嘀,比如'it'。
- 順序指代
在bot輸出輪剪侮,當(dāng)給用戶是一系列象列瓣俯,可在解析用戶回答的時候,可以使用一個順序指代映射來解決用戶問題中的指代詞腔剂。這個順序指代映射需要在KnowledgeBase類中定義:
{
"1": lambda l: l[0],
"2": lambda l: l[1],
"3": lambda l: l[2],
"4": lambda l: l[3],
"5": lambda l: l[4],
"6": lambda l: l[5],
"7": lambda l: l[6],
"8": lambda l: l[7],
"9": lambda l: l[8],
"10": lambda l: l[9],
"ANY": lambda l: random.choice(list),
"LAST": lambda l: l[-1],
}
key就是對應(yīng)到nlu標(biāo)注數(shù)據(jù)中的mention后面的值推掸,比如:does the [first one](mention:1) have [outside seating](attribute:outside-seating)?
普通指代
rasa的處理方案是將上文識最近別到的對象作為指代的對象驻仅。編寫ActionQueryKnowledgeBase
2. 代碼結(jié)構(gòu)分析和源碼學(xué)習(xí)
- DialogueStateTracker 保存對話狀態(tài),包括: