以 Facebook 的 wit.ai 為例,講解機器人對話平臺(Bot Framework)
本篇文章將會從理解和對話兩個方面去講解 wit.ai。enjoy~
什么是 Bot Framework ?
按照微軟的講法:”The Bot Framework is a platform for building, connecting, testing, and deploying powerful and intelligent bots.” 簡單的說,Bot Framework 就是一個用于搭建、鏈接、測試、和部署智能機器人的平臺。
什么是 wit.ai?
Wit.ai 是 Facebook 推出的用于將自然語言轉化為可處理指令的 API 平臺,其目的是為了幫助開發者便捷的打造類 Siri 語音對話應用或設備。
為什么是 wit.ai?
前些日子,云棲大會上,阿里的資深技術專家海青在介紹阿里 ALIME 團隊的 Bot Framework 時提到了 Google 的 api.ai 和 Facebook 的 wit.ai,所以我希望了解一下,對于我在做業務時遇到的問題、有過的想法,國外一線大廠是怎樣處理的。
為什么不是 api.ai?
因為頁面打不開…
本篇文章將會從理解和對話兩個方面去講解 wit.ai,主要參考資料為 wit.ai 的英文原版文檔:?https://wit.ai/docs/recipes 。
一、理解
1、意圖(話題)識別
(1)問題
我們需要對用戶的意圖進行區分,但問題在于用戶表達同一意圖的說法可能是無限的。
(2)方案
(注:如果看不清下圖,可以點擊放大來看)
我們在 Wit.ai 的 Understanding 模塊,輸入一條用戶問句 “what’s the weather”,然后選擇添加一個叫做 intent(也即意圖)的 entity(也即實體),將其意圖值置為 weather,也即我們完成了對該條用戶問句的意圖標注。
我們為此意圖標注的用戶問句越多,該意圖實體的抽取也就越準確。
2、實體抽?。ㄌ畈郏?/strong>
(1)問題
我們希望能夠從用戶的原始問句中抽出我們需要的關鍵信息。
(2)方案
我們輸入一條用戶問句 “what is the weather tomorrow”,然后選擇添加實體,可以看到 wit/datetime 這個系統內置的實體,選中之后,可以發現這個實體自動識別了句子中的 tomorrow,并自動填寫好了值。
wit.ai 內置了一些常用實體,這些內置實體不必通過用戶的標注就能夠完成實體識別。不過具體的業務場景下,我們還會用到一些自定義實體。如果需要 wit.ai 完成這些自定義實體的識別,就需要進行適當的用戶問句標注。
3、有限關鍵詞實體抽取
(1)問題
有些情況下,我們希望抽取的實體值是可枚舉的,也即我們能夠處理的實體值是一個有限的詞典。
(2)方案
舉個例子,在這里,我們自定義一個名為 pizza_type 的實體,并將用戶問句 cheese pizza 中的 cheese 標注為 pizza_type 的實體值。
在下方的實體欄目中,我們可以看到 pizza_type 這個實體,將它的搜索策略選為 keywords,也即關鍵詞,之后,便得到了一個可以識別 pizza 前 cheese 的實體 pizza_type。
我們當然不止希望 pizza_type 只識別 cheese,可以通過圖示的方式為這個實體增加可識別的 pizza_type 實體值,添加完成后,可以嘗試在 expression 中輸入 [新的實體值] + pizza,發現我們新增的 pizza_type 實體值,是可以被自動識別的。不過,識別范圍也僅限于我們在 pizza_type 中添加的 keywords。
4、非有限關鍵詞實體抽取
(1)問題
很多情況下,我們也希望能對有限詞典之外的詞進行識別,比如上例中的 pizza_type,當然,我們能處理的只有配置好的 pizza_type 實體值,但并不意味著當用戶需要其他類型的 pizza 時,我們就無法作答。
(2)方案
如圖所示,我們修改 pizza_type 的搜索策略為 free-text + keywords,這意味著,當用戶在 pizza 前使用詞典內 keywords 之外的詞時,也能夠被識別。也即我們可以得知用戶選擇了其他類型的 pizza。
5、子串實體抽取
(1)問題
在一些業務場景下,我們需要抽取用戶問句中的一個子串作為實體值,比如 “Tell Jordan that I will be home in ten minutes” 句中的 “I will be home in ten minutes” 就是我們需要抽取的實體值。
(2)方案
我們可以在 expression 中輸入 “Tell Jordan that I will be home in ten minutes”,隨后新增一個 message 實體,然后將 “I will be home in ten minutes” 作為 message 實體的標注結果。之后將 message 的搜索策略選為 free-text + keywords,message 實體就具有了從用戶問句中抽取 message 子串的能力。
如圖所示,嘗試輸入 “tell Alex I will be late” 后,wit.ai 也能將其中的 “I will be late” 抽取到 message 中。
6、搜索策略選擇
在上面的例子中,我們可以看到,實體的搜索策略有三種可選,分別是?trait、free-text?和?keywords。它們的區別在于:
- trait?策略不會嘗試去抽取用戶問句中的某個詞或是某個短語,而是會將整個句子作為一個整體來理解,比如意圖、情感等,通過分析整個用戶問句來得到實體值。
- free-text?策略被用來抽取用戶問句中的子串,這些子串通常不會包含在預定義的實體值詞典中。
- keywords?策略用于處理需要抽取的實體值可枚舉的情況,我們為實體準備好一個預定義的實體值詞典,該實體的抽取就通過使用實體值詞典做匹配來完成。
7、區分不同位置的同類實體
(1)問題
在一些經典的場景(比如訂票)中,按照上文的定義,實體的抽取確實應該使用 keywords 策略,但如果同一條用戶問句中需要抽取多個同類實體呢?建立起同類實體與多個詞典內實體值之間的對應關系就成了需要解決的問題。
(2)方案
wit.ai 中通過設定 role 來解決這個問題。
舉個例子,expression 為 “I want go from NY to SF”,其中 NY 和 SF 均為 wit/location 實體中的值。在這樣的業務場景下,我們需要同時抽取出兩個 wit/location 實體,值分別為 NY 和 SF,并且區分好 NY 是出發點,而 SF 是目的地。
我們在選擇實體時,設置抽取 NY 的 wit/location 實體的 role 為 origin,抽取 SF 的 wit/location 實體的 role 為 destination。
8、情感分析
(1)問題
我們想要知道用戶問句中的情感,是積極或消極。
(2)方案
可以按照上文中的方法進行 expression 的標注,區別在于,需要新增一個 sentiment 的 實體,將它的搜索策略選為 trait,值標注為為 positive 或 negative。
9、置信度下限選擇
(1)問題
對于每個抽取出的實體,wit.ai 都會提供一個置信度,當置信度足夠低時,或許我們應當采用特殊的處理方式,比如進行確認或直接丟棄。
但如何定義置信度的『足夠低』呢?
(2)方案
在實體頁的 Insights 模塊,我們能夠看到該實體抽取的置信度與準確率和召回率的關系,選擇不同的置信度能夠得到相對應的準確率和召回率。
如上圖,如果我們需要當準確率未達到1時進行特殊處理,那么我們就應該選取置信度為0.79,然后對置信度低于0.79的實體抽取情況進行特殊處理。
小結
由此看來:
- 規則未必都需要對應一個 intent,同一條規則在不同場景下應該會存在共用關系。
- 規則的使用是自始至終的,從識別 intent 到后續的對話過程。
- 規則應當有抽取非可枚舉值,也即子串的能力。
- intent 與通常意義的槽可以看做是平級的實體,只是搜索策略不同。
- 規則應當分為共用和非共用,不同業務方應當使用不同的規則域。因為同一位置的同一個詞可能會被不同規則抽取到不同的實體中,不同業務方之間不應相互影響,同一業務方在編寫規則時也應當注意通用性。
- 規則應當有能力根據位置/角色識別同類實體。
- 相似問句語料的提供可以通過與規則編寫相同的方式進行,搜索策略采用 trait 即可。
- 模型的訓練是實時的且不可見的,通過 expression 可以即時驗證結果。
還不了解的是:
- 如果一次標注中抽取了多個實體,那么在用戶問句不完整的情況下,能否將原標注結果中全部實體的一個子集抽取出來。也即抽取的粒度,是一個實體,還是一次完整的標注?推測為一個實體,但當出現沖突時,與完整標注更接近的應當擁有更高的優先級。
二、對話
1、實體的抽取與使用
(1)問題
當用戶講 “Where can I see Pulp Fiction?” 時,我們也許會需要將 Pulp Fiction 抽出來,去調用 Movie API,并將它保存在 context 中以供后續機器人時回答使用。
(2)方案
如圖所示,我們先輸入用戶問句,隨后標注問句的實體抽取方式:標注 intent 為 findTheater,以及標注好需要使用的其他實體。
隨后采用 Bot executes 調用 findTheater 函數,findTheater 以原 context 和抽取出的 entity 作為輸入,對 context 進行編輯,通過 add a context branch 可以對 findTheater 的輸出進行處理。
之后利用 context-key 拿到 movie 實體的實體值,使用 {} 在 bot sends 中引用。
2、基于槽的機器人(slot-based bot)
(1)問題
在大多數業務場景下,明確用戶指令所需的實體都不止一個,只有當用戶提供完整的實體信息之后,才能進行指令的執行;而信息不全時,就應當根據實體的缺失情況進行追問。
(2)方案
既然存在多種情況,我們就應當分多條分支進行處理。
首先我們處理信息完整的情況,如圖所示,我們按照上文講過的方式利用 context-key 同時拿到 showTime、theater、movie,然后將其拼裝成 Bot sends.
當用戶問句中缺失時間實體時,findTheater 函數應當返回 missingTime,由此新建一個多輪對話分支,該分支下,Bot sends 會追問用戶,系統用戶補全時間實體。
當用戶補全時間實體后,業務上應當等同于用戶一次提供完整信息的情況。
wit.ai 采用 bookmark 來做這種情況的處理。如圖所示,我們在 findTheater 函數的調用前添加一個 call-findTheater 的 bookmark,當用戶補全時間實體后,我們便利用 Jump 跳轉到 call-findTheater,隨之進行 findTheater 函數的調用,改走信息完整的分支。
3、處理是/非意圖
(1)問題
當我們向用戶確認問題時,用戶說『是』或『不是』大多數情況下會影響到后續的對話過程。我們需要做兩個不同的多輪對話分支來處理『是』和『不是』的情況。
(2)方案
具體操作如圖所示,與上文做多輪對話分支的方法基本相同,我們會新增一個實體 yes_no,并根據用戶的不同回答走不同的多輪對話分支。(quick replies 會在下文提到)
同時,我們當然希望不止能夠識別用戶的 yes,與之同意圖的 yep、yeah 等也應當被認定為是用戶的肯定回答。相對的,否定意圖除了 no 之外,也應當包含 nope 等其他實體值。
另外需要特別注意的是,yes_no 的搜索策略應當選為 trait,也即我們需要通過整句話來判定用戶的 intent,而不是某幾個詞。
同樣的,如圖所示,我們新增一個 branch 來處理用戶意圖為 no 的情況。
4、基于流的機器人(flow-based bot)
(1)問題
如上圖所示,如果我們的機器人需要做一個包含兩個問題的調查,特別的,根據第一個問題答案的不同,機器人會額外詢問一個附加問題。這樣的例子,就叫做基于流的對話。也即后續的對話路徑依賴于前序的實體值。
(2)方案
先處理第一種情況,用戶問句首先為:”I want to take the survey”,隨后機器人問第一個問題:”Do you watch sports on TV?”
這種情況下,如果用戶回答的意圖為 yes(處理方式上文中已經提到過),我們會追問一個額外的問題:”Which sports do you watch the most?”
接收到用戶的回復之后,首先進行 sport 實體的抽取,隨后調用 answer-tv 函數進行處理,此時調查的第一部分結束。
在調查的第二部分開始之前,我們先做一個 question-2 的 bookmark,為第一個問題 intent 為 no 的處理做準備。
之后進行第二個問題回答的處理,詢問用戶:”Ok. And do you watch sport online?”,當用戶回答的 intent 為 yes 時,調用 computer-result 函數,給出 result 作為返回值,拼裝成最后的 Bot sends. 同時在函數調用之前增加一個 end 的 bookmark.
之后我們來處理兩個問題 intent 均為 no 的情況。
按照之前的流程圖,當第一個問題的 intent 為 no 時,應當直接跳轉到第二個問題;當第二個問題的 intent 為 no 時,應當直接結束。
我們利用 bookmark 進行處理:當第一個 intent 為 no 時,我們使用 Jump 跳轉到 question-2 的 bookmark,直接開始第二個問題的詢問;當第二個 intent 為 no 時,我們同樣利用 Jump 跳轉到 end 的 bookmark,結束詢問。補全了整個對話過程。
5、了解 Context 和 Session ID
(1)問題
我不明白 Context 和 Session ID 的關系。
(2)方案
context 是用于追蹤當前對話狀態的對象,由我們自己的函數進行管理,用于幫助 wit.ai 預測接下來的行為。通常一個 Session 中只有一個 context 對象。
session_id 是我們自己產生的,用于標記與同一個用戶一次對話全部內容的唯一 ID. 需要注意的是,即便是同一個用戶,不同的對話也應當擁有不同的 session_id。
6、添加快速回復
(1)問題
我們希望能夠提供選項給用戶,使得用戶可以點選,以避免用戶主動輸入了我們無法處理的問句。
(2)方案
在 wit.ai 中,當我們在 Bot sends 下面的 Set quick replies 處填寫了若干個選項后,這些選項將會在實際對話時出現在用戶輸入框的上方,提供給用戶備選。
7、刪除回復和動作
(1)問題
我想要刪除我設置的一些回復和動作。
(2)方案
可以按照如圖所示的方式操作。
小結
由此看來:
- Bot 的回復應當能夠使用從用戶問句中抽取過的實體值。
- slot-based bot 的實體之間是平級關系,flow-based bot 的實體之間是依賴關系。
- 槽的必填/非必填、單值/多值、值的使用方式都被隱藏在調用的函數中。
- 對話狀態追蹤(DST)通過函數對 context 的管理來完成,候選動作排序也在函數內部處理完成,并以 context-key 的方式作用于后續對話。
- 與百度 UNIT 平臺相比,傳入 context 并由函數進行 DST 和 policy 的方式要比為答案提供設置準入條件的方法要更加靈活。
- 目前的 wit.ai 中似乎沒有反映出多輪過程與答案系統分離的思想,還是較為原始的,從頭至尾,非葉子節點中的 Bot sends 算作多輪過程,葉子節點的 Bot sends 作為答案。
- Facebook 也發現對話系統能夠利用的不應該只局限于用戶問句中提供的信息,推出了 Bot engine,可以使用用戶畫像以及場景信息;意識到答案也不應當只局限于簡單的文本,推出了 Built-in NLP for Messager,可以調用豐富的前端樣式來做答案的展示。 并準備于2018年2月1日廢棄掉對話部分所講的 Stories UI.
- 對話系統應當具有節點間跳轉的能力,wit.ai 采用 bookmark 來完成。阿里小蜜的在訂票場景下的『換出發地』應當也是相同的原理;商品推薦時的『換一換』推測是通過該方法重復進入相同的推薦節點,但 context 中會記錄該節點的進入次數,進而展示不同的結果。
- 常用的肯定、否定、請求更多等用戶動作應被當做 intent 來處理,同時要注意不能只將其看做一些詞的合集來處理,而是采用 trait 策略整體看待以識別意圖。
- bookmark 是可以跨 branch 訪問的。
- 同一個 Session 中,通常只有一個 context,這個context 由我們自己的函數維護,根據 context 的不同做出不同回應,返回不同的值,而后續的對話過程又依賴于函數調用的返回值來做多輪對話的分支。
- quick replies 可以每次單獨設置,但也可以嘗試把 keywords 類型實體的實體值詞典利用起來。
還不了解的是:廢棄現有的 Stories UI 后,用戶畫像以及場景信息由 context 傳遞,由函數來做 DST,應當是沒有疑問的。但前端模板的調用是由函數來做,還是由當前的 Bot sends 模塊改進得到?我個人傾向于由函數來做,一是更為靈活,二是可以將多輪過程與答案系統分離,Bot sends 只起到澄清以及推進對話的作用,而不是同時兼具答案提供的功能。
(完)
作者:我偏笑?,AI產品經理大本營”成員,“AI研習小分隊”的分享嘉賓之一
本文由人人都是產品經理專欄作家?@黃釗?授權發布于人人都是產品經理,未經作者許可,禁止轉載。
題圖來自 Pixabay,基于 CC0 協議
沒用過的話有點難看懂這篇文章,反正我是沒看懂