rasa笔记-rasa core等
rasa core
domain(领域)定义了对话机器人需要知道的所有信息,包括意图(intent)、实体(entity)、词槽(slot)、动作(action)、表单(from)和回复(response)
领域 - domain
动作 - action
- 是对话管理模型的输出。定义了机器人可执行的动作
- 控制对话按照填表方案进行
- 回复消息给用户
- 调用外部 API 或查询数据库
Rasa 中,以 utter_开头的动作表示渲染同名的模板并发送给用户,这属于特殊的约定
词槽 - slot
-
定义了机器人在对话过程中需要跟踪(记忆)的信息
-
slots: priority: type: categorical values: - low - medium - high mappings: - type: from_entity entity:priority
-
词槽名字是
priority
-
每一种词槽都有类型的区别,上例类型为 categorical
- 每种类型有自己特有的相关属性设定,可以帮助确定槽值的范围,从而帮助模型更好的将词槽转换成机器学习的特征
- 本例中,词槽的值被限定为3中:low、medium 和 high
-
每个词槽的定义还需要给出映射(mappings)
- 映射指定了在对话过程中如何自动的为这个词槽赋值
回复 - response
-
responses: utter_greet: - "你好 {name}!" # {name} 是模拟变量 utter_goodbye: - "再见" - "拜拜" # 当存在多个模板时,将随机选择一个 utter_default: - "这是一个默认消息"
-
示例有三个模板,所有回复模板都以utter_开头
-
Rasa 的模板字符串支持变量,{name}就是一个变量或占位符,在渲染时会被实际的名为 name 的词槽的真实值替换
- 也可以在自定义渲染模板时通过类似 dispatcher.utter_message(template="utter_gteet",name="Silly")来给出模板变量{name}的实际(silly)
-
Rasa 也可以给出富回复,支持图片和按钮
-
responses: utter_greet: - text: "您的性别是?" buttons: - title: "男性" payload: "/set_gender{"gender": "male"}" - title: "女性" payload: "/set_gender{"gender": "female"}"
-
title 是给用户看的,payload 字段则是用户单击对应按钮实际发送给 Rasa 的文本
-
根据通道选择输出模板
不同的通道具有不同的输出,如果一个回复具有多个模板,可以使用通道(channel)字段指定特定的模板去相应特定的通道
responses:
utter_welcome:
- text: "亲爱的 slack 用户,您好"
channel: "slack"
- text: "亲爱的用户,您好"
如果上例中用户使用的通道是 slack,就会使用这个绑定的模板
自定义输出内容
对于复杂输出,Rasa 提供了 custom 字段,方便开发者自定义复杂的响应内容。这需要客户端支持。
会话 - session
会话配置,会话是指用户和机器人之间的一场对话
一个会话可能横跨很多轮对话
目前 Rasa 支持的会话配置有 session_expiration_time
和 carry_over_slots_to_new_session
- 前者表示在用户最新消息多久后,会话被认为过期
- 后者表示当新的会话开始时,是否应该将上一个会话的词槽延续(继承)到新的会话
session_config:
session_expiration_time: 60 # 单位是 min,设为 0 表示无失效期
carry_over_slots_to_new_session: true # 设为 false 表示不继承历史词槽
全局性配置
rasa目前只有一个全局性配置选项:store_entities_as_slots
这个选项用于决定当得到 NLU 结果时,是否同步更新同名的词槽,其默认值为 true
故事 - story
rasa 通过学习故事的方式来学习对话管理知识
在较高语义层次上记录对话过程
不仅记录用户的语义表达,还需要记录系统内部正确的状态变化
stories:
- story: 这是一个 story 描述
steps:
- intent: greet
- action: action_ask_howcanhelp
- slot_was_set:
- ask_for_help: true
- intent: inform
entities:
- location: "上海"
- price: "实惠"
- action: action_on_it
- action: action_ask_cuisine
- intent: inform
entityies:
- cuisine: "意大利菜"
- action: restaurant_form
- active_loop: restaurant_form
每个故事都是 stories 列表中的一个元素
故事本身的结构是字典,必须要有的键是 story 和 steps
story 键给出的值代表这个故事的备注,用于给开发者提供关于这个故事的一些信息
故事的主体在 steps 键对应的内容中
steps 键通过列表线性的表示用户和机器人之间的交互:
- 每次用户发送消息后,机器人会先执行一次或一系列(多次)任务
- 再等待用户输入(story 中没有显式显示)
- 接着用户继续发送消息
- 如此重复
story 是由用户消息和机器人动作两部分接替形成的
用户消息
用户消息保存了用户的意图和实体信息
- intent: inform
entities:
- location: "上海"
- price: "实惠"
intent 提供意图,entities 键提供实体信息,location 实体的值是上海,price 实体的值是实惠
机器人动作与事件
在训练和测试对话管理系统中,rasa 并不会真正的去执行相关的动作,所以无法获得动作运行的结果(也就是事件)是什么,因此需要开发者在故事中明确给出
机器人动作部分可以分为机器人动作名和返回事件
-
机器人动作名
-
- action: action_ask_howcanhelp
-
action_ask_howcanhelp 就是机器人动作名
-
对于复杂的故事,可能用户一次请求连续多次动作:
-
- action: action_on_it - action: action_ask_cuisine
-
-
动作返回事件
-
使用自定义事件的故事时,由于 Rasa 无法在训练阶段确定自定义的动作会给对话状态带来什么样的改变,需要开发者手动给出动作改变的状态
-
这种状态的改变称为事件
-
常用事件包括词槽事件和 active_loop 事件
-
词槽事件就是能对词槽状态进行更改的事件:
-
- slot_was_set: - ask_for_help: true
-
将 ask_for_help 这个词槽的值设置为 true
-
-
active_loop 事件主要负责激活和取消激活表单(from)
-
- active_loop: restaurant_form
-
将 restaurant_form 的表单激活了
-
-
辅助符号
为了开发者利用故事更高效的表达复杂情节
-
检查点符号
-
checkpoint 用来减少故事中的重复部分
-
名字相同的检查点之间可以相互跳转
-
stories: - story: 流程开始 steps: - intent: greet - action: action_ask_user_question - checkpoint: check_asked_question - story: 处理用户确认 steps: - checkpoint: check_asked_question - intent: affirm - action: action_handle_affirmation - checkpoint: check_flow_finished - story: 处理用户否认 steps: - checkpoint: check_asked_question - intent: deny - action: action_handle_denial - checkpoint: check_flow_finished - story: 流程完成 steps: - checkpoint: check_flow_finished - intent: goodbye - action: utter_goodbye
-
一个故事结束时的检查点可以和另一个故事开始时名字相同的检查点连接,形成新的故事
- 流程开始可以和处理用户确定以及处理用户否认的故事通过检查点 check_asked_question 连接,形成2个新故事
- 2个新故事又可以通过 check_flow_finished 和流程完成故事连接,形成新的故事
-
使用检查点可以减少类似情节的重复编写,但过多使用会导致故事可读性变差或故事逻辑混乱
-
-
or 语句
-
某个节点小小不同可以用 or 来精简故事
-
stories: - story: steps: # ... previous steps - action: utter_ask_confirm - or: - intent: affirm - intent: thankyou - action: action_handle_affirmation
-
通过 or 语句生成 2 个故事,这 2 个故事的绝大部分都相同
-
动作 - action
动作接收用户输入和对话状态信息,按照业务逻辑进行处理,并输出改变对话状态的事件和回复用户的消息
回复动作
回复动作和 domain 里面的 response(回复) 关联在一起,调用这类动作时,会自动查找回复中同名的模板并渲染
由于需要和回复模板保持名字相同,所以这类动作和回复模板一样使用 utter_ 开头
表单
任务型对话的一个重要模式就是多次和用户交互,收集任务需要要素,直到收集完整
这种模式被称为填表
默认动作
rasa 对比较常见的和业务无关的管理动作提供了默认的动作
默认动作还可以被同名动作代替
自定义动作
自定义动作完全由开发者实现,可以满足各种后端交互和计算的需求,常见的后端交互包括查询数据库或发起对第三方 API 的请求
用 HTTP 请求接口的形式和 Rasa 进行交互
词槽 - slot
词槽是机器人的记忆机制
词槽以键值对(如,城市:上海)的形式存在,用于记录对话过程中发生了哪些关键信息,这些信息可能来自用户输入(意图或实体)或后端(如外卖购买结果:成功或失败)
通常情况下,这些信息对于对话的走向起关键作用,或者说这些信息会被对话管理系统用于预测下一个动作
-
例如,在天气查询应用中,城市和日期是决定对话管理系统下一个动作的核心信息
- 缺少日期,机器人会询问日期
- 缺少城市,机器人会询问城市
- 当两者都存在时,机器人会直接执行查询任务
- 这种情况系统只关心“城市”和“日期”这两个词槽是否存在,而具体值则不重要
-
一个词槽必须有名字和类型
-
slots: slot_name: type: text
-
这个词槽,名为 slot_name,类型是 text
-
词槽和对话行为
在词槽中,开发者可以通过 influence_conversation 来设置该词槽对对话过程是否有影响
influence_conversation: false时,该词槽仅用于存储信息,不会影响对话行为
slots:
age:
type: text
influence_conversation: false
名为 age 的词槽不会影响对话行为
词槽的类型
类型 | 功能 |
---|---|
text | 这一类型的词槽可以存储文本值。Rasa系统只判断该词槽是否设定了值,而不关心值的内容,因此该词槽比较适合作为通用实体的存储容器 |
bool | 这一类型的词槽,存储 true 或 false 的值,适合作为信号处理(如抢火车票是否成功)的存储容器 |
category | 这一类型的词槽能存储指定的有限个值(等同于编程语言的枚举值)。值得注意的是,Rasa 会在开发者定义的值之外再增加一个 other,当词槽被赋值时,若这个值并不匹配其他值,则会自动转换成 other。Rasa 可能会根据该词槽取值的不同做出不同的动作。这一类型的词槽适合存储范围有限的值,如性别情况或婚姻情况等 |
float | 这一类型的词槽可以用来存储浮点数,同时此类型的词槽需要设定最大值和最小值,如果赋值超出范围就会自动设成最大值或最小值。Rasa 会将该词槽的值作为预测动作的特征 |
list | 这一类型的词槽可以存储多个任意值。Rasa在将这一词槽转换成特征时只考虑列表是否为空,因此列表中有多少个元素,以及有什么样的元素都不会影响系统 |
any | 这一类型的词槽对 Rasa 的动作预测没用任何影响,开发者可以把一些无关系统运行状态的值放在这里进行信息传递 |
词槽的映射 - mapping
映射指定了在对话过程中如何自动的为这个词槽赋值,一个词槽可以同时有多个映射,在运行时会按照从上到下的顺序依次执行
在每一个映射中,type 字段给出映射的类型,其余字段都是这个类型的参数,和 type 字段密切相关
slots:
slot_name:
type: text
influence_converesation: false
mappings:
- type: from_entity
entity: entity_name
上面例子只有一个映射,这个映射的 type 为 from_entity,这个类型的映射表示将读取某个实体的值赋值词槽
具体使用哪个实体,将由参数 entity 来制定
词槽初始化
slots:
name:
type: text
initial_value: "human"
初始值设置为 initial_value
策略 - policy
策略负责学习故事,从而预测动作
策略需要通过特征提取组件(featurizer)将故事转换成对话状态,进而得到对话状态特征,按照对话特征预测下一个对话动作
在 Rasa 中,我们可以同时拥有多个策略,这些策略可独立进行训练和预测,最后通过优先级及预测得分共同决策
策略的配置
Rasa 项目的 config.yaml中,policies 键是保留给策略配置的
policies:
- name: "MemoizationPolicy"
max_history: 5
- name: "FallbackPolicy"
nlu_threshold: 0.4
core_threshold: 0.3
fallback_action_name: "my_fallback_action"
- name: "path.to.your.policy.class"
arg1: "..."
类似于 NLU 部分的流水线配置,策略由多个列表构成
每个列表元素都是一个字典
这个字典包含 name 和配置选择,name 用于指定组件的名字,除 name 外的其他值都作为配置选项
内建的策略
策略名称 | 描述 |
---|---|
TEDPolicy | TED 是 Transformer Embedding Dialogue 的缩写,是 Rasa 自行开发的一套对话预测算法,采用基于 transformer 的方案将当前的会话映射成一个对话向量,找到和这个向量最近的已知动作的对话向量 |
MemoizationPolicy | 这个策略比较简单,直接记住历史中出现的状态和对应的动作,把这种关系做成字典。在预测时,直接查询相关的字典,如果有这样的状态,则将对应的动作作为结果;如果没有,则预测失败 |
AugmentedMemoizationPolicy | 这个策略和 MemoizationPolicy 的工作原理一致,只是它有一个遗忘机制,会随机的遗忘当前对话历史中的部分步骤,随后视图在训练的故事集合中寻找和当前历史匹配的故事 |
RulePolicy | 这个策略是规则驱动的,它合并了 Rasa 1.x 中所有基于规则的策略 MappingPolicy、FallbackPolicy、TwoStageFallbackPolicy 和 FormPolicy |
策略的优先级
在 Rasa 中,每个策略独立预测下一个动作后,会使用得分最高的动作
在得分相同(通常都是满分 1 分)的情况下,策略之间是有优先级的(优先级数值越高,策略越优先)
Rasa 默认的优先级的设定让内建的策略在相同得分情况下能产生更为合理的结果
优先级 | 策略 |
---|---|
6 | RulePolicy |
3 | MemoizationPolicy 和 AugmentedMemoizationPolicy |
1 | TEDPolicy |
数据增强
默认情况下,Rasa 可以把故事首尾相接,生成新的故事,这就是故事的数据增强
开发者在使用 Rasa 命令时,添加 --augmentation 来设定数据增强的数量,Rasa 按照最多生成 --augementation 设置乘以 10 的数量来增强故事
--augementation 0 可以完全关闭数据增强功能
端点 - endpoint
endpoints.yml 定义了 Rasa Core 和其他服务进行连接的配置信息,这种信息被称为端点(endpoint)
目前支持的端点有 event broker、tracker store、lock store、动作服务器(action server)、NLU 服务器、NLG 服务器和 model storage
tracker 对象和事件对象
tracker 对象
tracker 代表对话状态追踪,也就是对话的历史记忆
在自定义动作中(外部动作服务器也可以),开发者可以通过 tracker 对象来获取当前(或历史的)对话状态(实体情况和词槽情况等),这通常作为业务的输入
tracker 对象的属性:
属性名称 | 说明 |
---|---|
sender_id | 字符串类型,当前对话用户的唯一 ID |
slots | 列表类型,词槽的列表 |
latest_message | 字典类型,包含 3 个键:intent、entities 和 text,分别代表意图、实体和用户的话 |
events | 代表历史上所有的事件 |
active_form | 字符串类型,表示当前被激活的表单,也可能为空(没有表单被激活) |
latest_action_name | 字符串类型,表示最后一个动作的名字 |
tracker 对象的方法:
方法名称 | 说明 |
---|---|
current_state() | 返回当前的 tracker 对象 |
is_paused() | 返回当前的 tracker 对象的过程是否被暂停 |
get_latest_entity_values() | 返回某个实体的最后值 |
get_latest_input_channel() | 返回最后用户所用的输入通道(input channel)的名字 |
events_after_latest_restart() | 返回最后一次重启后的所有事件 |
get_slot() | 返回一个词槽的具体值 |
事件对象
在自定义动作中,如果想要更改对话状态,则需要用到事件(event)对象
通用事件对象:
事件对象 | 说明 |
---|---|
SlotSet(key, value=None) | 要求系统将名字为 key 的词槽的值设置为 value |
Restarted() | 重启对话过程 |
AllSlotReset() | 重置所有的词槽 |
ReminderScheduled() | 在指定的时间发起一个意图和实体都给定的请求,也称为定时任务 |
ReminderCancelled() | 取消一个定时任务 |
ConversationPaused() | 暂停对话过程 |
ConversationResumed() | 继续对话过程 |
FollowupAction(name) | 强制设定下一轮的动作(不通过预测得到) |
Rasa 自动跟踪事件:
事件对象 | 说明 |
---|---|
UserUttered() | 表示用户发送的消息 |
BotUttered() | 表示机器人发送给用户的消息 |
UserUtteranceReverted() | 撤销用户最后消息(UserUttered)后发生的所有事件(包含用户事件本身),在通常情况下,这时只剩下 action_listen,机器人会回到等待用户输入的状态 |
ActionReverted() | 撤销上一个动作,会清除上个动作所有的事件效果,机器人会重新开始预测下一个动作 |
ActionExecuted() | 记录一个动作,动作创造的事件会被单独记录 |
SessionStarted() | 开始一个新的对话会话。重置 tracker,并触发执行 ActionSessionStart(在默认情况下,将已经存在的 SlotSet 拷贝到新的会话) |
基于规则的对话管理
表单
以完成任务为核心目的的对话过程,可以理解为引导用户填写表单(form)的过程
为了使 Rasa 正确的进行基于表单的对话管理,开发者需要将 RulePolicy 加入配置文件(config.yml)
policies:
- name: RulePolicy
定义表单
表单定义在 domain.yml
forms:
weather_form:
required_slots:
- address
- date-time
表单名字是 weather_form,每一个表单都需要指定其必须得词槽,这里是 address 和 date-time
激活表单
开发者需要设定什么时候进入该表单,通过规则(rule)指定
rules:
- rule: 激活 form
steps:
- intent: weather
- action: weather_form
- active_loop: weather_form
例子中如果用户的意图是 weather,就会执行 weather_form这个动作,这个作用的副作用(在对话状态中引起的变化)是进入名为 weather_form 的 active_loop,和前面表单定义的 weather_form 同名,因此会进入对应的填槽-询问的循环过程
执行表单任务
当表单要求的条件都满足后(也就是所请求的词槽全部已经获得时),就可以执行表单任务了,执行什么任务通过规则来设定
- rule: 提交 form
condition:
# Condition that from is active.
- active_loop: weather_form
steps:
- action: weather_form
- active_loop: null
- slot_was_set:
- requested_slot: null
# The action we want to run when the form is submitted.
- action: action_weather_form_submit
上面规则定义了当 weather_form 这个 avtive_loop 结束,且所有请求的词槽都已完成(- requested_slot: null)时,执行动作 action_weather_form_submit
开发者所有的业务逻辑都应在动作 action_weather_form_submit 中完成
--END--
参考资料:
1.《Rasa实战:构建开源对话机器人》
2. Rasa 中文文档