NLU(自然语言理解)智能算法测试从1到N的改进
From 智能化产品测试团队
# 1 前言
# 1.1 什么是NLP

在人工智能出现之前,机器只能处理结构化的数据(例如有明确的字段关系表格数据),但互联网中大部分数据都是非结构化的,例如:文章、图片、音频、视频......其中很多信息都是以文本为载体存在的,为了能够利用和分析这些文本信息,我们就需要利用NLP技术,让机器理解这些文本信息,并加以利用。
NLP(Natural Language Process ) ---- 自然语言处理就是人类和机器之间沟通的桥梁。
自然语言就是大家平时在生活中常用的表达方式,大家平时说的“讲人话”就是这个意思。
NLP是个很大的体系,其包含的内容如下图所示:

# 1.2 什么是NLU
我们用一个具体的案例来说明下什么是NLU。
对话系统这个事情在2015年开始突然火起来了,主要是因为一个技术的普及:机器学习特别是深度学习带来的语音识别(ASR)和NLU(自然语言理解)--- 主要解决的是识别人讲的话。这个技术的普及让很多团队都掌握了一组关键技能:意图识别和实体提取。
这意味着什么?我们来看一个例子。
在生活中,如果想要订机票,人们会有很多种自然的表达:
"订一张去北京的机票";
“有去北京的航班吗?”;
“看看航班,下周二出发去北京”;
“要去北京出差,帮我查下机票”;
……
可以说“自然的表达”有无穷多的组合(自然语言)都在代表“订机票”这个意图,而听到这些表达的人,可以准确理解这些表达指的是“订机票”这件事。
而要理解这么多不同的表达,对机器是个挑战。在过去,机器只能处理“结构化的数据”(比如关键词),也就是说如果要听懂人在说什么,必须要用户输入精确的指令。所以,无论你说“我要出差”还是“帮我看看去北京的航班”,只要这些字里面没有包含提前设定的关键词“订机票”,系统都无法处理。而且,只要出现了关键词,比如“我要退订机票”里也有这三个关键词,也会被处理成用户想要订机票。
我们本文将要分享的内容即为NLU(Natural Language Understanding)--- 自然语言理解的智能算法测试方法的改进思考和实践。

自然语言理解这个技能出现后,可以让机器从各种自然语言的表达中,区分出来,那些话归于这个意图,而哪些表达不是归于这一类的,而不再依赖那么死板的关键词。比如经过训练后,机器能够识别“帮我推荐一家附近的餐厅”,就不属于“订机票”这个意图的表达。
并且,通过训练,机器还能够在句子当中自动提取出来“北京”,这两个字指的是目的地这个概念(即实体),“下周二”指的是出发时间。
这样一来,看上去机器就能听懂人话了。

# 1.2.1 烽火在公安领域NLU相关的概念
我司在NLU领域探索开拓的有两个团队,IAO和KG,两个团队的NLU体系标准和定义有所区别,我们以较为复杂的烽火IAO-NLU体系为例进行讲解阐述。
对于”查询13301791708的酒店同房间人员“这个测试语料,其NLU算法服务处理返回结果为:
{
"code": 200,
"data": [
{
"apps": {
"app_op_seq": []
},
"content": {
"des": {
"phone_number": "13301791708"
},
"ont": "SIM_Card",
"rel": [
{
"des": {},
"ont": [
"SIM_Card",
"Person"
],
"rel": [
{
"behavior": [
{
"category": "伴随分析",
"location": [],
"modifiers": [],
"number": [],
"target": null,
"time": [],
"traffic": []
}
],
"des": {
"intent": [
"full"
]
},
"intentPro": [
"entity"
],
"ont": [
"Person",
"Person"
],
"relIdx": [
0,
"14-19"
],
"relName": "酒店同房间同宿",
"segs": [
"查询13301791708的酒店同房间人员"
]
}
],
"relIdx": [
0,
"13-19"
],
"relName": "使用人",
"segs": [
"查询13301791708的酒店同房间人员"
]
}
],
"segs": [
"查询13301791708的酒店同房间人员"
]
},
"content_op": "查询"
}
],
"data_op": {
"data_rel": [
""
],
"data_rel_property": []
},
"msg": "",
"unknown": [
{
"keyword": "酒店",
"ont": "unknown"
}
]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
结合NLU的业界标准,以及我司在公安领域的深耕和应用场景,我们对NLU的识别结果分为以下几个类别。
# 1.2.1.1 本体
本体(ontology,缩写为ont),在计算机科学与信息学领域,理论上,本体是指一种”形式化的,对于共享概念体系的明确而又详细的说明“,
我们可以简化的理解为自然语言中的诸多对象。
举个例子,对于”查询13301791708的酒店同房间人员“这句话,其中的本体为:
- SIM_Card
- ['SIM_Card', 'Person']
- ['Person', 'Person']
# 1.2.1.2 属性
属性(ontology_attribute),即指的是各个本体的属性。
举个例子,对于”查询13301791708的酒店同房间人员“这句话,其中的属性为:
- phone_number,其属性值为”13301791708“
# 1.2.1.3 关系
关系(relname),是指多个本体之间的关系名词。
举个例子,对于”查询13301791708的酒店同房间人员“,其中的关系为:
- 酒店同房间同宿
# 1.2.1.4 行为
行为(behavior),此为我们公司结合公安领域的特性定义的识别结果分类
举个例子,对于”查询13301791708的酒店同房间人员“,其中的行为类别为:
- category,其值为”伴随分析“
# 1.2.1.5 意图
意图(intention),即为一句话或一段话的目的是什么,烽火IAO-NLU体系对其定义为几个有限集合,便于上层业务查询使用。
举个例子,对于”查询13301791708的酒店同房间人员“,其中的意图为:
- ['full']
# 2 如何度量其质量---NLU评估指标
首先,我们需要明确从哪些维度去客观、严谨、全面的评估NLU算法质量。这里我们通过对NLU实现过程的深入了解,以及对标行业内在相关领域的实践经验,结合我司网安领域的业务场景,对IAO-NLU体系的NLU能力确定了如下维度的评估指标。
# 2.1 评估指标
# 2.1.1 本体识别
$$ 本体识别精确率 = \frac {识别正确的本体个数} {识别出来的本体个数} \times 100% $$
$$ 本体识别召回率 = \frac {识别正确的本体个数} {期望识别出来的本体个数} \times 100% $$
$$ 本体识别错误率 = \frac {识别错误的本体个数} {识别出来的本体个数} \times 100% $$
举例说明:
100条测试问句中,覆盖Person本体50个
- 识别出40个Person本体;
- 识别正确的38个Person本体;
- 识别错误的2个Person本体;
Person本体识别精确率=38 / 40
Person本体识召回率=38 / 50
Person本体识错误率=2 / 40
# 2.1.2 属性识别
$$ 属性识别精确率 = \frac {识别正确的属性个数} {识别出来的属性个数} \times 100% $$
$$ 属性识别召回率 = \frac {识别正确的属性个数} {期望识别出来的属性个数} \times 100% $$
$$ 属性识别错误率 = \frac {识别错误的属性个数} {识别出来的属性个数} \times 100% $$
举例说明:
100条测试问句中,覆盖person_name属性50个(假设其中1个元素重复了5次)
识别出person_name属性共计40个;
识别正确的的38个(重复元素正确识别3次);
识别错误的2个(重复元素错误识别1次,重复元素漏识别1次);
person_name属性识别精确率=38 / 40
person_name属性识别召回率=38 / 50
person_name属性识别错误率=2 / 40
# 2.1.3 关系识别
解释说明:
关系所在层级及关系值均正确,即视为正确。
$$ 关系识别精确率 = \frac {识别正确的关系个数} {识别出来的关系个数} \times 100% $$
$$ 关系识别召回率 = \frac {识别正确的关系个数} {期望识别出来的关系个数} \times 100% $$
$$ 关系识别错误率 = \frac {识别错误的关系个数} {识别出来的关系个数} \times 100% $$
# 2.1.4 行为识别
解释说明:
行为包括:category、location、modifiers、number、target、time、traffic;
当行为中的category、location、modifiers、traffic均正确时,即认为一个行为正确。
$$ 行为识别精确率 = \frac {识别正确的行为个数} {识别出来的行为个数} \times 100% $$
$$ 行为识别召回率 = \frac {识别正确的行为个数} {期望识别出来的行为个数} \times 100% $$
$$ 行为识别错误率 = \frac {识别错误的行为个数} {识别出来的行为个数} \times 100% $$
# 2.1.5 意图识别
解释说明:
一句话中同时出现Apps、Content、Content_op、data_rel时,需全部正确才判断为一个意图正确:
Apps:多组{action、module_name、module_type}均正确即认为意图正确;
Content:intentPro、des.intent、behavior中的target所在层级及内容均正确即认为意图正确;
Content_op:内容正确即认为正确;
data_rel:data_rel正确即认为正确;
$$ 意图识别正确率 = \frac {意图识别正确的问句个数} {测试问句总数} \times 100% $$
# 2.1.6 场景识别正确率
根据业务使用场景,对各场景下的测试语料测试结果分别统计其正确率,可以更清晰的体现NLU能力对上层业务的价值。 $$ 核心业务场景正确率 = \frac {识别正确的核心业务场景问句条数} {核心业务场景问句条数} \times 100% $$
$$ 非核心业务场景正确率 = \frac {识别正确的非核心业务场景问句条数} {非核心业务场景问句条数} \times 100% $$
$$ 多实体关系分析识别正确率 = \frac {多实体关系分析识别正确的问句数} {多实体关系分析测试问句总数} \times 100% $$
# 3 如何实现上述维度的客观、高效度量
在2019年,我们已经进行了NLU智能算法测试的探索,实现了从0到1的突破,积累了一批测试语料,也实现了一定程度上的各指标维度的分析计算。
但随着NLU智能算法服务能力的丰富,其识别结果的数据结构愈发的复杂,需要对已有的测试方法和工具进行优化改进:
降低测试语料准备工作的复杂度,
降低测试语料标注的成本,
提高测试语料标注的效率,
降低测试结果分析、统计和指标计算的代码难度,
我们需要实现从1到N的优化。
# 3.1 我们需要解决的问题
我们主要面临三个大方向的问题:
一、由于我司NLU的应用领域为公安领域,相关语料的获取渠道极为受限,无法从互联网采集,也难以从现有的线上业务系统中获取(对应的业务应用处于刚刚起步阶段,线上用户量很少,从用户使用日志中能获取的信息少)。
二、获取到所需的语料文本后,我们还需要根据我司的NLU体系定义进行(本体、属性、关系、意图、行为、业务场景等维度)语料标注(且我司目前有两套NLU体系定义:IAO和KG)。
三、我们需要对大量的语料测试结果进行各个维度的分析统计,进行各类指标的计算,并且快速的分析其各个指标维度下的失效原因,提供样例用于研发定位和改进NLU算法服务。
# 3.1.1 克服高效简单语料生成和语料标注难题
# 3.1.1.1 语料生成的局限性
语料生成的基本原理为通过语料模板和语料素材的组合生成问句。
举个例子,通过以下语料模板和语料素材:
【模板】查询{中文姓名}和手机号为{手机号码},{长时间段}的住宿记录,{酒店名称}
【素材】中文姓名 ['赵刚', '刘芳', '李白']
【素材】长时间段 ['一九九七年', '2020年1月', '2018年三月之后', '2020年2月份之后']
【素材】手机号码 ['13033918279', '13612349005', '8613368366846', '+8613532340976']
【素材】酒店名称 ['珠江路汉庭酒店', '珠江路如家酒店', '新模范马路香格里拉', '新城科技园桔子水晶']
2
3
4
5
我们可以生成以下语料
查询赵刚和手机号为13033918279,一九九七年的住宿记录,珠江路汉庭酒店
查询刘芳和手机号为13612349005,2020年1月的住宿记录,珠江路如家酒店
查询李白和手机号为8613368366846,2018年三月之后的住宿记录,新模范马路香格里拉
查询赵刚和手机号为+8613532340976,2020年2月份之后的住宿记录,新城科技园桔子水晶
2
3
4
在2019年的方案中,我们的语料素材存储方式为“文件夹+txt文本”,但语料素材有分类,有标签,有根据项目不同的归一化内容等诸多附加信息,使用“文件夹+txt文本”的存储方式有如下困难需要克服:
- 不利于表达多层级,多并列的语料素材信息;
- txt文本缺乏语法校验,手动编辑容易出错,需要通过编写代码对语料素材的导入内容进行预检查、归一化等处理,增加了代码量和维护成本;
- 各类附件信息体现在txt文件名中,通过
#等各类自定义的符号进行分隔,程序代码需要按照阅读切分字符串读取信息; - 随着语料素材的调整修正,维护成本逐步提高;
# 3.1.1.2 语料标注的局限性
在2019年的方案中,通过语料模板和语料素材生成的语料,我们的语料标注方案为自定义的一套语法规则,通过对语料的理解,手动编写标注规则信息

语料模板对应的标注信息示例:

从工具维护开发人员的角度来讲,这种标注方式需要有对应的代码将NLU服务的相应体解析为对应的格式进行比对,需要较强的代码能力。
从测试工程师使用的角度来讲,有以下事项需要优化改进,提高测试效率降低测试成本:
- 需要对每一条语料模板根据工具定义约定的规则(如上图所示),编写其标注信息,学习成本较高;
- 由于每条模板都需要手动编写,其成本较高,使用这套规则标注效率较低,且在此方案下,无法实现通过自动化预标注+人工审查的方式来提高标注效率;
- 标注质量有待提高,因为标注信息全靠手写,导致标注出错概率高;
- 语料内容与其标注信息深度绑定,不可解耦,同一批语料,随着NLU算法的迭代,以及不同的NLU算法项目,其标注信息是有变化的,需要将语料内容与标注信息进行解耦。
# 3.1.2 缺乏深度多维的测试结果分析
在2019年的方案中,我们的语料模板和语料素材生成的语料和语料标注信息示例如下:

可以看到,其语料标注信息是根据语料模板的标注规则回填的,其测试结果也需要将NLU算法服务的返回的json数据解析为对应的节点信息进行比对研判,这就有一定的局限性:
- 测试代码要递归解析
json结构的NLU服务响应体,提取对应的各个NLU识别关键信息,与标注结果进行比对,递归代码的编写维护难度高,不易修改和根据测试需求拓展;
# 3.2 重难点分析
# 3.2.1 重点分析
- 语料素材库的组织方式要更加合理,提高其可维护性;
- 语料标注的成本要降低,效率要提升;
- 对生成的语料数据集进行各维度的分布统计;
- 降低测试结果分析比对的开发难度,降低开发门槛,提高工具的可拓展性和易维护性;
- 给出宏观的NLU各个维度指标的结果;
- 给出每条语料各个指标维度的分析结果;
# 3.2.2 难点分析
# 3.2.2.1 如何将语料生成与语料标注解耦
将语料生成和语料标注解耦,可以对同一批语料进行不同标准体系的标注。就像图像类测试样本的标注,图片是不变的,但标注的维度却可以变化,标注信息与被标注对象可以是多对一的关系。
对每一条语料的标注,是由语料模板、语料素材、语料模板标注信息共同完成的,只需要将该语料的语料模板和语料素材组成一个数据对,与该语料文本进行映射存储,即可方便的完成标注,可以根据标注定义和标注标准的变更实现独立语料标注。
# 3.2.2.2 如何提供自动化的预标注能力
NLU智能算法经过几个版本的迭代,其能力与质量已经得到了一定的提升,具备了相当的使用价值。大胆设想,我们是否可以根据NLU算法服务的输出结果,自动回填各个维度(本体、属性、关系、意图、行为)的标注信息?再辅以人工对标注结果审核查验,进行修正确认,即可快速高效的完成文本标注工作。
这种自动化的标注的效率会随着NLU能力的逐步提升、产品质量的逐步优化,得到很大的提升,人工标注成本逐步降低。
但自动化预标住是把双刃剑,我们必须考虑风险:基于被测NLU服务进行预标注的正确性,将完全依赖于测试工程师对预标注的结果的严谨仔细审核。
# 3.2.2.3 如何实现测试结果比对分析的代码难度降低(平铺代码逻辑替代多层递归)
如何将递归解析NLU服务的响应体json替代掉呢?分析其本质,递归是为了找到对应的各个节点信息,然后基于自定义的规则进行比对分析。
如何将层层嵌套的json做一维的展开?可以使用jsonpath。
使用jsonpath将层层嵌套结构复杂的json结构展开,然后根据kv结构的节点路径和值进行结果比对,即可将递归逻辑给消解掉,使得代码编写调试更容易(本质上没有消灭递归,不过递归交由jsonpath库来做,降低了代码的维护成本)。
# 3.2.3 难点总结
经过上述三个难点的分析,我们发现了一个主要矛盾:标注信息的表达形式。
我们可以通过将标注信息用jsonpath来表达,即可与被测NLU服务返回结果形成直接的映射关系,不再需要记忆各种定义,手写各种标注规则关系了,且jsonpath可以通过json数据结构自动生成。
IAO和KG两个NLU体系并不互通,公司目前没有统一NLU的标准,因此标注信息只需对应其体系维护即可。
从哪些维度评估语音识别的质量,是我们首要解决的问题。
其次,智能化算法测试若是依托纯手工测试、亦或是半自动化测试,将面临着在执行效率、结果可靠性方面的局限性。
# 4 核心改进要点
经过本次优化,NLU的核心测试流程如下,整个测试过程中大部分环节都实现了自动化

# 4.1 基于yaml的语料构造和jsonpath的语料标注
当前NLP类智能算法服务测试的测试语料构造均可使用
CorpusFactory项目来提供能力,其标注的语料亦可用于ASR类智能算法的音频测试样本录制。
# 4.1.1 语料素材的组织形式
2019年方案的语料素材组织形式,如以下的示例:

现在我们将“文件夹 + txt文件“形态的语料素材组织形式使用yaml格式文件替代,为什么选择yaml?
yaml的可读性好、扩展性好;
yaml和脚本语言的交互性好;
yaml使用实现语言的数据类型;
yaml有一个一致的信息模型;
yaml易于实现;
使用yaml来管理组织语料素材的形态如下示例:

我们通过yaml实现了以下语料素材组织管理的能力:
- 实现了语料素材的灵活组合复用,避免了重复维护;
- 支撑对语料素材进行优先级的划分;
- 对同一语料素材支持区分不同NLU体系的标准化值;
# 4.1.1.1 语料素材优先级定义优化
M1~M4,从元素的常见程度、复杂程度、解析难度等方面综合判断
注:目前对于元素优先级的定义,以测试人员的主观判断为主,待真实用户日志数据累计到一定数量时,可结合数据分析结果进行调整;
# 4.1.2 语料模板的编写方式优化
因使用jsonpath来对语料进行标注,所以对语料模板也进行了变更,其变更形式如下:

核心内容即为语料模板,语料标注模板,其中的语料标注模板可以根据根据自动化预标注生成,我们将在接下来的章节阐述。
语料标注模板的编写,其``jsonpath也可以通可视化的方式使用工具从json`数据结构中直接获取

# 4.1.3 支持多种组合策略的全自动化语料生成
根据语料素材级别和模板等级的组合,控制各类语料的生成数量

语料生成的方式即为根据模板进行参数化组合,目前支持4种组合策略,默认策略为uniq

下面将语料的生成过程举个例子阐述下:
有如下语料模板
{查询操作}{手机号11位}的{伴随关系}人员
其对应的语料素材数据为【这是核心改进内容】
{
"查询操作": {
"md5_id": "5053080618ac09de144bd37b9568f9a6",
"value": "查询",
"father_tag": "辅助操作",
"child_tag": "查询操作",
"level": "M1",
"normalization": {},
"is_compose": 0,
"compose_object_list": [],
"yaml_file": "辅助操作.yml"
},
"手机号11位": {
"md5_id": "51a8a32c32aa59a6deeb0d38613e35d9",
"value": "13301791708",
"father_tag": "手机号",
"child_tag": "手机号11位",
"level": "M1",
"normalization": {},
"is_compose": 0,
"compose_object_list": [],
"yaml_file": "手机号.yml"
},
"伴随关系": {
"md5_id": "6c745dd7853666f83f0609f7e8f151ba",
"value": "酒店同房间",
"father_tag": "伴随关系",
"child_tag": "酒店同宿",
"level": "M1",
"normalization": {
"IAO": "酒店同房间同宿"
},
"is_compose": 0,
"compose_object_list": [],
"yaml_file": "伴随关系.yml"
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
生成一条语料信息用于预标注
查询13301791708的酒店同房间人员
有了语料模板和语料素材数据结构的绑定,我们即可根据不同的NLU体系标准,实现标注信息的重新生成。
# 4.1.4 基于jsonpath的自动化语料预标注
语料标注模板可以使用CorpusFactory自动生成预标住信息,仅需在配置文件中填写对应的配置即可

# 4.1.4.1 实现逻辑
通过语料模板和语料素材生成一条测试语料,请求NLU被测服务API,获取其API响应体json数据,将其转为jsonpath,根据语料生成的模板和素材,对生成的jsonpath进行变量替换,得到标注模板。
举个例子说明:
语料生成的示例见4.1.3小节,在生成语料的环节,我们得到了以下三个要素数据:
- 语料模板值
- 语料素材数据结构
- 语料文本实例
我们使用生成的语料用户预标注
查询13301791708的酒店同房间人员
该语料请求被测NLU服务API后,得到响应json数据
{
"code": 200,
"data": [
{
"apps": {
"app_op_seq": []
},
"content": {
"des": {
"phone_number": "13301791708"
},
"ont": "SIM_Card",
"rel": [
{
"des": {},
"ont": [
"SIM_Card",
"Person"
],
"rel": [
{
"behavior": [
{
"category": "伴随分析",
"location": [],
"modifiers": [],
"number": [],
"target": null,
"time": [],
"traffic": []
}
],
"des": {
"intent": [
"full"
]
},
"intentPro": [
"entity"
],
"ont": [
"Person",
"Person"
],
"relIdx": [
0,
"14-19"
],
"relName": "酒店同房间同宿",
"segs": [
"查询13301791708的酒店同房间人员"
]
}
],
"relIdx": [
0,
"13-19"
],
"relName": "使用人",
"segs": [
"查询13301791708的酒店同房间人员"
]
}
],
"segs": [
"查询13301791708的酒店同房间人员"
]
},
"content_op": "查询"
}
],
"data_op": {
"data_rel": [
""
],
"data_rel_property": []
},
"msg": "",
"unknown": [
{
"keyword": "酒店",
"ont": "unknown"
}
]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
将此响应json文件转为jsonpath结构(根据预标注信息,有些json结构对测试结果的比对是无意义的,已经根据配置规则忽略掉)
[
"code=200",
"$.data.[0].content_op='查询'",
"$.data.[0].content.ont='SIM_Card'",
"$.data.[0].content.des.phone_number='13301791708'",
"$.data.[0].content.rel.[0].ont=['SIM_Card','Person']",
"$.data.[0].content.rel.[0].relName='使用人'",
"$.data.[0].content.rel.[0].rel.[0].intentPro=['entity']",
"$.data.[0].content.rel.[0].rel.[0].ont=['Person','Person']",
"$.data.[0].content.rel.[0].rel.[0].relName='酒店同房间同宿'",
"$.data.[0].content.rel.[0].rel.[0].behavior.[0].category='伴随分析'",
"$.data.[0].content.rel.[0].rel.[0].des.intent=['full']"
]
2
3
4
5
6
7
8
9
10
11
12
13
此时需要根据语料素材数据和语料模板对其还原为标注模板
[
"code=200",
"$.data.[0].content_op='查询'",
"$.data.[0].content.ont='SIM_Card'",
"$.data.[0].content.des.phone_number='{手机号11位}'",
"$.data.[0].content.rel.[0].ont=['SIM_Card','Person']",
"$.data.[0].content.rel.[0].relName='使用人'",
"$.data.[0].content.rel.[0].rel.[0].intentPro=['entity']",
"$.data.[0].content.rel.[0].rel.[0].ont=['Person','Person']",
"$.data.[0].content.rel.[0].rel.[0].relName='{伴随关系}'",
"$.data.[0].content.rel.[0].rel.[0].behavior.[0].category='伴随分析'",
"$.data.[0].content.rel.[0].rel.[0].des.intent=['full']"
]
2
3
4
5
6
7
8
9
10
11
12
13
此时需要测试工程师审核其预标注信息是否正确合理!
通过这种预标注的设计,语料标注工作将是具备”加速度“的,随着NLU能力的提升,标注效率会逐步提高,标注成本逐步降低。
# 4.1.5 带有标注信息的测试语料输出
将生成的海量带有标注信息的语料输出到json line文件,即可用于测试,其输出的标注数据结构示例如下(其中一行语料测试数据):
{
"sentence": "进入水晶球",
"template": "{打开操作}{应用名称}",
"level": "S1",
"project": "IAO",
"key_word": [
"应用名称"
],
"is_core_scene": "是",
"first_transaction": "操作指令",
"second_transaction": "应用操作",
"third_transaction": "打开应用",
"annotation": [
"code=200",
"$.data.[0].apps.app_op_seq.[0].action='打开'",
"$.data.[0].apps.app_op_seq.[0].module_name='水晶球'",
"$.data.[0].apps.app_op_seq.[0].module_type='app'"
],
"material_info_dict_with_variable": {
"打开操作": {
"md5_id": "e068e68e0344f059aff3ee206334b6fe",
"value": "进入",
"father_tag": "辅助操作",
"child_tag": "打开操作",
"level": "M1",
"normalization": {},
"is_compose": 0,
"compose_object_list": [],
"yaml_file": "辅助操作.yml"
},
"应用名称": {
"md5_id": "80e6fe6bac09d577b3d36b8871e3c4bf",
"value": "水晶球",
"father_tag": "应用名称",
"child_tag": "应用名称",
"level": "M1",
"normalization": {
"IAO": "水晶球"
},
"is_compose": 0,
"compose_object_list": [],
"yaml_file": "应用名称.yml"
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
输出的json line文件示例:

此jl文件即可作为NLU测试工具的输入文件,且可以将每一条测试语料的测试结果补充到json line文件中,这样即可对每一条测试数据进行完整的声明周期跟踪和定位,便于结果分析,语料构造策略调整,工具开发debug等。
# 4.1.6 自动化语料分布统计
为了科学客观的对NLU能力进行评估,需要明确其语料构成分布情况,统计效果如下:
# 4.1.6.1 素材库概况统计示例

# 4.1.6.2 模板生成句子统计示例

# 4.1.6.3 业务场景维度句子统计示例

# 4.1.6.4 IAO本体&本体属性覆盖情况统计示例

# 4.1.6.5 IAO行为属性覆盖情况统计示例

# 4.1.6.6 IAO操作属性覆盖情况统计示例

# 4.1.6.7 IAO行为(category)覆盖情况统计示例

# 4.1.6.8 IAO关系(relname)覆盖情况统计示例

# 4.2 算法效果测试改进
# 4.2.1 比对规则的设计开发
- 通过面向对象的设计方法,定义各个指标维度的DataClass
- 设计jsonpath通用比对方法,对各个维度的比对规则进行封装定制,使用不同的函数将各评估所关注个NLU输出结果与标注结果的jsonpath进行比对,替代了晦涩难懂的递归解析比对,便于定位分析debug。
此处主要是代码的设计实现,篇幅较大,细节较多,就不展开阐述了,有兴趣可以查阅项目代码:IAO-TOOLKITS-IntellDialog (opens new window)

# 4.2.2 指标统计输出
# 4.2.2.1 定义各个指标期望阈值用于自动研判
通过配置文件定义各个指标阈值,自动研判指标是否通过
indicator_expectation:
# 冒烟用例正确率
smoke_test_correct_rate: 0.9
# 核心业务场景正确率
core_scene_correct_rate: 0.8
# 非核心业务场景正确率
not_core_scene_correct_rate: 0.7
# 多实体关系分析识别正确率
……
2
3
4
5
6
7
8
9
# 4.2.2.2 宏观指标统计结果示例
宏观指标即为NLU各个维度指标统计结果,并展示其各个分子分母的个数,便于分析影响指标的具体因素。

# 4.2.2.3 各语料详情分析结果示例
详情分析结果,可以根据各个指标维度的测试结果,进行筛选,分析其失败原因,并且可以看到该语料各个维度的分类标签信息,便于进行深入分析。

# 4.2.2.4 各三级业务场景统计示例
各业务场景是与上层业务沟通确认的,基于此维度进行指标分析,可以有效评估其在业务系统的应用情况,对业务侧提供有效的研判情报。

# 4.2.2.5 本体属性识别分析详情统计示例

# 4.2.2.6 关系识别分析详情统计示例

# 4.2.2.7 行为识别分析详情统计示例

# 5 优化效果评价
本次优化设计较以往的不同之处
基于实际结果:使用JSONPATH定义标注数据,代替之前的递归解析JSON响应体,降低结果比对部分的代码复杂度和维护成本;
基于预期结果:使用JSONPATH辅助以路径提取工具,对JSONPATH进行预标注,人工审核修正,提高标注效率和正确率,降低数据标注成本;
基于测试数据:将语料库(测试数据)的管理进行定义和分类优化,结合新的模板定义编写方式,降低编写的复杂度;
基于语料库(测试数据)管理:将语料生成和语料标注解耦开来,建立语料库基线,标注数据随被测项目进行更新迭代,提高NLP语义理解测试样本的可维护性和持续性;
整体上,代码可维护性提高30%,测试数据构造成本降低80%
IAO-TOOLKITS-IntellDialog-V3.2.0.0项目,测试准备了243种约28.7万的测试素材和900条不同优先级的测试语料模板,可在30分钟完成7000+的测试问句生成以及预期标注,1小时内完成算法指标的计算和统计分析(主要耗时为IAO被测服务性能较低,TPS仅为2)。
# 6 附录
# 6.1 CorpusFactory核心步骤使用流程图

# 6.2 CorpusFactory设计流程图

# 7 致谢
感谢以下同学,在整体框架设计、优化、应用过程中的努力付出,以及提出的宝贵意见,以下排名不分先后:
郭群、姜越、陈岑