跳至主要內容
所有文章

系列在地化的客服機器人第 2 篇

客服機器人要開在客人已經打開的那個 App 裡

Desk 的網頁版早就會回答了,但客人不會為了問幾點打烊去開一間店的網站。我們把同一個 brain 接上 LINE、Telegram,以及一行 script 的網頁小工具,驗收條件只有一個:同一題在三個通道要拿到同一個答案,底下那三個數字也要一模一樣。這篇是三個 adapter 各自不同的地方、一個節流的坑,以及一個型別檢查與單元測試全綠、只有真的瀏覽器才抓得到的 bug。

閱讀約 5 分鐘分類工程產品

一位店家老闆問:那客人要去哪裡問?

我說,網站上會有一個小視窗。

他說:客人不會為了問我幾點打烊,特地去開我的網站。

他是對的。網頁版是我們自己最方便驗證的地方,不是客人最方便問的地方。所以通道這件事被排到第一週。

但通道不是介面問題。把同一個助理放到三個地方,難的不是把字送出去,是讓三個地方拿到的是同一個答案——包括答案底下那三個數字:讀了幾段、送了幾段、引用驗了幾個。只要有一個通道少印一個數字,那個通道上的助理就變成一個看起來很像、但沒有證據的東西。

一個 brain,三個 adapter

檢索、早退、驗引用、轉人工規則全部寫在 brain 裡,寫一次。adapter 只負責兩件事:收進來長什麼樣,送出去長什麼樣。

驗收條件因此是可以直接寫成斷言的:同一題在不同通道,送出的來源清單與有據與否必須一致。實測(本機 llama3.1:8b 加語意檢索,假的 bot token):

通道讀了送出引用驗到有據
LINE28 段5 段1
Telegram28 段5 段1

完全一致。 這不是加分項,是這一項能不能算做完的門檻。

LINE:一張卡片,一個免費的回覆

LINE 收到的是一張回覆卡:答案、每個來源一顆按鈕直接開到那一頁、一顆把對話轉給真人的按鈕。它在讀的時候先出現讀取動畫,因為第一句話出來之前那幾秒是沉默的。

那三個數字放在卡片底部的小字:「讀了 41 段・送了 3 段・引用驗了 2/2」。同一個機制,只是畫面小。

有一件事決定了整個轉人工的設計:回覆客人的訊息是免費的,事後主動推播才計額度。 所以「已經把對話轉給店家」這件事,通知走的是信箱而不是推播;每週那封「這週問了幾題、幾題轉人工、答不出來的前十題」也走信箱。額度應該花在客人身上,不是花在通知我們自己。

LINE 不能就地編輯已經送出的訊息,所以在 LINE 上,答案是一次出現的。

Telegram:同一個答案,邊寫邊長

Telegram 可以就地編輯訊息,這是聊天通道裡最接近網頁串流的做法:文字會一段段長出來。

所以收集回應的函式多了一個選填的 onText,而 gateway 只在 adapter 宣告自己支援漸進更新時才傳進去——LINE 沒有這個能力,也就不用為它改任何一行。能力是 adapter 宣告的,不是 brain 假設的。

編輯要節流:最快 1.5 秒一次,內容沒變就不送——相同內容的編輯會被 API 當成錯誤退回來

這裡踩到一個只有看 log 才會發現的坑。在假 token 的測試下,每一個 delta 都在重試送出:因為送失敗就沒有被記成「已經有一則訊息在那裡」,下一個 delta 又走「第一次送」那條路,等於每一個 token 換一次失敗的 API 呼叫。節流改成呼叫前就先佔用,失敗也照樣退避,並補了回歸測試。

網頁:客戶要貼的是一行

<script src="https://desk.hangruiai.com/widget.js" data-key="demo-shop" async></script>

它開的是 iframe,不是直接把 DOM 塞進客戶的頁面。客戶頁面的 CSS 進不來、我們的出不去,而且 iframe 與後端同源,不必處理 CORS。代價是不能跟宿主共用字型——這是刻意選的,因為樣式互相污染是那種上線兩週後才有人回報、而且沒有人重現得出來的問題。內層用 postMessage 把自己的高度回報出去,面板才不會開起來半空、或把底下的來源切掉。

那個 bug,只有真的瀏覽器抓得到

iframe 的 sandbox 少了 allow-forms。瀏覽器直接擋掉表單送出:按鈕沒反應,而且沒有任何 console 錯誤。

讀程式碼讀不出來。型別檢查是綠的,單元測試是綠的,build 是綠的。

所以那一項的驗收後來換成一支真的開瀏覽器的腳本,十三項:啟動按鈕有沒有被注入、面板預設是不是收起的、iframe 是不是同源、答案有沒有文字、三個數字有沒有都印出來、五個來源是不是都可點、答案裡的 [1] 是不是連結、落選的來源能不能展開、丟亂碼進去會不會顯示「它選擇停在這裡,而不是用猜的」而且一個來源都不列、有沒有 console 錯誤。

一個測不到瀏覽器的測試,測的是我們對瀏覽器的想像。

這樣做的代價

  • 沒有座席介面。 轉人工的意思是「通知到人,並把整段逐字稿附上」,不是一套客服座席系統。真人要在自己的信箱裡回。這是這個階段最明顯的缺口。
  • 沒有 App 內 SDK。 產品頁原本寫「App 內」,那句話不成立,已經改掉了。客人是在 LINE 的 App 裡用它——那是他們的 App,不是我們的。
  • 推播要錢。 所以任何「事後主動找客人」的功能都不是免費的,這條會回頭限制產品能長成什麼樣。
  • 圖片先不理解。 顧客傳圖,回一句請用文字描述。
  • 雲端的對話還不持久。 pilot 的對話存在記憶體裡,重啟就沒了,多實例也不共享。換成 Redis 的程式寫完了,憑證還沒開通,所以這一項現在的狀態是「寫完,還沒驗收」——寫在這裡,因為驗收沒跑就不算做完。

接下來

三個通道跑的是同一個 brain,而 brain 裡最貴的一格是模型。它可以是外面的 API,也可以是店裡那台機器。下一篇量的是換模型到底換到了什麼——以及,在檢索問答上,換模型換不到什麼。

這個系列

在地化的客服機器人

要把一個客服助理放到真的客人面前,這裡需要什麼:它得在不知道的時候停下來、出現在客人本來就打開著的那個 App 裡,而且能夠跑在店家自己控制得住的一台機器上。

  1. 第 1 篇客服機器人最貴的那句話,是它猜出來的
  2. 第 2 篇客服機器人要開在客人已經打開的那個 App 裡

  3. 第 3 篇換模型不會改變它有沒有找到對的那份文件

心裡已經有想法了嗎?

說說你想做什麼,我們會老實告訴你,這件事適不適合交給我們。