知识引擎
我们在生活中应该多多少少接触过对话机器人,比如我们都知道很多客服其实都是机器人先档在前面回答用户问题的, 有些机器人有相当程度的知识储备, 比如你去买了一辆车, 然后想咨询客服这辆车的保险的细节。 你就会问: 请问车的每年的保险费是多少钱。 但很多时候不同的车型,年份等其他细节会决定了保险费的价格。这时候机器人要通过问询的形式收集这些信息(我们管这些信息叫词槽),所以机器人要先识别用户的意图, 然后识别为了回答这个问题还缺少的哪些关键词槽(就是信息),然后通过反复的询问和澄清收集这些信息后, 才能回答问题。 或者用户向机器人提一个很专业的问题, 比如询问《某个车型如何更换刹车油》,这就要求机器人有相当的知识储备, 很多时候它不能是随便一个搜索引擎搜出来的答案,而是根据客户企业内严格的操作手册提炼而来的。 所以大家知道了吧, 一个企业级的对话机器人不是说随便拿一个类似 GPT 这样的模型扔进去就可以的(GPT 只能当面向 C 端用户来用,企业的对话机器人或者客服机器人必须要有这个企业的专业知识), 所以我们需要有相当的专业领域的知识引擎的构建才可以。
如何构建知识引擎
首先我们现在处于一个大模型的时代, 所以一个类似 GPT 这样的大模型加入到产品中在大厂已经是比较普遍的现状了, 各个大厂都有训练自己的大模型。 有 GPT 这样的大模型在,可以极大的提升对话机器人的回答质量。 但我们上面也说了这样是不够的。 对于专业领域的问答, 需要有专业的知识库的建立。 所以在这样的产品中一般都有个比较大的系统名叫知识引擎。
文档上传:一般来说这种产品需要给客户上传文档的功能, 这些文档里就是这个企业的专业知识了, 客户把机器人需要了解的知识以文档的形式上传到系统中。
文档解析:这是一个非常重的步骤, 甚至这样一个文档解析的能力可以发展成一家公司的体量,因为客服的文档类型和格式五花八门,层出不穷。 这个文档可能是 word,excel,pdf。 像是 pdf 的话解析起来会更困难, 因为 pdf 里的数据格式太多了, 有图, 有文字, 有各种不同格式的表格, 有图文夹杂等等。 想要在这些文档中自动的把内容解析出来是非常困难的。 可能会有同学说为什么不规定一个格式然后让用户按这个格式来上传文档呢。 这个形式几乎是不可能的,这些文档是客户在多年的发展过程中积累的知识, 它的量是十分庞大的, 你让客户把这么庞大的文档按你的格式重新写一遍, 这是不可操作的。 所以一个知识引擎构建的如何,文档解析的能力起到决定性的作用,并且也是测试的重点。
文档拆分:也叫文档切片,是需要通过规则或者模型把文档按照语义切分成不同的段落。 因为一篇文档有非常多的内容, 它肯定不是只讲一件事的。 比如当用户提问说我想知道这辆车如何更换玻璃水的时候, 这个问题的答案可能记录在一份类似《不同车型下的保养操作手册》这个文档里的。那么当用户询问一个问题的时候, 你不能把这个近万字的文档一股脑的发给用户对吧。 我们预期只把更换玻璃水的那段内容发送给用户即可。 所以一个文档需要按语义进行拆分。
特征/词向量:词向量通常也叫做嵌入层(embedding),是 NLP 领域(自然语言处理)非常重要的特征工程手段。 它可以把一个词转换成一个 N 维的特征向量(比如 512 维)。我用下面一个例子来解释一下词向量是什么: 假设我们有一组信息:性别,年级,学校。处理这样的离散特征我们通常使用的 one-hot(独热编码)。比如我们有一群学生,他们可以通过 3 个特征来形容,分别是: 性别:[“男”,“女”] 年级:[“初一”,“初二”,“初三”] 学校:[“一中”,“二中”,“三中”,“四中”] 我们用采用 N 位状态寄存器来对 N 个状态进行编码,拿上面的例子来说,就是:[
因此,当我们再来描述一个学生的时候(男生,初一,来自一中),就可以采用 [1 0 1 0 0 0 1 0 0] 这样的形式来表示。这也一种用于特征组合的实现方法之一。或者我们也可以使用类似 bitmap 的方法做出一个 one—hot 向量来表示离散特征。 我们可以用类似下面的形式表达:
假设职业这一列一共有 100 个值, 假设教师在编号 6 这个位置上,编号 6 所在位置 ide 值就是 1,其他的值都是 0,我们以这个向量来代表教师这个特征. 以此类推,如果学生代表的编号是 10,那么
10 这个位置所在的值是 1,其他位置的值都是 0,用词向量来代表学生。 这样最后我们就有 100 个 100 维度的向量来表示这些特征。
上面两种方法都是很常见的用来用来表达文本特征的方法,但它们的问题是词与词之间是独立的,互相没有关联。 比如我们的训练数据中有一个句子 this is apple juice,我们期望当出现 this is orange __ 的时候,模型能够为我们推测出这个空白处也应该填写单词 juice。 也就是我们希望模型能通过之前针对第一个句子的训练就能找到单词与单词之间的关系,模型能够知道 apple 和 orange 是含义相似的词,从而能推测出 orange 后面也可以填写 juice。 而这正是词向量要做的事情。
如上图,词向量围绕这一些中心词(性别,事物,高贵程度),计算出每一个词与这些中心词的相关程度。这样我们可以通过每个词针对这些中心词的关联程度来计算词与词之间的关系。比如苹果和橘子在食物这个中心词的打分都是比较高且接近的,所以模型就可以知道苹果和橘子在某些场景下是类似的。同样的国王和王后在高贵程度上的打分也很高且很相近。 所以模型也知道在某些场景下国王和王后是相近的。 这样回到我们上面说的填空题, 当之前训练的时候我们在 apple 后面接了 juice 这个单词,那么根据词向量我们就知道 apple 和 orange 是相似的,所以 apple 后面接了 juice,那么 orange 后面也有比较高的概率是接 juice 的。 这么解释词向量的作用大家就知道了吧。实际上这种类似完形填空的模型(或者叫生成式模型,就是为用户生成答案的模型,比如对话机器人)的原理就是根据用户的问题和已经生成的词,去遍历一下词表中所有的词, 计算每个词出现在下一个位置的概率,然后取概率最高的那个词填写到下一个位置上。 所以大家看, 我曾经说过所有模型场景几乎都逃不开二分类,多分类和回归。 我们这种生成式模型实际上就是个超大的多分类模型(取每个分类的概率然后取概率最高的那个分类作为答案,而这里的每个分类就是词表中的每个词)。
- 入库:当文档解析,分片和特征都提炼好后, 就可以把特征进行入库了。这样后面用户提出问题后, 就会根据问题到库中检索对应的答案。
如何检索答案
首先需要澄清一下对话机器人的一个整体基本逻辑,当用户提出问题后,本身系统会先把问题经过一个多分类模型用于识别用户意图,因为根据用户问题的不同,我们需要给后面不同的子系统来回答, 比如是通用聊天类的,它可能直接发回给大模型进行回答。而如果是知识问答类的, 则需要发给知识引擎来检索相关答案。 又或者是通用检索类的, 比如用户问现在苹果的股价是多少,这显然不能直接发给知识引擎和大模型,而是调用搜索引擎 API 来进行查询, 当然这个查询结果很多时候要经过大模型的二次包装,这个我们后面再讲。 这里只是先讲一下对话机器人的基本逻辑。
当模型评估出当前问题需要发送给知识引擎后, 就要根据用户的问题去知识引擎的库中检索答案。 当然这里的检索可以有多种实现, 就看团队选择哪一种:
- 语义检索模型:这是一种专门用来检索文档的模型, 我们在搜索引擎中也是经常用到的。 它的核心是通过把用户的问题和文档切片分别做词向量处理(embedding 也称做嵌入层),把它们转换成特征向量,然后计算这两个特征向量之间的相似度。比如我们在测试的时候经常通过计算文本相似度来做一些验证, 而文本相似度就是计算两个特征向量的余弦相似度解决的。 只不过这个语义检索/匹配模型会更复杂。 这个方式目前比较主流。
- 问答模型:有一种专门通过一个文档来生成问答的模型,给定一个文档,提取其中的内容并生成问题和答案。所以也可以选择用这个模型事先提取问题和答案然后存到库中, 这样用户在提问的时候, 可以通过问题和问题进行匹配来完成检索的目的。事实上,我们很多时候用这个模型来生成测试数据。
- 用户直接上传问答形式的数据:用户可以直接上传问答形式的数据,这样可以免去了使用问答模型。 不过使用这个方式的就更少了。
综上所述, 使用语义检索/匹配模型的场景比较多。
如何针对这些模型进行测试
可以看出对话机器人是由 N 多个模型组合在一起的系统。 知识引擎也是由多个模型组合在一起才完成的内容检索。 那么我们来看一下要如何测试这些模型。
文档解析
文档解析重要的是要测试到客户可能会使用到的各种不同的文档类型(execl,word,pdf 等等)以及其中的各种格式(文本,图片, 文图夹杂,不同格式的表格,超链接等等)。 所以重要的是准备各式各样的测试数据, 然后统计相关的指标。 比如:文本序列相似度:一般会统计插入错误率=插入类型错误/算法输出序列长度,替换错误率=替换类型错误/算法输出序列长度,删除错误率=删除类型错误/算法输出序列长度,准确率=正确字符数/算法输出序列总长度。 这个跟我之前写的 ASR 系统里的那几个指标是很类似的。
当然最主要的还是测试的数据要覆盖不同过的场景:
比如覆盖不同行业的场景:
- 政务
- 汽车
- 金融
- 教育
- 文旅零售
- 其他(交通等)
比如覆盖不同格式的文档:
docx 格式文档:
- 纯文字
- 文字 + 图片
- 文字 + 图片 + 表格(标准 key-value 形式)
- 文字 + 表格(单斜线表头表格)
- 文字 + 表格(多斜线表头表格)
- 文字 + 表格(多行规则表头表格)
- 文字 + 表格(多行不规则表头表格)
- 水印/页眉/页脚/页码
pdf 格式文档:
- 纯文字
- 文字 + 图片
- 文字 + 图片 + 表格(标准 key-value 形式)
文档问答
考察重点:根据给定的文本或对话,提取出一个或多个问题 + 答案对。考察重点:模型从文本中提取关键信息并将信息转化为问题 + 答案的能力,要求模型对文本具有一定的理解能力,并且要求模型能正确回答自己挖掘出的问题。 评估指标:正确率。衡量生成的问答对中正确问答对的比例。正确率越高,表示模型生成的问答对越准确地反映了文本中的关键信息。
比如:乔治·奥威尔(1903-1950),原名埃里克·阿瑟·布莱尔,是一位英国作家、记者和评论家。他的作品以对极权主义和批判社会不公的关注而著称。奥威尔的两部最著名的小说是《动物庄园》和《一九八四》,这两部作品都被认为是 20 世纪最重要的文学作品之一。在他的一生中,奥威尔还撰写了大量的散文、报告文学和评论文章,其中包括《巴黎与伦敦的下层社会》和《向加泰罗尼亚致敬》。
那么根据模型假设我们需要提取 5 个问答:
- 问题 1:乔治·奥威尔的原名是什么? 答案 1:埃里克·阿瑟·布莱尔。
- 问题 2:奥威尔的哪两部小说被认为是 20 世纪最重要的文学作品之一? 答案 2:《动物庄园》和《一九八四》。
- 问题 3:奥威尔的作品主要关注哪些方面? 答案 3:对极权主义和批判社会不公的关注。
- 问题 4:《巴黎与伦敦的下层社会》和《向加泰罗尼亚致敬》是奥威尔的哪类作品? 答案 4:散文、报告文学和评论文章。
- 问题 5:乔治·奥威尔生活在哪个时期? 答案 5:1903-1950
所以测试人员需要评估这个模型的效果。 其实就是要评估它生成的问题和答案的正确性。 这里非常消耗人力的地方就是这个问答的生成可能每次都是不一样的问题和答案, 以及这些生成的问答是不是正确的也是较为主观的判断,很难通过自动化的形式进行验证。 所以其实我非常不喜欢测这种模型的效果。 因为就是纯纯的体力活。至于遇到主观问题要怎么处理。 可以参考我之前发的多人取平均分,和 3 人仲裁制度。
文档切片/语义切片
同样是一个非常主观的场景,需要模型在一个比较大的文档中去识别不同的语义, 然后把相同语义的文本切成一个片段并 embedding 处理后保存在数据库中。这样文档检索/匹配模型才会发挥作用。 这里需要测试人员来验证模型切的每一个文档片段都是符合同一个语义,且在这个语义下的文档片段是完整的。
文档检索/匹配
这个模型就是通过用户的问题去检索文档切片, 本来这也是一个经典的搜索引擎的场景, 但搜索引擎是可以返回多个结果并根据打分进行排序的。 而对话机器人往往不能返回多个文档切片。而是要取一个模型认为最优的答案。 所以搜索引擎原本使用的一些指标,比如 MAP 和 NDCG 可能在很多时候用不太上。当然如果我们是在就这个模型本身的能力进行测试,与实际业务场景无关, 那还是可以使用 MAP 和 NDCG 的。 但如果我们是测试端到端的效果,那么可能准确率才是最常用的指标。
在测试数据中除了需要覆盖各种不同行业场景的数据外, 还需要注意在测试的时候针对问题的长文本和短文本的指标统计, 因为在文档匹配领域里, 我们是通过把问题和文档切片都进行 embedding 后,根据一定的相似度算法来计算问题和文档切片的匹配程度,再根据匹配程度进行排序后把最接近的文档返回给用户。 所以在这个领域中经常有短文本匹配和长文本匹配两种经典场景, 就是当用户提的问题很简短的时候模型的效果是什么样子的, 而当用户使用了很长的一段文本来描述他的诉求时,模型返回的匹配效果是什么样子的。
意图识别模型
就如我们上面说的,系统需要先用一个多分类模型去识别用户问的这个问题是属于什么类型的,应该发往哪个子系统来回答。 只有属于知识问答这个意图的时候,才会发往知识引擎做文档检索/匹配。 而如何评估多分类模型, 怎么计算混淆矩阵,召回率精准率也建议看一下我这个系列第一篇帖子,科普常规模型评估指标那一块。
总结
可以看到现在的对话机器人就是 N 个人工智能模型的组合, 再加上一些工程手段来完成的复合场景。 这一次就先介绍在这个系统里知识引擎起到的作用以及测试人员一般要面对什么样的测试场景。 其实大家可以发现这里面的很多测试工作是繁琐的,人工的,很多就是纯纯的体力活。很多不了解人工智能的人会潜意识的觉得做人工智能的测试是很神秘的,技术含量非常高的,非常高大上的一种工作。 但其实很多时候并不是大家想的那个样子。