近期開發了一套基於天然語言處理的問答機器人,以前沒有作過python,主要作asp.net,寫這篇目的是給想要開發這類智能客服系統的朋友提供一個思路,項目已經上線,但在開發和設計過程當中仍然有不少問題沒有獲得解決,也指望和你們一同討論學習。html
最終的上線效果: python
開發過程大概3階段,第一階段 完成基礎一問一答功能;第二階段 加入意圖識別,能夠進一步區分用戶問題,特定意圖好比工資查詢,將會調用第三方接口;第三階段 上下文處理,引導用戶進行多輪問答;git
插一句微軟認知服務是雲端的較好解決方案, BOT Framework平臺集成了多種對接方式,無需本身開發。LUIS的配置和發佈也很是方便,特別的若是使用場景真的很是簡單(一問一答),能夠僅用QnAMaker。github
but... 基於業務數據暴露和其餘安全性考慮,有時須要將服務部署在本地(內網),我主要想說的就是本地開發搭建的問答服務。web
1.1選型算法
可以作基礎問答的開源項目很是多chatterbot,rasa_core等等。我選用的是chatterbot(0.7.6)json
1.2開發api
在搭建完開發環境後chatterbot能夠直接使用,默認算法是編輯距離,因此理論上支持任何語言,包括中文。數組
我主要修改了chatterbot算法模塊,適配器模塊和輸入輸出模塊,最終輸出格式以下安全
{ "text": "三方協議一式三方,三方蓋完章後,學校,公司,學生本人各留一份。", "in_response_to": [{ "text": "三方協議如何存檔?", "created_at": "2017-11-24T15:11:06.500966", "occurrence": 4 }], "created_at": "2017-11-24T15:11:06.500", "extra_data": { "userid": "1000058" }, "question": "三方協議如何存檔?", "oriquestion": "三方協議", "channel": "2", "suggestions": [ ["三方協議如何存檔?", 0.62], ["三方協議能夠他人帶簽署領取嗎?", 0.42], ["實習生三方協議上面部門怎麼填寫?", 0.4] ] }
text答案,in_response_to上下文,extra_data附加信息(能夠放用戶身份標識等),question匹配到的問題,oriquestion用戶輸入問題,channel詞庫編號(支持多詞庫每一個詞庫可能有不一樣的處理),感興趣問題列表(匹配度稍低的問題)
chatterbot的adapter原本設計是能夠放多個,每一個適配器完成本身的功能(解耦),但實際使用時(5000條問答),多適配器是很是緩慢的,因爲每一個適配器都會循環處理或比對問題,因此建議只放一個adapter實現全部功能
'logic_adapters':['mybot.MyLogicAdapter']
算法
位於comparisons.py中默認的編輯距離算法或傑拉德類似係數算法,都是基於簡單的文本比對,沒法處理同義詞近義詞。這裏咱們引入的word2vec算法
訓練數據來自中文維基百科,加入了特定業務文檔數據(僅73M,維基百科1.11G...)
使用jieba分詞,gensim word2vec訓練模型,特徵向量400維,大概須要14小時(參考個人吃雞電腦I7 7700 GTX1080)。
# 裝載以前訓練好的模型
custom_model = Word2Vec.load('data/custom.model')
用戶輸入先經過jieba分詞,獲得詞和詞頻的數組,例如:查詢個人薪資
查詢 2
我 5
的 1
薪資 3
# 查詢key在模型中向量 vec =custom_model['查詢']
# 加權(模型中向量*jieba分詞中權重)
sentvec = sentvec + vec * 2
把句子中詞向量相加獲得整個句子的向量。
再利用夾角餘弦,與業務詞庫中的問題比較,獲得最類似的問題匹配。
此方法,能夠處理諸如,皇后->女人 這類的近義問題。從圖上能夠看到女人與皇后餘弦夾角小於皇后與木頭餘弦夾角,結論爲女人與皇后更類似。
因此最終的算法:編輯距離+word2vec。
意圖識別屬於天然語言理解範圍,主流機器學習算法支持向量機、決策樹等分類方法。咱們使用意圖識別主要用來分離出用戶的查詢意圖,再調用對應的第三方接口將數據返回給用戶,例如 北京今每天氣?識別爲天氣意圖,實體爲北京。
2.1選型
咱們這裏選用開源項目rasa_nlu(11.0.3),這是一個集意圖識別,實體提取功能於一體的項目。能夠生成以下的數據
{ "intent": { "name": "weather", "confidence": 0.44477984330690684 }, "entities": [ { "entity": "city", "value": "大連", "start": 0, "end": 2, "extractor": "ner_mitie" }, { "entity": "date", "value": "後天", "start": 2, "end": 4, "extractor": "ner_mitie" } ], "intent_ranking": [ { "name": "weather", "confidence": 0.44477984330690684 }, { "name": "bookhotel", "confidence": 0.37330751883981904 }, { "name": "map", "confidence": 0.18191263785327412 } ], "text": "大連後每天氣怎麼樣" }
2.2開發
在實際使用中,有時可能僅須要提取實體,因此我額外作了一個流程,僅提取實體。
{ "entities": [ { "entity": "city", "value": "大連", "start": 0, "end": 2, "extractor": "ner_mitie" } ], "text": "大連天氣怎麼樣" }
2.3命名實體提取替換
項目最終使用"pipeline": ["tokenizer_jieba","ner_synonyms","intent_entity_featurizer_regex","intent_featurizer_mitie","intent_classifier_sklearn","ner_corenlp"]
以前使用MITIE做爲命名實體提取,但MITIE須要本身訓練,實際使用時訓練語句過少,正確率偏低,改用corenlp,默認支持中文 我截取目標默承認以識別的實體類型
# DATE: type:日期 eg:明天
# LOCATION: type:地點 eg:齊齊哈爾
# MISC: type:其餘 eg:怎麼樣
# MONEY: type:金額
# ORGANIZATION: type:組織
# PERCENT: type:百分比
# PERSON: type:人 eg:特朗普
# TIME: type:時間 eg:下午
# O: type:動詞或其餘 eg:查詢
# COUNTRY: type:國家 eg:中國
# STATE_OR_PROVINCE: type:城市/省會 eg:北京
# CITY: type:城市 eg:西安
2.0補充
系統缺陷修復,使用rasa_nlu意圖分類,基於sklearn-svmcv算法,可是分類後,各意圖結果相加始終等於1,我以前的設想(後面有詳細說明):設定一個閾值好比0.7,判斷最高匹配度的意圖是否大於閾值,若是大於則認爲明確意圖。但這基於問題是意圖的前提,
我訓練意圖用了三個分類weather,bookhotel,map,但我沒法將問答的5000個問題訓練爲other意圖,因爲5000個問答中涉及多領域,很是多的特徵向量會對意圖分類形成很大影響,使分類不許確。
目前的解決方案爲在乎圖識別前,加入一個二分類器,也基於sklearn的分類器,用於區分問題仍是意圖,訓練使用18000條生產環境用戶問題和6000*3加權的意圖問題(等量的訓練數據)訓練並比較準確率。
用戶問題 | 標識(1意圖0普通問題) |
今每天氣如何 | 1 |
我想預訂北京的酒店 | 1 |
機器人的內部處理流程是怎樣的 | 0 |
公司發展歷程 | 0 |
生成pkl文件。將pkl文件放入指定位置,替換最準確算法。
當前最高爲隨機森林算法
******************* NB ********************
accuracy: 90.06%
******************* KNN ********************
accuracy: 87.50%
******************* LR ********************
accuracy: 90.91%
******************* RF ********************
accuracy: 96.31%
******************* DT ********************
accuracy: 95.17%
******************* SVM ********************
accuracy: 25.28%
******************* SVMCV ********************
accuracy: 93.75%
******************* GBDT ********************
accuracy: 87.78%
看了不少大神基於深度學習算法的帖子還有論文,感受實在力不從心... 這裏使用模板配置的方式,引導用戶完成上下文。
JSON數據格式
{
"rule": [{
"intent": "weather",
"entities": [
{"name":"city","type":"city","required":"true","prompts":["請問查詢哪裏的天氣","想查詢哪一個城市的天氣"]},
{"name":"date","type":"date","required":"false","prompts":[]}
]
},
{
"intent": "bookhotel",
"entities": [
{"name":"city","type":"city","required":"true","prompts":["請問預訂哪裏","想預訂哪一個城市"]},
{"name":"checkindata","type":"date","required":"true","prompts":["請問什麼時候入住","預訂酒店的時間"]},
{"name":"checkoutdata","type":"date","required":"false","prompts":[]}
]
},
{
"intent": "bookticket",
"entities": [
{"name":"fromcity","type":"city","required":"true","prompts":["請提供出發城市","從哪起飛"]},
{"name":"tocity","type":"city","required":"true","prompts":["請提供到達城市","到哪落地"]},
{"name":"date","type":"date","required":"true","prompts":["請問預訂機票的時間","想預訂哪天的機票"]}
]
}
]
}
這就是上下文的控制流程,主要代碼邏輯控制,沒有使用機器學習算法。
特別的,這裏閾值很是的重要,閾值範圍0~1,越小越容易被理解爲意圖,當爲1時,等同於關鍵字匹配。
舉個栗子,若是閾值設定很是小,用戶的普通提問都會被理解爲意圖,不會進入chatterbot問答中,若是很是大,則難以進入意圖識別,訓練data 查詢工資,若是用戶輸入「查詢個人工資」可能也不會進入意圖查詢
閾值我使用梯度降低算法,擬合成二維曲線,找到最高點,0.74
項目開發過程大概4個月(第一週,學習python基礎語法,主要了解函數,變量賦值邏輯,web api實現,以後開始學習深度學習算法,主要從帖子、論文和視頻,MIT、臺大、Stanford的教學視頻都很是好,能夠在B站上看,選型時幾乎試用了全部開源的QA項目,通常QA項目都須要訓練,準備語料因此耗費了大量時間),獨立開發,實際編碼時間一個月,最後用asp.net mvc封裝了這些接口,作了問答頁面和簡單的後臺語料管理系統(我也想用python...來不及)
咱們業務問答5000多條,一共有3個實習生,配合我標註語料,編寫測試集和驗證集(真正的工做量在這)
最終正確率:68.4%(微軟驗證集正確率:81.7%)
chatterbot 項目主框架
https://github.com/gunthercox/ChatterBot
sklearn 意圖問題分類
https://github.com/automl/auto-sklearn
rasa_nlu 意圖識別模塊
https://github.com/RasaHQ/rasa_nlu
gensim word2vec算法實現
https://github.com/RaRe-Technologies/gensim
word2vec,中文處理
https://github.com/zake7749/word2vec-tutorial
類似度比較-向量餘弦夾角
https://github.com/kris2692/Vector-semantics
主要問題:
1.正確率過低:若是單用word2vec算法,正確率只有36.2%,單用編輯距離算法正確率59.8%,不知道爲什麼我寫word2vec算法正確率如此低,一直沒有找到緣由。
2.數據分散,用多種語言編寫:整個項目一共三部分:chatterbot,rasa_nlu,mvc web,在修改意圖時很是麻煩,在管理系統修改意圖後,生成json文件,須要手工拷貝到rasa_nlu項目中,再使用cmd命令train,start server。
補充