ChatBot framework 开发实践

前言

通常而言,通用聊天机器人(比如小冰等)底层技术是采用类似Seq2Seq等“生成”技术的。但是这种机器人属于探索性质,无法 提供特定的服务。而Siri则是兼具闲聊以及垂直领域功能的,比如可以预约提醒,打电话,定餐厅等特定功能。相信Siri在实现特定预约提醒,打电话功能等,则是使用了“语言模板”匹配技术以及结合分类器来实现精度的控制和定向动作的执行。

对于聊天机器人我个人是相当感兴趣的,奈何现在的已经公开的文章都“相对初级和入门”,或者说过于专注里面的某个算法,比如问答匹配算法。所以萌生了写一篇文章的想法。本文基于自己开发相应系统的经验,理论上会给大家带来一些帮助。但是因为是内部系统,只能谈及一些较为公开的思想。

现在我们的目标是探讨是如何设计和实现一个,只要通过简单配置就完成一个特定主题对话的机器人。有需要的话,可以经过插件(组件)开发,为其增加新垂直领域对话功能。这些插件,就如我前面所言,可能需要集成大量的针对特定领域问题的算法。

核心技术要点

  1. 语言模板引擎
  2. 对话配置系统
  3. 机器学习相关技术

语言模板可以保证意图识别的准确性,机器学习除了能否增加覆盖度以外,同时也是对话配置系统的核心所在。在今天这篇文章里我们会重点探讨1,2两点,3有需要的时候会提及。

语言模板引擎

语言模板很好理解,就是一句话匹配上了某个模板,这个模板会指向一个动作,从而能够给出一个响应。一个大致的配置如下:

{
      "action": "how to deal with <xdisease>",
      "template": [
       "<疾病>*怎么办",
       "<疾病>*怎么*治疗"
      ],
      "reg": "",
      "id": "24"
    }

比如 糖尿病怎么办,就会匹配上这个模板,并且执行action动作。如果怕模板定制的过于宽泛,可以再通过reg (正则)来进行限制。id 则是这个模板的唯一编号。 * 表示中间可以匹配任何字符。<疾病> 则表示特定实体,这需要有海量的实体词典支持。

通常语言匹配模板引擎会有比较明显的性能问题。当你有几千个上万个模板,每个模板里面又有几十个甚至上百个子模板,那么一次匹配的成本会相当高,对CPU压力也会非常大。所以通常我们会采用倒排索引技术,比如<xdisease>*怎么*治疗 会进行如下编码:

怎么 -> [24,100...... ]
治疗 -> [24,36...... ]

比如糖尿病应该怎么办治疗,我们会提取出”怎么“,”治疗“,两个词汇,然后获得他们的倒排列表,求交集,就能得到24,并且再做一次实体检查,就能实现快速查找了。当然具体如何做倒排列表,如何做抽词,包括做实体识别,实体积累我们在本文不做详解。

语言模板引擎是聊天机器人里较为核心的组件,通常算法在这种场景里是补充。

对话配置系统

对话配置系统,其实就是chatbot framework, 据说有一些开源实现,不过我没具体了解过。我这里说说我的设计。

通常对于一次性对话(一问一答)这个比较好处理,依托于上面的语言模板引擎基本就能实现了。对于有一个”对话引导流程“的会话,这种多伦对话则需要一个较为完善的对话配置系统。

对话配置系统会涉及到几个概念:

  1. 会话主题。每次对话应该都是围绕一个主题的,比如帮助用户完成转账流程,这期间要和用户发生多次交互,直到最后帮用户搞定。
  2. 跳转。 根据用户的反馈,又分为会话内跳转,和会话间跳转。因为一个会话会有多次交互,所以会有会话内跳转。会话间跳转,可以通过一个简单的例子来解释:比如用户问附近哪家餐厅比较好,你可能会询问用户是要西餐还是中餐,这个时候用户不搭理你了,说给我安排一个日程吧,这个时候时候就需要主题间的跳转。主题通常依托在特定会话中。
  3. 对话树。一个对话对话是一个树状结构。同时我们又会有多个对话,对话之间不一定是互通的,最终有个会话森林的概念。
  4. 对话树节点。前面我们提及,一个会话会有多伦交互,所以为了完成一个会话, 配置上至少有两种类型的节点:一个是条件节点,一个回答节点。

上面都是一些要点,我这里会举一个最简单的配置例子:

{
  "对话名称": {
    "id": 1,
    "intercept": [
      {
        "name": "......ConversationChangeInterceptor",
        "params": {
          "match": "template:6,8,9,10",
          "target_step": {
            "match_one": "3:1",
            "no_match": "2:0"
          }
        }
      }
    ],
    "conversation": [
      {
        "chain_type": "condition",
        "match": [
          "template:6,7,8"
        ],
        "desc": "",
        "msg": "",
        "step": 0,
        "target_step": {
          "question_finish": 11,
          "no_match": 10
        }
      },
     {
        "chain_type": "conversation",
        "match": [
        ],
        "desc": "",
        "format_class": {
          "name": ".....ClassifyFormatter",
          "params": {
            "url": "..../prediction"
          }
        },
        "msg": "您好 ${name}先生",
        "step": 6,
        "target_step": -1
      }

intercept表示会话拦截,在对话流程里任何一个环节,都需要检查下是不是发现了主题变更,如果符合,则会根据target_step实现对应的跳转。在interceptor的target_step 被表示为 A:B 这种形式,意思是跳转到A对话里的B节点上。

match 表示匹配了哪些模板,当然,也可以是一个算法模型,比如"model:com.org.QuestionClassify",比如我需要判定用户是不是在描述自己的身体状况,这个时候用模板显然是不行的,可能需要继承一个算法分类器。显然上面的配置是支持这种集成的。

如果匹配上了则跳转到对应的step 11,如果没有匹配则跳转到step 10。根据类型(chain_type),这是一个条件节点,所以他不会对用户做任何输出,而是默默的根据条件往其他节点条。

msg 表示应答的语句,如果你想动态调整这个输出,可以配置format_class。format_class主要实现复杂动态的应答逻辑。另外还有一个类似配置是query_class,会拦截进来用户的问题,并且改写用户的问题。

step 表示当前处于会话的那个节点,这个节点处理完后的下一个节点会是target_step。 通过适当形态,可以实现会话之间的跳转。我举的例子只是展示了内部跳转。

有了这套配置引擎后,比如做一个客服机器人,就变得很简单了,把用户的常见问题罗列下,之后执行特定的动作。当然,很多传统的客服机器人为了简单期间,主要是通过依托于QA算法做匹配,并不会采用这种我说的方案。

我们根据这套配置引擎,可以实现一个很复杂的对话。而且可以配置很多有趣的功能,比如 功能导航对话,比如吃饭请按1,睡觉轻按2 这种。只要配置一个新对话即可,然后这个对话作为作为起始对话,通过会话间跳转来完成导航功能。

因为千人千面,所以在实际的引擎实现过程中,我们需要记录每个用户当前所处的会话以及所在的节点,还包括会话期间的一些信息搜集,这也是一个较为复杂的话题了。我们底层采用redis做这个存储。

总结

一般而言,我们无法使用“某个”算法就实现一个复杂的系统,当然,“某个”算法可能很重要,甚至是系统能否成功的关键。一个复杂的系统通常都是根据每个环节的需求不同,综合利用了方方面面的算法,而每个算法使用的数据又是其他算法处理而来的。ChatBot framework 本身能够通过配置,复用一些已有的组件完成一些基础的对话功能,但是如果要实现更复杂的对话,则需要更多算法和组件的支持。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏java一日一条

为什么开源可以提高程序员的编程技能?

我已经写了很多年的软件。最近我意识到,我越涉及(致力于,结合于等)开源技术,我写出来的代码就更好。这不由地让我疑惑起来:难道里面有什么相关性或因果关系吗?

1023
来自专栏架构师之路

小小的公共库,大大的耦合,你痛过吗?

什么是耦合? 耦合,是架构中,本来不相干的代码、模块、服务、系统因为某些原因联系在一起,各自独立性差,影响则相互影响,变动则相互变动的一种架构状态。 感官上,怎...

3698
来自专栏python学习指南

计算机系统结构——01结论

1.1 计算机系统的层次结构 从使用语言的角度,一台由软、硬件组成的通用计算机系统可以被看成是按功能划分的多层机器级组成的层次结构。具体的计算机系统,其层次数的...

2378
来自专栏Java学习网

不要浪费时间写完美代码

 一个系统可以维持5年,10年,甚至20年以上,但是代码和设计模式的生命周期非常短,当对一个解决方案使用不同的方法进行迭代的时候,通常只能维持数月,数日,甚至几...

2925
来自专栏我是攻城师

如何学好一门编程语言或技术?

3745
来自专栏领域驱动设计DDD实战进阶

DDD实战进阶第一波(十五):开发一般业务的大健康行业直销系统(总结篇)

1853
来自专栏编程

浅谈CPU 并行编程和 GPU 并行编程的区别

CPU 的并行编程技术,也是高性能计算中的热点,那么它和 GPU 并行编程有何区别呢? 本文将做出详细的对比,分析各自的特点,为深入学习 CPU 并行编程技术打...

1948
来自专栏java一日一条

如何处理前任程序员留下的代码

作为软件工程师不可避免会遇到的一个场景是:我们在改变或添加一个功能到不是我们创建的、我们不熟悉的、与我们负责的系统部分无关的代码中时,会遇到麻烦。虽然这可能会是...

1032
来自专栏blackheart的专栏

[解读REST] 3.基于网络应用的架构

链接上文[解读REST] 2.REST用来干什么的?,上文中解释到什么是架构风格和应该以怎样的视角来理解REST(Web的架构风格)。本篇来介绍一组自洽的术语,...

2169
来自专栏顶级程序员

相较其他语言,Python到底好在哪儿?

就个人发展而言,选择学习的技术与要就读的大学可谓同等重要。如果决定做错了,那往往会收到一堆麻烦,而不是想要的高薪工作。我想,现在你点开这篇文章,就代表你已考虑选...

1183

扫码关注云+社区

领取腾讯云代金券