基于LUIS制作识别自然语言的聊天机器人

新开一个Bot系列的坑,本篇讲LUIS,下一篇预定讲BotFramework。

LUIS即Language Understanding Intelligent Service,是微软Azure提供的一个基于机器学习的NLP(自然语言处理)服务。简单地说,你可以预先输入一些用户可能输入的自然语句(如“今天上海的天气如何”),并在其中标记出关键点(如“今天”这是时间、“上海”这是地点、“天气”这是意图),通过少量的样本(最少大约5条即可),即可建立模型,随后该服务就可以接受其他相似但不相同的语句(如“查一下明天北京的天气”)并提炼其中的意图和关键信息(如“明天”、“北京”),通过这些关键信息,你就可以进一步做其他事情,最常见的应用就是制作智能的聊天或问答机器人,或是从用户发来的电子邮件中提取关键信息自动回复。

开通LUIS服务

首先,你需要开通Azure免费账户,当然这是指“国际服”的Azure,方式简要概括为申请一张VISA的信用卡,地区填中国香港。

如果你实在搞不定Azure,本文最后还会介绍一个替代品。

有了良心的Azure免费账户之后,到 主页 - Microsoft Azure 页面,创建资源——搜索Language Understanding,创建。

这里的注意点:创作位置和预测位置。

创作位置指的是你生成和测试【识别模型】的服务所在位置(可以理解成开发机),它的每秒调用次数和每月调用次数都远小于预测位置;

预测位置则是只管从创作位置那里获取到模型之后,接收输入计算输出的服务所在的位置(可以理解成运行编译好的程序的服务器)。

尽管Azure这里允许你选择不同的创作和预测位置,但实际上在LUIS界面中,这两者若想联动,必须位于同一位置。因此尽管预测位置中有更接近中国的日本服务器,我们也不能选。

对于免费的LUIS服务, 每秒调用次数和每月调用次数都是有限制的,但是对于个人小范围使用来说,基本上肯定够用了。巨硬在这里还是比较良心的。

创建成功后,到LUIS的官网:https://www.luis.ai,就可以开始创作模型了。

 

创作模型

首先注意,你可以在右上角的设置——General中把部分界面文本换成中文。

新建一个APP,区域性要选择你面向的语言,这里我们选择Chinese。创建后,页面会给出一个初始教程,里面简明扼要地讲述了大部分关键点,建议仔细阅读。

在此简单讲讲这些名词的意思:

意图(Intent):指的是用户的一种意向,比如“查天气”、“订票”、“肯定(确认)”、“否定(拒绝)”等都可以作为意图。也可以理解为机器人的一个具体的功能。

例句(Utterances):指用于训练模型的例句。当然要自己在每个例句上做好标记。

实体(Entity):指在句子中要提炼的有用信息,比如“查天气”句子里会出现的时间、地点都可以作为实体。

预生成域(Prebuilt Domains):指微软已经帮你训练好或者制作好的一些常用的意图和实体的集合。比如Calender里面包含了预定会议室、查某人生日等日历操作所需要的意图和实体。不过由于内容太杂,添加后需要手动去掉一些。

特征(Feature):指句子中出现的、不一定作为实体的元素,用来定位意图或者实体。比如“查天气”句子里通常会出现的“天气”“气候”“天(儿)”等词,提炼信息时并不需要,但出现这些词意味着意图极可能是“查天气”。

模式(Pattern):虽然通常会通过机器学习(ML)的方式来确定意图,但是也可以针对一个意图写几个固定的模式,可以保证符合这种格式的输入的识别一定不会有误差,近似的输入也有更好的识别率。格式例如 {date}{position}的天气(如何|怎么样) 。其中{}中是你定义的实体。

审查远端例句(Review endpoint utterances):当你在API请求时设置了“记录日志”(log=true)时,会把用户真正的输入记录在这里,这样你可以看到用户真实输入的置信度为什么这么低,以及把这些句子标记好之后加入到对应的意图中去,以提升之后的识别率。

 

接下来我们就做一个查天气的意图。

实体

首先我们先到Entities页面创建要提炼的实体。

由于我们会用到时间(“今天天气如何”),因此我们可以添加一个MS做好的预生成实体: 添加预生成实体——datetimeV2

datetimeV2是最精髓的预生成实体。假设今天是2021年9月12日,它能把“今天”准确地解析成2021-09-12,也能把“过去三天”解析成[2021-09-09, 2021-09-12),非常实用,可以说如果没有它和其它几个预生成实体,LUIS不会像现在这么有用。

除了datetimeV2之外,其他的预生成实体也都很实用,详情参考:所有预生成实体 - LUIS - Azure Cognitive Services | Microsoft Docs

此外我们还需要加一些ML实体,比如地点

实体有4种类型:

列表(List):固定的枚举集合。比如你可以把性别定义成列表实体gender:

最终从句子里提炼实体时,实体会以规范化值表示,比如原句“我是♂”,提取出来的gender仍然是“男”而不是“♂”(当然,如果你一定要取到“♂”,也可以从返回值的分词中取到)。

正则(Regex)实体:用正则表达式可以描述的实体。比如你可以把区号定义为正则表达式实体:

[1-9][0-9]{5}

很多查天气的API支持通过邮编或者区号来查天气,这个实体也就可以用得上。

 

模式·任意(Pattern.any)实体:这种实体只能在模式里用,代表提炼模式中处在这个位置的任意输入,有点像正则表达式中的捕获组。

比如你的任意实体叫extra,你的模式是:

{date}{position}的{extra}天气(如何|怎么样)

那么extra可以用来匹配……

今天上海的夜间天气如何 —— 夜间

今天南海的海上天气如何 —— 海上

今天火星的陨石坑天气如何 —— 陨石坑

 

机器学习(ML)实体:当不能用上述任意一种来表示这个实体时,就选择这个,用ML的力量来解决。

ML实体可以有结构。比如我们可以把详细地点定义成fullPosition,内含3个平级的子实体:国country、省province、市city。

每个ML实体还可以附加多个特征,来帮助确定是这一实体,比如“国”可以作为country的特征,“省”可以作为province的特征等等。特征默认不是必须出现在实体中的,但是也可以点击【*】按钮设置为必须。

当然特征可能也会导致一些误判,比如“德州市”这是一个市,但“美国德州”却是一个省。此时可以通过例句或者增加新的特征(把“山东德州”作为市的一个特征;把“美国德州”作为省的一个特征)来规避。

 

意图

随后在Intents里创建新意图AskWeather。

首先ML Features也就是之前提到的特征,我们可以先加一个常用天气短语的特征进去。

接着我们就可以开始输入例句了,要尽可能多想想用户平时是怎么说话的,同时尽量覆盖有实体和没实体的情况。

输入一个例句“今天的天气如何”,按Enter,可以看到【今天】已经被自动标记为datetimeV2,这便是LUIS的价值所在。

对于正则实体,LUIS也会自动标记。

在关键词上按住鼠标左键并拖动,然后选择合适的ML实体,就完成了一次标记

 

不过这里要补充一个实体的知识点。如果不特意做处理的话,一句话里可能也会有多个datetimeV2出现,比如用户可能会说“今天夜间到明天的天气如何”,这就会超出datetimeV2的知识范围了。

此时简单起见我们可以不处理,让用户换种问法;

或者,我们可以创建一个ML实体WeatherTime,它的特征可设置为datetimeV2,然后对每句话中的时间标记WeatherTime(标记“今天夜间到明天”)。这样尽管你还是没办法利用datetimeV2给你解析出具体的时间,但至少你可以得到"WeatherTime": "今天夜间到明天" 的结果,后续你可以再手动处理。

此外,对于“今天的天气相比昨天怎么样”这种输入,“今天”和“昨天”都会是datetimeV2。此时除了建立两个ML实体之外,还可以通过“角色”来区分两个时间的性质。在实体页面,点开datetimeV2,“角色”选项卡。

创建角色之后,回到意图页面,点击@图标可以打开实体窗口,选中datetimeV2,下方可以选择它可以成为的角色,选择一个角色如QueryTime,此时会进入标记状态,鼠标在例句的“今天”上按住拖动,可以把“今天”标记成datetimeV2:QueryTime。

这样,“今天”与“昨天”虽然都是datetimeV2,但“今天”还会额外作为“QueryTime”来提炼,我们用来查天气的日期还是今天,昨天其实不怎么需要。需要注意的是,进行角色标记的前提是它已经是这种(此处为datetimeV2)实体。不能在其他类型的实体上、或是非实体上做这种标记。

简单起见,后面我们不采用新建ML实体来标记时间的方式。

输入并标记一些例句后,可以点击Train(训练)来进行训练。训练通常只要十几秒钟。训练完后,可以点击测试(Test)按钮开始测试。

随便输入一句话,可以看到LUIS认为这句话是“问天气”意图的分数为0.990,也就是非常确定(满分为1)。此外它也识别出了时间(datetimeV2)是“明天”(虽然这里只显示了“明天”,但只要是datetimeV2,在最终API的返回结果中,会给出具体日期)。

但是,它并没有识别出地点,时间也没有标记出对应的角色。

我们可以通过“分配给新意向”按钮把它加入到AskWeather的例句中去,手动进行标记,再次训练。如果你发现这句话虽然是在问天气,但它的置信分数比较低(比如只有0.6),那么它很有必要加入到例句中。

经过一两轮训练后,再输入新例句时,你会发现在你标记之前,LUIS已经自动用虚线框标记出了它所认为的实体。如果它的标记没毛病,可以直接点击右侧的“接受实体预测”(对钩按钮)来接受;如果有毛病,则可以手动重新标记。

经过反复训练与测试,你的人工智障将会达到一个还不错的水平:

此时我们就可以发布之后试试API了。当然只要发现还有句子没有准确识别,就还是可以随时回来训练。

发布模型与测试

点击右上角的Publish(发布)按钮,有两个发布槽(Slot)可供选择:过渡槽和生产槽。其实这只是一种推荐的部署模式——一个槽用于提前测试,另一个用于正式发布。实际上它们在功能上没有区别。

这里我们先发布到过渡槽。发布完成后,到Manage —— Azure Resources页面下,选择Prediction Resources(预测资源)选项卡,如果这里是空的,你可以点击“添加预测资源”按钮,把之前创建的预测资源加进来。

页面最下面有个更改请求参数:关于请求参数中的三个开关,其实对应的就是示例查询URL中的show-all-intents、verbose和log。其中show-all-intents会给出这句话在所有已有意图下的置信分,否则只显示为分最高的那个意图;verbose会给出分词信息等,一般场景用不到;log就如之前所说,如果设为true,每次请求的例句会进入刚才创作界面的页面下等着你标记,如果会有很多请求,也懒得看用户的输入,建议还是关掉,后面可以在自己的应用里记录下用户的输入和LUIS返回的置信分,如果置信分比较低,再手动把例句加进来。