密级公开
版本10D.2

AICP NLU 资源管理 开发手册

3. 基本概念#

本章将介绍 NLU 资源的一些基本概念,在资源管理接口中的一些基础对象的结构也将在这里描述。

3.1 概述#

3.1.1 机器人#

机器人是 NLU 对话的主体,一次多轮对话是针对同一个机器人进行的。

机器人上会绑定多个技能,对话时会自动判断使用何种技能进行处理。

3.1.2 技能#

技能用于支持不同目的或者不同领域的机器人问答。AICP 10 NLU 平台提供如下不同类别的技能:

  • 问答型技能:有任务目标,但一般不需要把请求参数化
    • 问答库技能
    • 知识图谱技能
  • 任务型技能:
    • 意图对话技能: 有任务目标,需要把请求参数化,一般使用填槽方法即可
    • 场景对话技能:有任务目标,有比较复杂的流程,一般需要使用流程编辑的方法来定义对话过程
  • 其它
    • 闲聊技能:无任务目标
3.1.2.1 问答库技能#

问答库技能根据基于问答对的知识库来进行回答。通常就是检测知识库中和用户输入最匹配的问题,然后获得给用户的回复。

对话通常是单轮的,但有可能涉及到一些简单的上下文处理,例如指代消歧等。

答案通常是标准的、知识性的答案,但平台也允许对回复内容做进一步加工处理(例如进行变量替换)。

3.1.2.2 知识图谱技能#

知识图谱技能根据知识图谱(实体-关系-实体、实体-属性-值两类三元组),通过理解用户输入之后再查询知识图谱来获得给用户的回复。

对话通常是单轮的,但有可能涉及到一些简单的上下文处理,例如指代消歧等。

回复内容通常是模板,然后再根据知识图谱查询结果进行变量替换。

3.1.2.3 意图对话技能#

意图对话技能按照填槽、追问方式、确认等方式来和用户进行交互。

在一个意图中,通常定义了很多槽位。对话通常是多轮的,根据用户输入确认意图,进行填槽处理,并确认槽位信息。如果有未被填充的槽位,会进行追问(反问、澄清),直到所有必选词槽被填充。

回复内容可能是固定文本,也可能是模板。模板中的变量可能是对话过程中提取到的信息,也可能是在确认意图之后通过调用第三方服务或者云函数获取到的信息。

3.1.2.4 场景对话技能#

场景对话技能通过定义一个复杂的对话流程来完成多轮的对话,因此也称作场景对话技能。通常是采用可视化的方式,通过节点和连线来定义对话流程。

对话流程是完全自定义的,流程中可以定义任何条件分支、槽位/变量的处理、回复内容的处理等。

场景对话技能是十分灵活的,可以完成各种任务流程,实现业务目的。

3.1.2.5 闲聊技能#

目前闲聊技能是利用一个闲聊问答库实现的,因此基本等同于问答库技能。但后续有可能会有特殊的算法支撑,因此独立出来。

3.2 问题#

“问题”做为基础对象,都是从属于某个资源的子资源。

“问题”资源都定义为一个 Question 对象,其结构如下:

参数类型必选说明
textString标准问内容
extQuestionsArray of ExtQuestion扩展问

ExtQuestion 结构如下:

参数类型必选说明
textString扩展问内容
  • 词槽

QuestionExtQuestion 中的 text 项均为问题,中间可以有词槽表示,如下:

类型示例说明
不带词槽明天星期几?
意图词槽{date}星期几?仅用于意图的问题,且 date 为已被定义的意图词槽
因此可以从定义中反推出所用词典
命中后将实际内容赋值给变量 date
{明天:date}星期几?明天 为示例词,无实际意义
标准词槽{date@SYS.date}星期几?用于非意图的问题,绑定了系统词典 SYS.date
命中后将实际内容赋值给变量 date
{明天:date@SYS.date}星期几?明天 为示例词,无实际意义
匿名词槽{@ask}明天星期几?用于非意图的问题,绑定了自定义词典 ask
但无变量名,因此命中后无赋值操作,可用于一些辅助词
{请问:@ask}明天星期几?请问 为示例词,无实际意义
多个词槽{@ask}{date@SYS.date}星期几多个词槽组合,如果有不带词典的意图词槽
只能用于意图的问题
  • 模式码

问题的内容还支持模式码形式,也即以正则表达式的形式来表示问题,在匹配时也使用正则匹配的方式来进行。模式码问题总以 RE: 开头,例如 RE: ^(哈喽|你好|您好|你好呀|你好哇|你好啊)$

  • 示例
{
"text": "问题内容",
"extQuestions": [
{
"text": "扩展问1"
},
{
"text": "扩展问2"
}
]
}

3.3 回复#

“回复”做为基础对象,是从属于某个资源的子资源。

“回复”资源定义为一个 Response 对象,其结构如下:

参数类型必选说明
answersArray of Answer答案列表,一个回复可以有多个答案
通过标签筛选来返回某一条答案
returnTypeString当通过标签筛选后仍有多条答案时的返回策略
FIRST (缺省):返回第一个答案(id较小者)
RANDOM:随机返回一个答案

Answer 结构如下:

参数类型必选说明
typeString答案类型,参加下面的表格
contentString答案的具体内容
cmdString自定义串,通常用于指示客户端完成的动作
tagsArray of String答案所绑定的标签
  • 回复类型

type 可以指定的答案类型如下:

类型说明示例
TEXT纯文本请问你想订哪天的机票?
TTSTTS 文本,其中可能带有 SSML 标签或自定义标签请问你是〖曾志伟〗先生吗?
AUDIO音频(录音)音频URL
VIDEO视频视频URL
HTMLHTML 格式的内容<h1>标题</h1><link ref="xxxx"></link>
RECOMMEND推荐知识(菜单知识), json 表示{"start":"答案的前置提示语", "menuIds": [1111, 1112], "end":"答案的后置提示语"}
  • 推荐知识

RECOMMEND 类型的答案有两种可能,一种是在知识资源维护时,就将答案设为此类型。此时 content 中存储的 menuIds 是标准问 Id 列表。无论是问答库技能的问答对中的回复,还是任务型技能中流程中使用了此种类型回复,那么就会直接做为答案输出。但在最终输出时,会将 menuIds 转换为 menu,也即将 id 输出为问题内容。

另外一种可能是在问答库技能中,如果最高匹配度的问题其匹配度仍然低于“直接回答阈值”时,会将一定阈值范围内的多个匹配问题直接组织成 RECOMMEND 类型的答案。此时的输出中 "menu" 中已经是问题的文本。

由于问题中可能带有词槽,因此“推荐知识”输出时,问题内容要经过去词槽处理。去词槽处理时,优先使用示例词,如果没有示例词,则使用词槽名称,如果仍然没有,使用词典名称。

  • 变量替换

contentcmd 中,都可以指定变量名称,在返回时会使用实际的变量值替换。变量名称使用 {{}} (双大括号)包围,支持变量名称前后有空格。例如:

您的余额为{{ balance }},会被替换为 您的余额为2304.68元

从{{slots.fromCity.normValue}}到{{slots.toCity.normValue}}的机票已经订购成功,会被替换为 从上海到呼和浩特的机票已经订购成功

暂不支持数组变量的填充。也可以考虑直接支持 mustache 模板语言

  • 标签绑定

tags 是一个字符串数组,每一项都定义了一个标签。在一个 Answer 上可以打上多个标签,这些标签可以属于一个或多个标签组,但如果某个标签组是互斥的,则此标签组下的标签只能有一个。标签的格式都是 "tagGroup:tag" 的形式,例如 "channel:wechat"

假设 channel 是互斥的标签组, color 是不互斥的标签组,则如下标签列表都是合法的:

  • ["channel:wechat"]
  • ["channel:wechat", "color:red"]
  • ["color:red", "color:blue"]
  • ["channel:wechat", "color:red", "color:blue"]

但如下标签列表是不合法的

  • ["channel:wechat", "channel:phone"]
  • ["channel:wechat", "channel:phone", "color:red"]

关于标签筛选原则,请参见《对话接口开发手册》

  • 示例
{
"returnType": "RANDOM", // RANDOM or FIRST
"answers": [
{
"type": "TEXT", // TEXT, TTS, AUDIO, VIDEO, HTML
"content": "{$name},您好,有什么可以帮您的?",
"tags": [ // 可选,但必须是有效的标签组和标签,使用 `标签组:标签` 格式
"channel:wechat", "color:red", "color:blue",
]
},
{
"type": "TEXT",
"content": "xxxx",
"cmd": "xxxx", // 可选
"tags": [ // 可选,但必须是有效的标签组和标签,使用 `标签组:标签` 格式
"channel:text"
]
}
]
}

3.4 变量#

在对话中,在对话上下文中维护了一组变量,在流程中可以读取或保存,并加以使用。

3.4.1 变量规范#

变量的命名规则:

  • 只允许英文大小写字母、数字、_,必须以英文字母或 _ 开头。
  • 最长32个字符

变量的取值只能为如下几种情况:

  • 三种基本的类型,基本同 JSON 定义
    • String: 由 " (双引号) 包围的任意Unicode字符的集合,使用反斜线转义
    • Number: 数值类型,含整数或浮点数,支持负数、科学计数法等,不支持十六进制、八进制等格式
    • Boolean: 布尔取值,只能为 true, false
  • 上述三种基本类型的数组(10D.0暂时不支持数组变量)
    • [(左中括号)开始,](右中括号)结束。元素之间使用 ,(逗号)分隔
    • 一个数组的所有元素必须是同一种基本类型
  • 对象
    • 可以使用 JSON 表示法来对对象变量进行赋值(10D.0暂不支持)
    • 使用"." 的方式访问子域

3.4.2 变量类型#

在系统中的变量包括如下几种类型:

  • 全局变量 (global)
  • 词槽变量 (slots)
  • 用户变量 (user)
  • 本轮变量
3.4.2.1 全局变量#

全局变量都放在 global 对象下面,使用 global. 前缀进行访问。包括预置全局变量和自定义全局变量。

预置全局变量是由系统填充的,因此对于用户来说是只读的。预置全局变量包括如下:

名称类型说明
appKeyString应用标识
tenantObject租户信息
tenant.idString租户Id
tenant.nameString租户名称

自定义全局变量是指在各处理环节(包括问答库技能、图谱技能、意图技能中的自定义处理步骤以及场景技能中的处理节点)中进行赋值时,新产生的变量,如果此变量以 global. 开头,则表示是自定义的全局变量,其值会一直保留。自定义变量只能在 global 下面定义,不支持多级对象的定义。

3.4.2.2 词槽变量#

所有命中的问题中如果有词槽,则会进行填槽操作,也即将词槽的实际内容复制给以词槽的名称命名的变量(匿名词槽除外)。这些变量都称为词槽变量,都放在 slots 对象下面,使用 slots. 前缀进行访问。

例如:假设问题是 “我想买一张从{formCity@SYS.city}到{toCity@SYS.city}的机票”,实际用户输入是:“我想买一张从上海到呼市的机票”,则会有如下变量被赋值:

slots.fromCity.value = "上海"
slots.fromCity.normValue = "上海"
slots.toCity.value = "呼市"
slots.toCity.normValue = "呼和浩特"

问答型技能的词槽变量仅在本轮对话中有效(在对话接口的 context 中会返回,但下轮对话不再有这些变量)。

任务型技能的词槽变量一旦被填充后,则会在会话上下文中一直存在,直到退出此技能。如果在流转过程中,如果跳转到其它问答型技能,即使不自动恢复,词槽变量也会保留几轮。如果是跳转到其它任务型技能或者是直接分派到其它技能(另一个场景技能的无条件入口),那么此任务型技能的词槽变量也会被清空。

如果在会话中赋值的词槽变量之前已经被赋值过,那么其值会被覆写。因此,用户需要规划词槽变量的名称,以保证不同含义的词槽使用不同的词槽名称。

这个场景还是需要的

对于意图技能来说,所有定义的词槽会被系统创建出来,如果尚未赋值,则变量为空 nil。用户可以对其进行赋值,例如根据用户传入变量 user.city 来赋值词槽变量 solots.fromCity.value

其它技能中的问题中的词槽,只会创建出被命中问题的词槽变量。用户可以修改这些词槽变量的值,但无法创建新的词槽变量。

3.4.2.3 用户变量#

用户变量是指请求对话接口(包括 start_session 或者 dialog 接口)时通过请求参数传入的变量 (userVars),在系统内部都转化为用户变量,使用 user 前缀进行访问。

用户变量都是只读的,只能读取,不能覆写。多轮对话时,用户变量都是当前这一轮传入的变量,之前传入的变量不会保留。如果需要保留,可以将其赋值给某个自定义的全局变量。

3.4.2.4 本轮变量#

没有任何前缀的变量都是本轮变量,仅在本轮对话期间存在,包括一些预置的本轮变量以及自定义的变量。

预置变量对于用户来说是只读的。预置的本轮变量包括:

名称类型说明
hitQuestionObject本轮命中的问题
hitQuestion.idInteger本轮命中的问题Id
hitQuestion.labelString如果本轮命中的是“任务问题”时,其标签值
hitQuestion.textString命中问题的文本,可能是标准问也可能是扩展问
hitQuestion.scoreNumber命中问题的分数,[0.0-1.0]
hitQuestion.extObejct命中问题的扩展文信息,如果命中的是标准问,无此项
hitQuestion.ext.idInteger命中的扩展问Id
hitQuestion.ext.textString命中的扩展问文本

自定义本轮变量是指在各处理环节(包括问答库技能、图谱技能、意图技能中的自定义处理步骤以及场景技能中的处理节点)中进行赋值时,新产生的变量。目前自定义变量不支持以多级对象的方式进行定义。

3.4.3 变量使用#

在对话中,可以在如下情况下使用变量:

  • 使用变量进行比较操作进行节点跳转
  • 在回复中将引用变量替换为变量的值
  • SIMPLE 类处理步骤中使用变量进行条件判断,并对变量进行赋值
  • WEBAPI 类处理步骤中将应用变量替换为变量的值
  • FAAS 类处理步骤中的云函数中使用变量

3.4.4 变量替换#

变量替换出现在两个地方:

  • 在回复中将引用变量替换为变量的值
  • WEBAPI 类处理步骤中将应用变量替换为变量的值

都使用 {{varname}} 的方式定义,将来也可以考虑支持 mustashe 模板语言。

3.5 比较条件#

比较条件用于判断变量是否满足一定的条件,主要用于下面两个地方:

  • 场景技能中的分派节点,根据比较条件来确定分派分支
  • 简单类型的处理步骤中的比较条件

比较条件支持如下几种方式:

条件含义示例
等于(==)可以用于各种基本类型的等于比较var == 3
var=="abcd"
var==true
array_var[0]=="dog"
slot.fromCity="上海"
不等于(!=)可以用于各种基本类型的不等于比较var != 3
大于(>)
小于(<)
大于等于(>=)
小于等于(<=)
用于数字类型的字段比较var < 10
var >= 100.02
包含判断字符串是否包含子串substr(str_var, "abc")
判断数组是否包含某个元素contain(array_var, "abc")
contain(array_var, 25)
正则表达式用于判断参数值是否和正则表达式匹配var ~= /\d+/
数组是否为空判断数组是否为空is_empty(arra_var)
变量是否有效判断变量是否有效(不存在或者空对象都认为无效)is_valid(var)

10D.0暂不支持数组变量,因此上面和数组相关比较条件都暂不支持

比较条件支持两个变量之间的比较,也支持复杂条件与(&&)、或(||)、非(!) 和左右括号等,

当比较条件为“空”时,表示“无条件”,也即总是满足,在“处理步骤”中通常会出现。

3.6 处理步骤#

“处理步骤”做为基础对象,都是从属于某个资源的子资源。

处理步骤就是对上下文中的变量进行进一步的处理,包括修改当前变量或者给新变量赋值。

“处理步骤”定义为一个 Processor 对象,其结构如下:

参数类型必选说明
typeString处理节点类型
SIMPLE(缺省): 简单处理类型
WEBAPI: 调用第三方的WebAPI接口
FAAS: 调用云函数(脚本代码)
contentObject处理的具体内容,根据类型不同有不同的含义

type 可选的类型如下:

类型含义说明
SIMPLE简单处理定义一些简单的条件赋值操作
WEBAPI调用外部接口进行 HTTP/HTTPS的Web调用
FAAS云函数FAAS (Function as a Service),用户配置一段函数,
直接在服务器端执行,因而无需提供自己的服务器和访问地址。

3.6.1 SIMPLE#

typeSIMPLE 时,content存储了其判断条件以及满足条件时候的操作。可以定义多组判断条件,每个判断条件下也可以定义多个操作(目前这些操作只能是赋值操作)。

content 定义如下:

参数类型必选说明
opsArray of Operation一组条件操作

Operation 定义如下:

参数类型必选说明
conditionString比较条件,用字符串表示,为“空”表示无条件执行
evalsArray of String多个赋值操作,每个操作用一个字符串表示

consition 支持的比较条件参见 比较条件

  • 示例
{
"type": "SIMPLE",
"content": {
"ops": [
{
"condition": "param1 >= 3",
"evals": [
"param2 = 8",
"param3 = param1",
]
}
]
}
}

3.6.2 WEBAPI#

typeWEBAPI 时,此时 content 存放访问方式、访问的URL、额外的HTTP头、Body内容,这些定义的内容都可以带变量的占位符,在实际发送时会被参数的实际值替换。响应的结果将会被赋值给一个指定的变量。

此时 content 定义如下:

参数类型必选说明
methodStringHTTP 方法,缺省为 POST
urlString访问的URL地址
headersArray of String额外的 HTTP 头
bodyString发送的包体
resultObject响应结果的赋值变量

变量名称使用 {{}} (双大括号)包围,支持变量名称前后有空格。例如:

{
"type": "WEBAPI",
"content": {
"method": "POST",
"url": "http://www.example.com/test/{{global.param1}}/info?foo={{param2}}",
"headers": [
"X-Custom-Info: {{slots.corp.normValue}}"
],
"body": "{ \"bank\" : \"{{user.bank}}\", \"balance\" : {{balance}} }",
"result": "webapiResult"
}
}

替换时,对于字符串类型的变量值,不会自动加上双引号。如果需要在 body 的JSON串中给出双引号,需要写在 "body" 定义中。

暂不支持数组变量的填充。也可以考虑直接支持 mustache 模板语言

假设有变量如下:

global.param1 = "ABC"
param2 = 52003
slots.corp.normValue = "Apple"
user.bank = "ICBC"
balance = 2222

则上述的 WebAPI 请求将会按照如下方式发送:

POST http://www.example.com/test/ABC/info?foo=52003
X-Custom-Info: Apple
{ "bank": "ICBC", "balance": 2222 }

WebAPI调用后的返回结果,会赋值给 result 指定的本轮变量中,此变量是一个JSON对象,其结构如下:

参数类型说明
statusInteger响应的状态码,通常 200 为正常,其它为错误
responseString/Object响应的包体内容,如果返回为JSON格式,会以JSON对象的方式存放
如果是文本/XML格式,会以字符串方式存放
其它格式,置为 null

响应包体的格式通过 Content-Type 判断,如果是 application/json 则作为 JSON 格式,如果是 text/plain, text/xml, text/html , application/xml 则作为字符串格式。其它都设置为 null

需要控制访问 WebAPI 接口的时间,如果超长(缺省设为10s,可配置),则需要终止并返回错误。

3.6.3 FAAS#

10D.0 中暂不支持FAAS类型的处理步骤

typeFAAS 时,则用户会定义一段代码并在服务器端直接执行。代码可以访问上下文信息中的所有变量,例如 global.appKey, user.province, slots.fromCity.value, tempVar等。

处理过程也就是在上下文信息中添加新变量(给新变量赋值),或者更新现有变量的值。

此时 content 会存放编程语言信息和源代码。结构定义如下:

参数类型必选说明
langString编程语言信息,缺省为 javascript
codeString源代码

编程语言目前只支持 javascript,源代码需要进行转义。

{
"type": "FAAS",
"content": {
"lang": "javascript",
"code": "if (user.province=\"江苏\") {\ncapital=\"南京\"; \n}"
}
}

需要控制 code 所代表的代码执行的时间,如果超长(缺省设为10s,可配置),则需要终止并返回错误。

3.7 词典#

词典用于表示同一类词条的集合。但在不同的场景下,有如下类型的词典:

  • 系统词典
  • 自定义词典
    • 标准词典
    • 动态词典
  • 简单词典

其中,系统词典自定义词典都是用于词槽绑定的。 简单词典 则是用于其它目的,例如停用词、敏感词等。

3.7.1 词槽绑定#

词槽的概念可以参见上面“问题”定义中对词槽的介绍

每个词槽必须绑定一个词典,可以是系统词典,也可以是自定义词典。

不同的槽位可以绑定到同一个词典上,例如在问题是 “我想买一张从{formCity@SYS.city}到{toCity@SYS.city}的机票”{fromCity} (出发城市) 和{toCity} (到达城市) 都是绑定到系统词典 SYS.city 上。

除了匿名词槽外,当进行问题匹配时,会自动进行词槽变量的填充。此时词槽变量的 value 是原句中的内容, normValue 是归一化值(系统词典)或者标准词(自定义词典中每个词条的第一个词语)。

3.7.2 代表词#

无论是系统词典还是自定义词典,也无论是自定义词中的标准词典或者动态词典,都需要定义一个代表词。代表词的作用是用于在内部计算时替代词槽内容的。

代表词在词典创建时指定,一般不会被后续修改。

3.7.3 系统词典#

系统词典是系统预置的,不可修改。系统词典在使用时,都带有 SYS. 前缀。

目前支持如下系统词典:

名称解释例子归一化值
SYS.number提取数字(包括中文数字和阿拉伯数字),不包含负数一百二十五、100、零点三125, 100, 0.3
SYS.phone提取电话号码1311234567813112345678
SYS.ordinal提取序号第一、第二1,2
SYS.age提取年龄15 岁、30 了、五十岁15,30, 50
SYS.money提取金额三十块六角七分, 五百澳币,七千五百零四美元RMB 30.67, AUD 500.00, USD 7504.00
SYS.date提取日期明天、下周一、三月二十号、明年六月份、国庆节、2017-10-52017-11-11
SYS.time提取时间上午九点、中午 12 点半、傍晚八点一刻09:00:00, 12:30:00, 20:15:00
SYS.duration提取时间段15分钟,3小时25分钟,一小时零五分钟00:15, 03:25, 01:05
SYS.date-duration提取日期段过去三天,下周,这周末2020-07-21~2020-07-23, 2020-07-27~2020-08-02
SYS.country提取国家中国、美国中国、美国
SYS.province提取国内省份山东、河北山东、河北
SYS.city提取国内城市北京、呼市北京、呼和浩特
SYS.address提取地址,归一化值会通过地址库进行补全(地址补全暂未实现)西三旗北京市海淀区西三旗
SYS.person提取人名张三张三
SYS.org提取机构名国务院国务院
SYS.fight提取航班号CA989CA989
SYS.train提取火车车次G2403G2403
SYS.combine提取通用字母数字符号组合a12、B123cd、@456efa12、B123cd、@456ef
SYS.any_{x}_{y}匹配任何字符,在x~y字符之间

SYS.any 系统词典可以匹配任意字符,但可以规定最小和最大匹配字符数,例如 SYS.any_2_5 表示匹配2到5个任意字符。

当词槽使用系统词典时,提取过程除了普通的词条匹配外,也可能会用到命名实体识别等算法来进行处理。当检测到词槽时,还会对检测到的原始文本进行归一化的处理,也即表示成规范的形式。当填槽时,词槽变量的 normValue 会被赋值为归一化之后的结果。

3.7.4 自定义词典#

用户可以定义自定义词典,也可以用于词槽的绑定。自定义词典又分为标准词典和动态词典。

  • 标准词典

标准词典,就是一组词条,每个词条上都包含一个标准词和多个同义词(也即别称)。例如:

北京\t帝都\t首都
昆明\t春城
呼和浩特\t呼市

每个词条的第一个词语都是标准词,其后可以接0个或多个同义词。词汇之间以 \t 隔开。填槽时,词槽变量的 normValue 会被赋值为标准词。

  • 动态词典

动态词典是指在同样的词典名称下可以包含多个词条组(对应不同的动态类别),并规定了相应的使用条件。具体来说,就是根据当前上下文中的变量实际的值来选取对应动态类别的词条组。每个动态类别对应的词条组同标准词典。

可以定义根据不同的应用来选择不同的词条组。例如,针对一款外卖应用,当用户查询可以点的菜单时,可以通过请求时传入用户变量 city,来使用不同的菜单。

  1. 定义一个动态词典 dish,其匹配变量名称 (matchVar) 为 user.city
  2. 为每个城市定义一个 “动态类别”,其匹配值 (matchValue) 分别为 beijing, shanghai, hangzhou 等等
  3. 在每个动态类别下会定义此城市对应的菜单
  4. 当用户请求时,会传入用户变量 city,此时就会根据其值选取具体的菜单做接下来的匹配。

再比如,通过 global.appKey作为一个动态词典的匹配变量,就可以实现根据应用不同来使用不同的词典。

3.7.5 简单词典#

还有一类词典,就是简单词典,只是一些词条的列表,不需要代表词,一个词条中只包括一个词,因此也没有标准词、同义词的概念。

这种简单词典主要用在停用词、敏感词等地方。

3.8 问答库技能#

3.8.1 问答库资源 - 问答对/问答目录#

问答库技能的资源组成比较简单,就是由很多的问答对组成。

每个问答对都包括如下内容:

  • 一一对应的 问题回复
  • 启停状态
  • 生效和失效时间

一个租户下的所有问答库技能使用的问答对可以组织成多级目录结构,称为“问答目录”。首级节点一般又叫做“领域”或“问答领域”。在每个目录节点上,都可以包括很多的问答对。

一个问答库技能可以挂接到任何一个问答目录节点,此时在此技能中使用的问答对会包括了此节点和其下所有递归子节点的问答对。但在使用时,会同时查看此问答对是否启用和是否生效。

3.8.2 处理流程#

如果在机器人分派技能时进入了某个问答库技能,就是根据此技能挂接的问答目录节点,查找此节点和所有递归子节点中包括的问答对,并将用户输入和所有的问题进行匹配,并按照匹配度进行排序,找到匹配度最高的问题。如果此匹配度大于机器人中所定义的一个阈值,那么就认为“命中”此问题,然后得到其对应的回复。

如果匹配度比直接回答的阈值小,但是仍然大于另外的一个下限阈值,则这两个阈值之间的多个问题会组成“推荐问题列表”并返回,而不是返回最高问题对应的问答对中的答复。

如果在请求中定义了筛选标签,则需要在回复中筛选出满足标签条件的答案,如果最终的答案仍有多个,则按照回复的返回类型挑选第一个答案或者随机挑选一个答案。如果答案中有变量占位符,会进行替换。

支持在回复前进行“自定义处理步骤”的执行。

问答库技能可以支持“多意图”。“多意图” 是指一个长问题中可能包括了多个子“问题”,此时会按照组合回复的方式将多个问题对应的答复都返回。

3.9 知识图谱技能#

10D.0 中暂不支持知识图谱技能

3.9.1 知识图谱资源#

3.9.2 处理流程#

3.10 意图技能#

3.10.1 意图资源 - 意图/意图词槽#

意图技能的资源是由多个意图组成。

每个意图的定义如下:

  • 入口问题(又称“用户表述”)
  • 意图词槽列表
  • 意图的确认话术
  • 无法理解时的重试话术
  • 最大重试次数
  • 超过重试次数后的失败话术
  • 意图确认后的处理步骤
  • 最终回复
  • 无法理解时是否允许跳转到其它技能
  • 跳转到问答型技能完成答复后,是否立即返回
  • 立即返回后,是否要重复上次话术

意图词槽的定义如下:

  • 词槽名称,也称槽位,填槽时作为槽位变量的名称
  • 绑定词典
  • 优先级
  • 是否必须
  • 追问话术(又称“澄清话术”)
  • 确认话术

上述所有的“话术”实际上都定义为回复

一个意图对话技能中的资源包括了多个意图的定义。例如“星座”是一个意图会话技能,下面可以有“幸运数字”、“幸运颜色“等意图。或者”备忘录“是一个意图会话技能,下面可以有“订闹钟”、“取消闹钟”等意图。

在一个意图对话技能中可以流转,此时多个意图如果定义了相同的词槽名称,此词槽变量是可以共享的。

3.10.2 处理流程#

用户输入 和意图技能所支持的多个意图中的某个意图的“入口问题”匹配度最高时,就进入到这个意图技能中,并将当前意图设为此意图。

“入口问题”中一般都会有“意图词槽”的表示。在进行问题匹配时,就会根据所命中问题(标准问或扩展问)的词槽进行填槽工作,也即将上下文信息中对应的词槽变量填上 用户输入 中实际的值。

然后会检查此意图的词槽列表中所有词槽变量的填充情况,如果发现有必须的词槽但没有被赋值时,就会根据“优先级”和定义的词槽“追问话术”(例如 请问你要去哪个城市?)进行追问。

当完成所有必须词槽的填充后,也会按定义进行整体“意图确认话术”进行确认(可选),然后会按照 “最终回复” 进行回复。支持在回复前进行 “自定义步骤” 的执行,例如可以调用 WEBAPI 方法来查询实际的天气结果。

所有的话术和最终回复都定义为回复,因此都会有标签筛选和变量替换的步骤。

当完成“最终回复”后,仍然优先在此技能中流转。下一轮会话时仍在此意图技能中检查用户输入,以便能在保留相关变量的情况下优先处理此意图技能中其它意图。

例如:“星座”技能中包含了“幸运数字”和“幸运颜色”两个意图。

User: 今天的幸运数字是什么?
Robot: 请问您是几月出生的?
User:8月
Robot:您今天的幸运数字是3 // 此时“幸运数字”的意图已经结束,但不退出“星座”这个意图技能
User:那幸运颜色呢?
User:幸运颜色是红色 // 此时会继承“出生月份”、“查询哪天”的变量,不会再次追问

当在“追问”或者“确认”时,或者在“最终答复”后,优先检查本技能的其它意图时,发生了无法理解的情况,可能会发生技能间跳转。请参见“机器人-技能间跳转”

3.11 场景技能#

3.11.1 场景资源 - 场景/节点#

场景技能主要是使用节点和节点间的连线来定义对话流的,因此资源中主要就包括了各个节点和其关系的定义。

场景中的节点分为如下五类:

  • 入口节点(entry)
  • 理解节点(understand)
  • 分派节点(dispatch)
  • 处理节点(process)
  • 回复节点(response)
3.11.1.1 入口节点#

入口节点是整个场景技能最开始进入的地方。一个场景最多只能有一个“无条件入口节点”,但可以有一个或多个“条件入口节点”。

  • 无条件入口节点

无条件入口节点,只能从机器人的 “开场白”指定此技能时进入,或者其它分派节点时直接分派到此技能时进入。

  • 条件入口节点

条件入口节点会定义一组“任务问题” 作为入口条件。当命中其中某个“任务问题”时(和用户输入的匹配度最高),就可以进入此场景对话技能。

“任务问题”目前只用于场景技能,和普通问题相比,增加了一个“标签”的定义。在命中问题的同时,也会将变量 hitQuestion.label 置为此标签。之后就可以利用此变量按照标签进行分派。使用 histQuestion.id (问题ID)也可以进行分派,但以后如果进行技能的导入导出的话, id 可能会发生变化。因此最好利用 label 来进行分派。

3.11.1.2 理解节点#

理解节点也会定义一组“任务问题”,当命中某个“任务问题”时,会将 hitQuestion 置为此问题。其后就可以根据此命中问题进行分派。

当“任务问题”的最高匹配度也低于机器人定义的“场景问题匹配度阈值”时,表示没有命中任何“任务问题”,也即出现了“无法理解”的情况,此时 hitQuestion 会为空。

3.11.1.3 分派节点#

在分派节点上可以定义多个跳转条件,如果条件满足则跳转到某个子节点,也可以定义为跳转到某个其它技能(只能是跳转到另一个场景技能的无条件入口)。

跳转条件的定义参见 比较条件,规定了某个变量是否满足条件。常见的根据之前“理解节点”中命中的“任务问题”进行分派,就可以通过 hitQustion.label 进行判断。

3.11.1.4 处理节点#

处理节点定义了一个自定义的处理步骤,来对上下文信息中的变量进行处理。实际上就是定义了一个处理步骤 对象。

3.11.1.5 回复节点#

回复节点定义了要回复给用户的内容,作为对话接口的输出。实际上就是定义了一个回复 对象。

3.11.1.6 节点连接#

上述节点可以任意编排,但有以下限制。

  • 只有分派节点可以连接 0-多个后续节点,其它节点都是0-1个后续节点。
  • 一个场景技能可以有多个入口节点,但最多只能有0-1个“无条件”入口节点。
  • 任何节点都不能连接到“入口节点”。
  • 有条件入口节点和理解节点通常不会直接连接一个理解节点。(这意味着等待用户输入后,不做什么处理马上又等待另一个用户输入)

如果节点没有后续节点,流转到此处时表示跳出此场景技能。

3.11.2 处理流程#

有如下情况会进入场景技能:

  • 刚开始会话时,机器人的“开场白”定义为此场景技能的“无条件入口节点”
  • 某个场景技能的分派节点直接分派到此场景技能的“无条件入口节点”
  • 没有当前技能(会话刚开始或者之前的技能已退出),此时由机器人分派,而此场景技能的某个“条件入口节点”的某个“任务问题”匹配度最高,因而进入此场景技能的“条件入口节点”
  • 在其它意图技能或者场景技能下无法理解当前的“用户输入”,而且配置为“允许跳转到其它技能”,此时由机器人进行检查,而此场景技能的某个“条件入口节点”的某个“任务问题”匹配度最高,因而进入此场景技能的“条件入口节点”

进入场景技能后,会按照节点和连线进行流程的流转,只要流转到了一个理解节点,那么就会返回(可以认为是在等待下一轮的“用户输入”)。如果后继节点为空,则表示退出此技能,此时也会返回。

如果在流转过程中有回复节点,那么就会将回复节点定义的回复内容返回给用户。如果经过了多个回复节点,那么多个节点的回复内容会作为组合回复输出。如果没有经过任何回复节点,则使用机器人的“兜底话术”进行回复。针对回复也有标签筛选和变量替换的步骤。

如果在当前“理解节点”中没有命中任何“任务问题”,也即出现“无法理解”的情况时,此时只会将 hitQuestion 设为空,并不做其它处理操作。后续在分派节点时可以将其作为“无法理解”的判断条件进行分支处理。

如果走到分派节点时没有命中任何分支,可能会发生技能间跳转。请参见“机器人-技能间跳转”

3.12 机器人#

机器人是 NLU 对话的主体,一次多轮对话是针对同一个机器人进行的。

3.12.1 机器人资源#

机器人上会绑定多个技能,技能可以是多个不同类型的。(除了只能绑定一个“闲聊”技能外,其它类型的技能均可绑定多个。 10D.0 中暂不支持闲聊技能)。

绑定不同技能时,会为不同技能指定一些相关的配置。这些配置是放在机器人中的,因此不同的机器人即使绑定同一个技能时,可以指定不同的配置。

还有一些配置是属于机器人本身的,包括:

  • 开场白
  • 兜底话术
  • 敏感词及对应话术
  • 任务型技能遗忘轮数

3.12.2 处理流程#

当发起和一个机器人的对话时,将建立起一个会话。在会话中,将会保留上下文信息(也即除本轮变量外的各类变量信息),在多轮对话中,这些上下文信息将会被保留。

3.12.2.1 开场白#

机器人对话的发起方向包括:

  • 用户主动发起的(客服、导航)
    • 连接到机器人时,机器人会有一个 “欢迎语”,欢迎语中一般是普通寒暄,也可能包括“如何使用”的帮助信息
    • 也可以是在用户输入第一条请求时,才发送给机器人,此时机器人可以跳过欢迎语
  • 由机器人发起(外呼)
    • 连接到机器人,机器人发起一个 “开场白”,此开场白里一般就包含主动向用户询问的问题

当会话创建时,总是去查看机器人是否有“开场白”配置。开场白可以配置为一个简单的回复,或者是一个场景技能。

如果是一个简单回复,那么直接进行回复。

如果是一个场景技能,此场景技能必须有一个“无条件入口节点”。此时会从“无条件入口”进入,然后正常按照“场景技能”的处理流程进行节点的流转。如果其中途径“回复节点”,会作为回复给出。使用场景技能作为“开场白”的有点是在回复之前可以有处理节点,得到某些变量值(比如根据 user.userid 来获得用户姓名、性别等),然后再进行回复中的变量替换,以达到为不同用户生成不同的回复的目的。

“开场白”的场景技能通常是独立的,和绑定的技能无关。通常情况下,在“开场白”场景技能中走完回复节点就从此技能中退出。后续正常流程时只关注绑定的技能。

如果没有开场白配置,或者“开场白”场景技能流转时,并没有途经“回复节点”,那么将不会给出回复。这样也能支持“跳过欢迎语”的场景。

3.12.2.2 等待技能#

在建立起一个会话,或者完成一轮对话后,机器人可能会处在一个“等待技能”上,也可能停留在技能之外。 “等待技能”总是任务型技能,不会在一个问答型技能上“等待”。

“等待技能”通常都是下一轮的“入口技能”。

3.12.2.3 技能外流程#

如果停留在技能之外:

  1. 计算机器人绑定的所有技能的入口问题(问答库技能挂接的所有问答对的问题,意图技能的入口问题,场景技能的“入口节点”挂接的“任务问题”)和用户输入的匹配度
  2. 如果某个技能中入口问题最大的匹配度都低于对应技能的“匹配度阈值”的话,将直接排除掉
  3. 剩余的问题按照匹配度进行排序,找到匹配度最大的问题(后称命中问题)所属的技能
  4. 如果命中问题所属技能是问答库技能,需要查看其匹配度是否大于问答库技能“直接回答阈值”,
    • 如果大于,直接回答命中问题对应的回复,赋值 hitQuestion, slots 变量
    • 否则,找出匹配度最大的N个标准问作为 “推荐回答”
  5. 如果所属技能是意图技能,则进入意图技能,并将当前意图设为命中问题对应的意图,赋值 hitQuestion, slots 等变量
    • 然后根据此意图的词槽定义进行追问等操作
  6. 如果所属技能是场景技能,则进入场景技能,赋值 hitQuestion, slots 变量
    • 然后在此场景中进行节点流转
3.12.2.4 技能中流程#

如果等待在技能之中,只能停留在任务型技能中,也即意图技能或场景技能。此时都按照各自的技能内流程进行相关操作。

3.12.2.5 技能间跳转#

机器人中间多个技能之间跳转的流程发生在如下两种情况下:

  • 在意图技能中“追问”或者“确认”时,发生了无法理解的情况
  • 在场景技能中分派节点无法找到命中的分派分支时(注意,场景技能中“无法理解”也只是一个分派判断条件,并不直接做这里的处理)

当发生这两种情况时,都会看技能中的配置“是否允许跳转到其它技能”,如果允许跳转其它技能,那么会检查是否命中其它技能的入口意图,包括本技能“入口问题”(意图技能)或者“有条件入口节点”的问题(场景技能)。如果不允许跳转其它技能,则同下面的“不能命中问题”。

  • 能命中问题

如果能命中(也即首选的匹配度也足够高),将会跳转到命中问题对应的技能中,并进行相关处理。

如果跳转到的是问答型技能(包括问答库技能和知识图谱技能),当问答型技能回复完毕后,会根据定义的“是否立即返回” 来决定是否直接返回到本意图技能

如果是立即返回,根据“是否要重复”来看是否还要重复上次的话术。

如果不立即返回,则机器人等待在“技能之外”,但此时场景技能和相关变量也会保留几轮。在后续几轮中,都要优先检查是否能命中保留的技能中的当前问题。如果满足时,优先跳回此技能;不满足时,按照“等待在技能之外”来检查所有其它技能的入口意图。

当保留的轮数大于机器人配置中的“遗忘轮数”,才不再保留此技能及其相关的变量信息。如果是进入了另一个“任务型”技能,则之前保留的技能机器相关变量信息总是会立即清除。

  • 不能命中问题

如果没有命中任何问题(匹配度都很低),会使用“重试话术”(例如 对不起,我没有理解你的意思,请再说一遍)进行答复,如果没有定义定义“重试话术”,则此时会重复上次的回复话术。也有选项支持同时给出 “重试话术”+“重复话术”。

如果重试次数(每次无法识别开始累计,碰到理解了会重置)超过定义的“最大重试次数”,则此意图会失败,会回复“失败话术”,然后退出此技能。

3.12.2.6 闲聊技能#

当机器人绑定了闲聊技能时,在判断进入哪个技能的判断时,闲聊技能的优先级是最低的。也即如果在所有的技能“入口问题”匹配度都很低时,才会进行“闲聊技能”的匹配。此时如果在闲聊技能的匹配度足够高,则进入闲聊技能。如果闲聊技能的匹配度仍然不高,则表示不能命中任何问题。

目前10D.0尚不支持闲聊,因此现在不用考虑

3.12.2.7 兜底话术#

一轮交互,如果没有产生任何“回复”,此时如果定义了“兜底话术”,会使用兜底话术作为回复。注意,“开场白”中如果没有出现“回复”,不会应用“兜底话术”。

3.12.2.8 敏感词及对应话术#

一个机器人还支持配置多组敏感词,每组敏感词(由一个“简单词典”表示)有一个对应的话术。

敏感词主要是针对设置的涉黄、涉政、粗口等词汇,在机器人级别直接过滤,不再进行语义理解。也即敏感词处理是在每轮对话进入正式流程之前进行的,当判断用户输入中有敏感词时,就会使用对应的话术进行回复,而不会进入正式的流程。此轮会话会计入会话轮数,但是如果当前处在任务型对话的重试中,不影响“重试次数”。

敏感词支持正则表达式。(暂不考虑

3.12.3 机器人的测试#

NLU 资源管理服务会在机器人的资源发生变化时,将资源存储到数据库(MySQL)中,但同时也会在内存中维护对应的资源。这是为了能够对机器人进行快速的即时测试,及时体验资源修改对机器人对话效果的影响。

即时测试采用和NLU 能力服务一样的 HTTP 对话接口即可,此时测试的都是最新的机器人效果。

NLU 资源管理服务也支持针对某个发布的特定版本的机器人资源包进行测试,此时只需要在对话接口中指定机器人资源的“发布ID”即可。

3.12.4 机器人发布及上线#

NLU 资源管理服务提供机器人发布、上线、下线、回退的功能。

  • 发布:生成特定版本的机器人资源包,但此时 NLU 能力服务并不会立即使用此版本
  • 上线:指定某个特定版本的机器人资源包作为实际使用版本
  • 下线:取消某个机器人的实际使用版本,可以理解为将实际使用版本改为“空”
  • 回退:指定某个特定的历史版本作为实际使用版本

实际上上线、下线、回退都是使用同一个接口,区别只是指定的 “实际使用版本” 不一样,此时都会通知相应的 NLU 能力服务,NLU 能力服务会根据指定的版本来更新自身的机器人资源,并以新的机器人资源进行后续服务。

NLU 能力服务仅需要机器人资源包和对应的语义模型,即可进行服务,不依赖于数据库中的数据。

3.12.4.1 机器人资源包#

机器人资源包包含了智能问答所需的所有相关资源,包括语义模型的路径(可以是基础模型,也可以是优化模型)、问题、答案、问答库、意图、场景、技能、词典、机器人信息等等,这些资源数据已经进行了预处理再打包在资源包中,因此,加载机器人资源包时每个 NLU 能力服务并不需要再重新或重复进行预处理工作,将大大加快加载速度。

每当资源发生变化,机器人资源包都需要重新生成。由于资源数据的预处理和语义模型有关,因此当语义模型发生变化时,机器人资源包也需要重新生成。

每次重新生成,都称为一次机器人“发布”,机器人资源包的版本是用 “发布ID” 指定的,并不是整数格式。

机器人资源包是文件的方式,目前只支持存储在 LocalFS/NFS/NAS 等文件存储中。

3.13 语义模型#

语义模型是指在进行问题相似度计算时所使用的模型文件,目前也都是存储在文件系统中。

3.13.1 系统模型#

整个系统有一组语义模型,称为系统模型。可以利用 “查看系统模型列表” 系统接口中获取。

系统模型存储在文件存储中。

3.13.2 基础模型#

每个租户有一组基础模型,也就是从所有系统模型中选取此租户可用的模型。这一般在创建租户时由管理员配置好(通过“创建基础模型”接口创建好),确定后不会再发生变化。

由于基础模型只是系统模型的引用,因此其名称、描述、路径等和系统模型都是一致的,但有自己的一个ID。不会再使用其它路径复制一份系统模型。

3.13.3 优化模型#

租户可以通过 NLU 训练优化服务对模型进行训练优化。在训练生成了新的语义模型之后,语义模型的新版本会存储到文件存储中。之后会向 NLU 资源管理服务发起一个“新增优化模型” 的请求。

10D.0中暂不支持 NLU 训练优化服务,因此不会真正出现优化模型。

3.13.4 启用语义模型#

租户可以启用不同的语义模型,但一个租户只能启用一个模型,此模型可以是基础模型,也可以是优化模型。

当启用的语义模型发生变化时,因为需要重新进行资源的预处理工作,因此所有在内存中的机器人资源信息都会更新。这是一个较长时间的操作,需要在后台进行计算。在完成前,如果进行机器人测试,可能会出现“机器人正在维护”的错误信息。在完成后,可以进行机器人的“即时测试”工作。

由于发布的机器人资源包中包括了语义模型的路径,因此机器人资源包总是对应着某个特定的语义模型,其中的资源也是采用此语义模型进行预处理的。当租户启用的模型发生变化时,实际的 NLU 能力服务中使用的还是当前上线的机器人资源包中指定的模型。

因此,当启用的语义模型发生变化时,即使资源不发生变化,如果希望 NLU 能力服务使用到新的语义模型,仍然需要发布新的机器人资源包并进行上线操作。

3.14 多租户#

多租户作为整个 AICP-10 平台的通用概念,并不由 NLU 相关的服务维护,但 NLU 相关的服务支持 AICP-10 的多租户的配置。

在资源管理时每个租户的资源是隔离的,如果访问其它租户的资源,会返回错误。