如何落地一個智慧機器人
前言
隨著智慧 AI 的普及,對話式人工智慧產品也越來越常見。從產品定義出發,智慧問答類產品最根本的價值在於以低成本的優勢取代人工工作中大量重複性的部分。我司由於業務系統較為複雜,開發同學大部分的時間都在處理技術支援、業務方、測試同學反饋的真線"問題"。有些"問題"重複性極高,完全可以沉澱為 FAQ。但現狀是開發同學依然在重複性地回答之前已經處理過的類似問題,這也佔用了同學們大量的時間去進行無效的"溝通"。基於目前的痛點,我們覺得有必要使用智慧問答機器人來管理這部分 FAQ,除此之外,智慧問答機器人內部也閉環了線上 ONCALL 問答機制,這樣更加方便管理所有問題的生命流程,也方便後續問題資料的總結分類及覆盤。實現了 ONCALL 跟蹤,QA 應答的自動化能力。本文簡單聊一聊賦能給政採雲同學們的智慧問答機器人"賈維斯"的設計及落地推廣。
架構設計
為什麼要取名為"賈維斯"呢?相信喜歡鋼鐵俠的同學們都知道,它是鋼鐵俠的智慧助手,也是美國 漫威 漫畫旗下的人工智慧。全稱為Just A Rather Very Intelligent System(是一個相當聰明的 智慧系統 )。"賈維斯"的架構設計大體如下:
"賈維斯"整體的設計理念是微服務化的。這樣易於拓展,方便打通我司現有的任何能力,也反哺了現有能力的建設及落地場景。"賈維斯"的優勢便是能力易接入、體積更小巧、離使用者更近,當然我們最初給它的定位也很簡單明瞭,能為我司的同學們提供解決常見 QA 的應答以及自動化的能力。下面我就以這兩部分來介紹一下"賈維斯"。
QA 應答能力
第一部分是 QA 應答 能力。秉承著"能用 JS 做的最後都會用 JS" 的態度,我們的第一版 QA 能力是由 node-nlp 提供的,為什麼使用 node-nlp?第一個原因是於我們前端小夥伴來說它使用起來非常方便,第二個原因是我們想快速探索一下落地的可能性及真實使用場景。於是乎,我們的 V1.0 版本的"賈維斯"便誕生了,下面是它簡易的實現過程:
賈維斯 V1.0 版本
第一步:搭建專案
開啟您常用的 IDEA,新建一個工程資料夾,建立如下所示的專案結構:
├── buildable.js ├── dist │ └── bundle.js ├── index.html └── package.json
在 buildable.js 裡寫入如下基礎程式碼:
const core = require('@nlpjs/core'); const nlp = require('@nlpjs/nlp'); const langenmin = require('@nlpjs/lang-en-min'); const requestrn = require('@nlpjs/request-rn'); window.nlpjs = { ...core, ...nlp, ...langenmin, ...requestrn };
因為我們只使用 NLP 的核心程式碼和一個小的英語語言包,所以只需要向你的 package.json
寫入以下程式碼:
{ "name": "nlpjs-web", "version": "1.0.0", "scripts": { "build": "browserify ./buildable.js | terser --compress --mangle > ./dist/bundle.js", }, "devDependencies": { "@nlpjs/core": "^4.14.0", "@nlpjs/lang-en-min": "^4.14.0", "@nlpjs/nlp": "^4.15.0", "@nlpjs/request-rn": "^4.14.3", "browserify": "^17.0.0", "terser": "^5.3.8" } }
我們可以提前在 index.html 檔案內引用後面打包出來的 bundle.js 檔案,寫入以下程式碼:
<html> <head> <title>NLP in a browser</title> <script src='./dist/bundle.js'></script> <script> const {containerBootstrap, Nlp, LangEn, fs} = window.nlpjs; const setupNLP = async corpus => { const container = containerBootstrap(); container.register('fs', fs); container.use(Nlp); container.use(LangEn); const nlp = container.get('nlp'); nlp.settings.autoSave = false; await nlp.addCorpus(corpus); nlp.train(); return nlp; }; const onChatSubmit = nlp => async event => { event.preventDefault(); const chat = document.getElementById('chat'); const chatInput = document.getElementById('chatInput'); chat.innerHTML = chat.innerHTML + `<p>you: ${chatInput.value}</p>`; const response = await nlp.process('en', chatInput.value); chat.innerHTML = chat.innerHTML + `<p>chatbot: ${response.answer}</p>`; chatInput.value = ''; }; (async () => { const nlp = await setupNLP('http://raw.githubusercontent.com/jesus-seijas-sp/nlpjs-examples/master/01.quickstart/02.filecorpus/corpus-en.json'); const chatForm = document.getElementById('chatbotForm'); chatForm.addEventListener('submit', onChatSubmit(nlp)); })(); </script> </head> <body> <h1>NLP in a browser</h1> <div id="chat"></div> <form id="chatbotForm"> <input type="text" id="chatInput" /> <input type="submit" id="chatSubmit" value="send" /> </form> </body> </html>
第二步:打包專案
將 buildable.js 原始檔打包到 dist/bundle.js 中,執行如下命令:
npm run build
第三步:執行專案
接下來在瀏覽器中開啟 index.html,此時你應該看到了一個可以簡單互動的聊天機器人,如下圖所示:
使用它很方便也很香,因為這三步下來,你已經訓練了一個人工智慧,這種感覺可太棒了。但考慮到瀏覽器缺少對語料庫的安全和隱私保護,以及常見的自然語言處理功能。比如無法提供主動學習、實體提取、個性化需求定製的能力,所以 V1.0 版本我們也只是更多的去探索可能性,有興趣的同學可以跟著這篇 文章 把玩一波。
賈維斯 V2.0 版本
鑑於第一版能力的侷限,所以我們在開發第二版的時候,依靠著公司強大的資源,同 AI 團隊的同學進行協作,底層的訓練能力完全由 AI 團隊託管。比如使用市面上更流行的 BM25 快速演算法 進行匹配搜尋以及 BERT 進行語義解析構建網路模型等。我們只需要提供標準的訓練資料來源以及對應的落地頁來承載它即可。這樣一來,真正意義上打造了一個屬於我們公司自己的安全可靠的智慧問答機器人。
如何同 AI 團隊進行協作呢?我們約定使用 RESTful 標準設計介面來進行底層的通訊。這樣一來,我們便擁有了更多的互動形態,比如 web 端、移動端、各類外掛...,這些場景"賈維斯"都能應付自如。除此之外,我們還賦予了"賈維斯"更加豐富的互動形式,比如支援點贊、點踩、評論...,這些反饋資料後期都會作為負樣本進行模型訓練。
關於 web 端的搭建,我們使用了流行的 ChatUI 來幫助我們開發。它是一個服務於對話領域的設計和開發體系,助力智慧對話機器人的搭建框架,簡單幾步就可以搭建出來:
使用 ChatUI
編寫一個 HTML 檔案(index.html)和執行檔案(setup.js):
在 index.html 中寫入以下程式碼:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta name="renderer" content="webkit" /> <meta name="force-rendering" content="webkit" /> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0, viewport-fit=cover" /> <title>賈維斯</title> <link rel="stylesheet" href="//g.alicdn.com/chatui/sdk-v2/0.2.4/sdk.css"> </head> <body> <div id="root"></div> <script src="//g.alicdn.com/chatui/sdk-v2/0.2.4/sdk.js"></script> <script src="//g.alicdn.com/chatui/extensions/0.0.7/isv-parser.js"></script> <script src="/setup.js"></script> <script src="//g.alicdn.com/chatui/icons/0.3.0/index.js" async></script> </body> </html>
在 setup.js 中寫入以下程式碼:
var bot = new ChatSDK({ config: { navbar: { title: '智慧助理' }, robot: { avatar: '//gw.alicdn.com/tfs/TB1U7FBiAT2gK0jSZPcXXcKkpXa-108-108.jpg' }, messages: [ { type: 'text', content: { text: '智慧助理為您服務,請問有什麼可以幫您?' } } ] }, requests: { send: function (msg) { if (msg.type === 'text') { return { url: '//api.server.com/ask', data: { q: msg.content.text } }; } } }, handlers: { parseResponse: function (res, requestType) { if (requestType === 'send' && res.Messages) { // 解析 ISV 訊息資料 return isvParser({ data: res }); } return res; } } }); bot.run();
在瀏覽器中開啟 index.html 即可看到如下:
更詳細的使用文件可以參考 官網 。
搭建釘釘機器人
除了以上的載體,我們還深度結合釘釘機器人及釘釘推送的能力做了很多有意思的事。一方面是公司同事都是使用釘釘辦公,另一方面是訊息推送的即時效能夠更好的體現出來。如何開發一個企業內部機器人呢?以下流程可簡單快速的搭建一個釘釘機器人:
- 登入 釘釘開發者後臺 ,依次選擇 應用開發 > 企業內部開發 > 機器人 ,點選 建立應用 。並完善相關的配置機器人的基本資訊。
- 當用戶@機器人時,釘釘會通過機器人開發者的HTTPS服務地址,把訊息內容傳送出去,報文協議如下。
{ "Content-Type": "application/json; charset=utf-8", "timestamp": "1577262236757", "sign":"xxxxxxxxxx" }
- 開發者可以根據自己的業務需要,選擇回覆一段訊息到群中。目前支援text、Markdown、整體跳轉actionCard型別、獨立跳轉actionCard型別、feedCard這5種訊息型別。詳情參考 訊息型別和資料格式 。
當然你也可以去自定義更多的 訊息模版 ,甚至在釘釘上完成一些複雜人機互動形式,讓你的機器人看起來更酷。比如下面這樣:
- 企業成員使用路徑:進入要使用機器人的群依次點選 群設定 > 智慧群助手 > 新增機器人 ,在企業機器人列表中即可找到。
更詳細的使用文件可以參考這篇 文章 《企業內部開發機器人》。這樣一來我們便完成了釘釘機器人的搭建,後續使用需要手動在群內引入企業機器人即可。
打通釘釘推送
釘釘推送能力則是使用 ding-bot-sdk 來實現的:
const Bot = require('ding-bot-sdk') const bot = new Bot({ access_token: 'xxx', // Webhook地址後的access_token // 必填 secret: 'xxx' // 安全設定:加簽的secret 必填 }) bot.send({ "msgtype": "text", "text": { "content": "我就是我, @150XXXXXXXX 是不一樣的煙火" }, "at": { "atMobiles": [ "150XXXXXXXX" ], "isAtAll": false } })
完成以上這些,藉助釘釘機器人推送能力,我們的 QA 應答能力便更方便落地。
自動化能力
第二部分是"自動化能力"。自動化是相對人工概念而言的。指的是在沒人蔘與的情況下,利用指令碼使被控物件或過程自動地按預定規律執行。其最大好處是可以節省勞動力、將繁瑣的動作一鍵化,我們只需要提前將相應的系統流程編排起來的就可以實現自動化的工作。
"賈維斯"通過 指令 作為載體來觸發對應的指令碼。這裡我們有一個思考,如何區分使用者輸入的問題是不是我們內建的指令呢?我們簡單的做了兩件事。
指令模式
一是內建的指令儘可能的簡短,我們定義為某個特定單詞或者限定長度的字元,比如:ONCALL、值班、前端小報、百策這種關鍵詞觸發背後對應的指令碼。
當然,除了純指令的場景,我們還支援通過互動形式獲取到更多的引數,支援更多自定義的能力。如下所示:
這部分能力的實現只需要確定好一個引數標識,通過擷取就可以拿到。類似於我們 npm install webpack --save
中定義為 -- 來作為引數標識。稍微複雜的一個例子是,我們可以直接打通公司的基建 百策 系統,為我們提供頁面檢測功能,如下所示:
閾值計算模式
二是基於閾值進行弱匹配模式,我們會基於使用者的問題分數進行檢測,只有在低於閾值時才會走指令弱匹配模式並提示相關指令使用方式。這很類似於我們在終端使用腳手架拼錯單詞時,大部分 CLI 都會有一個很友好的提示一樣: 下面是虛擬碼實現方式:
const THRESHOLD = 0.25; const questionStr = '今天誰值班'; const instructionMap = [ { instruction: '值班', handler: () => console.log('獲取當前值班人員'), }, { instruction: 'oncall', handler: () => console.log('觸發ONCALL相關'), }, ]; const { scroe, qaAns } = await getQA(questionStr); if (scroe > THRESHOLD) { return qaAns; } // 獲取到指令及對應的指令碼動作 const [{ instruction, handler }] = instructionMap .filter(({ instruction }) => questionStr.indexOf(instruction) > -1); return handler();
實現的效果如下所示:
系統編排
除了單一系統實現自動化外,我們還可以將多個系統的核心邏輯進行編排組合。比如"賈維斯"的 ONCALL 能力,便是基於我司的值班系統、ICS 系統、語音系統及賈維斯內建的工單系統組合而成的一套解決線上問題告警及跟蹤的方案。
再結合"賈維斯"自身的 AI 能力,不僅可以對一個 ONCALL 問題進行跟蹤管理,還可以把 ONCALL 結單的資料反哺給 QA 進行訓練,這樣便形成了 ONCALL 提問,QA 解答的閉環能力。
提問同學視角:
值班同學視角:
下次使用者再遇到類似的問題時,只需要問"賈維斯"就可以獲取答案。於使用者而言,我們只需要去使用賈維斯即可,背後的那些自動化動作則全部由"賈維斯"託管。
推廣落地
首先我們需要肯定自己的產品,並清楚自己做的產品是有價值的,可以從以下角度思考:
- 解決了什麼問題
- 如何解決
- 使用者及場景分析
智慧機器人的定位就是幫助同學們解決常見 QA 的應答以及自動化的能力。明白了產品價值,下面一步就是推廣使用。
本著以小到大的策略,我們選擇從身邊的研發同學推廣起來。研發同學更多的是訴求問題,比如支援指令碼錄入 QA 資料、支援外部系統一鍵接入"賈維斯"...,通過不斷的調研,我們完成了其中部分"需求",不斷優化體驗甚至是新增功能,目的是留住這些寶貴的 VIP 使用者。初期的使用者口碑是非常重要的,他們能給產品帶來更多的推廣。
最後一步就是收集使用者反饋及使用痛點,可以用問卷調查的形式,也可以通過收集埋點資料進行復盤。目的是更好的清楚自己的產品使用情況。既能做到及時的查漏補缺也能瞭解到使用者的聲音。 總體來看就是以一個小點作為突破口,不斷探索發現更多的可能。在這個過程中不斷去調研並進行能力抽象,最後肯定它推廣它,後面落地也是很簡單的一件事。
總結和未來規劃
"賈維斯"的能力體系如下圖所示:
未來,"賈維斯"還有很多事情要做,比如支援上下文對話,能實現更精準的 QA 能力,或者打通更多的外部系統,沉澱出一套通用的編排能力,又或者是更好的分析同學們遇到的真實問題,合力解決問題,提升辛福感。未來希望"賈維斯"能夠小而美,巧而強,這一切都未完待續......。
❉ 作者介紹 ❉
- 淺談低程式碼平臺遠端元件載入方案
- 前端富文字基礎及實現
- 淺談前端埋點&監控
- 如何讓 x == 1 && x == 2 && x == 3 等式成立
- 淺析 path 常用工具函式原始碼
- web components-LitElement實踐
- 模組聯邦淺析
- 效能優化——圖片壓縮、載入和格式選擇
- 如何基於 WebComponents 封裝 UI 元件庫
- CDP 遠端除錯方案
- 如何落地一個智慧機器人
- Form 資料形式配置化設計
- Lerna 執行流程剖析
- Decorator 裝飾器
- 淺析snabbdom中vnode和diff演算法
- 函數語言程式設計(FP)
- 如何利用 SCSS 實現一鍵換膚
- 淺析FormData
- Flutter For Web 編譯的兩種方案
- Web 多執行緒開發利器 Comlink 的剖析與思考