聊天機(jī)器人的三個(gè)基本部分 一個(gè)聊天機(jī)器人,有三個(gè)基本部分: 輸入輸出:用來接受、理解用戶問題,并生成、返回答案給用戶。 對(duì)話控制:用來構(gòu)建雙向的關(guān)系。 i)用戶問題=>知識(shí)庫知識(shí) ii)知識(shí)庫知識(shí)=>機(jī)器人答案 知識(shí)庫:用于回答用戶問題的知識(shí)的集合。
NOTE:如上的三個(gè)部分是從功能角度的分析,并不是說一個(gè)Chatbot必須要有與之一一對(duì)應(yīng)的模塊或分層。 聊天機(jī)器人的實(shí)現(xiàn)技術(shù) 從學(xué)術(shù)研究的角度講,聊天機(jī)器人所需技術(shù)涉及到自然語言處理、文本挖掘、知識(shí)圖譜等眾多領(lǐng)域。 在當(dāng)前的研究中,大量機(jī)器學(xué)習(xí)、深度學(xué)習(xí)技術(shù)被引入。各種炫酷的算法模型跑在Google、微軟等IT寡頭的高質(zhì)量數(shù)據(jù)上,得到了頗多激動(dòng)人心的研究成果。 但具體到實(shí)踐當(dāng)中,在沒有那么巨量的人工標(biāo)注數(shù)據(jù)和大規(guī)模計(jì)算資源的情況下,于有限范圍(scope)內(nèi),開發(fā)一款真正有用的機(jī)器人,更多需要關(guān)注的往往不是高深的算法和強(qiáng)健的模型,而是工程細(xì)節(jié)和用戶體驗(yàn)。 此處,我們只是簡單介紹幾種當(dāng)前實(shí)踐中最常用,且相對(duì)簡單的方法: Solution-1: 用戶問題->標(biāo)準(zhǔn)問題->答案 知識(shí)庫中存儲(chǔ)的是一對(duì)對(duì)的“問題-答案”對(duì)(QA Pair)。這些Pair可以是人工構(gòu)建的,源于專家系統(tǒng)或者舊有知識(shí)庫的,也可以是從互聯(lián)網(wǎng)上爬取下來的。 現(xiàn)在互聯(lián)網(wǎng)資源這么豐富,各種網(wǎng)頁上到處都是FAQ,Q&A,直接爬下來就可以導(dǎo)入知識(shí)庫。以很小的代價(jià)就能讓機(jī)器人上知天文下曉地理。 當(dāng)用戶輸入問題后,將其和知識(shí)庫現(xiàn)有的標(biāo)準(zhǔn)問題進(jìn)行一一比對(duì),尋找與用戶問題最相近的標(biāo)準(zhǔn)問題,然后將該問題組對(duì)的答案返回給用戶。 其中,用戶問題->標(biāo)準(zhǔn)問題的匹配方法可以是關(guān)鍵詞匹配(包括正則表達(dá)式匹配);也可以是先將用戶問題和標(biāo)準(zhǔn)問題都轉(zhuǎn)化為向量,再計(jì)算兩者之間的距離(余弦距離、歐氏距離、交叉熵、Jaccard距離等),找到距離最近且距離值低于預(yù)設(shè)閾值的那個(gè)標(biāo)準(zhǔn)問題,作為查找結(jié)果。 但關(guān)鍵字匹配覆蓋面太小。距離計(jì)算的話,在實(shí)踐中比對(duì)出來的最近距離的兩句話,可能在語義上毫無關(guān)聯(lián),甚至滿擰(比如一個(gè)比另一個(gè)多了一個(gè)否定詞)。另外,確認(rèn)相似度的閾值也很難有一個(gè)通用的有效方法,很多時(shí)候都是開發(fā)者自己拍腦袋定的。 因此,這種方案,很難達(dá)到高質(zhì)高效。 Solution-2. 用戶問題->答案 知識(shí)庫中存儲(chǔ)的不是問題-答案對(duì),而僅存儲(chǔ)答案(文檔)。 當(dāng)接收到用戶問題后,直接拿問題去和知識(shí)庫中的一篇篇文檔比對(duì),找到在內(nèi)容上關(guān)聯(lián)最緊密的那篇,作為答案返回給用戶。 這種方法維護(hù)知識(shí)庫的成本更小,但相對(duì)于Solution-1,準(zhǔn)確度更低。 Solution-3. 用戶問題->語義理解->知識(shí)庫查詢->查詢結(jié)果生成答案 從用戶的問題當(dāng)中識(shí)別出用戶的意圖,并抽取這個(gè)意圖針對(duì)的實(shí)體。 相應(yīng)的,知識(shí)庫內(nèi)存儲(chǔ)的知識(shí),可以按照二維表的方式組織(類比關(guān)系數(shù)據(jù)庫中的table)。 Chatbot在提取了意圖和實(shí)體后,構(gòu)造出對(duì)知識(shí)庫的查詢(Query),實(shí)施查詢,得出結(jié)果后生成回答,回復(fù)給用戶。 我們下面講的框架,就是基于本方案的。 極簡版聊天機(jī)器人架構(gòu) 在此,給出一個(gè)極簡版Chatbot實(shí)現(xiàn)方案,幫助你在一天的時(shí)間內(nèi),開發(fā)一款問題解決型聊天機(jī)器人。 下圖是這款機(jī)器人的架構(gòu):
最左側(cè)的語言理解(Language Understanding)模塊,和右上的回復(fù)生成器(ResponseGenerator)加起來對(duì)應(yīng)的圖-1中的是I/O部分。 正中的對(duì)話管理器(Dialog Manager)和上下文存儲(chǔ)(Context Store)屬于圖-1里的中控部分。 最下方是知識(shí)庫。 語言理解 怎么能夠從用戶的提問當(dāng)中發(fā)現(xiàn)意圖和實(shí)體呢? 最簡單的是基于規(guī)則的方法:用關(guān)鍵字/正則表達(dá)式匹配的方式,來發(fā)現(xiàn)自然語言中的意圖和實(shí)體。 GET_INPUT IF "有(.+)嗎" inUser_Input Intent = “商品推薦” ELIF "(郵費(fèi)|郵資|運(yùn)費(fèi)|快遞費(fèi))+" inUser_Input Intent = “查詢郵費(fèi)” ELIF "(保修|維修|修理|售后)+" inUser_Input Intent = “查詢售后” … … FOREACH(Color in Colors) IF (Color inUser_Input) Entity.Type = “ProductColor” Entity.Value = Color … … 這樣做的優(yōu)點(diǎn)顯而易見:方便、直接。 缺點(diǎn)也很明顯:缺乏泛化能力。 一件事有很多種說法的時(shí)候,需要開發(fā)者將所有這些說法都手動(dòng)添加到白名單里。 這樣不僅很難面面俱到,而且,還會(huì)碰到不能夠靠匹配關(guān)鍵詞解決的問題。比如,有人問“郵費(fèi)能給免了嗎”,有人問“這個(gè)商品郵費(fèi)多少錢?”,這根本是兩個(gè)意思,如果都有“郵費(fèi)”匹配,給同一個(gè)答案,就答非所問了。 這個(gè)時(shí)候,就需要引入基于模型的方法:使用機(jī)器學(xué)習(xí)模型來進(jìn)行意圖識(shí)別和實(shí)體抽取。 基于模型的語言理解包含兩個(gè)子任務(wù): 意圖識(shí)別(intentionclassification):用來識(shí)別用戶所提問題的意圖,也就是用戶希望做一件什么事。 實(shí)體抽取(entityextraction):用于提取用戶對(duì)話中所提供的和意圖相關(guān)的參數(shù)(實(shí)體),例如時(shí)間、地點(diǎn)等。 具體某個(gè)Chatbot的意圖類型和實(shí)體類型,是其開發(fā)者自己定義的。例如小明的客服機(jī)器人可以如此定義: Case1:發(fā)到北京的貨包郵嗎?—— 意圖:查詢包郵;目的地實(shí)體:北京 Case2:00183號(hào)商品快遞到伊犁郵費(fèi)多少?—— 意圖:查詢郵費(fèi);目的地實(shí)體:伊犁,商品Id實(shí)體:00183 Case3:02465號(hào)商品有保修嗎?——意圖:保修查詢;商品Id實(shí)體:02465 引用-2-1 或者,換個(gè)定義意圖和實(shí)體的方式,也沒有問題: Case2’:00183號(hào)商品快遞到伊犁郵費(fèi)多少?—— 意圖:商品查詢;目的地實(shí)體:伊犁,商品Id實(shí)體:00183,商品屬性實(shí)體:郵費(fèi) Case3’:02465號(hào)商品有保修嗎?——意圖:商品查詢;商品Id實(shí)體:02465,商品屬性實(shí)體:保修 引用-2-2 一般來說,意圖識(shí)別是一個(gè)典型的分類模型(e.g. Logistic Regression,Decision Tree等),而實(shí)體抽取則是一個(gè)Sequence-to-Sequence判別模型(一般選用Conditional Random Field)。 語義理解模塊當(dāng)然可以自己開發(fā)。不過,這需要長期積累的自然語言處理(NLP)的專業(yè)知識(shí)和經(jīng)驗(yàn),高效的運(yùn)算框架,以及標(biāo)注工具的支持。 作為輕量級(jí)Bot的開發(fā)者,單獨(dú)開發(fā)一個(gè)語言理解模塊耗時(shí)耗力,效果還未必好。不如選用現(xiàn)成工具。在附錄中我們會(huì)介紹一款微軟對(duì)外發(fā)布的在線語言理解工具:LUIS。可以很方便的實(shí)現(xiàn)上述功能。 知識(shí)庫查詢和結(jié)果返回 知識(shí)庫用于存儲(chǔ)知識(shí),本身可以是各種形式:數(shù)據(jù)庫,API,或者文本文件等。 用戶的問題經(jīng)過語言理解,被提取成了意圖和若干實(shí)體。下面要做的是,針對(duì)不同的知識(shí)庫類型,將意圖和實(shí)體構(gòu)造成對(duì)應(yīng)的查詢。下表中幾種情況比較常用: 知識(shí)庫類型 查詢構(gòu)造 回答生成 關(guān)系型數(shù)據(jù)庫 根據(jù)意圖和實(shí)體確定table name,where條件,和目標(biāo)column等要素,構(gòu)建SQL Query 將SQL Query結(jié)果填注到對(duì)應(yīng)模板中,生成回答問題的自然語言 Web API 根據(jù)意圖和實(shí)體確定要調(diào)用的API類型和參數(shù),構(gòu)造Http Request 將Web API調(diào)用結(jié)果填注到對(duì)應(yīng)模板中,生成回答問題的自然語言 結(jié)構(gòu)化文本文件(json, xml等) 根據(jù)意圖和實(shí)體,確定對(duì)應(yīng)文件路徑和對(duì)其中存儲(chǔ)數(shù)據(jù)結(jié)構(gòu)的查詢 將獲取內(nèi)容填注到對(duì)應(yīng)模板中,生成回答問題的自然語言 非結(jié)構(gòu)化文本文件 根據(jù)意圖和實(shí)體,確定對(duì)應(yīng)文件路徑 直接返回文本內(nèi)容 針對(duì)小明的問題,我們選擇SQL Server作為知識(shí)庫。知識(shí)存儲(chǔ)在table中。 用戶的問題經(jīng)過語言理解,被提取成了意圖和若干實(shí)體。下面要做的就是:將解析出來的意圖和實(shí)體構(gòu)造成一個(gè)SQL Query,用于在知識(shí)庫table中進(jìn)行查詢。 例如,我們來看引用-2-2中的Case2’和Case3’。 知識(shí)庫里有一個(gè)Table,名字叫Product,其中每一個(gè)row對(duì)應(yīng)一種產(chǎn)品,每個(gè)column對(duì)應(yīng)一個(gè)屬性。 那么從Case2’中解析出來的意圖和實(shí)體(意圖:商品查詢;實(shí)體:[目的地:伊犁,商品Id:00183,商品屬性:郵費(fèi)]),則可以被構(gòu)造成一個(gè)SQL Query: SELECT ‘郵費(fèi)’ FROM Product WHEREProduct_name = '00183' AND Destination = ‘伊犁’ 引用-3 Query在SQL Server中運(yùn)行的結(jié)果(比如是26元),被放到一個(gè)預(yù)置的針對(duì)商品查詢的答案模板里,生成答案。 預(yù)置模板:“您查詢的${商品Id}號(hào)商品的${商品屬性}是${Query_Result}。” 生成答案:“您查詢的00183號(hào)商品的郵費(fèi)是26元。” 引用-4 上下文存儲(chǔ)客戶和客服對(duì)話的時(shí)候,經(jīng)常會(huì)問多個(gè)問題。而不同的問題之間,可能有一些信息是共享的。例如: 客戶:02366這款產(chǎn)品可以退換嗎?(問題1) 客服:7天之內(nèi)無理由退換。 客戶:寄到南昌郵費(fèi)多少啊?(問題2) 客服:10塊親。 客戶:武漢呢?(問題3) 引用-5 上例中,問題1詢問可否退換,并提到了一個(gè)產(chǎn)品的Id;問題2詢問到南昌的郵費(fèi),但是沒有提具體產(chǎn)品;問題3干脆只有一個(gè)地名。 但是作為人工客服很明白:問題2詢問的產(chǎn)品是問題1中出現(xiàn)的02366,而問題3則是詢問這款產(chǎn)品寄到武漢的郵費(fèi)。 這些同一個(gè)對(duì)話中不同語句之間共享的信息,就是上下文(Context)。 想要機(jī)器人具備上下文的記憶、理解功能,而不是把用戶的每一個(gè)單獨(dú)語句當(dāng)作本輪問題的全部信息來源,就需要有一個(gè)ContextStore來專門負(fù)責(zé)上下文信息的記錄、查詢、更新和刪除(CRUD)。參見圖-2中最右側(cè)下方的模塊。 每次用戶新輸入的信息都要先進(jìn)行語言理解,再結(jié)合現(xiàn)有ContextStore中存儲(chǔ)的內(nèi)容,或更新Context,或讀取之前的Context作為補(bǔ)充信息。 以引用-5為例,可以將意圖,和幾種實(shí)體類型對(duì)應(yīng)的實(shí)體值(例如Id,目標(biāo)屬性,目的地等)存儲(chǔ)在Context中。 當(dāng)新的用戶語句輸入后,假設(shè)從中能夠提取出新的意圖或?qū)嶓w值,則用新值更新Context,否則,讀入現(xiàn)有的對(duì)應(yīng)實(shí)體值,作為本次語言理解的補(bǔ)充。 在引用-5中,問題1中讀取到了商品查詢的意圖,商品Id,和“退換“這一商品屬性,將它們存入Context。 問題2中讀取到了”郵費(fèi)“這一商品屬性,和之前存儲(chǔ)的不同,則更新Context的商品屬性值,并新存入“目的地”這一實(shí)體。 問題3則更新了目的地,并讀取其他的包括意圖、商品Id和商品屬性的值,與目的地一起用來構(gòu)造查詢。 Context的場景針對(duì)性非常強(qiáng),很多時(shí)候需要針對(duì)不同的意圖,記錄不同類型的實(shí)體值。在不同意圖之間切換的時(shí)候,也有可能會(huì)保留部分原有實(shí)體。這些都要針對(duì)具體情況case by case分析。 具體ContextStore中存儲(chǔ)什么樣的內(nèi)容,CRUD策略是什么,都是開發(fā)者需要自己決定。 機(jī)器人的反問 某些情況下,Chatbot可能需要反問用戶若干問題,或者和用戶確認(rèn)之前的某個(gè)回答,在這種情況下,就需要有內(nèi)部流程控制。 例如:在商品查詢的目標(biāo)屬性為郵費(fèi)時(shí),目的地缺失,這時(shí)候就需要主動(dòng)要求用戶輸入對(duì)應(yīng)的值。 不同場景的需求不同,這樣的控制流程很難統(tǒng)一規(guī)劃,因此需要在具體實(shí)踐中根據(jù)具體需求,完成細(xì)節(jié)。 或者,也可以主動(dòng)提出幾個(gè)備選問題,請(qǐng)用戶選擇他們想問的。 開發(fā)一款機(jī)器人的基本流程 按照我們剛才說的: 1. 創(chuàng)建語言理解模塊。 定義意圖、實(shí)體類型;收集數(shù)據(jù),選取特征;進(jìn)行標(biāo)注、訓(xùn)練驗(yàn)證和測 2. 創(chuàng)建一個(gè)知識(shí)庫。 創(chuàng)建SQL Server Database及若干表格,用來存儲(chǔ)問答知識(shí)。 3. 編寫中控程序,負(fù)責(zé)負(fù)責(zé): i)接受用戶問題并調(diào)用語言理解模塊進(jìn)行解析; ii)根據(jù)語言理解結(jié)果構(gòu)知識(shí)庫查詢; iii)執(zhí)行知識(shí)庫查詢; iv)根據(jù)數(shù)據(jù)庫查詢結(jié)果構(gòu)造答案; v)創(chuàng)建并維護(hù)Context。 在完成了上述工作后,一個(gè)可以理解人類語言的聊天機(jī)器人就可以上線為顧客服務(wù)了。 在實(shí)踐當(dāng)中,還有一些問題需要注意: Tip-1:語言理解部分可以考慮同時(shí)采用model-based模型和rule-based模型。 Model-based模型雖然可擴(kuò)展性強(qiáng),但也會(huì)有精準(zhǔn)度不高,不容易即時(shí)修改等問題(雖然可以在線訓(xùn)練和發(fā)布,但作為model-based分類器和判別工具,如須改變某句話的分類,或許并不能靠添加單一的訓(xùn)練數(shù)據(jù)來完成)。 在這種情況下,考慮和rule-based的意圖、實(shí)體識(shí)別相結(jié)合。可以通過添加一系列正則表達(dá)式來匹配意圖,抽取實(shí)體。 Tip-2:某些情況下,Chatbot可能需要反問用戶若干問題,或者和用戶確認(rèn)之前的某個(gè)回答,在這種情況下,就需要有內(nèi)部流程控制。 例如:在商品查詢的目標(biāo)屬性為郵費(fèi)時(shí),目的地缺失,這時(shí)候就需要主動(dòng)要求用戶輸入對(duì)應(yīng)的值。 不同場景的需求不同,這樣的控制流程很難統(tǒng)一規(guī)劃,因此需要在具體實(shí)踐中根據(jù)具體需求,完成細(xì)節(jié)。 Tip-3:有些時(shí)候,在無法明確用戶意圖時(shí),也可以主動(dòng)提出幾個(gè)備選問題,請(qǐng)用戶選擇他們想問的。 總之,在實(shí)踐中由于具體的場景和需求,會(huì)遇到各種各樣的問題。到時(shí)候,就兵來將擋,水來土掩吧! 附錄:微軟語言理解智能服務(wù) LUIS 為了幫助普通開發(fā)者解決自然語言理解這一開發(fā)瓶頸,微軟推出了自己的語言理解智能服務(wù) - LUIS。
LUIS (LanguageUnderstanding Intelligent Service) 的使命是讓非NLP專業(yè)的開發(fā)者,能夠輕松地創(chuàng)建和維護(hù)高質(zhì)量的自然語言理解模型,并無縫對(duì)接到相關(guān)應(yīng)用中去。 使用LUIS,一個(gè)Bot需要?jiǎng)?chuàng)建一個(gè)(或多個(gè))LUIS App,然后標(biāo)注所期望的輸入(用戶的自然語言提問)和輸出(意圖和實(shí)體),再經(jīng)過在線訓(xùn)練來獲得自己的語言理解模型。 整個(gè)開發(fā)過程中,開發(fā)者只需要清晰地定義自己需要讓機(jī)器理解的用戶意圖和實(shí)體即可,并不需要了解背后算法的細(xì)節(jié)。 LUIS的開發(fā)流程包括三大步驟:
數(shù)據(jù)輸入和標(biāo)注 LUIS開發(fā)者可以在界面上輕松地進(jìn)行在線數(shù)據(jù)標(biāo)注。 首先,在對(duì)應(yīng)的用戶意圖中輸入自然語言語句,例如:在“商品查詢”意圖中輸入一句“00183號(hào)商品快遞到伊犁郵費(fèi)多少?” ;然后,通過鼠標(biāo)選取實(shí)體并指定類型,例如:選擇“郵費(fèi)”標(biāo)注為“商品屬性”。 標(biāo)注結(jié)果在頁面上顯示如下:
LUIS平臺(tái)會(huì)自動(dòng)從用戶輸入并標(biāo)注的數(shù)據(jù)中提取文本特征。這些特征,包括LUIS預(yù)設(shè)的常用文本特征(從大數(shù)據(jù)語料中提。,也包括用戶自定的新特征。 LUIS允許用戶通過兩種方式來定義新特征: 短語列表特征(Phrase List Features) 需用戶自己定義若干短語列表,這些被定義在同一列表中的短語,都會(huì)被當(dāng)作同一個(gè)實(shí)體類型中的實(shí)體處理。
在定義過程中,LUIS還會(huì)通過其語義詞典(semantic dictionary)挖掘技術(shù),根據(jù)用戶輸入的短語,自動(dòng)從海量的網(wǎng)絡(luò)數(shù)據(jù)中發(fā)現(xiàn)相似的短語,并推薦給用戶。從而有效地提升了效率。 模式特征(Pattern Features) 也稱為正則表達(dá)式特征。主要用于定義若干正則表達(dá)式。 LUIS根據(jù)這些表達(dá)式從用戶輸入數(shù)據(jù)中抽取符合其模式的實(shí)體。 模型的訓(xùn)練 LUIS的模型訓(xùn)練過程極其簡單,開發(fā)者只需點(diǎn)擊一下 “Train” 按鈕,后臺(tái)就會(huì)基于輸入數(shù)據(jù)進(jìn)行自動(dòng)訓(xùn)練。 訓(xùn)練的時(shí)間與標(biāo)注數(shù)據(jù)量相關(guān),標(biāo)注數(shù)據(jù)越多,訓(xùn)練所需的時(shí)間越長。同時(shí),訓(xùn)練時(shí)間還與LUIS App所支持的意圖和實(shí)體個(gè)數(shù)相關(guān),意圖和實(shí)體越多,訓(xùn)練時(shí)間也越長。 模型的測試、發(fā)布和服務(wù) 訓(xùn)練完模型,開發(fā)者可以對(duì)其進(jìn)行性能測試。方法有兩種: 交互式測試:開發(fā)者可以在頁面上直接輸入自然語言語句,然后目測模型輸出結(jié)果。 批量測試:開發(fā)者需要上傳一份測試數(shù)據(jù),LUIS完成全部測試后給出精準(zhǔn)率和召回率等統(tǒng)計(jì)數(shù)據(jù),并針對(duì)每一項(xiàng)意圖和實(shí)體的繪制出Confusion Matrix。 測試過的模型,只需點(diǎn)擊“Publish”按鈕,就可以發(fā)布到微軟的Azure云平臺(tái)上,成為一個(gè)立即可用的API Service。 開發(fā)者可以通過Http的Get方法,調(diào)用模型,對(duì)新的語句進(jìn)行意圖識(shí)別和實(shí)體抽取。 迭代更新 上述三個(gè)步驟是可以不斷重復(fù)迭代的。 模型訓(xùn)練完發(fā)布上線后,可以繼續(xù)輸入、標(biāo)注新的數(shù)據(jù),重新訓(xùn)練,再次發(fā)布。如此循環(huán)往復(fù),逐步改進(jìn)質(zhì)量。 使用提示 1. 當(dāng)前的LUIS是一個(gè)純粹model-based的語言理解工具。 雖然可擴(kuò)展性強(qiáng),但也會(huì)有精準(zhǔn)度不高,不容易即時(shí)修改等問題(雖然可以在線訓(xùn)練和發(fā)布,但作為model-based分類器和判別工具,如須改變某句話的分類,或許并不能靠添加單一的訓(xùn)練數(shù)據(jù)來完成)。 在這種情況下,可以考慮LUIS和rule-based的意圖、實(shí)體識(shí)別相結(jié)合?梢酝ㄟ^添加一系列正則表達(dá)式來匹配意圖,抽取實(shí)體。 2. 每一個(gè)LUIS App都有一個(gè)內(nèi)置的意圖,叫做None,非常有用。一般用它來收集那些用戶經(jīng)常會(huì)問,但是Chat Bot并不打算回答的問題。 若不在None中指定它們,這些問題很可能會(huì)被錯(cuò)誤的預(yù)測為其他用戶自定義的意圖,造成Chat Bot的over trigger(e.g.用戶問:你是女孩嗎?Bot回答:江浙滬包郵),從而嚴(yán)重影響用戶體驗(yàn)。
|