上一篇已经说明了自然语言处理的简单实现方法,在此基础上,如何实现一个机器人与我们交流,是这篇文章需要讨论的问题。希望这个机器人不算太笨。^_^
微信的交互方式是触发式的,由用户发起会话,一问一答。所有的设计都需要基于这个模式。
会话管理机制
想想平时交流时的行为,我们会根据对方的每句话来逐渐建立起一个语境,即对话上下文。根据不同的语境,即使是同一个问题,也会有不同的答案。
基于这个想法,设计一个简单的会话管理机制,即每个用户有一个独立的对话上下文context,每个context会有一个状态来标志当前的语境。
1、会话状态管理
public enumContextStateEnum {
WAIT_QUERY, //等待询问
WAIT_LEARN, //等待学习
WAIT_CONFIRM, //等待确认
WAIT_WEATHER_CITY, //等待指定需要查询天气的城市
WAIT_MUSIC_INFO; //等待指定需要搜索的歌曲信息
}
2、创建与删除会话
3、会话处理流程
有了这个基本思路,再来看看每个会话的处理流程。
我将用户的问题分为两类,非功能性问题和功能性问题:
Context的状态切换如下图:
Context模块与其他模块的关系
一些扩展的设想
当前的实现比较简单,如果继续扩展,可以加入一个解析模块。解析模块负责分析会话中的聊天记录,context模块根据分析结果切换会话状态,比如机器人可以有开心、愤怒、悲伤等状态,在不同的状态下,即使是同一个问题机器人也可以选择不同的回复。当然,这需要把知识库中的答案进行归类,机器人才能根据状态选择对应的答案。
实现过程中碰到的问题
问题:分布式服务器导致机器人状态机混乱
最初设计context保存在内存中,定义一个map容器,以用户ID作为key,context结构体作为value。
本地运行没有问题,但是发布到BAE服务器后,问题来了,通过微信与奇迹蛋robot对话,发现奇迹蛋的context状态机混乱,行为非预期。并且问题发生具有一定的随机性。
开始一直以为是多线程操作map引起的问题,在程序中又加了单例,满怀期待的发布了,结果还是不行。
折腾了挺久,最后在网上找到了一个比较靠谱的解释,参考:http://blog.csdn.net/ostrichmyself/article/details/8098119,“3.1 静态变量无法常驻内存”。
简单来说,由于BAE是分布式服务器,我们部署在上面的web应用会被放在多个容器里执行,而这些容器的内存是非共享的,如下图:
弄清楚了原因就好办了,有两种解决方法:
1. 使用BAE的cache服务,创建共享内存
研究了一下,要调用BAE的API,本地调试不方便,加上BAE的文档看的蛋疼,放弃了。
2. 使用数据库来保存
放弃使用内存的方式,用mysql来保存context map。尽管增加了数据库操作,不过用户也没几个,无所谓了。
奇迹蛋的主要设计思路基本就介绍完了,整个系统比较简单,有些功能设计了但是没有去实现。主要目的还是学习一下java web的开发方法,也顺便了解了解时下最火的微信APP。
Have fun~
下篇文章会聊一些代码实现中碰到的问题,并符上源码。
谢谢关注奇迹蛋~扫一下&调戏之