###### ============================== user agent 部分逻辑===============================================
1. step 函数
外界传入数据 inputs
step函数首先根据 inputs更新 user state中的当前的 1.对话者 2. 对话历史 3.将系统动作存入buffer中
然后在while循环中中调用 policy 函数
2. policy 函数
每次从 buffer 中 取出一个 system action ,然后生成对应 user action
1. sys action 是 非确定性澄清 IMPLICIT_COFIRM
从 action 参数中取出 需要澄清的 slot name 和slot value
判断 该slot 是否是用户slot 如果不是跑出异常
如果是 当前曹值同用户约束的值一样 或者用户约束的值是none(ignore)
不做任何处理
如果不满足约束,生成否认曹值的动作(reject) 或 否认+inform (reject + inform) 并返回
同时更新 user state 如果是 reject 将当前槽位置为 未输出 如果是 reject + inform 将当前槽位值置为已输出
2. sys action 是确定性澄清 EXPLICIT confirm
取出当前的slot name 和slot 值
判断是否是用户约束槽位
如果满足约束 返回 Action(UserAct.CONFIRM, (slot_type, slot_val)) 将user state 的slot 置为True
如果不满足约束 返回 Action(UserAct.DISCONFIRM, (slot_type, slot_val)) 将 user state 的 slot 置为 false
3. 系统的动作是INFORM
这时系统会将所有已经收集到的槽位返回, 需要执行 全部约束 是否满足的判断,返回不满足约束的槽位
如果满足约束
更新goal的状态 将当前 goal置为True: update_goals_met() , 随机的选择下一个goal state.unmet_goal()
如果新采样到的goal 为 none
随机改变约束槽位 _increment_goal()
如果随机采样的约束槽位不为None
更新 user state 中的约束改变, 并更新user state 中对应的约束曹值, 返回的动作是:
[Action(UserAct.NEW_SEARCH, (BaseSysSlot.DEFAULT, None)),
Action(UserAct.INFORM, (slot_key, self.usr_constrains[slot_key]))]
如果随机采样的约束槽位值为None:
告诉系统同对当前的搜索结果满意的动作, 并返回结束动作
[Action(UserAct.SATISFY, [(g, None) for g in complete_goals]),
Action(UserAct.GOODBYE)]
如果采样到的goal不为 None
将 user state 中的当前goal val 置为 新的goal val
user state 中的goal change 标记置为 True
将Action(UserAct.MORE_REQUEST, [(g, None) for g in complete_goals]) 作为待返回的 act前缀
随机采样当前是否 为yn 问题
如果是yn问题,name 找出goal对应的slot, 并采样一个slot值,将yn更新到 user state 中
追加 动作: [ack_act, Action(UserAct.YN_QUESTION, (slot.name, expected_val))]
如果不是yn问题, 返回正常问: [ack_act, Action(UserAct.REQUEST, (next_goal, None))]
如果不满足约束条件:
返回inform动作告诉系统不满足约束的槽位的值 Action(UserAct.INFORM, (wrong_slot, self.usr_constrains[wrong_slot]))
4. 如果系统的动作是request
取出当前request 对应的槽位 以及对应的值
如果 slot type 为 BaseSlot Need
返回一个没有满足的 goal Action(UserAct.REQUEST, (next_goal, None)) 并更新 user state 为当前的goal
如果 系统返回的槽位为 BaseSlot.HAPPY
就什么也不做返回 None
如果是用户约束槽位
# 采样出随机个数的多余槽位, 返回inform slot slotval 列表 ,更新 user state的状态
如果不满足上面所有的条件
抛出异常
5. 如果系统的动作是 澄清 SystemAct.CLARIFY
抛出异常,没有对应的处理方法
6. 再说一遍 : SystemAct.ASK_REPEAET:
从 userstate中取出上一次说的内容, 返回
7. 换一种方式说: SystemAct.ASK_REPHRASE:
# 取出最近一轮 , 向 action列表中追加again 标志
for a in last_usr_actions:
a.add_parameter(BaseUsrSlot.AGAIN, True)
8 如果系统动作是 QUERY: 这时需要查询数据库
从action 的参数中取出 参数列表 含有query 和goals
调用api 从数据库中查询出想要的数据
随机的选择一条返回的记录 为goals赋值
返回用户动作: Action(UserAct.KB_RETURN, [query, results])
以上就是policy 的处理逻辑
user state 中含有的记录内容
1. hisotry [] 历史对话 内容 speaker + action_list
2. spk_state : 当前的会话状态 listen or exit
3. input_buffer: 当前的系统动作列表
4. goal_met 有序字典: 当前goals是否满足
6. constrain_slot_state 有序字典 当前用户约束slot 是否满足
7. change_dic goal 约束 yn 的字典
8. change_slot_dic 改变的slot 以及对应的值
9. cur_goal: 当前的goal
含有的函数:
update history( speaker , actions)
is_terminal()返回当前的对话状态是否为 exit
yield_floor() 返回当前的对话状态是否为listen
unmet goal() 找到一个没有满足的goal
update_goals_met(top_action) 更新当前goal的met状态
update_usr_constrains(usr_slots, is_fill) 更新当前slot 填充状态
reset_goal() : 重置当前的goals 为未满足状态 当前的用户约束槽位为未输出状态
reset_change_dict: 置空change dict
###### ============================== system agent 部分的逻辑 ===============================================
system 部分使用的一个概率模型的 状态追踪类实现的, action的处理完全是基于概率的
1. belief slot 的逻辑
计算 一个槽位上各个曹值概率分布
首先设置 阈值
EXPLICIT THRESHOLD = 0.2 显式确认的阈值
IMPLECT THRESHOLD = 0.6 隐式确认的阈值
GROUND_THRESHOLD = 0.95 基础阈值
a 初始化方法:
uid slotname
value_map map key: slot value: prob
last_update_turn : 上一次更新的轮次
b 添加一个新的观测 参数为 : value值, conf 置信概率, turn_id 轮次
将最近一次更新改为当前的turn_id
# 更新曹值
如果 这个值在value map中,更新置信概率:
prev_conf = self.value_map[value]
self.value_map[value] = max([prev_conf, conf]) + 0.2
如果之前没有出现过, 将其他出现的曹值的置信都减少一半
记录当前曹值的置信为conf
c 根据 confirm_conf 和 disconfirm conf 更新槽位的置信值 参数 : confirm_conf, disconfirm_conf, turn_id, target_value=None)
更新 最后一次更新的轮次
如参数中没有目标曹值,选取置信最大的曹值为目标曹值
使用如下公式更新:
up_conf = confirm_conf * (1.0 - self.EXPLICIT_THRESHOLD) # 对曹值的确认概率增益
down_conf = disconfirm_conf * (1.0 - self.EXPLICIT_THRESHOLD) # 对曹值的不确定概率增益
old_conf = self.value_map[grounded_value]
new_conf = max(0.0, min((old_conf + up_conf - down_conf), 1.5))
d 获取最大置信的曹值
从 value map 中找到置信最大的曹值
e max_conf
从 value map 中找到做大的置信值
f clear:
将各个曹值的置信初始化为 self.IMPLICIT_THRESHOLD+self.EXPLICIT_THRESHOLD)/2.
BeliefGoal 类
goal slot 的状态追踪,
设置 阈值为 0.7
初始化:
uid: 用户id
conf : 置信度
ddelivered: 是否发出了
value : 当前的 value
expected_value : 期望的值
添加观测 参数 : 置信 conf , 期望值 exptected_value
首先根据观测置信,更新 值的置信: max(conf, self.conf) + 0.2
更新 期望goal值 为 expected_value
获取当前的置信
发出:
设置 delivered 为 true
clear
清空 置信 发出标志 期望goal值
DialogState(state):
dm 的状态跟踪类
设置inform 阈值
初始化函数:
持有的数据结构:
history list 历史对话信息
spk_state : 当前的对话状态
user_beliefs : 有序字典,当前曹值的置信度列表
sys_goals: 有序字典 当前 goal的置信列表
初始化 默认goal 的置信为1.0
valid_entries : 合法sample 从数据库中查询得到
pending return : 发出 当前追踪到的所有约束曹值
domian : 当前的domain
turn_id() : 返回当前的轮次
gen_query() :
获取用户slot 最大置信的value 组成数据库查询语句
has_pending_reture():
判断当前约束是否追加到return上
ready_to_inform()
判断当前是否可以输出信息了
遍历用户置信字典,判断每个槽位的最大置信是否大于基础阈值
遍历 goal slot 置信列表判断是否大于基础阈值
yield_floor:
判断系统动作是否在一下动作中 : SystemAct.REQUEST, SystemAct.EXPLICIT_CONFIRM, SystemAct.QUERY]
is_terminal(self):
self.spk_state == State.exit
reset_sys_goals():
重置 系统的goal置信列表, 将default goal 的置信设置为1.0
state_summary():
当前状态的总结
1. 当前各个用户约束的置信最大的曹值和置信度
2. goal 的置信 发出状态 当前值 期望值
3. 当前的return 是否有追加的数据查询语句
system 的 逻辑
step
用当前的inputs 更新 state tracker 历史状态
函数循环遍历 处理用户actionlist
调用policy处理各个action
判断是否结束
返回训练信息
policy 中的具体内容:
1. 首轮判断
返回问候动作 和对 NEED 槽位的request
2. 终止判断 获取最近一次的用户动作列表 查看是否有GOODBYE 动作
3. 判断是否有 pending 的查询结果
如果有就返回
actions.append(Action(SystemAct.INFORM, [dict(query), goals]))
actions.append(Action(SystemAct.REQUEST, (BaseUsrSlot.HAPPY, None)))
4. 判断当前是否准备好输出了
生成查询语句 (usr slot 约束 和goal 列表)
返回动作 actions.append(Action(SystemAct.QUERY, [query, goals]))
5. 其他状况
填充3个list
隐式确认列表 implicit_confirms = []
显式确认列表 exp_confirm = []
请求列表 requests = []
遍历各个 约束槽位的置信字典:
如果 当前槽位 的最大置信 小于 显式确认
生成 一个Action(SystemAct.REQUEST, (slot.uid, None))) 添加到 显式确认列表中
否则 小于 隐式确认
生成一个 Action(SystemAct.EXPLICIT_CONFIRM, (slot.uid, slot.get_maxconf_value()))) 添加到request列表中
否则 小于 基础阈值:
生出一个 ction(SystemAct.IMPLICIT_CONFIRM, (slot.uid, slot.get_maxconf_value()))) 添加到 隐式确认列表中
遍历各个 goal 的置信字典:
如果 当前goal的置信 大于0 小于基础阈值
那么将 Action(SystemAct.REQUEST, (BaseUsrSlot.NEED, None)) 添加到request列表中
总结上面三个列表:
如果 exp_confirm 列表不为空
将 expconfirm的第一个 加上 implicit_confirm 列表输出
否则如果request 列表不为空
将 request 的第一个 加上 implicit_confirm 列表输出
否则
只输出 implict_confirm
装填更新逻辑 state_update() 参数 usraction 置信conf
如果usraction 内容为空 直接返回
更新 state 的 历史信息
更新 state 的 对话状态
遍历 用户动作:
1. act 为 confirm:
取出 对应的slot 更新其状态追踪
self.state.usr_beliefs[slot].add_grounding(conf, 1.0 - conf, self.state.turn_id())
2. act 为 disconfirm
取出对应的 slot 更新其状态追踪
self.state.usr_beliefs[slot].add_grounding(1.0 - conf, conf, self.state.turn_id())
3. act 为 INFORM:
取出 参数中的slot 和slotvalue
为这个值初始化置信
self.state.usr_beliefs[slot].add_new_observation(value, conf, self.state.turn_id())
4. act 为 REQUEST:
取出参数中的slot
更新goal的观测置信
self.state.sys_goals[slot].add_observation(conf, None)
5. act 为 new search:
重置状态追踪中的 slot 置信列表
重置状态追踪中的goal置信列表
6. 当前用户的动作是yes or no 问题
取出当前参数中的slot 和 对应的 slot value
更新goal 的置信
self.state.sys_goals[slot].add_observation(conf, value)
7. 如果用户满意 sys goal的值,或者要求更多的goal时, 标注 该goal值是被用户接受的, 已经发出
for para, _ in action.parameters:
self.state.sys_goals[para].deliver()
8. 如果 用户的动作是 kb——return , 那么根据 query 携带的goal值更新 goal的置信
query = action.parameters[0]
results = action.parameters[1]
self.state.pending_return = query
for slot_name, goal in self.state.sys_goals.items():
if slot_name in results.keys():
goal.value = results[slot_name]
update_grounding(sys_actions):
根据已经选择的 sys action 更新基础置信
遍历 每一个选中的系统动作
如果当前系统动作是 IMPLICIT CONFORM
取出 slot 和其值
更新状态跟踪中的置信
self.state.usr_beliefs[slot].add_grounding(1.0, 0.0, self.state.turn_id())