3.0高级配置详解
更新时间:2021-07-16
前言
之前的章节,我们用一个例子让大家熟悉了TaskFlow的配置流程。接下来我们跟大家介绍各节点的高级配置。
词槽收集节点
-
澄清方式
- 是否随机询问:选择“否”时,每轮澄清时会按照话术顺序依次询问。
- 是否强制填充:选择“是”时,词槽澄清失败则终止对话;选择“否”时,达到最大询问次数后对话流程仍会进入下一个节点
-
打断恢复
- 打断后是否支持恢复:对话中节点若被打断到下一个流程(比如当前处于取快递流程,用户输入的语句进入了取外卖流程),默认处于等待恢复状态,当接收到下一个流程成功完成对话的信息后,会继续完成该流程的后续动作。若选择否,则不再恢复对话。
- 打断恢复话术:当恢复到原流程时,会主动答复用户打断恢复的话术,如果不填写,默认使用收集话术。
对话答复节点
-
打断恢复
- 当前节点是否支持恢复到原流程:对话中上一个流程是因为被打断才跳转到当前流程时,默认会在完成所有动作后,发送已完成的信息给上一个流程,若选否,则动作完成后直接结束。
- 打断后是否支持恢复:对话中节点若被打断到下一个流程(比如当前处于取快递流程,用户输入的语句进入了取外卖流程),默认处于等待恢复状态,当接收到下一个流程成功完成对话的信息后,会继续完成该流程的后续动作。若选择否,则不再恢复对话。
- 打断恢复话术:当恢复到原流程时,会主动答复用户打断恢复的话术,如果不填写,默认使用答复话术。
-
答复后动作
- 重置对话状态:若选择是,则会清空之前所有的对话信息,下一个节点时对话会重新开始,默认为否。
- 是否等待用户输入:默认为是,该节点完成所有动作后,接收到用户输入才会继续向下执行;若选择否,则不再等待,直接执行下一个节点的内容。
编程模式
考虑到业务的复杂需求,TaskFlow还为大家提供了节点编程机制,编程语言为Python,目前支持3.8.5版本。 支持节点编程机制的包括:
- 连线
- 对话答复节点
- 资源调用节点
- 自定义节点
编程变量
TaskFlow为大家预置了编程变量,方便大家的使用。
-
获取机器人请求参数的变量。
- 变量名称:svc_request
- 该变量支持获取机器人相关信息。
- 包含如下操作:
操作 类型 说明 svc_request.service_id string 机器人ID svc_request.skill_ids list<string> 机器人下绑定的技能列表 svc_request.log_id string 开发者在客户端生成的唯一id svc_request.context dict 上下文信息 svc_request.session_id string 当前session的ID svc_request.terminal_id string 开发者生成的对应终端每一个用户的ID svc_request.query string 本轮的用户输入query svc_request.query_info object query的附带信息,对应类名为TFQueryinfo svc_request.query_info.type string query的类型 svc_request.query_info.source string query的来源 svc_request.hyper_params dict 超参数 - 预置函数:
函数 说明 参数列表 返回值 svc_request.is_event() 判断本轮请求是否为事件 无 类型:bool
True:本轮为事件请求
False:本轮为普通请求svc_request.get_event_name() 获取事件名称 无 类型:string
当本轮为事件请求时,返回事件名
当本轮为普通文本请求时,返回空字符串- 使用示例
#判断是否为首轮 if svc_request.session_id == '': return True #根据用户输入进行判断 if svc_request.query == '你好': pass if '你好' in svc_request.query: pass if svc_request.query.startswith('你好'): pass # 判断是否为事件请求 if svc_request.is_event(): return True # 获取事件名 event_name = svc_request.get_event_name()
-
获取技能的解析结果
- 变量名称:slu_results
- 该变量支持获取技能的意图和词槽结果。
- 包含如下操作:
操作 类型 含义 slu_results[skill_id] dict 根据技能id获取技能解析结果 slu_results[skill_id].intents list<object> 技能的意图解析结果,无结果时为空字符串 slu_results[skill_id].intents[i] object 第i个命中意图下的解析结果,对应的类名为TFIntent slu_results[skill_id].intents[i].intent_name string 意图名 slu_results[skill_id].intents[i].intent_confidence double 意图置信度 slu_results[skill_id].intents[i].slots dict<string,list<object>> 命中意图下的词槽列表 - 预置函数
函数 说明 参数列表 返回值 slu_results.has_intent(skill_id, intent_name) 判断指定技能是否命中指定意图 skill_id:必需,技能ID
intent_name:必需,意图名类型:bool
True:命中意图
False:未命中意图slu_results.get_intent_names(skill_id) 获取命中的意图列表 skill_id:必需,技能ID 类型:list<string> slu_results.has_slot(skill_id, slot_name, intent_name=None) 判断指定技能下是否存在指定词槽 skill_id:必需,技能id
slot_name:必需,词槽名
intent_name:可选,意图名,作为筛选条件,用于判断指定意图下是否存在slot_name词槽类型:bool
True:词槽存在
False:词槽不存在slu_results.get_slots(skill_id, slot_name=None, intent_name=None) 获取词槽列表 skill_id:必需,技能id
slot_name:可选,词槽名,作为筛选条件,用于获取指定词槽名的词槽列表
intent_name:可选,意图名,作为筛选条件,用于获取指定意图下的词槽列表类型:list<object>
(列表中每一项为TFSlot类型)- 使用示例
skill_id = '12345' # 对单个技能意图进行判断 ## 判断技能skill_id解析意图是否包含WEATHER if slu_results.has_intent(skill_id, 'WEATHER'): pass ## 获取技能skill_id解析意图列表 intent_names = slu_results.get_intent_names(skill_id) if 'WEATHER' in intent_names: pass # 对单个技能词槽进行判断 ## 判断技能skill_id下词槽user_location是否存在 if slu_results.has_slot(skill_id, 'user_location'): pass ## 获取技能skill_id下能够被解析的所有词槽列表 all_slots = slu_results.get_slots(skill_id) for slot in all_slots: if slot.slot_name == 'user_location': pass if slot.slot_name == 'user_time' and slot.original_word == '今天': pass ## 获取技能skill_id下能够被解析的词槽名为user_location的词槽列表 location_slots = slu_results.get_slots(skill_id, 'user_location') # 判断是否所有技能结果均为空(True-均为空;False-至少一个技能有解析结果) no_result = True for skill_id in slu_results: if not skill_id.isdigit(): continue if slu_results.get_intent_names(skill_id): no_result = False break
-
机器人当前包含的词槽列表
- 变量名称:svc_slots
- 该变量支持获取机器人的词槽结果。
- 包含如下操作:
操作 类型 说明 svc_slots[slot_name] list<object> 指定词槽列表 svc_slots[slot_name][i] object 获取列表中第i个词槽对象,对应类名为TFSlot svc_slots[slot_name][i].slot_name string 词槽名 svc_slots[slot_name][i].original_word string 词槽原始值 svc_slots[slot_name][i].normalized_word string 词槽归一化值 svc_slots[slot_name][i].confidence double 词槽置信度 svc_slots[slot_name][i].session_offset int 词槽产生轮次,当前轮为0,上轮为1,以此类推 svc_slots[slot_name][i].begin int 词槽原始值在query中的起始位置 svc_slots[slot_name][i].length int 词槽原始值长度(字符个数) svc_slots[slot_name][i].sub_slots list<object> 子词槽,结构同父词槽(列表中每一项为TFSlot类型) -
预置函数
函数 说明 参数列表 返回值 svc_slots.has_slot(slot_name, original_word=None, normalized_word=None) 对话状态中是否存在指定词槽 slot_name:必需,词槽名
original_word:可选,词槽原始值,作为筛选条件,用于判断是否存在指定原始值的词槽
normalized_word:可选,词槽归一化值,作为筛选条件,用于判断是否存在指定归一化值的词槽类型:bool
True:存在
False:不存在svc_slots.get_slots(slot_name) 从对话状态中获取指定词槽 slot_name:词槽名 类型:list<object>
(列表中每一项为TFSlot类型)svc_slots.add(slot_name, original_word, normalized_word=None) 在对话状态中新增一个词槽 slot_name:必需,词槽名
original_word:必需,词槽原始值
normalized_word:可选,词槽归一化值类型:object
(对应TFSlot类型)svc_slots.remove(slot_name) 从对话状态中移除指定词槽 slot_name:必需,词槽名 类型:None svc_slots.clear() 清空对话状态(词槽) 无 类型:None - 使用示例
# 对机器人词槽进行判断 ## 判断机器人词槽中是否存在user_location词槽 if svc_slots.has_slot('user_location'): pass ## 判断机器人词槽中是否存在原始值为“北京”的user_location词槽 if svc_slots.has_slot('user_location', original_word='北京'): pass ## 判断机器人词槽中是否存在归一化值为“北京市”的user_location词槽 if svc_slots.has_slot('user_location', normalized_word='北京市'): pass ## 判断机器人词槽中是否存在原始值为“北京”归一化值为“北京市”的user_location词槽 if svc_slots.has_slot('user_location', original_word='北京', normalized_word='北京市'): pass # 获取机器人词槽 ## 获取词槽名为user_location的所有词槽列表 slots = svc_slots.get_slots('user_location') for slot in slots: if slot.original_word == '北京' and slot.normalized_word == '北京市': pass # 新增机器人词槽 ## 新增一个原始值和归一化值均为“北京”的user_location词槽 svc_slots.add('user_location', '北京') ## 新增一个原始值为“北京”归一化值为“北京市”的user_location词槽 svc_slots.add('user_location', '北京', '北京市') # 删除机器人词槽 ## 删除词槽名为user_location的词槽 svc_slots.remove('user_location') svc_slots.pop('user_location') # 清空机器人词槽 svc_slots.clear()
-
机器人的应答动作
- 变量名称:svc_actions
- 该变量支持处理机器人的应答动作。
-
包含如下操作:
操作 类型 说明 svc_actions[i] object 获取第i个机器人应答动作信息,对应类名为TFAction svc_actions[i].action_id string 应答动作id svc_actions[i].confidence double 应答动作置信度 svc_actions[i].say string 应答话术 svc_actions[i].type string 应答动作类型 svc_actions[i].custom_reply object 自定义应答动作事件,对应类名为TFCustomReply svc_actions[i].custom_reply.event_name string 事件名 svc_actions[i].custom_reply.func string 函数名 svc_actions[i].options list<object> 应答动作选项 svc_actions[i].options[i] object 第i个应答动作选项,对应类名为TFOption svc_actions[i].options[i].option string 选项内容 svc_actions[i].options[i].info dict 选项附加信息 -
预置函数
函数 说明 参数列表 返回值 svc_actions.add(action_id, say, event_name=None) 新增一个机器人应答动作,并返回新增的对象实例 action_id:必需,应答动作标识
say:必需,应答话术
event_name:可选,应答动作事件名类型:object
(对应TFAction类型)svc_actions.append(tf_action) 在机器人应答动作列表的末尾追加一个应答动作 tf_action:必需,为TFAction的实例化对象 类型:None svc_actions.pop(index=-1) 根据索引值来删除应答动作,并返回删除的对象实例 index:可选,索引值(下标) 类型:object
(对应TFAction类型)svc_actions.clear() 清空机器人应答动作列表 无 类型:None svc_actions.get_skill_actions(skill_id) 获取当前轮技能应答动作列表 skill_id:必需,技能id 类型:list<object>
(列表中每一项为TFAction类型)svc_actions.get_last_svc_actions() 获取上轮机器人应答动作列表 无 类型:list
(列表中每一项为TFAction类型) - 使用示例
# 新增机器人应答动作 ## 新增一个指定动作id和应答话术say的机器人应答动作 svc_actions.add('weather_satisfy', '为您查询天气') ## 新增一个包含特定事件“WEATHER_EVENT”的机器人应答动作 svc_actions.add('weather_satisfy', '为您查询天气', 'WEATHER_EVENT') ## 新增一个包含多个选项的机器人应答动作 tfoption1 = TFOption() tfoption1.option = '苹果' tfoption1.info['english'] = 'apple' tfoption2 = TFOption() tfoption2.option = '香蕉' tfoption2.info['english'] = 'banana' tfoption3 = TFOption() tfoption3.option = '桃子' tfoption3.info['english'] = 'peach' action = TFAction() action.action_id = 'select_clarify' action.confidence = 100 action.say = '你喜欢哪种水果?' action.type = 'guide' action.options.append(tfoption1) action.options.append(tfoption2) action.options.append(tfoption3) svc_actions.append(action) # 删除机器人应答动作 ## 删除机器人应答动作中末尾一项 svc_actions.pop() ## 删除机器人应答动作中下标为1的一项 svc_actions.pop(index=1) # 清空机器人应答动作 svc_actions.clear() # 获取技能应答动作列表(通常用于获取问答、闲聊等技能应答动作) ## 获取某个技能应答动作并将其作为机器人应答动作 skill_actions = svc_actions.get_skill_actions(skill_id) svc_actions.extend(skill_actions) ## 获取上轮机器人应答动作列表 last_svc_actions = svc_actions.get_last_svc_actions()
-
全局变量
- 变量名称:svc_vars
- 该变量为字典(dict)类型,控制全局变量的增删改查。
- 参考Python字典类型的操作语法。
- 使用示例
# 新增一个全局变量 if 'test_var' not in svc_vars: svc_vars['test_var'] = 0 # 查看一个变量的值 test_var = svc_vars['test_var'] # 注意key不存在报错 test_var = svc_vars.get('test_var', None) # 删除一个全局变量 svc_vars.pop('test_var') # 清空所有全局变量 svc_vars.clear()
Demo示例
我们将示例项目中,取快递的流程用编程方式新增了一条流程。 注意:编程节点流程因为优先级最低,对话流程会被优先级为1的流程处理,仅供开发者参考,也可以自己修改入口连线的条件。
- 取快递入口连线
def condition():
if slu_results.has_intent('1010204', 'EXPRESS_DELIVERY'):
return True
return False
- 资源调用
def process():
requrl = 'http://api.k780.com/?app=life.time&appkey=47834&sign=5f4452a33ef126dcfe324f26dfbd2321&format=json'
try:
res_data = requests.get(requrl)
res_str = res_data.text.strip()
res_json = json.loads(res_str)
svc_vars['datetime'] = res_json['result']['datetime_2']
except:
pass
- 对话答复节点
def process():
if 'datetime' in svc_vars:
say = '好的,您可以先放到收发室,我会通知主人' + str(svc_vars['datetime']) + '有个快递来电,让他看下这通电话。'
else:
say = '好的,您可以先放到收发室,我会通知主人有个快递来电,让他看下这通电话。'
svc_actions.add('express_delivery_satisfy', say)
- 获取个人信息连线
def condition():
if slu_results.has_intent('1010204', 'GET_USER_INFO'):
return True
return False
除支持使用预置变量和函数进行编程外,还可以使用Python进行编程,当前支持使用如下工具包:
- 所有节点都支持:time、datetime、calendar、pytz、dateutil、copy、re、random、math、jieba、hashlib、json、urllib、urllib3、requests、grequests。