智能客服对话平台ICS

    表达式说明

    本章介绍NGD产品表达式配置使用规范。 表达式可以用在会话树节点配置中,节点触发条件和节点执行回复内容的配置

    平台使用的表达式标识

    • 无前缀:表示内置DialogState对象的属性(welcome, conversation_start, anything_else, true, false, query等)
    • #:表示引用意图
    • @:表示引用实体
    • &:表示引用上下文context中的某个key
    • {%:模板标识前缀
    • %}:模板标识后缀

    触发/回复条件表达式举例

    Condition类型的表达式必须合法,且在创建此类表达式时需保证引用的意图或实体已存在,其求值结果只能是true/false,逻辑操作符(not, and, or, !, &&, ||)的操作数的类型必须为String、Integer、Boolean、null。如:

    • welcome(首轮会话,且用户输入的query为空时,结果为true)
    • conversation_start(首轮会话,则为true)
    • anything_else(query非空时,结果为true)
    • not query(用户输入的文本数据为空时,结果为true)
    • not @sys_date(sys_开头的表示系统实体,若命中,因取反,故结果为false)
    • @car_type(若命中自定义实体car_type,则结果为true)
    • &channel(context中包含key: channel,且对应的value非空,则为true)
    • #get_weather(自定义意图识别,若命中此意图,则为true)
    • &name == "baidu"(若context中,name对应的value为字符串"baidu",则为true)
    • @location?.indexOf('北京') > 0(建议使用?.)
    • &month and &month >= 1(若context中month对应的value非空且大于等于1,则为true)
    • {12,24,36}.contains(&month)(若context中month对应的value值为12,24,36中一个,则为true)

    Context 对象及包含的表达式举例

    context为json对象(key-value结构),其value为表达式字符串;在进行求值时,正常返回各子表达式结果用于填充context各value,若因对象不存在或解析异常,则原样返回表达式串,如:

    • {"ques":"@ques","quenum":"12"}(对于数字,直接写在json串的双引号中即可)
    • {"user":"'张女士'"}(对于常量字符串,需显式用单引号'或者\"括起来)
    • {"date":"@sys_date"}(sys_date为系统实体,系统实体见2.4节)
    • {"month":"@sys_number"}
    • {"sex":"@sex"}
    • {"car":"@car_type"}
    • {"location":"{% @location %}"}
    • {"date":"entities['sys_date'][1].value"}(entities为map,按key取值;entities['sys_date']结果为List,故按下标取其中第2个元素;entities['sys_date']``[1]结果为RecognizedEntity对象,使用.value获取其value属性的值)
    • {"entity":"entities.toString()"}(输出整个map对象)
    • entities['sys_date'].![value] ,遍历所有实体值

    回复内容表达式

    Output 为字符串表达式,其所有需要解析的表达式必须用模板标识包含起来,表达式用法同上;在进行求值时,若出现不能解析的情形,原样返回表达式串,如:

    • intent={% &intent %}, entitySize={% &entities?.size() %}(为更好可读性,{%之后,%}之前各加一个空格)

    不支持及特殊Case

    • ==操作符的使用,在对实体值进行==判断时,须保证左右操作数为字符串,如:(若@month实体值为"8") "@month == '8'"的值为true,而"@month == 8"的值为false。其它比较操作符>,>=,<,<=不受此约束。

    常用配置举例

    日期常用表达式

    1. 获取当前年:T(java.util.Calendar).getInstance().get(T(java.util.Calendar).YEAR)
    2. 获取当前月:T(java.util.Calendar).getInstance().get(T(java.util.Calendar).MONTH)+1
    3. 获取当前日:T(java.util.Calendar).getInstance().get(T(java.util.Calendar).DAY_OF_MONTH)
    4. 获取指定的年:T(Integer).parseInt(@sys_date.substring(0,4))或者@sys_year
    5. 获取指定的月:T(Integer).parseInt(@sys_date.substring(5,7))或者@sys_month
    6. 获取指定的日:T(Integer).parseInt(@sys_date.substring(8,10))
    7. 指定日期的7天后:new java.text.SimpleDateFormat("yyyy-MM-dd").format(new java.util.Date(new java.text.SimpleDateFormat("yyyy-MM-dd").parse(@sys_date).getTime()+7 * 24 * 60 * 60 * 1000))
    8. 判断用户输入的时间是否为6个月前: (new java.util.Date().getTime() - new java.text.SimpleDateFormat("yyyy-MM-dd").parse(@sys_date).getTime()) / 1000 >= 6 * 30 * 24 * 3600
    9. 将@sys_date的日期格式(yyyy-MM-dd)转化为更友好的,如:yyyy年MM月dd日 new java.text.SimpleDateFormat("yyyy年MM月dd日").format(new java.text.SimpleDateFormat("yyyy-MM-dd").parse(@sys_date)) 注:其它格式只需要自己修改表达式中的yyyy年MM月dd日即可
    10. 将@sys_month的日期格式(yyyy-MM)转化为更友好的,如:yyyy年MM月 new java.text.SimpleDateFormat("yyyy年MM月").format(new java.text.SimpleDateFormat("yyyy-MM").parse(@sys_month))

    注:同例9,其它格式只需要自己修改表达式中的yyyy年MM月即可;另外,格式上也支持时间,例如HH时mm分ss秒

    1. 获取当前日期 new java.text.SimpleDateFormat("yyyy-MM-dd").format(new java.util.Date());其中"yyyy-MM-dd"可替换成自己需要的格式,同上

    获取实体的值及原始值

    1. @entity返回实体entity的识别值;举例:用户query为:”我的户号是123456789012345678“,表达式@sys_number的求值结果为1.23456789012345678E18
    2. @entity.original返回实体entity的原始值;举例:用户query为:“我的户号是123456789012345678”,表达式@sys_number.original的求值结果为123456789012345678,该表达式在收集原始数字时经常用到。

    数字运算&计数

    1. @sys_number加1:T(Integer).parseInt(@sys_number) + 1
    2. 在会话树中进行计数:可以使用变量在会话过程中进行计数,在会话树变量赋值依次配置:number、表达式 、&number ? &number+1 : 1,表示对number变量进行计数累加,初始值为1
    3. 会话树节点访问计数:sys_counter为系统内置变量名,其可自动对会话过程中节点访问次数进行计数,使用方法:sys_counter['会话树节点名称'],该表达式返回指定定节点的访问次数。
    4. 获取@sys_number实体识别到的原始数值(以0开头的数字除外):@sys_number.indexOf('E') > -1 ? @sys_number.substring(0, @sys_number.indexOf('E')).replace(".", "") : @sys_number
    5. 获取@sys_number识别到的数字的长度(以0开头的数字除外) @sys_number.indexOf('E') > -1 ? T(Integer).parseInt(@sys_number.substring(@sys_number.indexOf('E') + 1))+1 : @sys_number.length()
    6. 货币实体sys_money默认返回的value单位为“分”,为了获取“元”,表达式为: T(Float).parseFloat(@sys_money) / 100 (需要确保sys_money实体存在)
    7. 数字格式转换,如想将某个变量xxx(数值),保留2位小数: new java.text.DecimalFormat("0.00").format(new Double(&xxx))
    8. 数字格式转换,如想将@sys_number的结果,保留2位小数: new java.text.DecimalFormat("0.00").format(T(Double).parseDouble(@sys_number))

    多实体值收集

    NGD支持多实体值收集,可以通过entities['实体名']获取实体对象列表,下面以sys_number实体进行举例,其它实体类似:

    1. 收集用户query中的所有数值,如收集“我可以接受的价格范围是1000到2000元”中的所有数值,可以配置表达式:entities['sys_number'].![value]进行收集,该表达式的值为:[1000, 2000]
    2. 若要收集用户query中原始的数字(如用户query中包含的是身份证号,直接使用1的办法,可能收集到的是精度丢失的科学计数法;或者数字前的0可能被丢弃),可以配置表达式:entities['sys_number'].![original],如用户query为“我的编号是01234和123456789”,该表达式的值为:[01234, 123456789]

    节点条件及回复使用正则表达式

    会话树节点条件中“高级模式”,支持使用正则表达式作为条件,语法为:query matches '正则表达式',注意:query必须完全命中正则表达式(从头到尾),如:

    1. 需要在某个节点收集户号(户号规则为10位数字),用户query为“我的户号是1234567890”,条件表达式query matches '.*(?<!\d)\d{10}(?!\d).*'的求值结果即为true;但表达式query matches '(?<!\d)\d{10}(?!\d)'的求值结果为false,所以需要使用第一种表达式写法,对首尾不关注的数据使用.*进行匹配。

    query抽取

    在会话树节点配置中,有些复杂的场景,需要对query进行抽取,如:正则抽取、包含于抽取等,现举例说明使用方法:

    1. 对query中的信息进行正则提取。如:需要从query中抽取出南航航班号,假设南航航班号规则为:CZ+4位数字;则提取可能包含的全部航班号的表达式为:extractQuery("CZ\d{4}");如用户query为:我考虑的航班号有CZ1234, CZ3091,则上述表达式识别结果为一个列表:["CZ1234", "CZ3091"];如果明确包含航班号,且只想取一个,则表达式可写为:extractQuery("CZ\d{4}")[0]
    2. 从query中抽取出所有从属于某个candidate列表(或逗号分隔的字符串)的数据。如:用户query为我说的是上海呀,而context为{"city_list":["北京", "天津", "上海"], "cities":"北京,天津,上海"},则getQueryContains(&city_list)getQueryContains(&cities)返回值均为["上海"]
    3. 返回query中抽取出所有从属于某个candidate列表(或逗号分隔的字符串)的数据的个数。如:用户query为我说的是上海呀,而context为{"city_list":["北京", "天津", "上海"], "cities":"北京,天津,上海"},则countQueryContains(&city_list)countQueryContains(&cities)返回值均为1

    节点回复话术循环遍历

    背景:

    业务系统返回的数据是个列表,如查询到最近一个月的交易记录,会有多条交易信息,需要支持在会话树中根据这些多条交易信息,构造出一个用户可识别的答案,即需要表达式支持对列表进行遍历。

    语法:

    对函数类的表达式进行求值,格式为:<f:函数标识 input=输入表达式 output=输出模板类表达式/>  其中,
     * 函数标识,支持的有:list(表示枚举)
     * 输入表达式:支持所有可求值的表达式,返回类型需与函数标识一致,如:list
     * 输出模板表达式:支持所有可求值的模板表达式(与回复话术一致)。
     * 当函数标识为list时,内置的变量有:&list_index表示list的下标、&list_element表示list中的元素
     * 如果list中每个元素为Map,则Map中key的取法为:list_key

    举例:

    例1. 某个dialogState.context为:
     {"order_list":[{"date": "2019-09-08", "money": 100}, {"date": "2019-09-10", "money":200}]}
     * 节点中回复话术配置为:
     您的账单是:<f:list input=&order_list output=第{% &list_index + 1 %}笔:日期{% &list_date %}, 金额:{% &list_money %};/>
     * 对应的求值结果为:
     您的账单是:第1笔:日期2019-09-08, 金额:100;第2笔:日期2019-09-10, 金额:200;
     
     例2. 某个dialogState.context为:
     {"date_list":["2019-09-08", "2019-09-10"]}
     * 节点中回复话术配置为:
     <f:list input=&date_list output=第{% &list_index + 1 %}项:{% &list_element %},/>
     * 对应的求值结果为:
     第1项:2019-09-09,第2项:2019-09-10,
     

    计算文本与query的相似度

    在会话树节点的高级表达式中可以配某个文本与query的相似度大于或小于某个阈值的条件,可以用simWithQuery,此函数会计算出某个文本信息与query的相似度

    举例及语法说明:

    例1:在某个会话树节点的条件想配一条text文本语句:”我想租车“,跟它的相似度大于0.75 语法:simWithQuery('我想租车') > 0.75

    例2:在某个会话树节点的回复话术中可以配成模板形式 语法:{% simWithQuery('我想租车') %}

    基本表达式语法

    请参考Spel

    上一篇
    会话机器人对接
    下一篇
    规则模板