使用 Node.js 和 Dialogflow 打造一個聰明的 LINE 電商客服機器人

以 Bottender 實作假的電商客服為例

大家好,我是卡米哥,LINE 官方認證的 API 專家,LINE API Expert。目前在維護知名 Node.js 聊天機器人框架 Bottender

今天要來教大家怎麼使用 Node.js 和 Dialogflow 打造一個聰明的 LINE 電商客服機器人。我會按照以下的順序來說明:

  1. 認識 Dialogflow
  2. 使用 Bottender 實作假的電商客服 LINE Bot
  3. 導入 Dialogflow 來優化用戶體驗

認識 Dialogflow 當中會簡單說明 Dialogflow 是什麼,以及使用 Dialogflow 有什麼好處。在使用 Bottender 實作假的電商客服 LINE Bot 當中會說明如何實作以規則解析對話的 LINE Bot,接著在導入 Dialogflow 來優化用戶體驗當中會說明如何用自然語言理解來優化用戶體驗。

認識 Dialogflow

Dialogflow 是 Google 出的聊天機器人開發工具,可以串接通訊軟體、解析對話內容和生成回覆。Dialogflow 提供多種方式使用,例如以下的兩種方式:

  • 不寫任何一行程式,在 Dialogflow 後台設定與 LINE Bot 串接
  • 自己寫串接程式,只使用 Dialogflow 的自然語言處理服務

沒錯,Dialogflow 在不寫任何程式的情況下依然可以做出聊天機器人。不過這次要跟大家介紹的是自己寫串接程式的使用方法。

既然 Dialogflow 有提供串接平台服務,為什麼還要自己寫?

有些事情 Dialogflow 是很難做到的,比方說跟自己的用戶資料做深度整合,或者做複雜的查詢計算或排程工作等。只有在自己寫程式的情況下,才可以掌握最大的彈性。

使用 Dialogflow 之後可以獲得什麼好處?

自然語言理解服務提供了強大的解析功能,讓你可以解析用戶的各種相同意思但是不同用詞的句型。如果不使用自然語言理解來解析用戶輸入,就是用規則來解析用戶輸入,但是規則是很難維護以及窮舉所有可能性的。

當用戶輸入無法正確被聊天機器人理解時,通常用戶會感到不耐煩而離開,或者意識到這個機器人很廢,只能對特定的句型做出反應。不論是哪一種情況,對用戶體驗都是扣分的,而 Dialogflow 可以用來改善用戶體驗。

不過自然語言理解技術只能用來作為改善用戶體驗的手段,在我的文章:人工智慧在聊天機器人上的應用當中曾經提到過,這裡就不多做說明了。

以下將示範實作一個假的電商客服系統 LINE Bot,並且使用 Dialogflow 來改善用戶體驗。

使用 Bottender 實作假的電商客服 LINE Bot

我們從一個基本的 Bottender LINE Bot 開始,如果你不知道 Bottender 如何使用,請到「從零開始在 Windows 使用 Node.js 打造專屬於你的 LINE Bot 聊天機器人」實作出一個基本的 LINE Bot 後再接續本文閱讀。

電商客服功能設計

作為一個電商,應該要能夠回答商品是否有庫存、以及回覆常見問題。針對這兩個需求,我們設計一個假的電商客服自動回覆以下兩種問題:

  1. 「請問{商品名稱}還有貨嗎?」
  2. 「請問門市營業時間為何?」

其中 {商品名稱} 代表任意的商品名稱,比方說「請問抱枕還有貨嗎?」。

這兩個問題有完全不同的特性。第一個問題的句型當中包含了關鍵字:商品名稱,這是句子當中的重要資訊,因為我們得根據用戶詢問的商品來回答庫存量,如何擷取出用戶輸入的句子中的商品名稱是一個重點。

擷取對話中的關鍵字是自然語言處理的重點功能

而門市營業時間就不會經常改變,所以他可以是固定寫死的答案,但商品庫存就不是這樣了,商品庫存會一直改變(如果你有客人的話QQ),可能你上一秒還有庫存,下一秒就賣光了也說不一定。針對這種情況,就必須串接商品資料庫來獲得即時的庫存資訊。

面對即時資訊的需求,就需要串接程式的協助

假設我們的假電商提供的商品有抱枕貼紙,營業時間是早上 10 點到晚上 10 點,我們可以使用 Bottender 提供的 router 來寫我們的規則,修改 src/index.js 如下:

src/index.js

這樣就完成了整個假電商客服系統(畢竟我們只處理兩種需求)。

Bottender Action

Action 是在 Bottender 當中處理對話的最小單位,你可以在 Action 的第一個參數 context 當中取得所有對話資訊。

關於 Bottender action,更多資訊請參考 https://bottender.js.org/docs/zh-TW/the-basics-actions

在這段程式當中我們寫了 3 個新的 Action:

  • queryInventory
  • queryBusinessHours
  • others

用來處理查庫存、查營業時間和其他問題。然後我們在 App (入口 Action) 當中使用 router 建立規則來組合上述 3 個 Action,以下是 App 的程式碼:

接下來會詳細講解 App 內部的程式。

Bottender router

Bottender 的 router 是由一群規則和對應 Action 所組成,根據對話循序判斷是否滿足規則,如果對話符合第一個規則,那麼就採用第一個 Action 來處理對話,如果不符合第一個規則,那麼就看有沒有符合第二個規則,以此類推,router 的功能就是這樣將對話分成幾種情形來處理。

關於 Bottender router,更多資訊請參考 https://bottender.js.org/docs/zh-TW/the-basics-routing

以上述程式來說,我們將對話分成三種情形,並分別指定其對應處理的 Action:

  • 在 queryInventory 回答「請問{商品名稱}還有貨嗎?」
  • 在 queryBusinessHours 回答「請問門市營業時間為何?」
  • 在 others 回答所有其他對話

這樣一來就可以將問題單純化,各個擊破。

正規表示式

在 JavaScript 當中,正規表示式是由斜線開頭,斜線結尾所組成的,使用一些符號可以用來代表各式各樣的字詞,例如 \S 用來代表任意的非空白字元,而+則是代表前面一個字元重複 1 次以上,所以 \S+代表 1 個以上的任意的非空白字元。而 (?<變數名稱>規則) 是 Named Capture Groups,可以用來擷取句子當中的關鍵字。當遇到符合規則的字串時將它擷取出來並給它一個名字。

以下是本次使用的正規表示式,我們希望擷取出符合商品名稱為關鍵字,商品名稱是由任意個非空白字元所組成,擷取出來後存放至變數 name 當中。

目標句型:「請問{商品名稱}還有貨嗎?」

正規表示式:/請問(?<name>\S+)還有貨嗎?/

處理查庫存

我們在 queryInventory 處理庫存查詢,以下是 queryInventory 的程式碼:

我們先從 props 當中取得正規表示式捕捉到的 name 變數,再拿去資料庫做查詢,為了方便講解,在這裡直接使用一個物件 inventoryData 代替資料庫。

如果查詢不到庫存量,代表商品名稱輸入錯了,此時回覆「我們沒有賣{商品名稱}哦。」如果有庫存,就回覆「{商品名稱}只剩下最後 {庫存量} 個了!要買要快!」如果庫存量是 0,則回覆「很抱歉,{商品名稱}已經賣完囉,到貨時再通知您~」

試用

Image for post
Image for post
規則型機器人的弱點

經過測試之後你就會發現,只要你輸入的文字跟規則有落差,即使差一個字或一個標點符號,都會導致機器人無法理解對話,這就是文字比對型機器人的弱點。

甚至當用戶輸入的句型完全正確,但關鍵字沒有完全正確時,如上圖情況,由於商品名稱是「抱枕」而不是「卡米狗抱枕」的關係,所以機器人就回覆查無此商品。

當然我們的文字比對型機器人的規則可以寫得更複雜,容錯率可以再提高,但其實要解決這個問題的最佳方法就是導入自然語言理解工具。

文字比對型機器人強迫用戶學會下指令;

自然語言理解型機器人傾聽用戶對話。

導入 Dialogflow 來優化用戶體驗

在完成了基本的文字比對型機器人之後,我們可以使用自然語言理解工具 Dialogflow 來優化用戶體驗,在這個階段我們需要做的事情如下:

  1. 登入 Dialogflow
  2. 建立 Dialogflow Agent
  3. 設定 Intent 和 Entity
  4. 建立 service account 金鑰
  5. 串接至 Bottender

登入 Dialogflow

首先,先開啟網頁 https://dialogflow.cloud.google.com/ ,如果你沒有登入,你會看到下圖:

Image for post
Image for post
Dialogflow 登入畫面

點擊 Sign-in with Google 登入 Google 帳號後,會看見:

Image for post
Image for post
登入 Dialogflow 後的第一個畫面

建立 Dialogflow Agent

一個 Dialogflow Agent(以下簡稱 Agent)相當於一隻機器人的腦,通常每個專案只需要一個 Agent,所以我們要建立一個 Agent,點擊 Create Agent 後會看到以下的表單:

Image for post
Image for post
填寫 create agent 的表單

我填寫的資料如下:

  • Agent Name:bottender-demo
  • Default Language:Chinese (Traditional) — zh-tw
    這是預設語言,設定了就不能修改,我選擇的是繁體中文。
  • Default Time Zone:(GMT+8:00) Asia/Hong_Kong
    這是預設時區,我選擇跟台北時間相同的 GMT+8 時區
  • Google Project:Create a new Google project
    Agent 隸屬於 Google Project 下,我選擇建立一個新的 Google project

填好之後按下 Create 按鈕:

Image for post
Image for post
建立 Agent 後的畫面

這樣就完成了 Agent 的建立了。

設定 Intent 和 Entity

Intent 代表用戶意圖(這個用戶想幹嘛),Dialogflow 在讀取用戶對話後,會嘗試識別用戶意圖,識別出來之後我們就可以根據用戶意圖來做不同的處理,通常是執行某個功能,每個意圖都會對應到一個功能,所以其實 Agent 就相當於 Bottender router,而每個 Intent 都是其中的一組規則。我們需要設定以下兩個意圖:

  1. 「請問{商品名稱}還有貨嗎?」
  2. 「請問門市營業時間為何?」

而 Entity 則是關鍵字,設定 Entity 有助於我們擷取出對話中的關鍵字,我們需要擷取的關鍵字是商品名稱。

首先點擊左側的 Entities:

Image for post
Image for post
空無一物的 Entities 頁面

點擊 Create Entity:

Image for post
Image for post

我們要定義的是商品名稱,所以在 Entity Name 上輸入 product_name,並且在下方輸入抱枕,你可以在這裡輸入商品別名,因為抱枕可能會被用戶稱為卡米狗抱枕,所以我輸入抱枕卡米狗抱枕,而貼紙的部分以此類推,輸入完成後按下 Save。

接下來要新增 Intent,點擊左側的 Intent 分頁上的+:

Image for post
Image for post
填寫 create intent 的表單

在 Intent Name 輸入 queryInventory,並且點擊 Add Training phrases,然後輸入請問抱枕有貨嗎?,如下圖:

Image for post
Image for post
設定 Intent 的 Training phrases

輸入完成後按下 Enter 鍵:

Image for post
Image for post
Training phrases 設定完成

你會發現抱枕兩個字被標上黃色標記,這表示 Dialogflow 自動捕捉到抱枕是商品名稱,點擊已經設定好的 Training phrases 你會看到細節:

Image for post
Image for post
Training phrases 當中的 entity 自動設定成名為 product_name 的 Parameter

這樣就設定完成 Intent 了,按下 Save 鍵,並且點擊左側的 Intents:

Image for post
Image for post
在 Intents 列表頁,可以看到 3 個 Intent

點擊 Create Intent 建立第二個 Intent,取名為 queryBusinessHours,並且輸入 Training phrases 為請問門市營業時間為何?

Image for post
Image for post

你會發現請問門市被 Dialogflow 視為 location 了,我們不需要這個 Parameter,所以直接按下 x 移除 Parameter。

完成後按下 Save,然後回到 Intents 頁面:

Image for post
Image for post
再次回到 Intents 頁面

其實我們不需要 Default Fallback Intent 和 Default Welcome Intent,所以就把它刪除,將游標停留在 Default Welcome Intent 就會看見垃圾桶在右側出現:

Image for post
Image for post
準備刪除 Default Welcome Intent

點擊垃圾桶後的畫面:

Image for post
Image for post
確認是否要刪除 Default Welcome Intent

直接點選 Delete 即可,以此類推,把另一個也刪除。

Image for post
Image for post

到這裡就算是設定完成了,你可以在右側的 Try it now 測試效果。

建立 service account 金鑰

service account 是一種可以登入 Google 做事情的帳號,這是 Google 設計給不是真人用的帳號,因為我們真人的帳號密碼更珍貴,而且也會擔心帳密洩漏的問題,所以 Google 設計了 service account 讓你可以專門授權給伺服器用。

接下來我們要取得授權金鑰並且放入我們的專案資料夾下,首先點擊左側的齒輪:

Image for post
Image for post
Agent 設定頁

可以看到上圖的下方有個 Google Project 區塊,這裡的 Project ID 請記錄下來備用,然後 Service Account 那個超連結點進去:

Image for post
Image for post
服務帳戶,也就是 service account

你會看到 Google Cloud Platform,這裡已經是另外一個世界了,注意不要迷路。在畫面中可以看到已經有一個 service account,點擊右側的動作:

Image for post
Image for post
對 service account 做事囉

點擊建立金鑰:

Image for post
Image for post
建立並下載金鑰

選擇 JSON 類型金鑰下載,點擊建立:

Image for post
Image for post
下載完成

將剛剛獲得的 JSON 檔放入專案資料夾根目錄下,所有的材料就準備齊全了,接下來就是串接到 Bottender 上了。

串接至 Bottender

我們 Bottender 已經幫你把大部分的程式都寫完,你只要寫幾行程式就能串接好,請在小黑框(Terminal)輸入以下指令安裝 Bottender Dialogflow 套件:

關於 Bottender Dialogflow 套件,更多資訊請參考:https://bottender.js.org/docs/zh-TW/advanced-guides-nlu#%E4%BD%BF%E7%94%A8-dialogflow-%E5%BB%BA%E7%BD%AE

然後修改 .env 檔如下:

除了聊天平台的設定之外新增了兩個環境變數:

  • GOOGLE_APPLICATION_CREDENTIALS:JSON金鑰檔路徑
  • GOOGLE_APPLICATION_PROJECT_ID:剛剛叫你備用的 Project ID

設定好之後修改 src/index.js 如下:

就完成囉!以下簡單說明程式碼的變動:

Bottender chain

在 App 當中原本使用 router 改為用 chain,chain 是 bottender 所提供的責任鏈結構,你可以看到在 chain 當中有 dialogflowAction 和 others,如果 dialogflowAction 能處理這個需求,那就輪不到 others,當 dialogflowAction 不能處理的時候就會交給排在後面的 others 來處理。

關於 Bottender chain,更多資訊請參考:https://bottender.js.org/docs/zh-TW/the-basics-chain

dialogflow

在第 36 行用到了 dialogflow 函數,並且傳遞了一個 actions 變數,這個 actions 就是用來建立 Dialogflow Intents 和 Bottender actions 之間的關聯,因為我們兩邊的命名都相同的關係所以這樣寫就可以了。

另外值得注意的是,在 queryInventory 當中需要擷取出商品名稱的寫法也跟著改變了。

Dialogflow 就是強化版的 Bottender router,它也提供 Action 分流功能

試用

機器人直接智商大升級,效果超讚,直接看圖就知道了:

Image for post
Image for post
努力沒有白費,獲得的成果是豐碩的

這只是最基本的示範,當然還有很多微調的空間,以後再給大家講解。

覺得寫得不錯的話歡迎分享哦~

在追求真理的道路上

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store