智能对话机器人多轮对话Chatbot 人机对话系统

谈 Bot Framework(以Facebook的wit.ai

2017-10-27  本文已影响1391人  我偏笑_NSNirvana

序言

什么是 Bot Framework ?
按照微软的讲法:"The Bot Framework is a platform for building, connecting, testing, and deploying powerful and intelligent bots."
简单的说,Bot Framework 就是一个用于搭建、链接、测试、和部署智能机器人的平台。

什么是 wit.ai?
Wit.ai 是 Facebook 推出的用于将自然语言转化为可处理指令的 API 平台,其目的是为了帮助开发者便捷的打造类 Siri 语音对话应用或设备。

为什么是 wit.ai?
前些日子,云栖大会上,阿里的资深技术专家海青在介绍阿里 ALIME 团队的 Bot Framework 时提到了 Google 的 api.ai 和 Facebook 的 wit.ai.
所以我希望了解一下,对于我在做业务时遇到的问题、有过的想法,国外一线大厂是怎样处理的。

为什么不是 api.ai?
因为页面打不开..

本篇文章将会从理解对话两个方面去讲解 wit.ai.

主要参考资料为 wit.ai 的英文原版文档:
https://wit.ai/docs/recipes

理解

意图(话题)识别

问题

我们需要对用户的意图进行区分,但问题在于用户表达同一意图的说法可能是无限的。

方案

我们在 Wit.ai 的 Understanding 模块,输入一条用户问句 "what's the weather",然后选择添加一个叫做 intent(也即意图)的 entity(也即实体),将其意图值置为 weather. 也即我们完成了对该条用户问句的意图标注。

我们为此意图标注的用户问句越多,该意图实体的抽取也就越准确。

实体抽取(填槽)

问题

我们希望能够从用户的原始问句中抽出我们需要的关键信息。

方案

我们输入一条用户问句 "what is the weather tomorrow",然后选择添加实体,可以看到 wit/datetime 这个系统内置的实体,选中之后,可以发现这个实体自动识别了句子中的 tomorrow,并自动填写好了值。

wit.ai 内置了一些常用实体,这些内置实体不必通过用户的标注就能够完成实体识别。不过具体的业务场景下,我们还会用到一些自定义实体。如果需要 wit.ai 完成这些自定义实体的识别,就需要进行适当的用户问句标注。

有限关键词实体抽取

问题

有些情况下,我们希望抽取的实体值是可枚举的,也即我们能够处理的实体值是一个有限的词典。

方案

举个例子,在这里,我们自定义一个名为 pizza_type 的实体,并将用户问句 cheese pizza 中的 cheese 标注为 pizza_type 的实体值。

在下方的实体栏目中,我们可以看到 pizza_type 这个实体,将它的搜索策略选为 keywords,也即关键词,之后,便得到了一个可以识别 pizza 前 cheese 的实体 pizza_type.

我们当然不止希望 pizza_type 只识别 cheese,可以通过图示的方式为这个实体增加可识别的 pizza_type 实体值,添加完成后,可以尝试在 expression 中输入 [新的实体值] + pizza,发现我们新增的 pizza_type 实体值,是可以被自动识别的。不过,识别范围也仅限于我们在 pizza_type 中添加的 keywords.

非有限关键词实体抽取

问题

很多情况下,我们也希望能对有限词典之外的词进行识别,比如上例中的 pizza_type,当然,我们能处理的只有配置好的 pizza_type 实体值,但并不意味着当用户需要其他类型的 pizza 时,我们就无法作答。

方案

如图所示,我们修改 pizza_type 的搜索策略为 free-text + keywords,这意味着,当用户在 pizza 前使用词典内 keywords 之外的词时,也能够被识别。也即我们可以得知用户选择了其他类型的 pizza.

子串实体抽取

问题

在一些业务场景下,我们需要抽取用户问句中的一个子串作为实体值,比如 "Tell Jordan that I will be home in ten minutes" 句中的 "I will be home in ten minutes" 就是我们需要抽取的实体值。

方案

我们可以在 expression 中输入 "Tell Jordan that I will be home in ten minutes",随后新增一个 message 实体,然后将 "I will be home in ten minutes" 作为 message 实体的标注结果。之后将 message 的搜索策略选为 free-text + keywords,message 实体就具有了从用户问句中抽取 message 子串的能力。

如图所示,尝试输入 "tell Alex I will be late" 后,wit.ai 也能将其中的 "I will be late" 抽取到 message 中。

搜索策略选择

在上面的例子中,我们可以看到,实体的搜索策略有三种可选,分别是 traitfree-textkeywords.

它们的区别在于:

区分不同位置的同类实体

问题

在一些经典的场景(比如订票)中,按照上文的定义,实体的抽取确实应该使用 keywords 策略,但如果同一条用户问句中需要抽取多个同类实体呢?建立起同类实体与多个词典内实体值之间的对应关系就成了需要解决的问题。

方案

wit.ai 中通过设定 role 来解决这个问题。

举个例子,expression 为 "I want go from NY to SF",其中 NY 和 SF 均为 wit/location 实体中的值。在这样的业务场景下,我们需要同时抽取出两个 wit/location 实体,值分别为 NY 和 SF,并且区分好 NY 是出发点,而 SF 是目的地。

我们在选择实体时,设置抽取 NY 的 wit/location 实体的 role 为 origin,抽取 SF 的 wit/location 实体的 role 为 destination.

情感分析

问题

我们想要知道用户问句中的情感,是积极或消极。

方案

可以按照上文中的方法进行 expression 的标注,区别在于,需要新增一个 sentiment 的 实体,将它的搜索策略选为 trait,值标注为为 positive 或 negative.

置信度下限选择

问题

对于每个抽取出的实体,wit.ai 都会提供一个置信度,当置信度足够低时,或许我们应当采用特殊的处理方式,比如进行确认或直接丢弃。

但如何定义置信度的『足够低』呢?

方案

在实体页的 Insights 模块,我们能够看到该实体抽取的置信度与准确率和召回率的关系,选择不同的置信度能够得到相对应的准确率和召回率。

如上图,如果我们需要当准确率未达到1时进行特殊处理,那么我们就应该选取置信度为0.79,然后对置信度低于0.79的实体抽取情况进行特殊处理。

小结

由此看来:

还不了解的是:

对话

实体的抽取与使用

问题

当用户讲 “Where can I see Pulp Fiction?” 时,我们也许会需要将 Pulp Fiction 抽出来,去调用 Movie API,并将它保存在 context 中以供后续机器人时回答使用。

方案

如图所示,我们先输入用户问句,随后标注问句的实体抽取方式:标注 intent 为 findTheater,以及标注好需要使用的其他实体。

随后采用 Bot executes 调用 findTheater 函数,findTheater 以原 context 和抽取出的 entity 作为输入,对 context 进行编辑,通过 add a context branch 可以对 findTheater 的输出进行处理。

之后利用 context-key 拿到 movie 实体的实体值,使用 {} 在 bot sends 中引用。

基于槽的机器人(slot-based bot)

问题

在大多数业务场景下,明确用户指令所需的实体都不止一个,只有当用户提供完整的实体信息之后,才能进行指令的执行;而信息不全时,就应当根据实体的缺失情况进行追问。

方案

既然存在多种情况,我们就应当分多条分支进行处理。

首先我们处理信息完整的情况,如图所示,我们按照上文讲过的方式利用 context-key 同时拿到 showTime、theater、movie,然后将其拼装成 Bot sends.

当用户问句中缺失时间实体时,findTheater 函数应当返回 missingTime,由此新建一个多轮对话分支,该分支下,Bot sends 会追问用户,系统用户补全时间实体。

当用户补全时间实体后,业务上应当等同于用户一次提供完整信息的情况。

wit.ai 采用 bookmark 来做这种情况的处理。如图所示,我们在 findTheater 函数的调用前添加一个 call-findTheater 的 bookmark,当用户补全时间实体后,我们便利用 Jump 跳转到 call-findTheater,随之进行 findTheater 函数的调用,改走信息完整的分支。

处理是/非意图

问题

当我们向用户确认问题时,用户说『是』或『不是』大多数情况下会影响到后续的对话过程。我们需要做两个不同的多轮对话分支来处理『是』和『不是』的情况。

方案

具体操作如图所示,与上文做多轮对话分支的方法基本相同,我们会新增一个实体 yes_no,并根据用户的不同回答走不同的多轮对话分支。(quick replies 会在下文提到)

同时,我们当然希望不止能够识别用户的 yes,与之同意图的 yep、yeah 等也应当被认定为是用户的肯定回答。相对的,否定意图除了 no 之外,也应当包含 nope 等其他实体值。

另外需要特别注意的是,yes_no 的搜索策略应当选为 trait,也即我们需要通过整句话来判定用户的 intent,而不是某几个词。

同样的,如图所示,我们新增一个 branch 来处理用户意图为 no 的情况。

基于流的机器人(flow-based bot)

问题

如上图所示,如果我们的机器人需要做一个包含两个问题的调查,特别的,根据第一个问题答案的不同,机器人会额外询问一个附加问题。这样的例子,就叫做基于流的对话。也即后续的对话路径依赖于前序的实体值。

方案

先处理第一种情况,用户问句首先为:"I want to take the survey",随后机器人问第一个问题:"Do you watch sports on TV?"

这种情况下,如果用户回答的意图为 yes(处理方式上文中已经提到过),我们会追问一个额外的问题:"Which sports do you watch the most?"

接收到用户的回复之后,首先进行 sport 实体的抽取,随后调用 answer-tv 函数进行处理,此时调查的第一部分结束。

在调查的第二部分开始之前,我们先做一个 question-2 的 bookmark,为第一个问题 intent 为 no 的处理做准备。

之后进行第二个问题回答的处理,询问用户:"Ok. And do you watch sport online?",当用户回答的 intent 为 yes 时,调用 computer-result 函数,给出 result 作为返回值,拼装成最后的 Bot sends. 同时在函数调用之前增加一个 end 的 bookmark.

之后我们来处理两个问题 intent 均为 no 的情况。

按照之前的流程图,当第一个问题的 intent 为 no 时,应当直接跳转到第二个问题;当第二个问题的 intent 为 no 时,应当直接结束。

我们利用 bookmark 进行处理:当第一个 intent 为 no 时,我们使用 Jump 跳转到 question-2 的 bookmark,直接开始第二个问题的询问;当第二个 intent 为 no 时,我们同样利用 Jump 跳转到 end 的 bookmark,结束询问。补全了整个对话过程。

了解 Context 和 Session ID

问题

我不明白 Context 和 Session ID 的关系。

方案

context 是用于追踪当前对话状态的对象,由我们自己的函数进行管理,用于帮助 wit.ai 预测接下来的行为。通常一个 Session 中只有一个 context 对象。

session_id 是我们自己产生的,用于标记与同一个用户一次对话全部内容的唯一 ID. 需要注意的是,即便是同一个用户,不同的对话也应当拥有不同的 session_id.

添加快速回复

问题

我们希望能够提供选项给用户,使得用户可以点选,以避免用户主动输入了我们无法处理的问句。

方案


在 wit.ai 中,当我们在 Bot sends 下面的 Set quick replies 处填写了若干个选项后,这些选项将会在实际对话时出现在用户输入框的上方,提供给用户备选。

删除回复和动作

问题

我想要删除我设置的一些回复和动作。

方案

可以按照如图所示的方式操作。

小结

由此看来:

还不了解的是:

上一篇下一篇

猜你喜欢

热点阅读