rasa是我去年的时候学习使用的,但是后面没怎么用了。如今已经过去一年了,rasa代码的变化已经很大了,比如原来使用flask作为网络框架,现在已经换成性能更高的sanic了(https://www.jianshu.com/p/636833c71c2a),具体性能表如下图所示;rasa core和rasa nlu合并成了rasa。
我看到最近一年以来,网上有很多关于rasa的相关技术文档,但是很多都是入门级别的,或者翻译一下rasa的官方的doc,缺乏对rasa内部组件的定制化开发和关键代码的走读。我这里打算通过两篇文章写一下相关内容。
如果你是一个还没有接触过的rasa的萌新,你可以先看一下别人写的技术博客先学习一下。
下面推荐几个我觉得不错的。
1. 来自 colin_gao 的 《rasa对话系统踩坑记》:https://www.jianshu.com/p/5d9aa2a444a3
代码地址: https://github.com/GaoQ1/rasa_chatbot_cn
2. 来自 邱震宇(https://www.zhihu.com/people/qiu-zhen-yu-87/activities) 的 《基于RASA的task-orient对话系统解析》:https://zhuanlan.zhihu.com/p/75517803
3. rasa翻译系列:https://zhuanlan.zhihu.com/p/88112269
4. 最后还有我自己的 《rasa安装和测试》:https://blog.csdn.net/hero00e/article/details/85122797,不过版本已经过时了,只能看看,使用就不推荐了。
其中,第一个有10篇内容,第二个有3篇内容。
先说一下我的环境:
centos7
python 3.6
rasa 1.2.0 (用的版本比较旧,不过不影响后面的开发)
rasa-sdk 1.2.0
我对应的github地址:https://github.com/tedljw/rasa_instructions
首先你需要下载rasa-1.2.0(下载地址: https://github.com/RasaHQ/rasa/tree/1.2.0)和rasa-sdk-1.2.0(下载地址: https://github.com/RasaHQ/rasa-sdk/tree/1.2.0)的代码。分别取出rasa-1.2.0中的rasa目录,和rasa-sdk-1.2.0中的rasa_sdk目录放到我的代码的根目录下就可以了,具体如下图所示。当然,你也可以通过pip install rasa==1.2.0 rasa-sdk==1.2.0来处理,不过我因为会改动源码就不这么操作了。
下面介绍一下我的目录结构
.
├── config.yml pipeline的component和policy的配置
├── credentials.yml 开放的端口类型,这里我用rest
├── data 训练需要的数据
│ ├── nlu.md
│ └── stories.md
├── domain.yml 配置你的意图和对应的action执行的地方
├── endpoints.yml 输出地址和端口配置
├── __init__.py
├── models
├── reference 参考代码
├── mychat
│ ├── actions
│ │ └── actions.py action文件
│ ├── components
│ │ └── preprocessing.py components文件
│ ├── policies
│ │ └── fqa.py policy文件
│ └── web 这个是我的web端测试api
│ ├── __init__.py
│ ├── server.py
│ ├── static
│ └── templates
├── rasa rasa-1.2.0的代码
└── rasa_sdk rasa_sdk-1.2.0的代码
component就是根目录下config.yaml里的pipeline,它属于rasa_nlu,你可以理解为rasa的文本预处理过程。关于如何自定义自己的component文件,官方有一个文档说明:
https://blog.rasa.com/enhancing-rasa-nlu-with-custom-components/?_ga=2.239609795.1168581134.1563776558-761997264.1555054139
component文件有以下结构构成:
name = "my_preproces" #组件名字
provides = [] #当前组件能够计算出什么上下文
requires = [] #当前组件需要提供什么上下文
defaults = {} #组件的默认参数,可以被pipeline中参数覆写
language_list = ["en"] #组件支持的语言
__init__ #组件的初始化
create #在训练之前初始化组件
train #训练组件,如果不需要训练就不需要实现
persist #保存组件模型到本地以备将来使用,如果没有需要保存的东西,可以不实现
load #定义如何加载persist(持久化)后的模型,或者说从本地加载保存的东西,若没有保存东西到本地,也不需要实现
process #使用组件进行处理,从message中取想要的数据,计算完成后更新到message中
具体实现可以参看我的代码中的preprocessing.py文件,你的工作主要是在process中对你收到的文本进行处理,然后通过message类的set来把你的处理结果以json的形式放进message中,然后往下游传递。
完成以上步骤后,你还需要去 rasa/nlu/registry.py 文件下添加你写的component函数。
具体参考我reference目录下的registry.py文件的 34,73,126行。
policy用来决定对话中的每一步将执行的action,它的配置在config.yaml中。它属于rasa_core模块。具体内容可以查看官方文档:https://rasa.com/docs/rasa/core/policies/。
priority: int = 4, #policy的优先级
nlu_threshold: float = 0.3, #触发本policy所需的最低阈值
core_threshold: float = 0.3, #触发action的所需的最低阈值
fallback_action_name: Text = "fqa", #如果意图或操作的置信度低于各自的阈值,则调用后备操作的名称
train #训练组件,如果不需要训练就不需要实现
predict_action_probabilities #预测下一步需要执行的action,这也是我们可以自定义处理的地方
persist #保存pilicy组件模型到本地
load #加载保存好的policy组件模型
具体实现可以参考我的代码中的fqa.py文件,你的工作主要是在predict_action_probabilities函数中对你接收到的 tracker进行操作(https://rasa.com/docs/rasa/api/tracker/),配合你能操作的action(domain类),具体的使用,你可以参考rasa的源码或者我写的fqa.py文件的predict_action_probabilities部分。
完成以上步骤后,你还需要去 rasa\core\policies\__init__.py 文件下添加你写的policy类。
from mychat.policies.fqa import FqaPolicy
如官方说述,action有4种类别,Utterance actions,Retrieval actions,Custom actions,Default actions。我们这里讨论Custom actions(https://rasa.com/docs/rasa/core/actions/#custom-actions),通过自定义的action,我们可以完成一些复杂的操作。action的使用需要rasa_sdk的支持。
一般来说,action代码包括2个函数
name #用以返回action的名字
run #执行action的具体操作,通过传入的tracker类来获取对话的状态,比如:message,slot,state等
一句话,action内,你可以编写你的任何想法,不论是sql的调用,还是训练好的model,网络爬虫。
改了config,domain,data等需要执行一下rasa train。或者你第一运行,也需要执行以下rasa train。这个指令的目的是为了生成多轮对话模型,当然这里面还有你设定好的配置信息。
python -m rasa train
结果生成在在models文件中
启动action
python -m rasa_sdk --actions mychat.actions.actions
启动程序,其中 -m 指定train那一步生成的多轮模型的文件夹地址,--enable-api 开放web server api, --log-file log输出文件, --endpoints 指定连接action端口
python -m rasa run -m models --enable-api --log-file out.log --endpoints endpoints.yml
最后,你可以选择使用
curl -XPOST http://localhost:5005/webhooks/rest/webhook -d '{"sender": "user1", "message": "你好"}' -H "Content-type: application/json"
发送消息
收到回复:
[{"recipient_id":"user1","text":"Hello World!"}]
也可以选择我的代码中的web前端。
只需要在根目录下执行 python mychat/web/server.py