高效聯(lián)動(dòng),攜程機(jī)票IVR可視化的探索和實(shí)踐
作者簡(jiǎn)介
Michael,攜程全棧開發(fā)專家,追求以技術(shù)手段解決業(yè)務(wù)上的共性問題,構(gòu)建靈活可配置且可視化的系統(tǒng),提高生產(chǎn)力,降低溝通成本。
CunShun,攜程后端開發(fā)工程師,專注系統(tǒng)架構(gòu)、穩(wěn)定性、低代碼等領(lǐng)域。
一、引言
IVR(交互式語音應(yīng)答,Interactive Voice Response)系統(tǒng),是指用戶通過撥打指定號(hào)碼后可以根據(jù)語音提示,收聽和點(diǎn)送所需語音信息,并且協(xié)助完成自助服務(wù)。通過不斷完善IVR交互邏輯,可以實(shí)現(xiàn)客戶來電自助操作,減輕客服座席壓力,使之僅處理確實(shí)需要人工處理的呼叫。
本文將主要分享攜程機(jī)票IVR可視化系統(tǒng)的探索與實(shí)踐。
二、攜程機(jī)票IVR系統(tǒng)的演進(jìn)過程
攜程呼叫中心系統(tǒng)結(jié)構(gòu)如下圖所示,客人進(jìn)線后由公共網(wǎng)關(guān)處理后轉(zhuǎn)到相應(yīng)部門的IVR流程中,然后由各自部門完成IVR內(nèi)部處理邏輯。
2.1 攜程機(jī)票IVR系統(tǒng)V1.0
最開始的機(jī)票IVR系統(tǒng),主要面向國(guó)內(nèi)市場(chǎng)的用戶,語種只有中文并且業(yè)務(wù)流程只有一套。系統(tǒng)采用的是“InTag-OutTag”+“策略模式”的設(shè)計(jì)方案,和公共平臺(tái)約定客戶來電后第一次請(qǐng)求IVR時(shí)傳入固定InTag,然后后續(xù)都使用客戶按鍵對(duì)應(yīng)的OutTag作為下一次請(qǐng)求機(jī)票IVR自助服務(wù)的InTag,然后機(jī)票IVR采用策略模式根據(jù)InTag處理對(duì)應(yīng)的業(yè)務(wù)場(chǎng)景。
公共平臺(tái)無需關(guān)心機(jī)票內(nèi)部處理邏輯以及Tag的含義,機(jī)票方如果有業(yè)務(wù)變更也只需要新增InTag或OutTag場(chǎng)景即可。并且代碼采用策略模式,所以新增業(yè)務(wù)邏輯對(duì)原有系統(tǒng)代碼侵入很少。雖然業(yè)務(wù)場(chǎng)景是樹狀發(fā)散的,但是實(shí)際上從代碼設(shè)計(jì)的角度其實(shí)是將業(yè)務(wù)場(chǎng)景完全平鋪的。
2.2 攜程機(jī)票IVR系統(tǒng)V2.0
后來隨著業(yè)務(wù)擴(kuò)張,在全球化戰(zhàn)略的背景下,也要面向國(guó)際市場(chǎng)的用戶,機(jī)票IVR系統(tǒng)也從原本單一的國(guó)內(nèi)中文流程,擴(kuò)展到20多條語言線。使得如果沿用原有IVR系統(tǒng)架構(gòu)會(huì)存在以下痛點(diǎn):
開關(guān)配置個(gè)數(shù)爆炸
由于各條語言線功能點(diǎn)上線速度不同、邏輯不一致等問題,采用硬編碼開發(fā)過程中會(huì)產(chǎn)生大量開關(guān)配置。并且隨著業(yè)務(wù)發(fā)展,上述問題愈發(fā)嚴(yán)重,業(yè)務(wù)邏輯也是愈發(fā)難以梳理。
無直觀的處理流程
語言線眾多,需求變更頻繁且各條語言線邏輯不一致,業(yè)務(wù)文檔往往無法及時(shí)更新,產(chǎn)品、流程等人員會(huì)經(jīng)常找開發(fā)人員確認(rèn)業(yè)務(wù)邏輯,開發(fā)人員需要花費(fèi)大量時(shí)間翻代碼查邏輯。
話術(shù)配置效率低下
沒有直觀的配置頁面供業(yè)務(wù)人員使用,只能通過郵件溝通等方式來確認(rèn)話術(shù)配置,然后由開發(fā)人員手動(dòng)配置所有語言線的話術(shù)。在多語言背景下,溝通成本極大并且容易配置錯(cuò)誤。
針對(duì)原有系統(tǒng)中存在的痛點(diǎn),產(chǎn)研團(tuán)隊(duì)溝通后提出了IVR可視化、可配置化的設(shè)想,為此設(shè)計(jì)并開發(fā)IVR可視化平臺(tái)。該系統(tǒng)完全顛覆原有的IVR系統(tǒng)架構(gòu),引入可視化流程樹、規(guī)則引擎、腳本引擎、話術(shù)模板動(dòng)態(tài)配置、多版本管理等全新概念,業(yè)務(wù)和產(chǎn)品可隨時(shí)查看業(yè)務(wù)流程,通過配置調(diào)整快速需求上線,通過嚴(yán)格的權(quán)限控制、版本管理確保系統(tǒng)穩(wěn)定性,通過可視化來電軌跡協(xié)助快速排查問題。該系統(tǒng)使產(chǎn)品、業(yè)務(wù)、開發(fā)、測(cè)試及TS人員高效聯(lián)動(dòng),減少不必要的溝通成本,提高工作效率。
2.3 系統(tǒng)對(duì)比
機(jī)票IVR系統(tǒng)V1.0 | 機(jī)票IVR系統(tǒng)V2.0 | |
語種 | 只有中文 | 20多條語言線 |
流程是否可視化 | 無可視化流程,只有流程圖 | 完全可視化的業(yè)務(wù)流程 |
軌跡是否可視化 | 可視化頁面,需要通過DB數(shù)據(jù)反推執(zhí)行流程。需要對(duì)業(yè)務(wù)邏輯以及字段含義有較深理解才能看懂 | 有可視化頁面,并記錄經(jīng)過節(jié)點(diǎn)以及中間數(shù)據(jù),一目了然 |
業(yè)務(wù)邏輯實(shí)現(xiàn)方式 | 定義`InTag/OutTag`,通過硬編碼實(shí)現(xiàn)業(yè)務(wù)邏輯 | 通過可視化平臺(tái)配置業(yè)務(wù)邏輯 |
話術(shù)配置 | 話術(shù)模板存放在配置中心,然后硬編碼解析動(dòng)態(tài)話術(shù) | 提供可視化的話術(shù)配置頁面,并且實(shí)現(xiàn)通用解析話術(shù)邏輯 |
開關(guān) | 需要在代碼中定義開關(guān) | 通過語言線配置解耦、灰度版本控制支持開關(guān)功能,無需硬編碼 |
三、攜程機(jī)票IVR可視化平臺(tái)介紹
3.1 系統(tǒng)架構(gòu)設(shè)計(jì)
機(jī)票IVR可視化平臺(tái)分為兩個(gè)部分:IVR可視化管理頁面、IVR自助應(yīng)答服務(wù)。
IVR可視化管理頁面
通過管理頁面提供可視化應(yīng)答樹編輯器、版本管理、來電軌跡查詢等功能,開發(fā)、產(chǎn)品、業(yè)務(wù)、測(cè)試、TS人員都通過該頁面進(jìn)行操作。
IVR自助應(yīng)答服務(wù)
解析IVR應(yīng)答樹配置并監(jiān)聽版本變更,根據(jù)流程樹配置真正對(duì)客提供IVR自助服務(wù)。
原有系統(tǒng)中業(yè)務(wù)處理流程、調(diào)用接口、話術(shù)配置等功能都是在代碼中編寫,無法做到靈活調(diào)整。為了實(shí)現(xiàn)IVR完全可視化、配置化的業(yè)務(wù)需求,就需要將這些邏輯從代碼中抽離出來,通過可配置的方式來實(shí)現(xiàn)。在系統(tǒng)設(shè)計(jì)過程中面臨以下幾個(gè)難點(diǎn):如何通過配置調(diào)整修改業(yè)務(wù)流程、如何在配置中處理接口調(diào)用、如何優(yōu)雅的動(dòng)態(tài)話術(shù)模板配置。
針對(duì)如上難點(diǎn),對(duì)系統(tǒng)做出如下設(shè)計(jì):
數(shù)據(jù)定義
根據(jù)業(yè)務(wù)流程定義所有需要用到的數(shù)據(jù)屬性,全局?jǐn)?shù)據(jù)定義是后續(xù)一切可視化配置的基礎(chǔ),后續(xù)所有的配置都是依托數(shù)據(jù)定義才能夠優(yōu)雅且合理的實(shí)現(xiàn)。
規(guī)則引擎
通過可視化的規(guī)則引擎,實(shí)現(xiàn)業(yè)務(wù)流程配置。
腳本引擎
在腳本引擎中,可以編輯`JavaScript`腳本實(shí)現(xiàn)服務(wù)調(diào)用,并且可以對(duì)接口返回的結(jié)果進(jìn)行處理。
話術(shù)模板
可以插入動(dòng)態(tài)話術(shù)、支持循環(huán)播報(bào)、支持時(shí)間格式化。
3.2 可視化平臺(tái)展示
話不多說,先展示一下配置頁面,讓大家能夠?qū)VR可視化平臺(tái)有比較直觀的印象。
平臺(tái)通過以下功能實(shí)現(xiàn)IVR可視化流程樹配置:
- 數(shù)據(jù)定義:將IVR流程中需要用到的數(shù)據(jù)(如邏輯判斷、話術(shù)播報(bào)場(chǎng)景)進(jìn)行數(shù)據(jù)定義,為后續(xù)操作做準(zhǔn)備。
- 編輯數(shù)據(jù)訪問腳本:在腳本中完成服務(wù)調(diào)用,將調(diào)用結(jié)果轉(zhuǎn)換成IVR流程中需要的數(shù)據(jù)格式,再setPropertyValue完成數(shù)據(jù)的值填充。
- 調(diào)整IVR流程樹:根據(jù)IVR業(yè)務(wù)特性,將可視化樹中節(jié)點(diǎn)定義為10種類型,然后根據(jù)節(jié)點(diǎn)類型的不同展示相應(yīng)的右鍵菜單,實(shí)現(xiàn)流程配置。
- 編輯子節(jié)點(diǎn)路由規(guī)則:依托規(guī)則引擎,配置流程邏輯流轉(zhuǎn)的規(guī)則。
- 掛載數(shù)據(jù)訪問腳本:將數(shù)據(jù)訪問腳本掛載到節(jié)點(diǎn)中,當(dāng)執(zhí)行到該節(jié)點(diǎn)時(shí)執(zhí)行腳本。
- 話術(shù)模板配置:配置播報(bào)話術(shù)模板。
同時(shí)該平臺(tái)支持仿真撥號(hào)和來電軌跡查詢,這兩個(gè)頁面中都會(huì)詳細(xì)記錄用戶進(jìn)線后的每一次請(qǐng)求、響應(yīng)以及內(nèi)部處理流程,結(jié)合數(shù)據(jù)庫(kù)記錄及日志埋點(diǎn)等能夠更快、更直觀的分析數(shù)據(jù)。
- 仿真撥號(hào):流程配置完成后提交申請(qǐng)發(fā)布的過程中,通過模擬進(jìn)線的方式對(duì)業(yè)務(wù)流程進(jìn)行測(cè)試。
- 來電軌跡查詢:支持查詢用戶進(jìn)線后的IVR流程軌跡、播報(bào)話術(shù)等信息,便于分析數(shù)據(jù)和排查問題。
3.3 實(shí)現(xiàn)方案設(shè)計(jì)
IVR可視化平臺(tái)最核心的思想是:通過“腳本配置及解析”實(shí)現(xiàn)流程動(dòng)態(tài)變更。
我們的首要任務(wù)就是確定選用何種腳本語言,IVR可視化平臺(tái)中有兩部分需要使用腳本配置(子節(jié)點(diǎn)路由規(guī)則、數(shù)據(jù)訪問腳本),特別是數(shù)據(jù)訪問腳本需要支持服務(wù)調(diào)用、數(shù)據(jù)轉(zhuǎn)換、數(shù)據(jù)值設(shè)置等功能。javascript語言既可以在服務(wù)端執(zhí)行腳本又可以直接在瀏覽器端直接調(diào)試腳本,和Node服務(wù)端無縫銜接,經(jīng)過考量后我們選用javascript作為腳本語言。
然后圍繞選用的腳本語言,最終服務(wù)端采用Node+javascript腳本的實(shí)現(xiàn)方式。然后在前端頁面設(shè)計(jì)及開發(fā)的過程中,使用許多優(yōu)秀的第三方組件,包括react-awesome-query-builder、AntV G6、Monaco Editor等等,提高開發(fā)效率以及頁面美觀程度。
下面從前端頁面設(shè)計(jì)和服務(wù)端解析兩個(gè)方面,對(duì)IVR可視化平臺(tái)的設(shè)計(jì)方案中的關(guān)鍵點(diǎn)做說明:
(1)全局?jǐn)?shù)據(jù)定義
"流程未動(dòng),數(shù)據(jù)定義先行"。只有數(shù)據(jù)定義完成后,后續(xù)規(guī)則配置、腳本編輯、動(dòng)態(tài)話術(shù)配置時(shí)才能有數(shù)據(jù)可依。目前支持string、integer、boolean、datetime、date、object、array、enum類型定義,然后設(shè)置屬性值的來源(每一次請(qǐng)求參數(shù)、指定請(qǐng)求參數(shù)、腳本設(shè)置)。
(2)流程樹配置
根據(jù)業(yè)務(wù)特性選用樹狀結(jié)構(gòu)展示業(yè)務(wù)流程,支持子樹,條理清晰,易于理解。技術(shù)上是選用`AntV G6`圖可視化引擎作為可視化展示的組件,該組件提供了圖的繪制、布局、交互等能力且具備高可擴(kuò)展的自定義機(jī)制。
定義樹中Node類型并利用顏色、邊框、icon等區(qū)分。并且使用子樹把復(fù)雜的流程拆分后展示,避免流程樹過于龐大不利于維護(hù),同時(shí)子樹可以掛在不同的節(jié)點(diǎn)后面,提高流程復(fù)用性。
(3)規(guī)則引擎
規(guī)則引擎用于IVR流程中條件分支規(guī)則判斷,我們基于react-awesome-query-builder開源組件,并對(duì)該組件進(jìn)行擴(kuò)展,支持輸出javascript腳本,滿足業(yè)務(wù)需要。該組件支持"=="、 ">"、 "<"、 "includes"、 "between"、 "startWith"、 "endWith"、 "some"、 "all"等十多種操作符,支持常用的函數(shù),同時(shí)還支持"or"、"and"、"not"的自由組合。
(4)腳本編輯及調(diào)試
腳本編輯使用Monaco Editor編輯器,支持智能提示,并且我們對(duì)智能提示進(jìn)行擴(kuò)展,使編輯器支持自定義的方法和對(duì)象,更加人性化,操作更方便。
// 額外的類型(數(shù)據(jù)定義、自定義方法等)
MonacoEditorManager.setExtraLibs([{ content: extraLib }]);
MonacoEditorManager.addPageSuggestionCallback("TriggerListDialog", (model: any,
position: any) => {
const text = model.getValueInRange({
startLineNumber: position.lineNumber,
startColumn: 1,
endLineNumber: position.lineNumber,
endColumn: position.column
});
// 自定義智能提醒
return getSuggestions(text, props.getPropertiesCallback, () => props.serviceOperations);
});
腳本如果無法調(diào)試的話,就無法保證腳本的正確性,不能在腳本上線之前發(fā)現(xiàn)問題。我們利用源映射(**Source Map**)實(shí)現(xiàn)將腳本生成JS文件,并在瀏覽器控制臺(tái)中調(diào)試。
// 構(gòu)建__debug_script.js文件
const loadScriptCode = (scriptString: string) => {
const sourceUrl = '//# sourceURL=__debug_script.js';
const functionDef = 'async function __debug_script(Props, getPropertyValue, setPropertyValue, invokeServiceMethod){';
const scriptLines = (scriptString?.split('\n') || []).map(line => ' ' + line);
const lines = [sourceUrl, functionDef, ...scriptLines, "}"];
const codeNode = window.document.createTextNode(lines.join('\n'));
const script = window.document.createElement('script');
script.type = 'text/javascript';
script.appendChild(codeNode);
window.document.body.appendChild(script);
return scriptString;
};
// F12打開控制臺(tái)后,執(zhí)行腳本
const debugCode = async (inputPropertyValues) => {
// 相關(guān)參數(shù)傳入,執(zhí)行腳本
window["__debug_script"](Props,getPropertyValue,setPropertyValue,invokeServiceMethod);
// ...
}
(5)腳本解析及執(zhí)行
為了保證執(zhí)行自定義腳本時(shí)的系統(tǒng)安全性,本系統(tǒng)選用在VM2沙箱中運(yùn)行不受信任的代碼,并且限制VM2可使用的模塊,僅支持與業(yè)務(wù)相關(guān)的幾個(gè)自定義方法,如:getPropertyValue(從數(shù)據(jù)流讀取數(shù)據(jù))、setPropertyValue(向數(shù)據(jù)流寫入數(shù)據(jù))、invokeServiceMethod(服務(wù)調(diào)用)等 。
在運(yùn)行沙箱中的代碼時(shí),使用try/catch進(jìn)行包裹,避免腳本出現(xiàn)問題導(dǎo)致全局崩潰。在服務(wù)初始化以及版本更新時(shí)采用預(yù)編譯VMScript腳本的方式來提升性能,經(jīng)過性能測(cè)試,預(yù)編譯后的腳本和原生JS腳本執(zhí)行速度相當(dāng)。
// 腳本編譯
const vmScript = `const asyncFunction = async () => {\n${this.script}\n};\r\n
asyncFunction().then(result=>onVmScriptComplete(result)).catch(error=>onVmScriptError(error));`;
this.vmScript = new VMScript(vmScript).compile();
// 腳本運(yùn)行
const runInVM(param: object, callback: () => void = null): any {
return new Promise((resolve, reject) => {
const vm = new NodeVM({
console: 'inherit',
sandbox: {
...param,
onVmScriptComplete: (result) => resolve(result),
onVmScriptError: (error) => reject(error)
}
});
vm.run(this.vmScript);
});
}
(6)話術(shù)配置
根據(jù)以往IVR開發(fā)經(jīng)驗(yàn),各條語言線中關(guān)于數(shù)字、時(shí)間類型的話術(shù)TTS播報(bào)存在差異,所以在開發(fā)話術(shù)模板組件時(shí),需要支持動(dòng)態(tài)屬性配置并且可以自定義格式轉(zhuǎn)換。基于react-quill富文本組件友好的展示話術(shù)模板,并且支持自定義時(shí)間格式。
(7)服務(wù)端執(zhí)行流程
服務(wù)端執(zhí)行分為兩部分:配置初始化、IVR自助服務(wù)接口。
在服務(wù)啟動(dòng)時(shí),首先需要對(duì)配置初始化。包括從DB中加載IVR配置,對(duì)規(guī)則引擎和腳本引擎中的腳本預(yù)編譯,話術(shù)模板配置預(yù)處理,根據(jù)配置中的節(jié)點(diǎn)父子關(guān)系以及節(jié)點(diǎn)類型定義nextNode()方法,并且開啟監(jiān)聽版本變更,實(shí)現(xiàn)配置熱更新。
然后在IVR自助服務(wù)調(diào)用過程中,通過DataContext存放請(qǐng)求鏈路中的數(shù)據(jù)(配置版本、經(jīng)過的路由、已經(jīng)獲取的屬性信息等等),根據(jù)nodeId定位到當(dāng)前處理節(jié)點(diǎn)后,執(zhí)行nextNode()方法找到下一個(gè)節(jié)點(diǎn)。如果節(jié)點(diǎn)中掛載腳本的話,則執(zhí)行腳本并將腳本中獲取的屬性值放入DataContext中。然后直到響應(yīng)類型的節(jié)點(diǎn),根據(jù)節(jié)點(diǎn)類型做最終的響應(yīng)(轉(zhuǎn)人工、掛斷、拼接話術(shù)模板并播報(bào)等)。
(8)多版本管理
在該IVR可視化系統(tǒng)中,為了能夠保證系統(tǒng)靈活性,通過配置化的方式實(shí)現(xiàn)系統(tǒng)功能。但是可配置的功能越豐富,出錯(cuò)的可能性越高,為了保證系統(tǒng)穩(wěn)定性,需要進(jìn)行版本管理以及規(guī)范發(fā)布流程。
首先所有的流程修改都是在草稿版本中編輯,當(dāng)草稿版本申請(qǐng)發(fā)布時(shí)可以進(jìn)行版本對(duì)比以及仿真測(cè)試,如果測(cè)試通過后可以生成預(yù)發(fā)布版本。然后開發(fā)人員審核后發(fā)布灰度版本,配置灰度手機(jī)號(hào)碼,業(yè)務(wù)人員在生產(chǎn)驗(yàn)收通過后才能發(fā)布正式版本。
四、結(jié)語
攜程機(jī)票可視化平臺(tái)正式上線近一年時(shí)間,一直平穩(wěn)運(yùn)行,且給各方協(xié)調(diào)溝通帶來極大便利。隨著AI、ChatGpt等技術(shù)發(fā)展,攜程機(jī)票也在推進(jìn)將語音識(shí)別技術(shù)應(yīng)用到客戶來電交互中,通過ASR(Automatic Speech Recognition)優(yōu)化處理流程,提升客戶體驗(yàn)。
該平臺(tái)其實(shí)算是低代碼結(jié)合特定領(lǐng)域的實(shí)踐,如果有其他小伙伴也希望在自己的業(yè)務(wù)中結(jié)合低代碼,希望該文章能夠?qū)δ兴鶐椭?/span>