文章目录
- 1. 领域 domain
- 2. 故事 story
- 用户消息
- 机器人动作与事件
- 辅助符号
- 3. 动作 action
- 回复动作
- 表单
- 默认动作
- 自定义动作
- 4. 词槽 slot
- 词槽和对话行为
- 词槽类型
- 词槽映射
- 5. 策略 policy
- 6. 端点 endpoints.yml
- 7. rasa SDK、自定义动作
- 自定义动作
- 运行自定义动作
- 8. rasa 支持的客户端
- 9. 实战:报时机器人
- nlu.yml
- stories.yml
- domain.yml
- config.yml
- endpoints.yml
- actions.py
- 测试
learn from https://github.com/Chinese-NLP-book/rasa_chinese_book_code
rasa core
对话记录 和 选择下一个动作
1. 领域 domain
定义了所有信息:
- 意图、实体、词槽、动作、表单、回复
意图、实体 应该 跟 rasa nlu 中的保持一致
utter_
开头的回复 表示 渲染同名模板发送给用户
responses:
utter_greet:
- "你好 {name}!" # {name} 是模板变量
回复 还支持 富文本,指定通道
会话配置:会话过期时间,是否继承历史词槽
2. 故事 story
代码语言:javascript复制version: "3.0"
stories:
- story: happy path
steps:
- intent: greet
- action: utter_greet
- story: query time
steps:
- intent: query_time
- action: action_query_time
必须要有的 key 是 story、steps steps 表示用户和机器人之间的交互
用户消息
代码语言:javascript复制 - intent: inform # 用户意图
entities:
- location: "上海" # 实体信息
- price: "实惠"
机器人动作与事件
动作: action 返回事件:词槽事件(对词槽的值进行变更)、active_loop 事件(激活or取消激活表单)
辅助符号
- 检查点符号,checkpoint 减少故事中重复的部分,名字相同的检查点可以互相跳转 不同的故事之间,可以通过一个尾部,一个首部 相同的 checkpoint 连接成一个新的故事
- or 语句
stories:
- story:
steps:
# 上一个step...
- action: utter_ask_confirm
- or:
- intent: affirm
- intent: thankyou
- action: action_handle_affirmation
大部分相同,仅有其中一个步骤用户的意图不同
3. 动作 action
接受用户输入、对话状态信息,按照业务逻辑处理,并输出改变对话状态的事件和回复消息
回复动作
与 domain 里的 回复 关联在一起
当调用这类动作时,会自动查找回复中的同名的模板并渲染
表单
收集任务所需的所有要素
默认动作
rasa内置的一些默认动作
自定义动作
满足后端交互计算需求,如查数据库、第三方api请求
4. 词槽 slot
词槽必须要有 名字
和 类型
slots:
slot_name: # 名字
type: text # 类型
influence_conversation: false
initial_value: "hello" # 初始值
mappings: # 映射
- type: from_entity
entity: entity_name
词槽和对话行为
设置 influence_conversation
bool 选项: 词槽是否影响对话行为
词槽类型
text、bool、category(枚举)、float(需要设置取值范围)、list、any(不影响系统动作预测)
词槽映射
如上mappings
字段,from_entity
表示将读取某个实体(entity指定)的值来赋值词槽
5. 策略 policy
策略负责学习故事,从而预测动作
有一些内置的策略,他们有优先级,除非是专家,不要随意修改优先级
数据增强: 使用 Rasa 命令时,添加 -- augmentation
来设定数据增强的数量
6. 端点 endpoints.yml
定义了 rasa core 和 其他服务进行连接的配置信息
7. rasa SDK、自定义动作
安装 rasa时,默认安装
单独安装 pip install rasa-sdk
自定义动作
代码语言:javascript复制class ActionQueryTime(Action):
def name(self) -> Text:
return "action_query_time"
def run(
self,
dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any],
) -> List[Dict[Text, Any]]:
current_time = datetime.now().strftime("%H:%M:%S")
dispatcher.utter_message(text=current_time)
return []
- 重写
name()
向服务器申明动作名字 - 重写
run()
获取当前对话信息 tracker 对象(对话状态追踪,获取历史实体、词槽等) domain 对象 用户消息对象 dispatcher 根据这些信息完成业务动作,如想改变对话状态,需要返回事件发送给 rasa服务器,没有的话,返回[]
运行自定义动作
跟rasa一起安装的sdk,rasa run actions
单独安装的 python -m rasa_sdk --actions actions
8. rasa 支持的客户端
支持 Facebook、Rasa Webchat、Chatroom
等
跟 IM 连接的组件 称为 connector
其负责实现通信协议
rasa支持自定义 连接器,支持同时使用多个连接器连接IM,需要在 credentials.yml
文件中配置如何连接客户端
9. 实战:报时机器人
tree
代码语言:javascript复制.
├── actions.py
├── config.yml
├── credentials.yml
├── data
│ ├── nlu.yml
│ └── stories.yml
├── domain.yml
├── endpoints.yml
├── __init__.py
├── media
│ └── demo.png
├── README.md
└── tests
└── conversation_tests.md
nlu.yml
代码语言:javascript复制version: "3.0"
nlu:
- intent: greet
examples: |
- 你好
- 您好
- hello
- hi
- 喂
- 在么
- intent: goodbye
examples: |
- 拜拜
- 再见
- 拜
- 退出
- 结束
- intent: query_time
examples: |
- 现在几点了
- 什么时候了
- 几点了
- 现在什么时候了
- 现在的时间
- intent: query_date
examples: |
- [今天](date)几号
- [今天](date)是几号
- [昨天](date)几号
- [明天](date)几号
- [今天](date)的日期
- [今天](date)几号了
- [明天](date)的日期
- 几号
- intent: query_weekday
examples: |
- [今天](date)星期几
- [明天](date)星期几
- [昨天](date)星期几
- [今天](date)是星期几
- 星期几
stories.yml
代码语言:javascript复制version: "3.0"
stories:
- story: happy path
steps:
- intent: greet
- action: utter_greet
- story: query time
steps:
- intent: query_time
- action: action_query_time
- story: query date
steps:
- intent: query_date
- action: action_query_date
- story: query weekday
steps:
- intent: query_weekday
- action: action_query_weekday
- story: say goodbye
steps:
- intent: goodbye
- action: utter_goodbye
domain.yml
代码语言:javascript复制version: "3.0"
session_config:
session_expiration_time: 60
carry_over_slots_to_new_session: true
intents:
- greet
- goodbye
- query_time
- query_date
- query_weekday
entities:
- date
slots:
date:
type: text
influence_conversation: false
mappings:
- type: from_entity
entity: date
responses:
utter_greet:
- text: 你好,我是 Silly,我可以帮你查询时间、日期和星期几。你可以对我说「现在几点了?」、「今天几号?」或者「明天星期几?」。
utter_goodbye:
- text: 再见!
actions:
- action_query_time
- action_query_date
- action_query_weekday
- utter_goodbye
- utter_greet
config.yml
代码语言:javascript复制recipe: default.v1
language: zh
pipeline:
- name: JiebaTokenizer
- name: LanguageModelFeaturizer
model_name: "bert"
model_weights: "bert-base-chinese"
- name: DIETClassifier
epochs: 100
tensorboard_log_directory: ./log
learning_rate: 0.001
policies:
- name: MemoizationPolicy
- name: TEDPolicy
max_history: 5
epochs: 100
- name: RulePolicy
endpoints.yml
代码语言:javascript复制action_endpoint:
url: "http://localhost:5055/webhook"
actions.py
代码语言:javascript复制from typing import Any, Text, Dict, List
from datetime import datetime, timedelta
from rasa_sdk import Action, Tracker
from rasa_sdk.executor import CollectingDispatcher
def text_date_to_int(text_date):
if text_date == "今天":
return 0
if text_date == "明天":
return 1
if text_date == "昨天":
return -1
# in other case
return None
weekday_mapping = ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期天"]
def weekday_to_text(weekday):
return weekday_mapping[weekday]
class ActionQueryTime(Action):
def name(self) -> Text:
return "action_query_time"
def run(
self,
dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any],
) -> List[Dict[Text, Any]]:
current_time = datetime.now().strftime("%H:%M:%S")
dispatcher.utter_message(text=current_time)
return []
class ActionQueryDate(Action):
def name(self) -> Text:
return "action_query_date"
def run(
self,
dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any],
) -> List[Dict[Text, Any]]:
text_date = tracker.get_slot("date") or "今天"
int_date = text_date_to_int(text_date)
if int_date is not None:
delta = timedelta(days=int_date)
current_date = datetime.now()
target_date = current_date delta
dispatcher.utter_message(text=target_date.strftime("%Y-%m-%d"))
else:
dispatcher.utter_message(text="系统暂不支持'{}'的日期查询".format(text_date))
return []
class ActionQueryWeekday(Action):
def name(self) -> Text:
return "action_query_weekday"
def run(
self,
dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any],
) -> List[Dict[Text, Any]]:
text_date = tracker.get_slot("date") or "今天"
int_date = text_date_to_int(text_date)
if int_date is not None:
delta = timedelta(days=int_date)
current_date = datetime.now()
target_date = current_date delta
dispatcher.utter_message(text=weekday_to_text(target_date.weekday()))
else:
dispatcher.utter_message(text="系统暂不支持'{}'的星期查询".format(text_date))
return []
测试
rasa run actions
运行动作服务器
rasa run actions
2022-11-28 09:50:58 INFO rasa_sdk.endpoint - Starting action endpoint server...
2022-11-28 09:50:58 INFO rasa_sdk.executor - Registered function for 'action_query_time'.
2022-11-28 09:50:58 INFO rasa_sdk.executor - Registered function for 'action_query_date'.
2022-11-28 09:50:58 INFO rasa_sdk.executor - Registered function for 'action_query_weekday'.
2022-11-28 09:50:58 INFO rasa_sdk.endpoint - Action endpoint is up and running on http://0.0.0.0:5055
rasa train
rasa shell
2022-11-28 21:16:49 INFO root - Rasa server is up and running.
Bot loaded. Type a message and press enter (use '/stop' to exit):
Your input -> 你好呀
Building prefix dict from the default dictionary ...
Loading model from cache /tmp/jieba.cache
Loading model cost 1.346 seconds.
Prefix dict has been built successfully.
你好,我是 Silly,我可以帮你查询时间、日期和星期几。你可以对我说「现在几点了?」、「今天几号?」或者「明天星期几?」。
Your input -> bye
你好,我是 Silly,我可以帮你查询时间、日期和星期几。你可以对我说「现在几点了?」、「今天几号?」或者「明天星期几?」。
Your input -> 拜拜
再见!
Your input -> 现在几点
21:18:11
Your input -> 今天是几号
2022-11-28
Your input -> 明天是几号
2022-11-29
Your input -> 后天是几号
系统暂不支持'后天'的日期查询
Your input -> 昨天是几号
2022-11-27
Your input -> 今天星期几
星期一
Your input -> 明天周几
星期二
Your input -> 现在几点了?
2022-11-29
修改:
nlu里添加 - [后天](date)的日期
actions.py 添加 if text_date == "后天": return 2
重新训练,测试
代码语言:javascript复制Your input -> 后天几号
2022-11-30
Your input -> 后天星期几
星期三