aiml简介+源代码解析+中文分词(java)
本文整合了看到的幾篇博客并結合了筆者自己的嘗試,記錄下對aiml的淺顯理解,想了解的更深入還是要靠自己探索呀!
目錄
一、簡介
二、原理+源代碼解析
三、中文分詞嘗試
四、注意
五、優勢與缺點(個人理解)
?
一、簡介
AIML,全名為Artificial Intelligence Markup Language(人工智能標記語言),是一種創建自然語言軟件代理的XML語言,最初來源于一個名為"A.L.I.C.E."的聊天機器人。
簡言之,AIML就是用戶通過定義的規則模板進行問答匹配,來實現聊天機器人自動問答的功能
下面展示了一個最基本的例子,僅包含最主要的<category><pattern><template>三種標簽
<category><pattern>你好</pattern><template>您好,很高興認識您。</template> </category>當用戶輸入問題“你好”時,機器人就會匹配到這個pattern,然后將<template>中的內容作為答案返回
標簽的詳細說明可以參考https://www.tutorialspoint.com/aiml/index.htm
二、原理+源代碼解析
1.原理
原理參考了春雨里de太陽的AIML知識庫數據匹配原理解析這篇博客(感謝!)
一個通常流程是:
首先系統初始化,包括問句規范化配置、加載許多配置屬性等然后將aiml問答知識庫以樹的形式加載到內存,將其拆分成單個詞,結構類似trie tree,在java源碼中就是Graphmaster對象(節點和子節點來存儲知識節點)
然后接受用戶輸入,將問句規范化,并將其拆成一個個單詞
進而查詢匹配標簽
最后根據最佳匹配,完善模板(比如*填充,index填充等)返回答案
?
2.源代碼解析
代碼邏輯:
(1)用Chat類實現會話,工廠創造bot對象
(2)解析aiml,在aiml包下 AimlHandler類,里面包含對多種標簽的解析,生成context和graphmaster對象
解析主入口在aliceBotParser的parse方法。
主要通過AimlHandler中的startElement和endElement方法調用pushTextNode()方法,將解析的一個完整標簽內容壓入stack
然后構造context對象(包含了所有aiml文件的節點、配置和上下文信息,節點存在transformation屬性中,配置信息存儲在properties屬性中),其中transformations對象主要存儲的是語句分離器,問句規范化處理信息
同時構造了graphmaster對象,通過newGraphmaster方法把解析的<category>加入到graphmaster對象中
handler.unload方法從讀取xml生成的stack里面彈出元素
aiml中的基本知識單元<category></category>主要存儲在category對象中,如上圖所示,解析aiml文件后,返回存儲問答對的Category類型的list,然后作為graphmaster對象的屬性
bot要裝載context對象和graphmaster對象,這樣,bot就帶著aiml中的配置和知識去回答用戶提問
(3)用戶輸入,調用bot對象的respond方法
先利用用戶的input生成request對象,request對象是請求對象,屬性為original和sentences,original為問句,然后將sentence規范化,賦給request對象
(4)進一步調用重載的respond方法,調用graphmaster的match方法匹配sentence到對應的category,調用process方法,返回<template>標簽的內容:value.toString
再調用response.append方法,將response對象的original(答案)設置為category的template回復內容
(5)把response添加進context的response鏈表中,這樣會話歷史就被存儲到context對象中
(6)返回respond的最終返回值:response.original.toString()
三、中文分詞嘗試
參考了https://blog.csdn.net/zhang_hui_cs/article/details/22686951這篇博客
aiml默認是不支持中文的,如原理中知識節點圖所示,知識節點都是按空格切分的,所以aiml支持默認按空格分割的英文,這樣才能匹配,而不支持中文,所以支持中文的關鍵就是將中文分詞后加空格分割
因而需要修改的地方有三個:
(1)解析aiml文件時<pattern>和<that>標簽內容中文分詞空格分割
對應于源碼解析中的解析aiml時利用putNextNode方法將標簽壓棧,修改中文分詞即可,我采用了Hanlp,可個性化定制
/*** 中文分詞重載, 分詞后中間加空格* 然后應用到that和pattern標簽* @param isToChineseSegment*/private void pushTextNode(Boolean isToChineseSegment){String pushed = text.toString();text.delete(0, text.length());if (ignoreWhitespace)pushed = pushed.replaceAll("^[\\s\n]+|[\\s\n]{2,}|\n", " ");if(!"".equals(pushed.trim())){if(!isToChineseSegment){stack.push(new Text(pushed));}else{String result = "";List<Term> list = HanLP.segment(pushed);for(Term term:list){result += term.word + " ";}stack.push(new Text(result.trim()));}}}然后在調用它的startElement和endElement方法中修改
//pushTextNode(); //英文分詞pushTextNode(qname.toLowerCase().equals("pattern") ||qname.toLowerCase().equals("that") || qname.toLowerCase().equals("srai")); //中文分詞(2)讀取用戶question中文分詞空格分割
修改Transformation類的normalization方法
public void normalization(Sentence sentence){//String input = breakWords(sentence.getOriginal());//---對用戶輸入中文分詞---String result = breakWords(sentence.getOriginal());String input = "";List<Term> list = HanLP.segment(result);for(Term term:list){input += term.word + " ";}//------------------------input = ' ' + input + ' ';input = input.replaceAll("\\s{2,}", " ");sentence.setOriginal(input);Mapper mapper = new Mapper(input);input = substitute(input, mapper);input = fit(input, mapper);sentence.setMappings(mapper.toArray());sentence.setNormalized(input);}(3)規范化處理類Transformations中需要修改正則表達式匹配,使其能夠匹配中文
//private final Pattern fitting = Pattern.compile("[^A-Z0-9]+"); //正則表達式匹配英文+數字private final Pattern fitting = Pattern.compile("[^A-Z0-9\u4e00-\u9FA5]+"); //添加中文字符經筆者簡單測試,可以進行中文模糊匹配
<category><pattern>_行不行_</pattern><template>不可以!</template></category> <category><pattern>*能不能*</pattern><template>能!</template></category>四、注意
1. aiml元素屬性是大小寫敏感的,修改時,pattern元素中的英文都要大寫
2. 自定義標簽:只需繼承TemplateElement類,核心方法是process方法,它的返回值直接作為答案返回給用戶
然后在aiml文件中添加
<category><pattern>測試</pattern><template><b/></template></category>
其中B就是自定義的標簽類
public class B extends TemplateElement {/*Constructors*/public B(Attributes attributes){}public B(Object... children){super(children);}/*Methods*/public String process(Match match){return "user-defined";} }這樣輸入“測試”,機器人就會回復“user-defined”
3. bot.respond()往往需要一個session參數,因為面對不同用戶時,能夠進行區分
五、優勢與缺點(個人理解)
1.優勢:
第一部分展示的demo例子其實完全可以用問答對構建,然后檢索的方式解決,不需要如此復雜。
aiml的優勢有以下幾點:
(1)支持通配符,即模糊匹配
這就使得aiml可以利用一個category解決很多相同句式的問題;而且,<srai>標簽解決了檢所匹配問答對擴充時答案的冗余
(2)多種功能標簽的輔助
比如<random>,增加了回復的多樣性
<if><condition>判斷條件
<topic>根據主題匹配
<system>learn</system>學習功能,學習用戶輸入的正確答案
(3)會話機制
基于aiml構建的chatbot支持會話機制,使得機器人具有一定程度的基于上下文語境的多輪對話功能,而且機器人能夠區分不同的用戶角色。
比如同樣的問句“你好”,機器人對于不同人就會回復“你好,張三”、“你好、李四”
?
2.缺點
因為是基于規則匹配,缺點也很明顯
(1)依賴規則的構建復雜程度,以及aiml覆蓋知識的多少,規則構建完善、語料大效果自然好。
當針對特定領域的問答時,采用aiml方式構建個性化的標簽和采用其他方式比如檢索匹配,知識圖譜,深度學習技術等等需要評估可行性和效果,可以采用aiml進行輔助,多模塊整合
(2)人工的費時費力
總結
以上是生活随笔為你收集整理的aiml简介+源代码解析+中文分词(java)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 线性代数公式合集
- 下一篇: 伯努利方程实验装置QY-HGYL23