Python-聊天机器人构建指南-全-

Python 聊天机器人构建指南(全)

原文:Building Chatbots with Python

协议:CC BY-NC-SA 4.0

一、可爱的聊天机器人

当你开始构建聊天机器人时,了解聊天机器人做什么和它们看起来像什么是非常重要的。

你一定听说过 Siri,IBM Watson,Google Allo 等。这些机器人试图解决的基本问题是成为一个中介,帮助用户变得更有生产力。它们通过允许用户更少地担心如何检索信息以及获取特定数据可能需要的输入格式来做到这一点。随着机器人处理用户数据输入并从中获得更多见解,它们往往会变得越来越智能。聊天机器人之所以成功,是因为它们能给你想要的东西。

当您每次在不同的网站上必须输入相同的姓名、电子邮件 ID、地址和密码时,您是否感到恼火或沮丧?想象一下,一个单独的机器人来完成你的任务——比如,从不同的供应商那里订购食物,从各种电子商务公司在线购物,或者预订机票或火车票——并且你不必每次都提供相同的电子邮件 ID、送货地址或支付信息。机器人有能力知道这些信息,并且足够聪明,当你用自己的语言或计算机科学中称为自然语言的语言询问时,它可以检索到所需的信息。

聊天机器人的开发比几年前容易多了,但是聊天机器人在几十年前就已经存在了;然而,聊天机器人的受欢迎程度在过去几年里呈指数级增长。

如果你是一个技术人员,或者对 web 应用程序或移动应用程序的工作原理有所了解,那么你一定听说过术语 API。您今天需要的任何类型的数据都可以以不同服务提供商和机构提供的 API 的形式使用。如果你在寻找天气信息、订票、点餐、获取航班信息、将一种语言转换成另一种语言,或者在脸书或 Twitter 上发帖,所有这些都可以使用 API 来完成。基于 web 或移动设备的应用程序使用这些 API 来完成这些任务。聊天机器人也可以根据我们的请求使用这些 API 来完成相同的任务。

聊天机器人比传统的在线完成事情的方法更有优势的原因是你可以在聊天机器人的帮助下做多件事情。它不仅仅是一个聊天机器人,它就像你的虚拟私人助理。你可以在 booking.com 上预订一个酒店房间,也可以在酒店附近的餐厅预订一张桌子,但是你可以使用你的聊天机器人。聊天机器人满足了多用途的需求,因此节省了大量的时间和金钱。

在本书中,我们将学习如何使用机器人建立自然的对话体验,以及如何教机器人理解我们的自然语言,并让它从单一界面为我们完成任务。

一般来说,机器人只不过是一台足够智能的机器,可以理解你的请求,然后以其他软件系统可以理解的方式制定你的请求,以请求你需要的数据。

聊天机器人使用的普及程度

聊天机器人变得流行起来,就像最近的事情一样。让我们试着看一下图 1-1 ,图中描绘了聊天机器人的崛起,同时也试着理解为什么对构建聊天机器人有巨大的需求。

img/461879_1_En_1_Fig1_HTML.jpg

图 1-1

Y 轴上的数字表示相对于图表最高点的全球所有类别的搜索兴趣

想到的简单答案是,这不是一个复杂的软件,任何人都可以使用。当我们构建软件时,我们的目标是将使用它的受众,但是当它被其他任何人使用时,它就变得困难和不可用了。当我们开发聊天机器人时,我们牢记它将被所有年龄段的人使用。这种情况只发生在聊天机器人身上,这种软件试图表现得像一个哑巴(但它是智能的),让用户做他或她自己。在所有其他软件中,你会发现你应该知道一些术语,或者逐渐知道如何最佳地利用它,但聊天机器人不是这样。如果你知道如何与人交谈,使用聊天机器人就不会有任何问题。

对聊天机器人的需求持续增长。然而,还没有太多的研究从经验上试图找出使用聊天机器人背后的动机。在最近的一项研究中,一份在线问卷调查了美国 16 至 55 岁的聊天机器人用户,询问他们在日常生活中使用聊天机器人的需求。调查显示“生产力”是使用聊天机器人的主要动机。

Python 的禅以及为什么它适用于聊天机器人?

我记得 Python 的禅,它说,“简单比复杂好”,这适用于软件中的许多地方。

Python 的禅是影响 Python 编程语言设计的 20 个软件原则的集合。

—蒂姆·彼得斯

想知道“Python 的禅是什么?"试试下面的步骤。

如果您的计算机上已经安装了 Python。只需进入您的 Python 解释器并import this:

Python 2.7.15 (default, May  1 2018, 16:44:08)
[GCC 4.2.1 Compatible Apple LLVM 9.1.0 (clang-902.0.39.1)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one—and preferably only one—obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea—let's do more of those!

你可能无法理解以上所有关于聊天机器人的观点,但你肯定能理解其中的大部分。

好吧,回到我们的话题,我记得当我来自 Orkut 背景时,开始使用脸书用户界面时遇到了困难。如果你从未使用过 Orkut,你不会理解它,但是试着想想你生活中的一个情景,你开始使用一些新的软件或应用程序,你很难掌握它的窍门。也许从 Windows 切换到 MacOS/Linux 或者相反?当你使用一个新的应用程序时,你需要学习一些东西,这需要时间来适应它,并知道它做什么和如何工作。有时,即使在使用了几年之后,您还是会知道这个应用程序的一些特性。如果你在 MacOS 上,试试 Shift + Option +音量调高/调低,看看会发生什么。如果这让你感到惊讶,如果你还不知道,请告诉我。

就聊天机器人而言,用户和服务器或后端系统之间的通信非常简单。这就像使用消息应用程序与其他人交谈一样。

你只需键入你想要的,机器人应该能够给你你想要的,或者应该指导你如何得到它。换句话说,它应该通过给你一个链接或文档来给你指出正确的信息。机器人甚至能够从文章和文档中挖掘信息并提供给用户的时代已经到来。

谷歌、脸书和 IBM 等公司以及亚马逊 Lex、wit.ai、api.ai、luis.ai、IBM Watson、亚马逊 Echo 等机器学习服务在人工智能方面取得了重大进展。导致了这种机器人的惊人增长和需求。

对聊天机器人的需求

现在,我们将尝试从两个不同的角度来看待聊天机器人在这个快速发展的信息创建和检索时代的需求:商业角度和开发者角度。因此,如果你是产品经理、销售经理,或者来自市场营销或任何直接推动业务的相关领域,那么你不应该跳过聊天机器人的业务视角。它将让您清楚地了解当今的企业需要采用这项技术来增加收入。

商业视角

我们将尝试从商业的角度来看待聊天机器人。对于一个企业来说,拥有一个聊天机器人或者将大量的工作转移到聊天机器人身上是好的吗?

企业将聊天机器人视为这一代营销工具之一的时机已经到来。

  • 可访问性:它们很容易访问。消费者可以打开网站,开始提问或开始解决他们的疑问,而不必拨打号码,并遵循 IVR 中“按 1 这个,按 2 那个”的丑陋方式。他们只需要一组基本的信息就能很快抓住要点。

  • 效率:顾客可以坐在办公室的办公桌前或客厅的沙发上观看比赛,并获得信用卡申请状态,查找食品订单状态,或对任何问题提出投诉。

如果你让客户变得高效和多产,他们就会开始喜欢你。机器人正是这样做的,并有助于促进业务。

  • 可用性 : 聊天机器人每周 7 天、每天 24 小时都可以使用。他们永远不会向你请假,也不会像人类员工一样累。他们每次都会以同样的效率和表现完成同样的任务或新任务。当一些客户服务电话号码说,“请在上午 9:00 到下午 6:00 之间打电话给我们”,只是为了一条信息时,你一定很沮丧。你的机器人永远不会这么说。

  • 可扩展性****:One Bot =>100 万员工。你看到这个了吗?是的,如果你的机器人可以做客户需要的事情,它可以轻松地同时处理成千上万的客户查询,而不用担心。你不需要让你的客户排队等候,直到客户代表有空。

  • 成本 : 不用说,它为企业节省了大量成本。谁不喜欢省钱?当机器人为你做这些的时候,你没有理由不喜欢它们。

  • 洞察力 : 你的销售代表可能无法记住用户的行为,并为你提供关于消费者行为模式的独家见解,但你的机器人可以使用机器学习和数据科学的最新技术。

聊天机器人带来收入

事实证明,聊天机器人成功地为企业带来了更多收入。与竞争对手相比,以聊天机器人支持或创建新的聊天机器人来支持客户查询开始的企业在市场上表现良好。

根据 stanfy.com 上的一篇博文,在引入脸书聊天机器人后的头两个月,1-800-Flowers.com 报告称,超过 70%的 Messenger 订单来自新客户。这些新客户也普遍比该公司的典型购物者年轻,因为他们已经熟悉 Facebook Messenger 应用程序。这大大增加了他们的年收入。

聊天机器人最大的附加值之一就是利用它们创造潜在客户。你可以在潜在客户关注的地方直接接触他们(信使),并向他们展示你的最新产品、服务或商品。当客户想要购买产品/服务时,他/她可以在聊天机器人中进行购买,包括支付过程。1-800flowers.com、易贝和 Fynd 等机器人已经证明了这一点。

——Julien Blancher,联合创始人@ Recast。人工智能

在 ChatbotsLife 的创始人 Stefan Kojouharov 的一篇文章中,他提到了不同的公司如何比没有聊天机器人的公司赚更多的钱。他说,

电子商务领域已经开始以多种方式使用聊天机器人,这迅速增加了他们的利润。让我们看看早期的成功案例:

  • 1–800-Flowers:报告称,超过 70%的 Messenger 订单来自新客户!

  • 丝芙兰:通过 Facebook Messenger 聊天机器人,她们的化妆预约增加了 11%。

  • Nitro Café: 通过他们的 Messenger chatbot,销售额增加了 20 %,该聊天机器人旨在方便订购、直接支付和即时双向交流。

  • Sun 的足球:聊天机器人通过特定的足球报道将近 50%的用户引回了他们的网站;43%的聊天机器人用户在其最好的时期点击进入。

  • Asos: 使用 Messenger 聊天机器人,订单增加了 300 %,获得了 250%的投资回报,同时接触到了 3.5 倍多的人。

图 1-2 试图让你了解为什么聊天机器人和收入之间有直接的关联。让我们看看图 1-2 来了解一下。

img/461879_1_En_1_Fig2_HTML.jpg

图 1-2

聊天机器人带来收入

聊天机器人用法一瞥

我们将尝试看看聊天机器人因其可用性和效率对消费者有多大帮助。在这个炙手可热的 IT 时代,每个人都想在每件事上都快一点,使用聊天机器人让你的工作每天都变得更容易、更快。它是个性化的,不会重复显而易见的事情;这让我们重新思考软件的传统用法。图 1-3 提供了一个图解,应该可以让你对聊天机器人的使用有一个大致的了解。

img/461879_1_En_1_Fig3_HTML.jpg

图 1-3

消费者使用聊天机器人一瞥

顾客更喜欢聊天机器人

聊天机器人不仅仅是现代的软件。聊天机器人就像我们的私人助理,理解我们,可以微配置。它们会记住我们的好恶,而且永远不会忘记我们已经教过它们的东西,这也是为什么每个人都喜欢聊天机器人的原因。下次你遇到一个人或者你的客户,不要忘记问他们是喜欢传统的软件还是新的尖端聊天机器人。让我们看一下图 1-4 来理解为什么相比其他人机交互软件系统,客户更喜欢聊天机器人。

img/461879_1_En_1_Fig4_HTML.jpg

图 1-4

顾客更喜欢聊天机器人

在本章的下一节,我们将讨论为什么聊天机器人是初露头角的开发者的下一件大事。无论您是新手、中级开发人员还是有经验的 SME,您都必须了解开发人员在构建聊天机器人时可以使用什么。

开发者的视角

当你为了使用新功能而不得不更新电脑、手机或任何其他应用程序的操作系统时,你有没有感到痛苦?如果没有太多需要每次更新 app 才能使用新功能怎么办?或者说,不是有多个应用程序,而是可以有一个应用程序来完成当前由多个应用程序完成的大部分事情?

开发人员创建机器人很有趣。这就像教你的孩子走路、说话、举止和做事。你喜欢让它变得更加智能和自给自足。从开发者的角度来看,聊天机器人是一个非常重要的话题。

功能发布和错误修复

许多功能可以轻松地添加到聊天机器人中,而无需用户更新你的聊天机器人应用程序。如果你发布了一个有 bug 的应用程序版本,这可能是一件痛苦的事情,你必须修复它,并在 AppStore 中再次发布以获得批准,最重要的是,用户最终将不得不更新应用程序。如果他们不更新,那么客户会一直抱怨这个问题,这会导致每个人的生产力损失。在聊天机器人中,一切都是基于 API 的,因此您只需在后端修复问题,在生产中部署更改,然后就可以为您的用户解决问题,无需担心。您还可以从用户报告的错误中节省大量时间。

假设您构建了一个查找餐馆的机器人,然后您想添加搜索酒店、航班等的功能。用户可以很容易地请求这些信息,你的后台聊天系统会处理好一切。

假设你正在构建一个 Facebook Messenger 聊天机器人;你可以直接从你的后端控制几乎一切,包括用户在他的应用程序中看到的界面。在 Facebook Messenger 机器人中,你可以选择用户是点击一个按钮来说是/否,还是仅仅输入简单的文本。

市场需求

2016 年,全球 54%的开发者首次开发聊天机器人。构建一个适用于公司的简单聊天机器人有着巨大的需求,他们正在寻找能够为他们构建聊天机器人的开发者。一旦你完成了这本书的第三章,我打赌你可以很容易地开始向公司推销你的服务。你也可以在你擅长的领域里通过引入聊天机器人来创业。能够建立一个端到端的聊天机器人是一项新技能,这就是为什么聊天机器人开发者的平均市场薪酬也非常高。

对聊天机器人日益增长的需求可以从脸书等开发者平台上开发的聊天机器人数量中看出。脸书的 Messenger 平台上每月有 10 万个活跃的机器人,而且还在增加。你会惊讶地知道,2015 年 4 月,Messenger 的用户有 6 亿,2016 年 6 月增长到 9 亿,2016 年 7 月 10 亿,2017 年 4 月 12 亿。

学习曲线

无论你是来自前端/后端背景,还是对编程知之甚少,当你正在构建或学习构建聊天机器人时,有巨大的可能性去学习新的东西。在这个过程中你会学到很多东西。例如,你可以学到更多关于人机交互(HCI)的知识,它讨论计算机技术的设计和使用,重点是人和计算机之间的界面。您将学习如何构建或使用 API 或 web 服务,使用第三方 API,如 Google APIs、Twitter APIs、优步 API 等。你将有巨大的机会学习自然语言处理,机器学习,消费者行为,以及许多其他技术和非技术的东西。

受聊天机器人影响的行业

让我们快速浏览一下将从聊天机器人中受益最多的行业。Mindbowser 与 Chatbots Journal 联合进行的一项研究收集了 300 多名个人的数据,这些人来自广泛的行业,包括在线零售、航空、物流、供应链、电子商务、酒店、教育、技术、制造和营销&广告。如果我们看看图 1-5 中的图表,很明显电子商务、保险、医疗保健和零售是聊天机器人的最大受益行业。这些行业在很大程度上依赖于客户服务团队以节省时间的高效方式做出响应。鉴于聊天机器人在这方面的优势,很明显它将很快在这些行业大受欢迎。

img/461879_1_En_1_Fig5_HTML.jpg

图 1-5

从聊天机器人中受益最多的顶级行业

此时此刻,聊天机器人仍然以不同的形式在较新的领域受到关注。未来 5 到 10 年将是聊天机器人在没有聊天机器人工作经验的不同行业传播信息的关键时期。

聊天机器人的简要时间表

让我们看看聊天机器人是如何形成的时间线的简史。了解聊天机器人技术的来源和形成过程非常重要。聊天机器人最近当然越来越受欢迎,但这种努力是利用这项技术几十年的工作来进行的。聊天机器人的历史肯定会让你惊讶,自从我们开始以来,我们已经走了多远。

One thousand nine hundred and fifty

图灵测试是由艾伦·图灵开发的。这是一项对机器表现出与人类同等或不可区分的智能行为的能力的测试。

One thousand nine hundred and sixty-six

第一个聊天机器人伊莱扎(Eliza)是由约瑟夫·韦岑鲍姆(Joseph Weizenbaum)创建的,旨在成为一名治疗师。它过去通过使用“模式匹配”和替代方法来模拟对话,给用户一种理解机器人的错觉。

One thousand nine hundred and seventy-two

精神病学家和斯坦福大学科学家肯尼斯·科尔比的计算机程序 Parry 模拟了偏执型精神分裂症患者的行为。

One thousand nine hundred and eighty-one

贾巴沃克聊天机器人是由英国程序员罗洛·卡彭特创建的。它始于 1981 年,并于 1997 年在互联网上推出。

这个聊天机器人的目的是“以有趣、娱乐和幽默的方式模拟自然的人类聊天。”

One thousand nine hundred and eighty-five

这款名为 Tomy Chatbot 的无线机器人玩具可以重复录制在磁带上的任何信息。

One thousand nine hundred and ninety-two

Sbaitso 博士是由 Creative Labs 为 MS-DOS 开发的聊天机器人,它用数字化的声音与用户“对话”,就像一个心理学家一样。用户反复的咒骂和错误的输入导致斯拜索博士在它能够自我重置之前就“崩溃”在“奇偶校验错误”中。

One thousand nine hundred and ninety-five

A.L.I.C.E(人工语言互联网计算机实体)是由诺贝尔奖获得者理查德·华莱士开发的。

One thousand nine hundred and ninety-six

由 Jason Hutchens 开发的 Hex 以 Eliza 为原型,于 1996 年获得了 Loebner 奖。

Two thousand and one

Smarterchild 是由 ActiveBuddy 开发的智能机器人,广泛分布在全球实例消息传递和 SMS 网络中。最初的实现很快发展到提供对新闻、天气、股票信息、电影时间、黄页列表、详细的体育数据以及各种工具(个人助理、计算器、翻译器等)的即时访问。).

Two thousand and six

沃森的想法是在餐桌上创造出来的;它被设计用来参加电视节目《危险边缘》的比赛。在第一次测试中,它只能获得大约 15%的正确答案,但后来沃森能够定期击败人类参赛者。

Two thousand and ten

智能个人助理 Siri 是作为 iPhone 应用程序推出的,然后集成为 iOS 的一部分。Siri 是 SRI 国际人工智能中心的副产品。它的语音识别引擎由 Nuance Communications 提供,Siri 使用先进的机器学习技术来运行。

Two thousand and twelve

谷歌推出了 Google Now 聊天机器人。它最初的代号是“Majel ”,以 Majel Barrett 命名,Majel Barrett 是吉恩·罗登伯里的妻子,也是《星际迷航》系列中计算机系统的声音;它的代号也是“助手”

Two thousand and fourteen

亚马逊发布了 Alexa。单词“Alexa”与 X 有一个硬辅音,因此可以更精确地识别它。这是亚马逊选择这个名字的主要原因。

Two thousand and fifteen

微软打造的虚拟助手 Cortana。Cortana 可以设置提醒,识别自然语音,并使用来自 Bing 搜索引擎的信息回答问题。它是以《光环》电子游戏系列中一个虚构的人工智能角色命名的。

Two thousand and sixteen

2016 年 4 月,脸书宣布了一个用于 Messenger 的机器人平台,包括用于构建聊天机器人与用户互动的 API。后来的增强包括机器人能够加入群体,预览屏幕,以及通过 Messenger 的摄像头功能将用户直接带到机器人面前的 QR 扫描功能。

2016 年 5 月,谷歌在该公司的开发者大会上发布了其亚马逊 Echo 竞争对手的语音机器人 Google Home。它使用户能够说出语音命令来与各种服务进行交互。

Two thousand and seventeen

Woebot 是一个自动化的对话代理,可以帮助你监控情绪,了解自己,让你感觉更好。Woebot 使用 NLP 技术、心理学专业知识(认知行为疗法【CBT】)、优秀的写作和幽默感的组合来治疗抑郁症。

使用聊天机器人可以解决什么样的问题?

当你不知道你的机器人的范围或者不想限制它回答查询时,这个问题变得具有挑战性。

记住聊天机器人的能力是有限的,这一点非常重要。它总感觉我们在和一个很智能的类似人类的东西对话,但特定的 bot 是被设计和训练成以某种方式表现的,并且只解决特定的问题。它不能做所有的事情,至少目前是这样。前途肯定是光明的。

所以,我们来看看你的问题陈述是不是真的很好,你可以围绕它建立一个机器人。

如果这三个问题的答案都是肯定的,那么你就可以走了。

问题可以通过简单的问答或者来回的交流来解决吗?

在解决任何对你来说非常新的问题时,不要逞英雄,这真的很重要。你应该始终致力于限制问题的范围。构建基本功能,然后在此基础上进行添加。不要试图在第一次切割时就把它复杂化。它在软件中不起作用。

想象一下马克·扎克伯格从一开始就大胆思考并花时间构建脸书的所有功能。给朋友加标签、有喜欢按钮、喜欢用户评论、更好的消息传递、实时视频、对评论的反应等等。—即使脸书在平台上注册用户超过 100 万,这些功能也不存在。如果他先构建这些功能,然后推出平台,他真的会成功吗?

因此,我们应该总是尝试创建只在当前需要的功能,而不必过度设计。

现在,回到第一个问题,“问题可以通过简单的问答或来回沟通来解决吗?”

你只需要保持你的范围有限,你的答案将是肯定的。我们并没有把自己局限于解决复杂的问题,而是明确地把自己局限于一次性解决一个复杂的问题。

“你必须让每个细节都尽善尽美。你必须限制细节的数量。”

—杰克·多西

它是否存在需要分析或获取数据的高度重复性问题?

这个问题很重要,因为无论是从商业的角度还是从开发者的角度来看,chatbot 所做的和被要求做的是让人们使用它变得高效和多产。你是怎么做到的?通过消除用户自己做重复事情的需要。

聊天机器人无疑更有能力自动化一些高度重复的东西,但你总是会发现大多数聊天机器人主要试图解决同一问题——无论是在监督下学习(阅读:“通过监督学习”)还是自学(阅读:“通过无监督学习”)。

你的机器人的任务可以自动化和固定吗?

除非你只是出于学习的目的而想建造一个聊天机器人,否则你应该确保你试图解决的问题可以自动化。机器已经开始自己学习和做事情,但这仍然是一个非常初级的阶段。你认为现在不能自动化的,几年后可能会自动化。

QnA 机器人

QnA 机器人是构建聊天机器人的问题陈述的一个很好的例子。想象一下,一个经过训练的机器人能够理解用户提出的各种问题,这些问题的答案已经可以在网站的 FAQ 页面上找到。

如果你回过头去试着寻找前述三个问题的答案,答案会是肯定的。

见图 1-6 你会发现一个 FAQ 机器人在做什么。

img/461879_1_En_1_Fig6_HTML.jpg

图 1-6

常见问题聊天机器人示例

这些都是非常重复的问题,特定商店的顾客可能会打电话询问,或者试图通过访问网站并浏览页面来找到答案。

想象一下,当你有一个像这样的聊天机器人,它像人一样在几秒钟内回答你的问题,甚至做的比你想象的还要多。这只是聊天机器人能力的一小部分。

现在,我们试着以 QnA Bot 为例,分析一下前面提到的三个问题及其答案。

  • 问题可以通过简单的问答或者来回沟通来解决吗?

    是的,FAQ 只不过是简单的常见问题及其相关答案。可能会有一个基于上下文的 FAQ,但是除非你正在使用聊天机器人解决一个多领域的问题,否则你不会有这个问题。可能会有两个或更多的问题看起来相似的情况,但是你总是可以设计机器人在有疑问的时候问用户一个问题。

  • 它是否存在需要分析或获取数据的高度重复性问题?

    是的,常见问题要求我们从数据库中提取数据,并在网站上一次性显示出来,或者动态显示。但是用户必须一个接一个地浏览所有的问题来找到他/她正在寻找的问题,然后看到它的答案。在消费者真正得到答案之前,需要对用户界面进行大量的梳理...也可能不是。为什么不让我们的机器人替我们做呢?

  • 你的机器人的任务可以自动化和固定吗?

    是的,FAQ 机器人需要获取问题,分析问题,从数据库中获取信息,并将其返回给用户。这里没有什么是使用编码做不到的。此外,它几乎固定的流程不会实时改变。

从聊天机器人开始

在构建聊天机器人之前,应该遵循三个步骤。我们将在这里简要讨论它们中的每一个。

  1. 考虑你希望你的聊天机器人能够完成的所有场景或任务,并以不同的形式收集所有相关的问题来完成这些任务。你希望你的聊天机器人做的每一项任务都会定义一个意图

  2. 你列出的每个问题或意图都可以用多种方式来表达。就看用户怎么表达了。

    比如:Alexa,关灯。Alexa,你能把灯关掉吗?你能关掉灯吗?用户可以使用这些句子中的任何一句来指示机器人关灯。所有这些人都有同样的意图/任务去关灯,但是他们被要求用不同的话语 / 差异

  3. 在您认识到用户的意图后,编写所有的逻辑来保持用户与您选择的流程的联系。

    例如,假设您正在构建一个预约医生的机器人。然后你要求你的用户给一个电话号码,姓名,和专家,然后你显示插槽,然后预订它。

在这种情况下,你可以期望用户知道这些细节,而不是试图适应机器人本身的所有事情,就像一个耳朵问题的专家被称为耳鼻喉科。然而,这样做并不是什么大事。因此,这又回到决定你的机器人的范围,取决于你必须建立应用程序的时间和资源。

聊天机器人中的决策树

如果你知道决策树,那很好,因为在设计聊天机器人的流程时,你会经常需要这些知识。但是如果你不知道决策树,那么谷歌搜索将帮助你学习这个在计算机科学中广泛使用的简单概念。

在聊天机器人中使用决策树

在聊天机器人的环境中,决策树只是帮助我们找到用户问题的准确答案。

决策树 是一种决策支持工具,它使用决策及其可能后果的树状图形或模型,包括偶然事件结果、资源成本和效用。这是显示只包含条件控制语句的算法的一种方式。

—维基百科

构建聊天机器人时最困难的部分是跟踪 if...else 代码块。要做的决策越多,如果...否则会出现在代码中。但同时需要这些块来编码复杂的对话流。如果问题很复杂,并且在现实生活中需要很多 if…else,那么这将需要代码以同样的方式进行调整。

决策树有什么帮助?

决策树的编写和理解都很简单,但它们是对问题解决方案的有力表示。他们继承了一种独特的能力来帮助我们理解很多事情。

  • 有助于全面了解手头的问题。查看决策树,我们可以很容易地了解缺少什么或需要修改什么。

  • 有助于更快地调试。决策树就像一本简短的圣经,或者说,软件需求规范文档的可视化表示,开发人员、产品经理或领导层可以参考它来解释预期的行为或在需要时进行任何更改。

  • 人工智能仍然没有达到可以用大量数据训练并以 100%的准确率执行的阶段。它仍然需要通过编写业务逻辑和规则进行大量的手动操作。决策树在要求机器学习和做这件事变得有点困难的任何地方都有帮助。

让我们举一个简单的例子,并尝试理解它如何帮助构建聊天机器人。请看聊天机器人的示例图,该图以用户是在找 t 恤还是牛仔裤的问题开始,基于输入,图流通过询问更多的问题进一步给出与产品相关的选项。你不需要创建一个完全成熟的决策树,但在开始构建聊天机器人之前,你肯定应该在每一步都定义一个问题流。

假设你正在开发一个类似的聊天机器人,帮助人们在线购买服装。你要做的第一件事是做一个类似的决策树或流程图,帮助你的聊天机器人在正确的时间问适当的问题。这对于设定每个步骤的范围以及在该阶段需要做什么是非常必要的。当你真正编写你的第一个聊天机器人时,你将需要状态图或者简单的流程图。在创建如图 1-7 的图表时,切记不要过于严格;尽可能保持简单,以后再添加扩展功能。这种过程的好处是开发时间将会减少,以后功能将会松散耦合,并开始作为组件有意义。像示例中一样,在创建基本功能后,您还可以添加颜色选择、价格范围、评级和折扣选项。

img/461879_1_En_1_Fig7_HTML.jpg

图 1-7

一个服装聊天机器人的简单表示,用于在线购买服装

根据您的需求,肯定有更多的东西可以添加到早期的用例中。但是你必须确保不要让它对你自己和用户来说都太复杂。

决策树不仅可以帮助你将用户与流程联系在一起,也是一种非常有效的方式来识别下一个意图,这个意图可能是来自客户的一个问题。

所以,你的机器人会按照你建立的决策树问一系列问题。每个节点通过聊天机器人的意图缩小客户的目标。

假设您正在为一家金融机构——比如说一家银行——创建一个聊天机器人,它可以在身份验证后根据您的请求进行转账。在这种情况下,您的 bot 可能首先希望验证帐户详细信息,并要求用户确认金额,然后 bot 可能要求验证目标帐户名称、帐号、帐户类型等。您不能或不想调用 OTP(一次性密码)API,除非您已经验证了用户的帐户余额是否大于请求的金额。

这发生在我们所有人身上,也发生在顾客身上。当他们的问题没有得到正确回答时,他们会感到沮丧。在聊天机器人中使用决策树肯定会比不使用决策树给用户带来更好的体验。

很多时候,你会发现以编程方式解决一些意图的问题。所以,底线是,"如果你不能通过编程来解决问题,那么就通过设计来解决它。"

请看图 1-8 ,机器人正试图进行一项健康测试,并想知道抗生素是否对所有疾病都有效。

img/461879_1_En_1_Fig8_HTML.jpg

图 1-8

通过设计解决用例的例子

因为答案应该是一个布尔值(真/假),所以您只给用户两个按钮来点击,而不是让他们键入并等待修复他们的错误。

这是通过设计来解决,而不是编写大量代码来处理意外的用户输入。在创建聊天机器人时,你会有很多场景,只要按下按钮,你就能很快知道用户的意图。理解这样的场景并提供按钮是很重要的,这既是为了你自己的方便,也是为了那些不需要输入明显的可选答案的用户。

最佳聊天机器人/机器人框架

  • https://woebot.io/

    • 可以跟踪你的心情

    • 让你感觉更好

    • 通过观察你的情绪模式给你洞察力

    • 教你如何变得积极和精力充沛

  • https://qnamaker.ai/

    • 基于 FAQ、URL 和结构化文档,在几分钟内构建、训练和发布一个简单的问答机器人。

    • 使用熟悉的聊天界面测试和优化回复。

  • https://dialogflow.com/

    • 原名 api.ai,在聊天机器人爱好者中广受欢迎。

    • 通过构建由人工智能支持的引人入胜的基于语音和文本的对话界面,为用户提供与您的产品交互的新方式。

    • 在 Google Assistant、Amazon Alexa、Facebook Messenger 和其他流行的平台和设备上与用户联系。

    • 分析并理解用户的意图,帮助你以最有用的方式做出回应。

  • https://core.rasa.ai

    • 构建对话式软件的框架

    • 您可以用 Python 代码实现您的 bot 可以采取的操作。

    • 你的机器人的逻辑不是一堆 if…else 语句,而是基于在示例对话中训练的概率模型。

  • https://wit.ai

    • Wit.ai 让开发者可以轻松构建你可以与之交谈或发短信的应用和设备。

    • wit.ai 团队在推出后 21 个月内被脸书收购,为脸书在脸书开发自己的 NLP 引擎做出了贡献。

    • 你可以使用 wit.ai 来构建聊天机器人、家庭自动化等。

    • Wit.ai 类似于 Dialogflow 的工作方式,但功能不如 Dialogflow 丰富。人们最初使用 wit.ai,因为它是免费的,而 Dialogflow 不是,但后来 Dialogflow 也变得免费了。

  • https://www.luis.ai/

    • 基于机器学习的服务,将自然语言构建到应用程序、机器人和物联网设备中。

    • 快速创建可持续改进的企业级定制模型。

  • http://botkit.ai

    • 可视对话生成器

    • 内置的统计数据和指标

    • 可以很容易地与脸书、微软、IBM Watson、Slack、Telegram 等集成。

聊天机器人的组件和使用的术语

聊天机器人系统的组件非常少。在这一节中,我们将简要讨论您将在后面章节中遇到的聊天机器人的组件。

在深入潜水之前,对任何系统有一个基本的理论了解总是有帮助的。在阅读完这一节之后,您应该对使用 Python 构建聊天机器人时使用的技术术语有一个大致的了解。当我们真正开始构建聊天机器人时,这些术语将在接下来的章节中频繁使用。

目的

当用户与聊天机器人交互时,他使用聊天机器人的意图是什么/他的要求是什么?

例如,当用户对聊天机器人说:“预订电影票”时,我们作为人类可以理解用户想要预订电影票。这是机器人的意图。可以命名为“book _ movieintent。

另一个例子是当用户说,“我想点餐”,或者“你能帮我点餐吗?”这些可以被命名为“订单 _ 食品”意图。同样,您可以定义任意多的意图。

实体

意图有关于意图的元数据,称为"实体。“在示例中,“预订电影票”,预订票可以是一个意图,并且实体是“电影,”,这也可以是其他的东西,如航班、音乐会等。

您可以将通用实体标记为在整个意图中使用。实体可以用数量、计数或体积来表示。意图也可以有多个实体。

比如:给我订一双 8 码的鞋。

这里可能有两个实体:

类别:鞋子

尺寸:8

言论

话语只不过是你的用户可能表现出的同一问题/意图的不同形式。

  • 记得我们讨论过关掉灯的意图吗?这是一个用户如何使用不同的话语来表达相同意图的例子。

  • 建议每个意图有最佳的 10 个话语,最少 5 个,但这不是限制性的。

训练机器人

训练本质上意味着建立一个模型,该模型将从已定义的意图/实体和话语的现有集合中学习如何对新的话语进行分类,并提供一个置信度得分。

当我们使用话语训练系统时,这被称为监督学习。我们很快会学到更多关于实际操作的知识。

置信度得分

每当你试图找出一个话语可能属于什么意图时,你的模型就会给出一个置信度得分。这个分数告诉你你的机器学习模型在识别用户意图方面有多自信。

这就是我们想在“聊天机器人简介”的第一章中介绍的全部内容你必须从商业角度和技术角度对聊天机器人有一个公平的想法。我们走过了属于聊天机器人的历史车道。聊天机器人的进化程度令人着迷。

我们了解了聊天机器人在一段时间内是如何发展的,以及为什么聊天机器人是一个企业在这场残酷的竞争中成长的必备工具。我们了解了不同的聊天机器人框架,并通过示例了解了聊天机器人的术语。我们将在接下来的章节中使用它们。你现在应该已经知道你想要构建什么样的聊天机器人,以及它在构建后会有什么样的表现。

如果需要的话,做好你所有的记录和决策树,在下一章我们学习了自然语言理解的基础知识之后,我们可以快速开始构建我们的聊天机器人。

即使你没有任何想法,也不要担心。我们将尝试用接下来几章学到的所有概念一步一步地构建一个很酷的聊天机器人。

下一章见。

二、聊天机器人的自然语言处理

本章旨在让你开始使用 Python 进行自然语言处理(NLP)来构建聊天机器人。您将使用一个名为 spaCy 的令人惊叹的开源库来学习 NLP 的基本方法和技术。如果您是 Python 生态系统的初学者或中级用户,那么不要担心,因为您将开始学习聊天机器人 NLP 所需的每一步。这一章不仅教你 NLP 中的方法,还用实际例子和编码例子来演示它们。我们还将讨论为什么聊天机器人可能需要特定的 NLP 方法。注意 NLP 本身就是一种技能。

我们将密切关注词性标注、词干、实体检测、停用词、依存句法分析和名词组块,并找出单词之间的相似性。当你构建你的用例的聊天机器人时,所有这些方法都会对你很有帮助。

除了本章介绍的方法之外,还有很多其他的 NLP 方法。基于你对正在构建的聊天机器人的需求,你可以尝试学习它们。在本章结束时,我们将要学习使用的 SpaCy 库将会给你足够的关于如何扩展你的 NLP 知识库及其理解的想法。所以,让我们开始,在下一节中首先尝试理解聊天机器人的 NLP。

为什么我需要知道自然语言处理来构建聊天机器人?

要了解这个问题的答案,我们先来了解一下自然语言处理(NLP)。

自然语言处理(NLP) 是人工智能的一个领域,使计算机能够分析和理解人类语言。

现在,为了执行 NLP,或者说,自然语言理解(NLU),我们有很多方法,接下来我们将讨论这些方法。你听到了一个新术语自然语言理解(NLU)——那是什么?

简单来说,NLU 是 NLP 更大图景的子集,就像机器学习、深度学习、NLP 和数据挖掘是人工智能(AI)更大图景的子集,人工智能是任何做一些智能事情的计算机程序的总称。

一个很好的经验法则是使用术语 NLU 来表达机器理解人类提供的自然语言的能力。

现在,关于你是否真的需要了解 NLP 来构建一个聊天机器人的问题——答案是肯定的和否定的。困惑了吗?你没听错,不是说你不知道 NLP 的方法和技术就根本造不出聊天机器人,只是你的范围会有些局限。您无法在扩展应用程序的同时保持代码整洁。当聊天机器人不能行走和奔跑时,NLP 给了它飞翔的翅膀。

对于普通人来说,聊天机器人只不过是与另一端的智能机器进行交流的一种方式。这种机器既可以是基于语音的,也可以是基于文本的,用户将用他们自己的语言输入,这在计算机科学中通常被称为自然语言。

我们知道不存在有魔力的黑盒,一切都很好。一要知道 AI 里没有什么人工的东西;它实际上是由伟大的人编写的机器学习和深度学习算法,在引擎盖下运行。机器还没有达到可以像人类一样思考拥有自己智能的阶段。今天的人工智能系统——它们做什么和它们的行为方式——是我们如何训练它们的结果。

因此,要理解用户的自然语言,不管它是什么语言,也不管它是什么输入形式(文本、语音、图像等)。),我们必须编写算法并使用 NLP 的技术。NLP 被认为是聊天机器人的大脑,它处理原始数据,执行 munging,清理数据,然后准备采取适当的行动。

NLP 本身是一个巨大的主题,需要时间和毅力来完全学习,但是对于一个聊天机器人开发者来说,有一些方法是必须知道的,这是我们在本章将要学习的。

spaCy 是什么?

spaCy 是一个用于高级 NLP 的开源软件库,用 Python 和 Cython 编写,由 Matthew Honnibal 构建。它提供了直观的 API 来访问其由深度学习模型训练的方法。

spaCy 提供了世界上最快的语法分析器。直接取自 spaCy 的文档,他们有一些惊人的基准测试结果,如下所示。

spaCy 的基准结果

2015 年的两篇同行评议论文证实,spaCy 提供了世界上最快的语法分析器,其准确性在现有最佳水平的 1%以内。少数更精确的系统要慢 20 倍甚至更多。让我们试着看一下图 2-1 ,它显示了基于速度和准确性的 spaCy 基准测试结果,与其他库进行了比较。

img/461879_1_En_2_Fig1_HTML.jpg

图 2-1

空间基准测试结果

spaCy 还提供多种语言的统计神经网络模型,如英语、德语、西班牙语、葡萄牙语、法语、意大利语、荷兰语和多语言 NER。它还为各种其他语言提供了标记化。此表显示了 Choi 等人的速度基准,因此在不同硬件上比较 spaCy v2.x 基准是不公平的。这就是您看不到 spaCy v2.x 的速度列值的原因。

spaCy 提供了什么?

spaCy 声称提供了三个主要的东西,并且非常有帮助。让我们来看看这些,并理解为什么人们应该知道并使用 spaCy 作为进行 NLP 的首选模块。

世界上最快的图书馆

spaCy 在提取大规模信息方面做得非常好。在 Cython 库的帮助下,它是从零开始编写的,对内存有着极大的关注。

把事情做完

spaCy 的设计理念是“把事情做好”。它帮助我们完成真实世界的 NLP 场景。干净的文档为开发人员和计算语言学爱好者节省了大量时间,并使他们更有效率。它很容易安装,就像任何其他 Python 包一样。

深度学习

spaCy 是开源社区中处理深度学习算法文本的最佳库之一。它与 TensorFlow、PyTorch、scikit-learn、Gensim 以及 Python 的其他相关技术无缝协作。深度学习开发者可以很容易地为一系列 NLP/NLU 问题构建语言复杂的统计模型。

空间特征

没有其他 NLP 库提供了范围极其广泛的 API 来做几乎所有的事情,这正是 spaCy 所做的。这个库最大的优点是它在不断发展,变得越来越好。让我们先睹为快,看看他们官网[ https://spacy.io/ ]上提到的 spaCy 的特性。

  • 非破坏性标记化

  • 命名实体识别

  • 支持 28 种以上的语言

  • 8 种语言的 13 种统计模型

  • 预先训练的单词向量

  • 轻松的深度学习集成

  • 词性标注

  • 标记依存句法分析

  • 句法驱动的句子分割

  • 语法和 NER 的内置可视化工具

  • 方便的字符串到哈希映射

  • 导出到 numpy 数据数组

  • 高效的二进制序列化

  • 简单的模型打包和部署

  • 最先进的速度

  • 稳健、经过严格评估的精确度

现在,让我们深入研究 Python 中这个令人敬畏的 NLP 模块:spaCy。

安装和先决条件

在我们真正深入空间和代码片段之前,请确保您的操作系统上安装了 Python。如果没有,请参考[1]。

你可以使用你喜欢的任何版本的 Python。今天,大多数系统都预装了默认的 Python 2.7 . x 版本。在本章中,我们将使用 Python 3。所以,如果你想使用 Python 3,请从 https://www.python.org/downloads/ 下载 Python 3 安装在你的操作系统上。如果已经安装了 Python 2,也可以使用它;它可能需要也可能不需要微小的代码更改。

我们将通过 pip [2]安装 spaCy。

我们将使用虚拟环境[3]并将 spaCy 安装到一个用户目录中。

如果您使用的是 macOS/OSX/Linux,请遵循以下步骤:

Step 1:
python3 -m pip install -U virtualenv

Step 2:
virtualenv venv -p /usr/local/bin/python3 #Make sure you use your own OS path for python 3 executable.

Step 3:
source venv/bin/activate

Step 4:
pip3 install -U spacy # We'll be using spaCy version 2.0.11.

最后一步可能需要时间,所以耐心等待。

如果您使用的是 Windows,只需将步骤 3 更改为

venv\Scripts\activate

现在,我们将在我们的虚拟环境中安装 Jupyter Notebook ,这是我们在步骤 3 中激活的。使用 Jupyter Notebook 比标准的 Python 解释器要容易得多,效率也更高。在接下来的章节中,我们将执行 Jupyter 笔记本中的所有片段。

要安装 Jupyter Notebook,请运行以下 pip 命令:

pip3 install jupyter

此命令将在您的系统中安装 Jupyter 笔记本。

此时,您应该已经在您的 virtualenv 中安装了 spaCy 和 Jupyter Notebook。让我们验证一下是否所有的东西都安装成功了。

  1. 转到您的命令行界面,键入以下内容,您应该会看到一个服务器正在启动,并在您的默认浏览器中打开一个 url。

    $ jupyter notebook
    
    

    默认的网址是http://localhost:8888/tree。它应该看起来像图 2-2 。

  2. Click on New as shown in Figure 2-2, and choose Python 3. It will open a new tab in your current browser and create a new notebook for you, where you can play with the Python code. You can execute any Python code, import libraries, plot charts, and markdown cells.

    img/461879_1_En_2_Fig2_HTML.jpg

    图 2-2

    木星笔记本第一眼

  3. Type import spaCy and run the cell by clicking on “Run” button or by pressing Shift + Enter. It should look something like Figure 2-3.

    img/461879_1_En_2_Fig3_HTML.jpg

    图 2-3

    验证空间安装

如果步骤 3 没有抛出任何错误消息,那么您已经成功地在您的系统上安装了 spaCy 模块。你应该在你的笔记本上看到你安装的空间版本。如果您想安装相同版本的 spaCy,那么您可以在通过 pip 安装 spaCy 时指定版本。

pip3 install –U spacy==2.0.11

什么是 SpaCy 模型?

SpaCy 模型就像任何其他机器学习或深度学习模型一样。模型是算法的产物,或者说,是在使用机器学习算法训练数据之后创建的对象。spaCy 有很多这样的模型,可以像下载其他 Python 包一样直接放在我们的程序中。

现在,我们将把 spaCy 模型作为 Python 包安装。

为此,我们将利用 notebook 的 magic 命令在 notebook 中运行以下命令。通过前缀!在 shell 命令之前,我们也可以从 Jupyter 笔记本中运行 shell 命令。让我们看看它看起来怎么样。

!python3 -m spacy download en

使用 Jupyter Notebook 下载Python 3的空间模型时,您可能会遇到权限问题。转到您的终端,运行以下命令:

sudo python3 –m download en

参见图 2-4 进行参考。

img/461879_1_En_2_Fig4_HTML.jpg

图 2-4

下载空间模型

如图 2-4 所示,spaCy 试图下载一些核心文件,并作为 Python 包安装。

注意

!【感叹号运算符】只在 Jupyter 笔记本中起作用。要直接从终端安装 spaCy 型号,您需要删除!【感叹号运算符】;否则会导致错误。

  1. https://www.python.org/downloads/

  2. https://packaging.python.org/tutorials/installing-packages/#installing-from-pypi

  3. http://docs.python-guide.org/en/latest/dev/virtualenvs/

构建聊天机器人的自然语言处理基本方法

擅长基础知识,成为某方面的专家,并高效地完成它,这真的很重要。要构建聊天机器人,我们需要了解自然语言处理的基本方法。这些方法有助于我们将输入分解成块,并使其有意义。在下一节,我们将学习一些最常用的自然语言处理方法,这些方法不仅能帮助你擅长自然语言处理,还能帮助你构建很酷的聊天机器人。我们越能更好、更有效地处理输入文本,我们就能更好地响应用户。

词性标注

词性标注是一个过程,在这个过程中,你阅读一些文本,并为每个单词或标记分配词性,如名词、动词、形容词等。

当你想识别给定句子中的某个实体时,词性标注变得极其重要。第一步是做词性标注,看看我们的文本包含什么。

让我们用一些真正的 POS 标记的例子来弄脏我们的手。

例 1:

nlp = spacy.load('en') #Loads the spacy en model into a python object
doc = nlp(u'I am learning how to build chatbots') #Creates a doc object
for token in doc:
    print(token.text, token.pos_) #prints the text and POS

输出:

('I', 'PRON')
('am', 'VERB')
('learning', 'VERB')
('how', 'ADV')
('to', 'PART')
('build', 'VERB')
('chatbots', 'NOUN')

例 2:

doc = nlp(u'I am going to London next week for a meeting.')
for token in doc:
    print(token.text, token.pos_)

输出:

('I', 'PRON')
('am', 'VERB')
('going', 'VERB')
('to', 'ADP')
('London', 'PROPN')
('next', 'ADJ')
('week', 'NOUN')
('for', 'ADP')
('a', 'DET')
('meeting', 'NOUN')
('.', 'PUNCT')

正如我们所看到的,当我们打印从方法nlp,返回的Doc对象的标记时,方法nlp,是一个用于访问注释的容器,我们得到了用句子中的每个单词标记的 POS。

这些标签是属于单词的属性,它们决定了单词在语法正确的句子中的使用。我们可以利用这些标签作为信息过滤等领域的词汇特征。

让我们试着举另一个例子,我们试着探索来自Doc对象的令牌的不同属性。

例 3:

doc = nlp(u'Google release "Move Mirror" AI experiment that matches your pose from 80,000 images')

     for token in doc:
          print(token.text, token.lemma_, token.pos_, token.tag_, token.dep_,
                token.shape_, token.is_alpha, token.is_stop)

输出:

|

正文

|

引理

|

位置

|

标签

|

dep

|

形状

|

alpha

|

停止

|
| --- | --- | --- | --- | --- | --- | --- | --- |
| 谷歌 | 谷歌 | -好的 | NNP | 复合的 | 五 x 综合征 | 真实的 | 错误的 |
| 发布 | 释放;排放;发布 | 名词 | 神经网络 | 模式 | 电影站 | 真实的 | 错误的 |
| | " | 点点 | `` | 点点 | " | 错误的 | 错误的 |
| 移动 | 移动 | -好的 | NNP | 模式 | 电影站 | 真实的 | 错误的 |
| 镜子 | 镜子 | -好的 | NNP | 模式 | 五 x 综合征 | 真实的 | 错误的 |
| | " | 点点 | " | 点点 | " | 错误的 | 错误的 |
| | 人工智能 | -好的 | NNP | 复合的 | xx | 真实的 | 错误的 |
| 实验 | 实验 | 名词 | 神经网络 | 根 | 电影站 | 真实的 | 错误的 |
| 那个 | 那 | 形容词 | 禁水试验 | nsubj | 电影站 | 真实的 | 真实的 |
| 匹配 | 比赛 | 动词 | 核黄素 | relcl | 电影站 | 真实的 | 错误的 |
| 你的 | PRON | 形容词 | PRP 元 | 可能的 | 电影站 | 真实的 | 真实的 |
| 姿势 | 姿态 | 名词 | 神经网络 | 扔过来 | 电影站 | 真实的 | 错误的 |
| 来自 | 从 | 腺苷二磷酸 | 在…里 | 准备 | 电影站 | 真实的 | 真实的 |
| 8 万 | Eighty thousand | 全国矿工联合会 | 激光唱片 | nummod | dd,ddd | 错误的 | 错误的 |
| 图像 | 图像 | 名词 | 非营养性吸吮 | 比吉 | 电影站 | 真实的 | 错误的 |

例 4:

doc = nlp(u'I am learning how to build chatbots')
for token in doc:
    print(token.text, token.lemma_, token.pos_, token.tag_, token.dep_,
        token.shape_, token.is_alpha, token.is_stop)

输出 :

|

正文

|

引理

|

位置

|

标签

|

dep

|

形状

|

alpha

|

停止

|
| --- | --- | --- | --- | --- | --- | --- | --- |
| | PRON | 代词 | 富含血小板血浆 | nsubj | X | 真实的 | 错误的 |
| 上午 | 是 | 动词 | 文件 | 去吧 | xx | 真实的 | 真实的 |
| 学习 | 学习 | 动词 | 静脉全血葡萄糖 | 根 | 电影站 | 真实的 | 错误的 |
| 如何 | 怎么 | 副词 | war refugee board 战时难民事务委员会 | advmod | xxx | 真实的 | 真实的 |
| | 到 | 部分 | 到 | 去吧 | xx | 真实的 | 真实的 |
| 建造 | 建设 | 动词 | 动词 | 断续器 | 电影站 | 真实的 | 错误的 |
| chatbots | 聊天机器人 | 名词 | 非营养性吸吮 | 扔过来 | 电影站 | 真实的 | 错误的 |

请参考下表,了解我们在代码中打印的每个属性的含义。

|

文本

|

正在处理的实际文本或单词

|
| --- | --- |
| 引理 | 正在处理的单词的词根形式 |
| 刷卡机 | 词的词性 |
| 标签 | 它们表达词性(如动词)和一定量的形态信息(如动词是过去式)。 |
| 资料执行防止 | 句法依赖性(即,标记之间的关系) |
| 形状 | 单词的形状(例如,大写、标点、数字格式) |
| 希腊字母的第一个字母 | 令牌是字母字符吗? |
| 停止 | 这个单词是停用词还是停用列表的一部分? |

您可以参考下表来了解 token 对象的每个 POS 属性值的含义。这个列表给出了 spaCy 模型分配的词性标签的详细想法。

|

位置

|

描述

|

例题

|
| --- | --- | --- |
| ADJ | 形容词 | 大,老,绿,不可理解,第一 |
| ADP | ADHD 位置 | 在,到,在期间 |
| ADV | 副词 | 很,明天,下来,哪里,那里 |
| au | 辅助的 | 是,已经(做了),将要(做了),应该(做了) |
| CONJ | 结合 | 与,或,但 |
| cconj | 并列连词 | 与,或,但 |
| | 限定词 | 一个,一个, |
| intj | 感叹词 | 嘶,哎哟,好极了,你好 |
| 名词 | 名词 | 女孩,猫,树,空气,美女 |
| 中的 | 数字 | 1,2017,一,七十七,四,MMXIV |
| 部分 | 颗粒 | 的,不是的, |
| pron | 代词 | 我,你,他,她,我自己,他们自己,某人 |
| 提议 | 专有名词 | 玛丽、约翰、伦敦、北约、HBO |
| | 标点 | 。, (, ), ? |
| scoj | 从属连词 | 如果,虽然,那 |
| SYM | 标志 | $、%,、、、+、-、×、:、 |
| 动词 | 动词 | 跑,跑,跑,吃,吃,吃 |
| X | 其他的 | sfpksdpsxma |
| 空间 | 空间 |   |

那么为什么聊天机器人需要词性标注呢?

回答:降低理解一篇无法训练或者训练的信心不足的文本的复杂度。通过使用词性标注,我们可以识别文本输入的各个部分,并仅对这些部分进行字符串匹配。例如,如果您要查找一个位置是否存在于一个句子中,那么词性标记会将位置词标记为名词,因此您可以从标记列表中获取所有名词,并查看它是否是预设列表中的位置之一。

词干化和词汇化

词干化是将屈折词还原为词干(基本形式)的过程。

词干算法将单词“say”简化为词根单词“say”,而“proposely”变成了 propose。如你所见,这可能是也可能不是 100%正确的。

词汇化词干化密切相关,但词汇化是根据单词的预期含义确定其词汇的算法过程。

例如,在英语中,动词“行走”可能显示为“行走”、“散步”、“散步”或“散步”人们可能会在字典中查找的基本形式“walk”被称为该词的词条。spaCy 没有任何内置的词干分析器,因为词汇化被认为更加正确和有效。

词干化和词汇化的区别

  • 词干提取以一种粗糙的、启发式的方式来完成这项工作,即砍掉单词的末尾,假设剩下的单词就是我们真正要找的,但它通常包括去除派生词缀。

  • 词汇化试图通过使用词汇和词形分析来更优雅地完成这项工作。它尽最大努力只删除屈折词尾,并返回单词的字典形式,称为词条。

尽管很少有库提供词干化和词汇化的方法,但使用词汇化来正确获取词根始终是最佳实践。

让我们通过一些例子来探讨词汇化:

例 1:

from spacy.lemmatizer import Lemmatizer
from spacy.lang.en import LEMMA_INDEX, LEMMA_EXC, LEMMA_RULES
lemmatizer = Lemmatizer(LEMMA_INDEX, LEMMA_EXC, LEMMA_RULES)
lemmatizer('chuckles', 'NOUN') # 2nd param is token's part-of-speech tag

输出:

[u'chuckle']

例 2:

lemmatizer('blazing', 'VERB')

输出:

[u'blaze']

例 3:

lemmatizer('fastest', 'ADJ')

输出:

[u'fast']

如果您想比较词干分析器和 lemmatizer,那么您需要安装 Python 最流行的库之一:自然语言工具包(NLTK)。spaCy 最近很受欢迎,但正是 NLTK 让每个 NLP 爱好者投身到 NLP 及其技术的海洋中。

查看下面的例子,我们尝试使用 NLTK 提供的两种词干技术。首先,我们尝试使用 PorterStemmer 获得单词“First”的词干,然后使用 SnowBallStemmer。两者给出的结果是一样的——也就是“最快”——但是当我们用 spaCy 的方法做引理化时,它给我们的是“fast”作为“fast”的词干,这更有意义,也更正确。

from nltk.stem.porter import *
from nltk.stem.snowball import SnowballStemmer
porter_stemmer = PorterStemmer()
snowball_stemmer = SnowballStemmer("english")
print(porter_stemmer.stem("fastest"))
print(snowball_stemmer.stem("fastest"))

fastest
fastest

注意

在尝试运行这段代码之前,确保使用 pip3 安装nltk包。

既然你很清楚在 NLP 中词干化或词元化是做什么的,你应该能够理解每当你遇到需要单词的词根形式的情况时,你需要在那里做词元化。例如,它经常被用于构建搜索引擎。你一定想知道谷歌是如何在搜索结果中给你你想要的文章的,即使搜索文本没有被恰当地表达。

这就是使用词汇化的地方。想象一下,你用文字“搜索,《权力的游戏》下一季什么时候上映?

现在,假设搜索引擎做简单的文档词频匹配,给你搜索结果。在这种情况下,前面提到的查询可能不会匹配标题为“Game of Thrones next season release date”的文章

如果我们在将输入与文档进行匹配之前对原始问题进行词汇化,那么我们可能会得到更好的结果。

在接下来的章节中,我们将尝试测试这一理论。

命名实体识别

命名实体识别(),又名实体识别实体提取,是在给定文本中寻找命名实体并将其分类到预定义类别的过程。

**NER 任务非常依赖于用来训练 NE 提取算法的知识库,因此它可能工作也可能不工作,这取决于它被训练的所提供的数据集。

spaCy 带有一个非常快速的实体识别模型,能够从给定的文档中识别实体短语。实体可以是不同的类型,例如人、位置、组织、日期、数字等。这些实体可以通过doc对象的.ents属性来访问。

让我们借助 spaCy 强大的 NER 标记功能,通过一些例子来尝试找到命名实体。

例 1:

my_string = u"Google has its headquarters in Mountain View, California having revenue amounted to 109.65 billion US dollars"
doc = nlp(my_string)

for ent in doc.ents:
    print(ent.text, ent.label_)

输出:

('Google', 'ORG')
('Mountain View', 'GPE')
('California', 'GPE')
('109.65 billion US dollars', 'MONEY')

我们可以看到 spaCy 模型是如何漂亮和自动地识别出单词 Google 是一个组织California 是一个地缘政治实体,在给定的句子中,我们谈论的是1096.5 亿美元,实际上是关于钱的。

让我们试着探索更多的例子。

例 2:

my_string = u"Mark Zuckerberg born May 14, 1984 in New York is an American technology entrepreneur and philanthropist best known for co-founding and leading Facebook as its chairman and CEO."
doc = nlp(my_string)

for ent in doc.ents:
    print(ent.text, ent.label_)

输出:

('Mark Zuckerberg', 'PERSON')
('May 14, 1984', 'DATE')
('New York', 'GPE')
('American', 'NORP')
('Facebook', 'ORG')

例 3:

my_string = u"I usually wake up at 9:00 AM. 90% of my daytime goes in learning new things."
doc = nlp(my_string)
for ent in doc.ents:
    print(ent.text, ent.label_)

输出:

('9:00 AM', 'TIME')
('90%', 'PERCENT')

如您所见,实体提取器可以很容易地从给定的字符串中提取时间信息。此外,正如你所看到的,实体提取器不仅试图识别数字,而且准确的百分比值。

根据 spaCy 的文档,在onto notes 51语料库上训练的模型支持以下实体类型。

|

类型

|

描述

|
| --- | --- |
| | 人,包括虚构的 |
| NORP | 国籍、宗教或政治团体 |
| FAC | 建筑物、机场、高速公路、桥梁等。 |
| 组织 | 公司、代理处、机构等。 |
| gpe | 国家、城市、州 |
| LOC | 非 GPE 地区、山脉、水体 |
| 产品 | 物体、交通工具、食物等。(非服务) |
| 事件 | 命名飓风、战役、战争、体育赛事等。 |
| 艺术品 | 书籍、歌曲等的名称。 |
| 定律 | 被命名为法律的文件 |
| 语言 | 任何命名语言 |
| 日期 | 绝对或相对的日期或时期 |
| 时间 | 小于一天的时间 |
| 百分比 | 百分比,包括“%” |
| | 货币价值,包括单位 |
| 数量 | 测量,如重量或距离 |
| 序数 | “第一”、“第二”等等。 |
| 基数 | 不属于另一种类型的数字 |

每当我们打算用简单的术语构建一个对话代理或聊天机器人时,我们总是在头脑中有一个域。例如,我们希望聊天机器人预约医生、点餐、支付账单、填写银行申请、电子商务等。聊天机器人也可以解决这些问题。通过找出问题中的实体,人们可以对提出问题的背景有一个公平的想法。

让我们以两个单词相似但意思不同的句子为例来试着理解这一点。

my_string1 = u"Imagine Dragons are the best band."
my_string2 = u"Imagine dragons come and take over the city."

doc1 = nlp(my_string1)
doc2 = nlp(my_string2)

for ent in doc1.ents:
    print(ent.text, ent.label_)

上面的for循环遍历doc1对象给出一个输出:

('Imagine Dragons', 'ORG')

太棒了,不是吗?当您意识到实体识别器不能识别第二个字符串中的任何实体时,这将变得更加有趣。运行下面的代码,doc2不会产生任何输出。

for ent in doc2.ents:
    print(ent.text, ent.label_)

现在,假设您要在真实环境中提取上述两个字符串的上下文。你会怎么做?在实体提取器的帮助下,人们可以很容易地找出语句的上下文,并智能地进一步展开对话。

停止言语

停用词是像 a、还有这样的高频词,我们有时想在进一步处理之前将其从文档中过滤掉。停用词通常没有什么词汇内容,也没有多少意义。

下面是在 Reuters-RCV1 中常见的 25 个语义非选择性停用词的列表。

a   an    and    are    as    at    be    by    for
from    has    he    in    is    it    its    of    on
that    the    to    was    were    will    with

让我们进入一些代码,试着理解事物是如何工作的。

要查看 spaCy 中定义为停用词的所有词,可以运行以下代码行:

from spacy.lang.en.stop_words import STOP_WORDS
print(STOP_WORDS)

您应该会看到类似这样的内容:

set(['all', 'six', 'just', 'less', 'being', 'indeed', 'over', 'move', 'anyway', 'fifty', 'four', 'not', 'own', 'through', 'using', 'go', 'only', 'its', 'before', 'one', 'whose', 'how',
......................................................................................................................................................................................................................................................................................................
'whereby', 'third', 'i', 'whole', 'noone', 'sometimes', 'well', 'together', 'yours', 'their', 'rather', 'without', 'so', 'five', 'the', 'otherwise', 'make', 'once'])

spaCy 的停用词表中定义了大约 305 个停用词。如果需要,您可以随时定义自己的停用字词,并覆盖现有列表。

要查看一个单词是否是停用词,可以使用 spaCy 的nlp对象。我们可以使用nlp对象的is_stop属性。

例 1:

nlp.vocab[u'is'].is_stop

输出:

True

例 2:

nlp.vocab[u'hello'].is_stop

输出:

False

例 3:

nlp.vocab[u'with'].is_stop

输出:

True

停用词是文本清理的一个非常重要的部分。它有助于在我们尝试进行实际处理以理解文本之前删除无意义的数据。

假设你处于这样一种情况,你正在建造一个机器人,通过评估人们的情绪来让他们开心。现在,需要分析用户输入的文本中的情感,以便可以制定正确的响应。这里,在乞求做基本的情感分析之前,我们要去除数据中以停用词形式存在的噪音。

依存句法分析

依赖解析是 spaCy 更漂亮、更强大的特性之一,它既快又准确。解析器还可以用于句子边界检测,并让您遍历基本名词短语或“组块”

spaCy 的这个特性为您提供了一个解析树,它解释了单词或短语之间的父子关系,并且与单词出现的顺序无关。

让我们举一个例子,你必须分析下面的句子:

帮我订一张从班加罗尔到果阿的机票

例 1:

doc = nlp(u'Book me a flight from Bangalore to Goa')
blr, goa = doc[5], doc[7]
list(blr.ancestors)

输出:

[from, flight, Book]

上面的输出可以告诉我们,用户希望预订从班加罗尔出发的航班。

让我们试着列出goa.ancestors物体的祖先:

list(goa.ancestors)

输出:

[to, flight, Book]

这个输出可以告诉我们,用户希望预订飞往果阿的航班。

依存解析中的祖先是什么?

祖先是这个标记的语法后代的最右边的标记。就像上例中对于对象blr的祖先分别是从、书。

记住,你总是可以使用ancestors属性列出一个doc对象项目的祖先。

list(doc[4].ancestors) #doc[4]==flight

上面的代码将输出:

[flight, Book]

为了以编程方式检查一个doc对象项是否是另一个 doc 对象项的祖先,我们可以做以下事情:

doc[3].is_ancestor(doc[5])

以上返回True,因为doc[3](即 flight)是doc[5](即 Bangalore)的祖先。您可以尝试更多这样的例子,以便更好地理解依赖解析和祖先概念。

如果我们试着想象一个真实世界的场景,我们可能会在尝试构建聊天机器人时遇到类似这样的句子

我想预订一辆去酒店的出租车和一张餐馆的桌子。

在这句话中,重要的是要知道请求了什么任务以及它们的目标是哪里(即用户是想预订出租车去酒店还是餐馆 )

让我们试着用下面的代码来做这件事:

例 1:

doc = nlp(u'Book a table at the restaurant and the taxi to the hotel')
tasks = doc[2], doc[8] #(table, taxi)
tasks_target = doc[5], doc[11] #(restaurant, hotel)

for task in tasks_target:
          for tok in task.ancestors:
              if tok in tasks:
                  print("Booking of {} belongs to {}".format(tok, task))
      break

输出:

Booking of table belongs to restaurant
Booking of taxi belongs to hotel

依存解析中的子元素是什么?

子代是该标记的直接语法依赖项。我们可以像使用ancestors一样使用children属性来查看单词的子单词。

list(doc[3].children)

将输出

[a, from, to]

用于依存解析的交互式可视化

第一次理解完整的依存解析概念是非常困难的。spaCy 提供了一种非常简单的交互式方法来理解它的依赖解析。spaCy v2.0+有一个可视化模块,在这里我们可以传递一个Doc或一列Doc对象给 displaCy,并调用 displaCy 的serve方法来运行 web 服务器。

图 2-5 显示了交互式可视化将如何寻找依赖解析。

img/461879_1_En_2_Fig5_HTML.jpg

图 2-5

用于依存解析的交互式可视化

您也可以生成图 2-5 中的依赖解析可视化。要创建这样的可视化效果,运行下面的代码,然后在浏览器中转到http://localhost:5000

让我们试着将我们的任务示例和任务目标可视化。

from spacy import displacy
doc = nlp(u'Book a table at the restaurant and the taxi to the hotel')
displacy.serve(doc, style="dep")

运行这段代码将得到如图 2-6 所示的输出。如果你得到类似的东西,那么转到浏览器的另一个标签,输入http://localhost:5000

img/461879_1_En_2_Fig6_HTML.jpg

图 2-6

正在本地主机上启动依赖关系解析服务器

我们在代码中得到这个字符串的依赖解析的可视化(如图 2-7 所示)。

img/461879_1_En_2_Fig7_HTML.jpg

图 2-7

依存解析示例

让我们再举一个依赖解析的例子,我们假设用户在问下面的句子:

柏林有哪些值得参观的地方,在吕贝克逗留的时间有哪些?

我们将首先创建 d oc对象,如下所示:

 doc = nlp(u"What are some places to visit in Berlin and stay in Lubeck")

现在,我们得到了正在谈论的地点和用户想要的动作:

places = [doc[7], doc[11]] #[Berlin, Lubeck]
actions = [doc[5], doc[9]] #[visit, stay]

因为您已经知道了词性标注和实体提取,所以您可以很容易地自动获得位置和动作。

现在我们有了位置,让我们遍历它的每个祖先,并检查是否在 actions 中找到了任何祖先。在动作列表中找到的 place 的第一个父代应该是有问题的 place 的动作。

for place in places:
    for tok in place.ancestors:
        if tok in actions:
            print("User is referring {} to {}").format(place, tok)
            break

输出:

User is referring: Berlin to visit
User is referring: Lubeck to stay

正如我们在这些例子中看到的,依赖解析使得理解用户所指的内容变得非常容易。我们看到,在两个不同任务的情况下,我们可以很好地计算出期望,并在此基础上,制定下一个响应。

聊天机器人中的依赖解析有什么用?

从零开始构建聊天机器人时,依赖解析是最重要的部分之一。当你想弄清楚用户向聊天机器人输入的文本的含义时,这就变得更加重要了。可能会有这样的情况,你没有训练你的聊天机器人,但你仍然不想失去你的客户或像一个哑机器一样回复。在这些情况下,依赖解析确实有助于找到关系,并解释更多关于用户可能要求的内容。

如果我们要列出依赖关系解析有所帮助的事情,有些可能是:

  • 它有助于发现语法正确的句子的单词之间的关系。

  • 它可以用于句子边界检测。

  • 发现用户是否同时谈论一个以上的上下文是非常有用的。

你一定想知道,如果你的机器人用户说了任何语法不正确的句子,或者在输入一些东西时使用了任何短信,那该怎么办?正如在第一章中所讨论的,你必须对这些情况保持谨慎,并相应地使用 NLP 技术来处理它们。

你需要编写自己的自定义 NLP 来理解用户或聊天机器人的上下文,并在此基础上识别用户可能犯的语法错误。

总而言之,您必须准备好应对用户输入垃圾值或语法错误句子的情况。您不能一次处理所有这样的场景,但是您可以通过添加自定义 NLP 代码或通过设计限制用户输入来不断改进您的聊天机器人。

名词块

名词组块或 NP 组块基本上是“基本名词短语”我们可以说它们是以名词为中心的扁平短语。你可以把名词块想象成一个名词和描述这个名词的词。

让我们试着举个例子,更好地理解它。

例 1:

doc = nlp(u"Boston Dynamics is gearing up to produce thousands of robot dogs")
list(doc.noun_chunks)

输出:

[Boston Dynamics, thousands, robot dogs]

尽管从给定的句子中获取名词块很有帮助,spaCy 还提供了其他有用的属性。让我们试着探索其中的一些。

例 2:

doc = nlp(u"Deep learning cracks the code of messenger RNAs and protein-coding potential")
for chunk in doc.noun_chunks:
    print(chunk.text, chunk.root.text, chunk.root.dep_,
          chunk.root.head.text)

输出:

|

正文

|

根。正文

|

根。DEP_

|

根。头.正文

|
| --- | --- | --- | --- |
| 深度学习 | 学问 | nsubj | 裂缝 |
| 代码 | 密码 | 扔过来 | 裂缝 |
| 信使核糖核酸 | royal naval air station 皇家海军航空兵基地 | 比吉 | 关于 |
| 蛋白质编码潜能 | 潜在的 | 连词 | royal naval air station 皇家海军航空兵基地 |

从这个表中我们可以看到,我们得到了名词块和它们的属性。下表将帮助您理解每一列。

|

|

意为

|
| --- | --- |
| 正文 | 原始名词块的文本 |
| 根文本 | 连接名词块和剩余语法分析的原始单词的文本 |
| 根 dep | 连接根和头的依赖关系 |
| 根头文字 | 根令牌头的文本 |

寻找相似性

寻找两个词之间的相似性是一个用例,你会发现大部分时间都在使用 NLP。有时发现两个词是否相似变得相当重要。在构建聊天机器人时,你会经常遇到这样的情况,你不仅要找到看起来相似的单词,还要找到两个单词在逻辑上有多接近。

spaCy 使用高质量的单词向量,使用手套算法(单词表示的全局向量)来查找两个单词之间的相似性。

GloVe 是一种无监督学习算法,用于获取单词的矢量表示。GloVe 算法使用来自语料库的聚合的全局单词-单词共现统计来训练模型。

让我们尝试使用令牌的 vector 属性来查看 spaCy 的向量内部的实际值。

doc = nlp(u'How are you doing today?')
for token in doc:
    print(token.text, token.vector[:5])

输出:

(u'How', array([-0.29742685,  0.73939574, -0.04001453,  0.44034013,  2.8967502 ],      dtype=float32))(u'are', array([-0.23435134, -1.6145049 ,  1.0197453 ,  0.9928169 ,  0.28227055],      dtype=float32))(u'you', array([ 0.10252178, -3.564711  ,  2.4822793 ,  4.2824993 ,  3.590245  ],      dtype=float32))(u'doing', array([-0.6240922 , -2.0210216 , -0.91014993,  2.7051923 ,  4.189252  ],      dtype=float32))(u'today', array([ 3.5409122 , -0.62185854,  2.6274266 ,  2.0504875 ,  0.20191991],      dtype=float32))(u'?', array([ 2.8914998 , -0.25079122,  3.3764176 ,  1.6942682 ,  1.9849057 ],      dtype=float32))

看到这个输出,没有太大的意义和意义。从应用程序的角度来看,最重要的是不同单词的向量有多相似——也就是单词本身的意思。

为了找到空间中两个词之间的相似性,我们可以做以下工作。

例 1:

hello_doc = nlp(u"hello")
hi_doc = nlp(u"hi")
hella_doc = nlp(u"hella")
print(hello_doc.similarity(hi_doc))
print(hello_doc.similarity(hella_doc))

输出:

0.7879069442766685
0.4193425861242359

如果你看到单词 hello,它与单词 hi 更相关和相似,尽管单词 hellohella 之间只有一个字符的区别。

让我们再举一个句子的例子,了解 spaCy 是如何进行相似性比较的。还记得我们前面章节中的《权力的游戏》的例子吗?我们将尝试这样做,看看相似之处。

代码:

GoT_str1 = nlp(u"When will next season of Game of Thrones be releasing?")
GoT_str2 = nlp(u"Game of Thrones next season release date?")
GoT_str1.similarity(GoT_str2)

输出:

0.785019122782813

正如我们在这个例子中看到的,两个句子之间的相似度约为 79%,这足以说两个句子非常相似,这是真的。这可以帮助我们在构建聊天机器人时节省大量编写自定义代码的时间。因此,我们得出一个事实,spaCy 使用单词向量给我们两个单词之间有意义的相似性,而不仅仅是看它们的拼写或字母。

我们将举一个非常简单的例子,试图找出单词之间的相似性。

example_doc = nlp(u"car truck google")

for t1 in example_doc:
    for t2 in example_doc:
        similarity_perc = int(t1.similarity(t2) * 100)
        print "Word {} is {}% similar to word {}".format(t1.text, similarity_perc,  t2.text)

输出:

Word car is 100% similar to word car
Word car is 71% similar to word truck
Word car is 24% similar to word google
Word truck is 71% similar to word car
Word truck is 100% similar to word truck
Word truck is 36% similar to word google
Word google is 24% similar to word car
Word google is 36% similar to word truck
Word google is 100% similar to word google

当我们打算构建任何非常依赖于 NLP 实现的应用程序时,寻找单词或句子之间的相似性变得非常重要。如果你曾经使用过 StackOverFlow,每当我们试图提出一个新的问题时,它都会试图列出平台上已经问过的类似问题。这是最好的例子之一,在这种情况下,寻找两组句子之间的相似之处可能会有所帮助。spaCy 基于一个已经训练好的模型找到两个词之间相似性的信心纯粹取决于所采取的一般假设的种类。

在构建聊天机器人时,查找相似性对于以下情况非常方便:

  • 当构建聊天机器人进行推荐时

  • 删除重复项

  • 构建拼写检查器

我们学到的这些东西在构建聊天机器人时非常重要,这样我们就知道如何解析用户输入,以便在代码中编写业务逻辑时它们有意义。

聊天机器人了解自然语言处理方面的知识很好

在这一节中,我们将了解几个有趣的主题,当您计划编写自己的自定义 NLP 方法来处理某些场景时,这些主题经常会派上用场。确保你看完它们,因为当你最不期待的时候,它是最需要的。我们将简要讨论在聊天机器人场景中正则表达式的标记化和使用。

标记化

标记化是 NLP 的一个简单而基本的概念,我们将文本分割成有意义的片段。spaCy 首先对文本进行标记(即,将其分割成单词,然后是标点符号和其他东西)。您可能会想到一个问题:为什么我不能使用 Python 语言内置的 split 方法来进行标记化呢?Python 的 split 方法只是一个原始的方法,在给定分隔符的情况下将句子分割成标记。它不考虑任何意义,而标记化也试图保留意义。

让我们尝试一些代码,看看标记化是如何工作的。

例 1:

doc = nlp(u'Brexit is the impending withdrawal of the U.K. from the European Union.')
for token in doc:
    print(token.text)

输出:

Brexit
is
the
impending
withdrawal
of
the
U.K.
from
the
EuropeanUnion

如果您在上面的输出中看到,在标记化过程之后,U.K .作为一个单词出现,这是有意义的,因为 U.K .是一个国家名称,拆分它是错误的。即使在这之后,如果您对 spaCy 的标记化不满意,那么在完全依赖 spaCy 的标记化方法之前,您可以使用它的add_special_case case 方法来添加您自己的规则。

正则表达式

您必须已经了解正则表达式及其用法。这本书假设你必须熟悉一般的正则表达式。在本节中,我们将浏览一些例子,看看正则表达式在构建聊天机器人时是如何有益和有用的。

文本分析和处理本身就是一个大课题。有时候,单词以一种让机器极难理解和训练的方式组合在一起。

正则表达式可以方便地用于机器学习模型的一些回退。它具有模式匹配的能力,可以确保我们正在处理的数据是正确的还是不正确的。在“聊天机器人的历史”一节的第一章中讨论的大多数早期聊天机器人都非常依赖模式匹配。

让我们举两个简单易懂的例子。我们将尝试使用正则表达式从两个句子中提取信息。

帮我订一辆从机场站到香港站的地铁。

帮我订一辆从香港机场到亚洲国际博览馆的出租车。

代码如下:

sentence1 = "Book me a metro from Airport Station to Hong Kong Station."
sentence2 = "Book me a cab to Hong Kong Airport from AsiaWorld-Expo."

import re
from_to = re.compile('.* from (.*) to (.*)')
to_from = re.compile('.* to (.*) from (.*)')

from_to_match = from_to.match(sentence2)
to_from_match = to_from.match(sentence2)

if from_to_match and from_to_match.groups():
    _from = from_to_match.groups()[0]
    _to = from_to_match.groups()[1]
    print("from_to pattern matched correctly. Printing values\n")
    print("From: {}, To: {}".format(_from, _to))

elif to_from_match and to_from_match.groups():
    _to = to_from_match.groups()[0]
    _from = to_from_match.groups()[1]
    print("to_from pattern matched correctly. Printing values\n")
    print("From: {}, To: {}".format(_from, _to))

输出:

to_from pattern matched correctly. Printing values
From: AsiaWorld-Expo., To: Hong Kong Airport

尝试将sentence2改为sentence1,看看代码是否能很好地识别模式。鉴于目前机器学习的能力,正则表达式和模式匹配已经后退了一步,但请确保您对它有所了解,因为它可能随时需要从单词、句子或文本文档中解析特定细节。

摘要

在这一点上,你必须有公平的想法,为什么我们需要知道 NLP 之前,开始建立聊天机器人。在本章中,我们学习了 Python 中的 spaCy 模块,它的特性,以及如何安装它。我们深入研究了 NLP 的各种方法,这些方法在构建聊天机器人时被广泛使用。我们学习了词性标注、词干化和词条化之间的区别、实体识别、名词组块以及寻找单词集之间的相似性。

我们执行了所有这些概念的代码,并通过实践而不仅仅是阅读来学习所有这些,这正是本书所强调的。我们还复习了记号化和正则表达式的基础知识。我们将在下一章使用一个免费的工具 Dialogflow 来构建我们的聊天机器人。我们将在下一章学习如何训练我们的聊天机器人理解并提取用户给出的信息。

**

三、使用最简单的方式构建聊天机器人

构建聊天机器人的简单方法已经写好了,请记住,有时你不想从头开始构建一切,只想把事情做好。这一章并不要求你做大量的编码工作,但是仍然给你一个公平的想法,如何以一种简单的方式构建聊天机器人,并将其公开。

这一章之所以对学习构建聊天机器人变得更加重要,是因为软件世界发展得太快,以至于无法适应。有时我们需要非常快速地构建应用程序,我们试图在开源库中寻找可用的工具,这些工具可以用来快速构建应用程序,而不需要重新发明轮子。有时候,我们不擅长编码来从零开始构建一切。即使我们想从头开始构建应用程序,我们也不能,因为对于新手来说,学习曲线太陡了。

本章将帮助你快速构建聊天机器人,并将其公之于众。

我们将尝试一个以前被称为 Api.ai 的工具,现在它被称为 Dialogflow。

Dialogflow 简介

Dialogflow 通过构建引人入胜的基于语音和文本的对话界面,如语音应用程序和聊天机器人,为用户提供了与产品互动的新方法。Dialogflow 由 AI 提供支持。它可以帮助你在你的网站、移动应用程序、谷歌助手、亚马逊 Alexa、Facebook Messenger 和其他流行的平台和设备上与用户联系。

Dialogflow 中的下图显示了它们如何处理用户请求。

img/461879_1_En_3_Fig1_HTML.jpg

图 3-1

Dialogflow 架构的工作图

事情是这样的:

  1. 用户对着输入设备说话。

  2. 用户查询进入 Dialogflow 引擎。

  3. Dialogflow 试图识别其意图。

  4. 根据意图,完成一个履行,并从数据库返回数据。

  5. 响应返回给意图。

  6. 响应被转换成可操作的数据。

  7. 用户对信息的请求被反馈给输出设备。

在 Dialogflow 中有一个代理的概念,最好描述为自然语言理解(NLU)模块。这些可以包含在你的应用、产品或服务中,并将自然的用户请求转化为可操作的数据。当用户输入与代理内部的意图之一相匹配时,就会发生这种转换。

代理也可以被设计成以特定的方式管理对话流。这可以借助上下文、意图优先级、位置填充、责任和通过 webhook 的实现来完成。

入门指南

了解到目前为止我们所学到的东西是非常重要的,因为开源的免费工具和软件包并不总是有助于构建一个成熟的聊天机器人应用程序。

很多时候,您可能会遇到这样的情况:您希望自己构建所有东西,以便对应用程序有更多的控制权。我们将在下一章学习这些,并使用以前学过的 NLP 技术。

这一章是关于创建一个聊天机器人作为一个概念的证明,并使它准备好以最少的编程或没有编程经验的世界使用。

构建一个点餐聊天机器人

我们将创建一个聊天机器人的帮助下,一个特定的餐厅的 Dialogflow。我们把它命名为 OnlineEatsBot 。简而言之,我们可以称之为在线产品。您可以选择您想要构建聊天机器人的任何其他用例。在这一章中,我们将构建一个点餐聊天机器人。

确定范围

让我们来决定这个聊天机器人的范围——也就是说,它能做什么,能做到什么程度。

  • 它应该能够动态地问候用户。

  • 它应该能够理解菜单项及其数量的要求。

  • 聊天机器人应该能够代表用户下订单。

  • 当被询问时,告诉用户订单的状态。

上市意向

这里我们列出了我们希望聊天机器人用来训练的意图,这样当用户询问时它可以理解这些意图。

意图

  • 默认欢迎意图:当用户给聊天机器人发消息时

  • 下单意图:当用户要求机器人点餐时

  • 项目描述意图:当用户告诉他们想要什么项目和数量时

  • 订单状态:当用户想知道他的订单状态时

  • order _ ID:bot 需要理解用户的订单 ID 以便跟踪。

  • 用户感谢:当用户感谢机器人时

列出实体

我们将尝试在这里列出所有可能的实体。在这一章的后面,我们将看到它们被定义为适用的任何意图。

实体

  • food_items:用户想点什么菜?

  • 数量:用户愿意订购的食物数量是多少?

  • order_id:用户下订单的 order_id

构建一个点餐聊天机器人

让我们根据我们应该能够看到聊天机器人做的最少事情来设定对它的期望值。为此,让我们创建一个聊天机器人和用户之间的对话脚本。这有助于我们坚持计划,准备好一个基本的工作聊天机器人,假设用户以一种良好和正确的方式进行对话。

聊天机器人和用户对话脚本:

  • 用户:你好

  • 你好,欢迎光临!我能帮你什么吗?

  • 用户:我想点中餐。

  • 当然,你今天想点什么?

  • 用户:一份鸡肉馅饺子,两份春卷。

  • OnlineEatsBot: 完成。您的最终金额是 XYZ,您的订单是 1 个鸡肉饺子和 2 个春卷。

  • 用户:我还没有收到我的订单。我的食物在哪里?

  • 你能帮我输入你的订单 ID 吗?

  • 用户: 123456

  • OnlineEatsBot: 订单 ID 为 123456 的订单状态。送货员在你所在的地方,你的食物将在 5 分钟内到达。

  • 用户:谢谢。

  • 非常感谢你的合作。

既然我们已经编写了一个基本脚本来构建我们的聊天机器人,现在我们将进入 Dialogflow。

Dialogflow 入门

让我们按照这些步骤在 Dialogflow 中创建一个帐户,然后创建一个代理。(代理只不过是聊天机器人的另一个名字。)

  1. https://dialogflow.com 创建账户,并登录账户。

  2. Create an agent.

    img/461879_1_En_3_Fig2_HTML.jpg

    图 3-2

    在 Dialogflow 中创建新代理

输入详细信息,如代理名称、时区、默认语言和您想要选择的 Google 项目,或者创建一个新的 Google 项目。

  1. 创造意图。

如果你看到图 3-3 ,你会看到我们已经有了两个意图。

  • 默认回退意图:如果用户的输入与任何常规意图或启用的内置闲聊都不匹配,则触发回退意图。创建新代理时,会自动创建默认的回退意图。如果愿意,您可以修改或删除它。

  • Default welcome intent: We can extend this welcome intent for our own chatbots. You should add some of your own user expressions and default responses.

    img/461879_1_En_3_Fig3_HTML.jpg

    图 3-3

    在对话流中创建意图

在我们创建自己的意图之前,让我们先在默认的欢迎意图中添加一些话语,并使用以下步骤做好准备:

  1. 点击默认欢迎意向。

  2. 在训练短语中添加您自己的用户表达式。

  3. 点击保存。

当我们点击保存时,后台的机器学习模型会运行并训练我们提供的数据(即用户表情)。训练数据意味着让机器理解它基于我们提供的数据的意图,并能够预测我们何时向它提供任何新数据。例如,如果我们看图 3-4 ,在那里我们已经定义了五个用户表达式,机器已经知道它们属于“欢迎意图”,如果用户说“你好”,这在任何地方都没有定义呢?机器仍会将“Hello there”归类为默认欢迎意图,因为在新的用户表情中,训练中使用的功能和机器的欢迎意图是相似的。

img/461879_1_En_3_Fig4_HTML.jpg

图 3-4

在 Dialogflow 中定义默认欢迎或问候意图

让我们试着看看欢迎的意图是否对我们有用。有了 Dialogflow,我们可以在仪表板本身中完成这项工作。见图 3-5 。

img/461879_1_En_3_Fig5_HTML.jpg

图 3-5

测试 Dialogflow 中的欢迎意图

创建意图时要记住的几点

让我们看看在 Dialogflow 上创建意图时需要知道的一些要点。

  • Dialogflow 的 intent 还具有对每个 intent 进行默认响应的功能。默认响应是每次识别出意图时返回给用户的响应。在我们的例子中,当用户说“你好”,我们得到的是“你好!”作为机器人的回应。

  • 如果你愿意,你可以添加更多的响应或删除现有的响应,拥有多个响应会使机器人看起来更真实,这样它就不会每次都用相同的响应进行回复,并且对与机器人交谈的用户来说感觉更像人类。

  • 对话流中的意图也能够被标记为对话的结束。换句话说,您可以让机器人假设用户将不再参与对话,机器人可以根据这些信息采取必要的措施来结束对话。

创造意图和添加话语

现在我们已经创建了欢迎意向,让我们创建订单意向。我把它命名为 place_order_intent 。以下是我输入的用户表达式:

我想要食物

我想尽快点餐

你能帮我点菜吗?

请为我点餐

我想点中餐

我想下订单

请你帮我点餐好吗?

你能帮我点餐吗?

我想点餐

我想点泰国菜

我想点中餐

现在,我们已经建立了识别上述用户表达式或相关用户表达式的意图。现在,是时候使用对意图的默认响应将响应添加回用户了。

将默认回应添加到意向中

我们将添加三个可能的响应,一旦遇到 place_order_intent ,这些响应将返回给用户。

当然,你今天想要订购什么?

当然,你今天想吃什么?

当然,我会尽力帮助你。你今天想吃什么?

现在,下一步是等待用户输入他想要的条目并解析这些条目。

现在我们将创建一个新的意图,告诉我们用户实际想要点什么(例如,食物)。

我们创建一个名为 items_description 的新意图

首先,我们添加我们的标准用户表达式。

一份鸡肉饺子和两份春卷。

当我们添加用户表达式时,我们可以选择想要指定为意图实体的特定单词。这可能是数量、日期或时间、位置等。,这是预定义的,但我们可以在获得弹出框后,通过单击右下角的 Create New 按钮来创建自己的实体。

突出显示要将所选单词作为实体的话语中的单词。之后,它打开弹出框来创建我们自己的实体。

在这个例子中,我们应该能够以一种良好的可读格式解析数据,这样我们就可以使用任何编程语言来使用它。JSON 格式是当今跨平台应用程序中最好的格式。默认情况下,Dialogflow 以 JSON 格式返回数据,可以将其解析为类似下面的代码。人们总是建议让你的数据尽可能少;不要给出过多的数据来淹没 API 的响应。记住,所有这些都是要花钱的。

{

  "food_items": {
    "chicken dumpling": 1,
    "Spring rolls": 2
  }

}

项目说明意图和所属实体

我们可以选择一个和两个,并将其定义为@sys.number,它只不过是数据类型。我们将创建一个名为 food_items_entity 的新实体来标识食品。

如果你看一下图 3-6 ,你会发现我们有一个名为 food_items_entity 的实体,但是当我们选择单词时,我们将参数命名为 food_items_entity1food _ items _ ENTITY 2;食物数量也是如此,我们将第一个和第二个参数分别命名为 quantity1quantity2,

img/461879_1_En_3_Fig6_HTML.jpg

图 3-6

项目描述意图

我们在这里定义的内容将帮助我们理解 JSON 响应,我们将在 intent 被触发后得到它。我们应该有所有这些价值,以推进聊天机器人流程。

因此,选择整个单词或单词组合,然后点击 Create New 一个新的创建实体的屏幕将出现;只需输入这个新实体的名称并保存即可。

现在,回到我们对物品 _ 描述的意图,你应该会看到类似图 3-6 的东西。

继续在训练短语中添加更多的用户表达式,并继续定义其中的实体。

到目前为止,我们已经添加了四种话语,这是它们的样子。我们将添加尽可能多的,以便我们的代理对意图分类的准确性更好。

Dialogflow 还具有共享代理培训数据的功能。本书中使用的训练数据可通过 press 网站 https://github.com/Apress/building-chatbots-with-python 获取。正如您在图 3-7 中看到的,我们试图在 dialogflow 代理的项目描述意图中添加更多示例。

img/461879_1_En_3_Fig7_HTML.jpg

图 3-7

在项目描述意图中添加更多话语

现在,在这一点上,一旦我们保存了我们的意图,我们的代理已经完成了模型的训练。如果我们在右边输入下面的句子,我们应该能够看到下面的 JSON 响应:

一份鸡肉饺子和两份春卷

意向响应:

{
  "id": "e8cf4a44-6ec9-49ae-9da8-a5542a80d742",
  "timestamp": "2018-04-01T21:22:42.846Z",
  "lang": "en",
  "result": {
    "source": "agent",
    "resolvedQuery": "One chicken dumpling and two spring rolls",
    "action": "",
    "actionIncomplete": false,
    "parameters": {
      "quantity1": 1,
      "food_items_entity1": "chicken dumpling",
      "quantity2": 2,
      "food_items_entity2": "spring rolls"
    },
    "contexts": [],
    "metadata": {
      "intentId": "0b478407-1b37-4f9a-8779-1866714dd44f",
      "webhookUsed": "false",
      "webhookForSlotFillingUsed": "false",
      "intentName": "items_description"

    },
    "fulfillment": {
      "speech": "",
      "messages": [
        {
          "type": 0,
          "speech": ""
        }
      ]
    },
    "score": 1
  },
  "status": {
    "code": 200,
    "errorType": "success",
    "webhookTimedOut": false
  },
  "sessionId": "e1ee1860-06a7-4ca1-acae-f92c6e4a023e"
}

如果您查看 JSON 响应的参数部分,我们会看到

{
"quantity1": 1,
"food_items_entity1": "chicken dumpling",
"quantity2": 2,
"food_items_entity2": "spring rolls"
}

我们可以轻松地编写一些 Python 代码,将 JSON 转换成我们讨论过的预期格式。

你能做到吗?

只需测试您的 Python 技能,并尝试编写一段代码来读取类似前面的 JSON,并以我们之前讨论过的另一种 JSON 格式返回属于它的数量和食物项目。

理解并回复用户

现在,对话中的下一步是让机器人回复用户订单已被理解,以及任何新的信息。新信息可以是生成的 order_id、订单金额或预期交货时间。这些东西将在你的服务器端被填充,你可以用机器人的响应把它公式化给用户。

现在,让我们尝试在我们的案例中添加订单金额;为此,我们可以使用 Dialogflow 的默认响应特性,并将其添加到 intent 中。现在让我们硬编码这个金额,因为这个金额会根据食物项目、它们的数量或餐厅而变化。在本章的后面,我们将讨论如何通过调用一个 API 来使它动态化。

有趣的是,我们可以访问从意图中获得的参数(例如,食物项目及其数量)。

响应可以包含对参数值的引用。我们马上就会明白这一点。

如果一个参数出现在参数表中,我们可以使用下面的格式在“文本响应”字段中引用它的值:$parameter_name。

我们可以在默认响应中使用这个参数,以便机器人向用户确认订单。

添加“完成。您的最终金额为 XYZ,作为回应,您的订单为$数量 1 fooditemsentity1数量 2 $food_items_entity2"

注意

如果我们的意图无法解析食物项目或它们的数量,我们需要给出不同的默认响应,要求解释我们的机器人无法理解的内容,或者至少确认一下。我们已经在“向意向添加默认响应”一节中学习了如何向意向添加默认响应

订单状态意图

现在,让我们创建 order_status 意图,其中用户可能试图在下订单后询问订单的状态。

图 3-8 提供了我们为订单状态意图添加的一些训练短语,我们将该意图命名为 order_status

img/461879_1_En_3_Fig8_HTML.jpg

图 3-8

创建订单状态意图

现在,让我们尝试一些随机的订单状态询问话语,看看我们的代理是否足够聪明来识别意图。

我试了试,“还没有收到我的食物,瞧,我的代理完全正确地认为这是一个订单状态意向。

参见图 3-9 中 JSON 的 resolvedQuery 及其 intentName。

img/461879_1_En_3_Fig9_HTML.jpg

图 3-9

查询解析后来自 Dialogflow 的 JSON 响应

User_Order_ID 意图

现在,接下来是向用户询问订单 ID,所以让我们设置这个意图的默认响应来询问下面的问题。

你能帮我处理一下你的订单 ID 吗?

现在,用户将给出他们的订单 ID,我们的任务是识别并再次给出响应。

因此,为此我们需要创建另一个意图来识别用户何时谈论订单 ID。

请注意,我们正在创建的意图几乎是相互独立的。在这种情况下,我们知道用户将给出订单 ID,这在大多数情况下是正确的。如果它是错误的,你可以随时回到用户那里再次询问。

我们还应该注意,在某些情况下,order_id 和电话号码可能都是整数。在这种情况下,我们需要进行一些验证,比如 order_id 或电话号码中的位数。此外,根据上一个问题的上下文,您可以判断用户给出的是 order_id 还是电话号码。正如在第一章中所讨论的,我们总是可以使用决策树来更好地管理聊天机器人的流量。此外,我们可以通过编程保持跟踪,在 order_status intent 之后,我们请求订单 ID,用户将发送一些订单 ID(一些数字),这在代码中更容易解析,而不是创建一个新的 intent。

在本例中,我们将创建 user_order_id 意向,因为不存在冲突。

现在,我们创建一个名为 user_order_id 的新意图

图 3-10 显示了我们的 user_order_id 意图的样子。

img/461879_1_En_3_Fig10_HTML.jpg

图 3-10

在我们的代理中定义用户订单 ID 意图

我测试了几个表达式,将它们正确分类为 user_order_id intent 效果很好。始终使用 Dialogflow 控制台进行测试,以查看您的意图是否如预期的那样运行。

现在,让我们将 user_order_id intent 的默认响应设置为来自机器人的以下响应:

订单 ID:$Order _ ID 的订单状态。送货员在你所在的地方,你的食物将在 5 分钟内到达。

我们再次使用从 user_order_id intent 解析的参数来准备对用户的回复。

User_Thanks 意图

接下来,用户可能会感谢,如果不是别的,所以我们创建了一个新的意图,称为 user_thanks 来识别用户说谢谢的不同方式。这很重要,因为一旦用户以某种方式说谢谢你,我们的机器人应该会同样回答。

我们不应该只是期望用户在交付状态默认响应后说谢谢并盲目回复,而是尝试使用自定义意图来识别它。

图 3-11 显示了我们的用户 _ 感谢意图的样子。

img/461879_1_En_3_Fig11_HTML.jpg

图 3-11

定义用户说谢谢时的意图

现在,是时候对使用默认响应功能的用户说谢谢了,并将这一意图标记为对话的结束。

让我们添加一些文本,如“非常感谢您的合作,”作为我们的默认响应。

我们可以添加更多这样的响应,让机器人看起来更真实(见图 3-12 )。

img/461879_1_En_3_Fig12_HTML.jpg

图 3-12

在代理中添加违反用户意图的响应

查看图 3-12 ,我们已经将此意图作为对话的结束。

如果我们试图将我们的机器人与谷歌助手集成,那么启用这意味着当意图完成时关闭谷歌助手中的麦克风。

现在,在这一点上,我们已经创建了我们的机器人,按照我们最初的设计和脚本构建它,并训练它。现在,是时候把它部署到网络上,看看它看起来怎么样。

在 Web 上部署 Dialogflow 聊天机器人

在这一部分,我们将把我们的机器人与各种平台整合起来,如 Facebook Messenger、Twitter、Slack 等。,看看它们是否有效。还有很多平台可以让你轻松集成这个机器人。

现在,我们将使用 Web 演示和 Facebook Messenger 测试我们的机器人。

让我们转到我们的 Dialogflow 帐户中的集成页面,并启用 Web 演示。您将会看到一个弹出窗口,如图 3-13 。单击弹出窗口中的链接。

img/461879_1_En_3_Fig13_HTML.jpg

图 3-13

“安静”web 演示链接

你将会看到类似于图 3-14.1 到 3-14.4 的东西。我用我们写的对话测试了我的机器人,我的机器人非常好用。

img/461879_1_En_3_Fig17_HTML.jpg

图 3-14.4

OnlineEatsBot 演示对话屏幕 IV

img/461879_1_En_3_Fig16_HTML.jpg

图 3-14.3

OnlineEatsBot 演示对话屏幕 III

img/461879_1_En_3_Fig15_HTML.jpg

图 3-14.2

OnlineEatsBot 演示对话屏幕 II

img/461879_1_En_3_Fig14_HTML.jpg

图 3-14.1

OnlineEatsBot 演示对话屏幕 I

除此之外,我们还可以使用弹出窗口中的 iframe 代码将这个机器人嵌入到我们自己的网站中。

在此与我的在线食客交谈:

https://bot.dialogflow.com/c9b3f731-599e-4396-a35f-0d77497b46ef

与你的朋友和家人分享你自己的机器人,看看他们如何以合法的方式与机器人互动。如果你的聊天机器人没有做预期的事情,那么试着去解决它。

在 Facebook Messenger 上集成 Dialogflow 聊天机器人

在这一部分,我们将尝试将我们的聊天机器人集成到 Facebook Messenger 中,这样我们在脸书平台上的用户也可以使用它,而不必访问我们的网站。

让我们返回到 Dialogflow 仪表板中的 integrations 页面,启用 Facebook Messenger 图标,然后单击该图标,这将弹出一个与之前类似的弹出窗口。

在这里,我们需要去脸书,注册一个应用程序,并获得所需的令牌。

  • 验证令牌(任何字符串,仅供您使用)

  • 页面访问令牌(输入在脸书开发人员控制台中生成的令牌)

基于 Dialogflow 技术,Dialogflow 脸书集成非常有助于使用 NLU 轻松创建 Facebook Messenger bot。

建立脸书

为了让我们的机器人像在脸书那样工作,我们需要做以下事情:

  1. 创建一个脸书账户,如果你还没有

  2. 创建脸书页面,您可以添加您的机器人。

当用户访问你的脸书页面并向你发送消息时,他们将直接与你的机器人对话。

创建脸书应用程序

以下是创建应用程序的步骤:

  1. 登录脸书开发者控制台

  2. 点击右上角的我的应用

  3. 点击添加新应用并输入姓名和联系电子邮件地址。

  4. Click Create App ID as shown in the Figure 3-15 below.

    img/461879_1_En_3_Fig18_HTML.jpg

    图 3-15

    在脸书开发者平台创建新应用

  5. 在下一页,点击信使选项的设置按钮。

  6. Under the Token Generation section, let’s choose the Facebook page to which we want our bot to connect (see Figure 3-16).

    img/461879_1_En_3_Fig19_HTML.jpg

    图 3-16

    通过为您的机器人选择脸书页面来生成令牌

这将生成一个页面访问令牌。请将此令牌放在手边,因为我们需要在 Dialogflow 中输入它。

设置对话流控制台

以下是步骤:

img/461879_1_En_3_Fig20_HTML.jpg

图 3-17

使用 Facebook Messenger 设置和集成 Dialogflow】

  1. 点击左侧菜单中 Dialogflow 控制台中的集成选项,并打开 Facebook Messenger ,如果你还没有打开的话。在打开的弹出窗口中,输入如下信息,如图 3-17 设置并集成 Dialogflow 与 Facebook Messenger:

    • 验证令牌:这可以是您想要的任何字符串,并且用于您自己的目的

    • 页面访问令牌:输入在脸书开发人员控制台中生成的令牌

  2. 点击开始按钮。

您应该会收到一条消息说,“Bot 已启动。”这意味着我们可以走了。

您一定想知道什么是回调 URL、验证令牌和页面访问令牌。让我们试着去理解这些。

回拨 URL

一个回拨网址只不过是一个公众可访问的网址,脸书将发布任何来自你的脸书页面的实时请求。

假设你试图在网上支付你的食物,然后你被重定向到一个银行的支付页面。现在, OnlineEats 必须给银行一个回拨 URL,在支付完成后,他们可以将用户重定向到该 URL。

在这里,脸书不会做任何重定向,但会把我们的用户在页面的聊天框中发送的所有信息发布到 webhook 或回调 URL。

现在,一旦我们在服务器上收到消息,我们就进行意图分类和实体解析,然后制定您想要回复给用户的内容。

验证令牌

验证令牌是在验证订阅时发送到端点的任意字符串。之所以需要它,是为了确保我们的服务器知道请求是由脸书发出的,并且与我们刚刚配置的订阅相关。

假设别人知道了你的 webhook,冒充脸书发布消息,那么 verify_token 就会进入画面,你来验证消息来源是否正确。基于这个令牌,您还可以处理来自多个源的 POST 请求,因为将为不同的源定义不同的令牌,但是回调 url 是相同的。

访问令牌

脸书 API 需要页面访问令牌来管理脸书页面。它们对每个页面、管理员和应用程序都是唯一的,并且有过期时间。

注意

保留回调 URL 和验证令牌,以便现在配置 webhook。

配置 Webhooks

要配置我们的 bot 的 webhook,让我们回到脸书开发人员控制台:

  1. 点击仪表板上的添加产品部分下的设置按钮。如果您还没有订阅 webhooks,那么您将会看到一个选项“订阅这个对象”点击此按钮,弹出一个新窗口,并输入以下信息:

    • 回调 URL :这是 Facebook Messenger 集成页面上提供的 URL。

    • 验证令牌:这是您创建的令牌。

  2. 进入信使➤设置➤设置网页挂钩。你会得到一个类似图 3-18 的弹出窗口。添加您的回拨 url 并验证令牌。

  3. 勾选订阅字段下的消息消息 _ 回发选项。您完全可以选择您的用例所需的任何一个。

  4. 点击验证并保存按钮。查看图 3-18 以供参考。

你将被带回到设置页面,并且 Webhooks 应该有一个“完成”状态。请确保选择一个页面,您可以为页面事件订阅您的 webhook。

img/461879_1_En_3_Fig21_HTML.jpg

图 3-18

在脸书为 Dialogflow bot 设置 webhooks

测试信使机器人

为了能够测试我们的机器人,我们需要公开我们的应用程序:

  1. 点击脸书开发者控制台左侧菜单中的应用审查

  2. 点击下的开关让<你的 APP 名>公开?如果您得到一个无效隐私政策 URL 的提示,然后转到对话框中的基本设置链接,如果您还没有,暂时输入隐私政策 URL 的任何 URL,然后单击保存更改。现在,回到应用审查页面,尝试再次将应用切换到公共。

  3. 系统将提示您为您的应用选择一个类别。

  4. 从列表中选择教育。随意选择最适合你的机器人。

  5. Click the Confirm button as shown in the Figure 3-19, Making your facebook app public.

    img/461879_1_En_3_Fig22_HTML.jpg

    图 3-19

    公开你的 facebook 应用

我们还需要为我们的页面创建一个用户名。这是用户使用我们的机器人聊天时使用的用户名。要设置用户名,点击页面“关于”部分下的创建页面@用户名链接,如图 3-20 所示。这有助于与仅使用短名称的人共享您的页面或 bot。

img/461879_1_En_3_Fig23_HTML.jpg

图 3-20

创建您的脸书机器人的页面用户名

让我们在 Facebook Messenger 上测试我们的机器人的相同流程,我们在 Dialogflow 的网站上测试过。从图 3-21.1 到图 3-21.4 ,你应该可以看到我的 Facebook Messenger 机器人是如何回应的。

img/461879_1_En_3_Fig27_HTML.jpg

图 3-21.4

Facebook Messenger 在线版演示屏幕四

img/461879_1_En_3_Fig26_HTML.jpg

图 3-21.3

Facebook Messenger 在线版演示屏幕 III

img/461879_1_En_3_Fig25_HTML.jpg

图 3-21.2

Facebook Messenger 在线版演示屏幕 II

img/461879_1_En_3_Fig24_HTML.jpg

图 3-21.1

Facebook Messenger 在线 EatsBot 演示 屏幕 I

伙计们,这就是我们建造机器人的方式。

第四章将会更加有趣。在第四章中,我们将尝试在不依赖于 Dialogflow 的 API 或 dashboard 的情况下实现同样的功能。

当你能完全控制你所拥有的一切的时候总是好的,不是吗?

注意:您可以转到您的帐户设置,导出一个代理或直接导入其他代理。可以下载 zip 文件( OnlineEatsBot.zip )。您可以使用这个 zip 文件将它导入到 Dialogflow 中,并使用我们在本章中构建的聊天机器人。

您一定想知道,如果我想实时下订单,并使用供应商/餐馆的 API 查找订单状态,然后相应地回复用户,会怎么样?它可以是您想要进行的任何 API 调用——实时检索数据并制定机器人的响应。在我们结束本章并为下一章做准备之前,是时候知道如何做了。

让我们来了解一下 Dialogflow 中被称为“ Fulfillment ”的东西。

完成

为了获得用户请求的实时信息,我们需要开发一些 API 或使用现有的 API。为了使用 Dialogflow 实现这一点,我们需要设置 fulfillment ,这需要部署一个服务并调用一个 API。

我们不会深入构建 API 以及如何部署它的细节,但是如果你曾经尝试过使用任何谷歌或脸书的 API,你至少应该熟悉如何调用它们。

我已经构建了一个基于 Flask 的小 API,并将其部署到 Heroku。我将把它用于履行,它只接受 url 中的任何 order_id,并返回一个随机的 order_status。如果您不熟悉 Heroku,那么不要担心,您可以运行本地系统上提供的代码并测试它。在接下来的章节中,我们将使用 Heroku 部署大量的应用程序,您可以从中学习相关的知识。

在代码中,您可以了解 order_identity、intentName 等。,被解析。

在这里找到代码:flask _ online eats _ demo . zip

请求网址: https://radiant-bayou-76095.herokuapp.com/onlineeatsbot/api/v1.0/order_status/

因此,在 Dialogflow Fulfillment 中,会将来自 intent 的 JSON 响应发送到这个 URL,您需要解析它以获得相关的实体及其值,并执行特定的操作。

您还可以尝试在 Heroku 上部署示例 Flask 应用程序代码,并让您自己的端点在您的 bot 中工作以实现。

现在,Dialogflow 将发布我们的端点上启用 webhook 调用的目的的 JSON 响应。它有代码来解析 order_id 实体并基于此采取行动。目前,代码只返回从列表中随机选择的状态。

要测试 API 是否工作,请使用图 3-22 中的样本数据进行测试。如果您在本地运行 Flask 应用程序,那么使用本地 url。

img/461879_1_En_3_Fig28_HTML.jpg

图 3-22

在 POSTMAN 中测试 heroku 上部署的实现 API

启用 Webhook

因此,让我们转到 Dialogflow 中的 fulfillment 页面,并尝试启用 webhook(参见图 3-23 )。

img/461879_1_En_3_Fig29_HTML.jpg

图 3-23

在 Dialogflow 中为实现设置 webhook

确保您已经为 user_order_id intent 启用了 webhook 调用(参见图 3-24 )。

img/461879_1_En_3_Fig30_HTML.jpg

图 3-24

为特定目的启用 webhook 调用

Dialogflow 将向您的 webhook URL 发布一个 JSON 主体,看起来如图 3-25 所示。

img/461879_1_En_3_Fig31_HTML.jpg

图 3-25

从 Dialogflow 到我们的 webhook 端点的传入 JSON 数据

检查响应

每当 Dialogflow 向您的 web 服务发布一个 intent 的 JSON 响应(如图 3-25 所示)时,它都会期待来自您的 web 服务的如图 3-26 所示格式的响应。

img/461879_1_En_3_Fig32_HTML.jpg

图 3-26

Dialogflow 需要来自 webhook URL 的响应

如果你认为你的 API 的响应应该和图 3-26 的格式完全一样,那么放松点——事实并非如此。您的意图不会抛出错误,因为 JSON 主体中的所有键都是可选的。

下面是我的 API 响应的外观和工作方式:

{
    "fulfillmentText": "Order ID: 9999\. It's on the way",
    "payload": {
        "facebook": {
            "text": "Order ID: 9999\. It's on the way"
        }
    }
}

当我再次尝试点击相同的 API 时,我得到了不同的订单状态文本,但格式与 Dialogflow 引擎预期的相同。

{
    "fulfillmentText": "Order ID: 9999\. Rider has picked up your food, please wait for another 10-15 minutes",
    "payload": {
        "facebook": {
            "text": "Order ID: 9999\. Rider has picked up your food, please wait for another 10-15 minutes"
        }
    }
}

fulfillmentText 是代理回复用户的关键。

现在,使用公共 URL 或在 Dialogflow 代理本身中尝试 bot,以查看来自 API 的响应,而不是我们前面添加的默认静态响应。

这就是我们如何使用 Dialogflow 的 fulfillment 特性将外部 API 或我们自己的 API 集成到我们的 chatbot 中,从而使事情变得动态和实时。

摘要

在本章中,我们学习了 Dialogflow 以及如何使用 Dialogflow 来构建聊天机器人。我们学会了定义意图和它们各自的实体。我们构建了一个简单的点餐聊天机器人,它可以理解用户点餐的意图,也可以理解用户点了什么食物以及数量。我们还增强了我们的聊天机器人,让用户可以询问他们的订单状态,并从他们那里获取他们的订单 ID,然后用不同的订单状态来制定响应。

我们还学习了 Dialogflow 中的 fulfillment,我们从自己的 API 中提取订单的状态,并基于此向用户给出响应。我们学会了创建聊天机器人的 web 演示,还将聊天机器人与 Messenger 集成在一起。至此,您应该对聊天机器人的端到端工作方式有了大致的了解。

在下一章中,我们将尝试构建聊天机器人的更难的方法。是的,你没听错。我们将消除对 Dialogflow 等工具的依赖,并通过编程自己构建一切。让我们为下一章做好准备,因为当你自己从头开始构建一切的时候,那将会更加有趣。这就像训练和驯服你自己的聊天机器人。

下一章见。

四、使用困难方式构建聊天机器人

“艰难地构建聊天机器人”并不难学。完全控制你自己的聊天机器人是构建聊天机器人的艰难方式。如果你想自己做所有的事情,那么你会选择困难的路线。更难的路,当你走过的时候是艰难的,但当你回头看的时候却是美丽而清晰的。

这是一条通向伟大顶峰的崎岖之路。

——卢修斯·安纳乌斯·塞内卡

如果你很了解 Python,并且对如何设置包有一点了解,等等。,学习这一章不会有任何问题。如果你是开发者,对你来说应该很容易。如果你是一个管理人员或者非技术人员,你仍然可以像每个部分提到的那样一个一个地做步骤,把事情做好。我强烈建议每个人都完成这一章,这样你就能学到关于构建聊天机器人的核心知识。

本章不仅教你从零开始构建聊天机器人,还向你展示了核心机器学习(ML)如何在拉莎·NLU 的帮助下与 NLP 一起工作。正如本书第一章提到的,当你在构建聊天机器人时,有决策树总是好的。在这一章中,我们几乎不用任何规则,但是 ML 还没有达到 100%可靠的程度。因此,这个决定完全基于您的用例,以及您是否想在 ML 模型中应用一些业务逻辑。有时候,你的 ML 模型可能工作得很好,以至于你根本不需要任何启发。但是根据我的经验,当你继续销售你的聊天机器人或者将它们商业化的时候,你必须小心一点。没有功能总比有一个没有意义的功能好。

我们将使用一个名为 Rasa NLU 的开源库来学习如何从头开始构建聊天机器人,而不使用任何云服务,如 Dialogflow,Watson,wit.ai 等。记住,拉莎·NLU 是一个非常复杂的图书馆,里面有很多功能。我们将只涉及对我们构建聊天机器人很重要的概念和特性。

什么是拉莎·NLU?

Rasa NLU 是一个开源的自然语言处理库,用于聊天机器人的意图分类和实体提取。它帮助你为你的聊天机器人构建和编写定制的 NLP。

我们将在本章中讨论 Rasa 的两个部分。

  • 拉莎·NLU:在拉莎·NLU 的帮助下,我们将学习为聊天机器人准备训练数据,编写配置文件,选择管道和训练模型。最后,我们将使用我们的模型预测文本的意图。我们还将学习如何使用 Rasa NLU 解析实体。

  • Rasa Core: 在第二部分中,我们将学习训练 Rasa Core 对话管理模型来准备对用户的响应。当你的聊天机器人有各种各样的意图以及他们的后续问题或回答时,这一部分就变得非常重要。与其在我们的决策树中编写大量条件,并在大型企业级应用程序的情况下花费数小时进行调试,不如教会模型创建响应。看看我们训练有素的模型在这方面表现如何会很有趣。我们不能只是把什么都以文字的形式吐槽给用户;应该说得通。

我为什么要用拉莎·NLU?

拉莎·NLU 不仅仅是一个有很多方法来做一些事情的图书馆。它有能力构建你能想象到的几乎任何类型的聊天机器人。Rasa 为您带来了训练机器理解文本含义的神奇能力,而不是您编写规则来理解它。

让我们从以下几点来看为什么我们应该使用 Rasa NLU:

  • Rasa NLU 是一个积极维护的项目,有一个很好的社区来支持它。

  • 如果我们不想与第三方分享我们用户的敏感数据,我们必须使用像拉莎·NLU 这样的开源工具从头开始构建聊天机器人。这样,所有数据都保留在我们自己的服务器上进行处理。

  • 依靠第三方服务来训练您的数据并发现用户话语的意图将需要您调用可能并不总是可靠的 API。如果他们的服务器关闭了,你的 chatbot 应用程序会怎么样?

  • 使用拉沙·NLU 建造聊天机器人将会让你完全控制你的聊天机器人。您可以使用您想要的数据,按照您想要的方式对其进行训练、调整和优化。使用 Rasa NLU,我们可以试验哪种最大似然算法最适合我们的数据集,而不是依赖于固定的算法。

直接潜入拉萨 Into

在本节中,我们将直接进入动手部分,尝试安装 Rasa 堆栈,并通过训练数据开始构建我们的 ML 模型。我们将使用一些更酷的开源库来让我们的生活更轻松。

安装 Rasa

要安装 Rasa,运行下面的 pip 命令,我们在前面的章节中尝试安装 spaCy。请注意,我们将使用 Rasa 版本 0.13.2。

pip install rasa-nlu==0.13.2

Rasa NLU 有多个用于分类意图和识别实体的组件。Rasa 的不同组件有自己的依赖集。

当我们训练模型时,拉莎·NLU 会检查是否安装了所有必需的依赖项。如果您想要安装完全使用 Rasa 库所需的全部要求,可以执行以下步骤:

git clone https://github.com/RasaHQ/rasa_nlu.git #Clone the repo
cd rasa_nlu #Get into the rasa directory
pip install -r alt_requirements/requirements_full.txt #Install full requirements

第一步可能需要一些时间。像地球一样耐心,直到它完成。

决定 Rasa 的管道

Pipeline 不过是一套用来训练你的模型的算法。Rasa NLU 有两条被广泛使用的管道,分别叫做spacy_sklearntensorflow_embedding。让我们了解一下这两者。

  • spacy_sklearn pipeline 利用来自 GloVe 算法或脸书人工智能团队开发的 fastText 算法的预训练单词向量。

  • spacy_sklearn 在这样的情况下非常有效,假设你有这样一句话,“波士顿的天气如何?”当我们在同一个话语示例上训练我们的模型,然后要求它预测“伦敦的天气如何?”我们的模型现在足够智能,可以知道单词“Boston”和“London”是相似的,它们属于相同的意图。

  • 这种管道对于小数据集非常有用。

spacy_sklearn

  • tensor flow _ embeddingpipeline 不使用任何像 spacy_sklearn 这样预先训练好的词向量,而是根据我们自己提供的数据集进行自我调整。

  • 关于 tensorflow_embedding 管道的好处是,我们的词向量将与我们的域一致。

  • 为了用一个例子来解释 tensorflow_embedding 是如何工作的,在英语中,单词“play”可能与“一项运动”或“一项享受或娱乐的活动”密切相关,它可能看起来与单词“一个行为”非常不同。在一个戏剧领域中,“戏剧”和“一个行为”是密切相关的,其中“戏剧”意味着“剧作家写的一种文学形式”,非常有必要告诉我们的模型学习特定于我们的领域,而不是由于一些预先训练的模型而混淆。

tensorflow_embedding

从头开始训练和构建聊天机器人

如果你读过这本书的第三章,你一定很熟悉我们用 Dialogflow 搭建的“点餐聊天机器人”。你必须意识到聊天机器人的意图、实体和对最终用户的回应。

同样,在本章中,我们将采用聊天机器人的一个用例,并从头开始构建它。你不一定要用同样的例子。请随意查找您自己的用例,遵循本章中的步骤,并在本章结束时构建您自己的聊天机器人。

我们将建立一个星座机器人,它可以理解用户的查询,并告诉他们当天的星座。那么,我们开始吧。

建造一个占星机器人

在这个使用开源库 Rasa NLU 完全自主构建聊天机器人的例子中,我们将构建一个占星机器人。让我们决定这个聊天机器人的范围,看看它做什么和能做什么。

  • 星座机器人应该能够理解问候,并回复问候。

  • 机器人应该能够理解用户是否在询问星座。

  • 如果用户不提供,机器人应该可以询问用户的星座。

  • 如果用户不知道他/她的星座,机器人应该询问用户的出生日期(DOB)并为他们找到它。

  • 机器人应该订阅/取消订阅用户获得每日星座。

  • 机器人应该从现有的响应中学习,以制定新的响应。

  • 机器人应该能够处理用户的拼写错误。

我们的机器人应该做的事情非常简单。

可能的意图

  • 问候意图:用户以问候开始

  • 获取星座意向:用户询问星座

  • 用户的星座意图:用户说出星座

  • 用户的 DOB 意图:用户告知他/她的 DOB

  • 订阅意图:用户请求订阅

根据你设计你的机器人和编写代码的方式,你可能需要也可能不需要以上所有的意图,或者你可能需要定义一些额外的意图来涵盖我们希望我们的机器人做的所有用例。随着本章的深入,我们将尝试构建一个机器人来完成给出星座的基本任务;作为练习的一部分,我们可以添加更多的用例。

这就是我们到目前为止所做的,根据机器人和用户之间的简单对话来识别可能的意图。

占星机器人和用户之间的对话脚本

让我们在聊天机器人和用户之间创建一个可能的对话脚本。正如第一章中提到的,编写对话脚本就像在构建软件之前准备软件需求文档一样。它以后可能会改变,但会让您对最终的 chatbot 应用程序有一个总体的了解。

下面是我们在用户和机器人之间的对话:

  • 用户:你好

  • 星座机器人:你好!希望你一切都好。

  • 用户:我想知道我的星座。

  • 当然,我可以知道你的星座吗?

  • 使用者:反复无常

  • 星座机器人:对不起,你是说摩羯座吗?

  • 用户:是。

  • 星座机器人:好了,这是你今天的星座。今天你可能会感到乐观和积极。与那些感到不满足的人分享这种能量。你的态度会对你的朋友、伴侣、配偶和孩子产生深远的影响。邻居和大家庭可以在你没有意识到的情况下吸取你的精神。如果有人受伤或生气,要鼓励他。一切最终都会解决的。

  • 星座机器人 : 你想订阅每日更新吗?如果是,就说订阅。

  • 用户:是的,请订阅。

  • 星座机器人:太好了,你现在订阅了。祝你愉快。

这个对话只是为了对我们的聊天机器人对话有一个公平的想法。我们可能想也可能不想根据自己的需求改变谈话的流程。

我们可以训练我们的聊天机器人模型本身来准备一个有效的响应,而不是写一堆 if…else 语句。

为聊天机器人准备数据

Rasa NLU 有多种方法来定义我们的自定义数据的意图及其实体。它支持 markdown 中的数据、JSON 中的单个文件或包含多个文件的目录。

我们将首先讨论最困难但高度可扩展的方法。手动创建 JSON 文件很困难,但是通过编程非常容易且可伸缩。

以 JSON 格式为模型创建数据

Rasa NLU 期望的数据的 JSON 格式有一个名为 rasa_nlu_data 的顶层对象,键为 common_examplesentity _ synonymsregex _ features

我们将要使用的最重要的工具是。下面是我们的 JSON 数据的大致形式:

{
    "rasa_nlu_data": {
        "common_examples": [],
        "regex_features" : [],
        "entity_synonyms": []
    }
}

JSON 数据中的 common_examples 键是用于训练我们的模型的中心位置。我们将在 common_examples 数组中添加我们所有的训练示例。

regex_features 是帮助意图分类器识别实体或意图,提高意图分类准确率的工具。

让我们开始编写 JSON 文件。姑且称之为 data.json.

  1. 创建一个名为占星 _ 机器人的文件夹。

  2. 将当前工作目录更改为占星 _bot。

  3. 开始 Jupyter 笔记型电脑#jupyter 笔记型电脑。

  4. 创建一个名为 data 的新文件夹。

  5. 点击数据文件夹,进入 Jupyter 笔记本新菜单下的“文本文件”。

  6. 点击创建的文件名,将名称改为 data.json ,并为聊天机器人编写您的意图。

对于第 5 步和第 6 步,请随意使用您喜欢的编辑器,如 Sublime、Notepad++和 PyCharm 等。,来处理 JSON 文件。

下面是我在数据文件夹下的 data.json 的样子:

{
  "rasa_nlu_data": {
    "common_examples": [
      {
        "text": "Hello",
        "intent": "greeting",
        "entities": []
      },
      {
        "text": "I want to know my Horoscope",
        "intent": "get_horoscope",
        "entities": []
      },
      {
        "text": "Can you please tell me my horoscope?",
        "intent": "get_horoscope",
        "entities": []
      },
      {
        "text": "Please subscribe me",
        "intent": "subscription"
      }
    ],
    "regex_features": [],
    "entity_synonyms": []
  }
}

正如你所看到的,用手准备这个看起来很笨拙。你一定还记得我们在 Dialogflow 中使用的简单易用的方法。因此,让我们来看看一个很酷很有趣的工具,它可以以 Rasa 期望的格式创建训练数据。它是由 Polgár András 创建的,对于检查和修改我们之前准备的现有数据也非常有用。如果您正在处理一个必须手动创建数据的小项目,此工具可以节省大量时间。在您构建的任何完全由数据驱动的应用程序中可视化数据总是一个好主意。

因此,只需保存我们之前创建的 data.json 文件,直到我们使用更好的方法扩展数据收集。

可视化和修改 Rasa 的 JSON 数据格式

在本节中,我们将利用一个名为 Rasa NLU 训练器的工具来可视化我们的数据。(即,我们到目前为止已经创建的数据)。这个工具也帮助我们注释数据。如果你还记得 Dialogflow 接口是在第三章中解释的,那么定义实体、它们的名字和类型是非常容易的。我们将使用开源工具做同样的事情。

Rasa NLU 教练是一个非常好和方便的工具,编辑我们的训练数据的权利,从我们的浏览器本身。处理 JSON 数据很棘手,也可能导致错误。有了这个方便的工具,我们可以很容易地添加更多的例子到我们的训练数据或编辑现有的。它节省了手动注释数据的大量时间。rasa-nlu-trainer 是一个基于 javascript 的工具,所以我们需要安装 node.js 来在我们的系统上运行这个工具。做那件事不需要超过 5 分钟。让我们按照以下步骤进行设置:

  1. 前往 https://www.npmjs.com/get-npm 下载 node.js

  2. 按照网站上的指导在您的系统上安装软件包。安装完成后,进入系统上一个新的终端/命令行界面,键入“npm ”,看看它是否能工作。

我已经安装了 LTS 版本 8.11.4。安装后,运行以下命令来安装 rasa-nlu-trainer:

sudo npm i -g rasa-nlu-trainer

成功安装该命令后,您将看到类似于以下内容的日志:

[fsevents] Success: "/usr/local/lib/node_modules/rasa-nlu-trainer/node_modules/fsevents/lib/binding/Release/node-v57-darwin-x64/fse.node" already installed
Pass --update-binary to reinstall or --build-from-source to recompile
npm WARN slick-carousel@1.8.1 requires a peer of jquery@>=1.8.0 but none is installed. You must install peer dependencies yourself.

+ rasa-nlu-trainer@0.2.7
added 492 packages in 10.14s

即使您的消息看起来不像这样,只要它没有抛出任何错误,也不用担心。我们很快就会知道我们的 rasa-nlu-trainer 是否安装成功并且运行良好。

让我们转到之前在终端中创建的数据文件夹,并运行以下命令:

rasa-nlu-trainer

键入此命令将启动端口 55703 上的本地服务器,并在默认浏览器中打开它。它看起来有点像图 4-1 。

img/461879_1_En_4_Fig1_HTML.jpg

图 4-1

本地主机中的 rasa-nlu-trainer

如您所见,data.json 中的所有现有数据都是由这个神奇的工具挑选出来供我们删除或编辑的,我们还可以从这里添加新的示例,它将继续扩展 data.json 文件。

我建议你在你的意图中增加更多的数据,以便更好地训练这个模型。你可以在发行商提供的源代码 zip 或 repo 中获得这个 data.json,如果你正在尝试构建本章解释的相同的聊天机器人。

正如我们在第三章中使用 Dialogflow 选择话语中的实体来定义它们一样,我们可以使用这个工具做同样的事情,并为我们的实体命名,以便稍后进行解析。因此,单击示例中的切换按钮,选择文本,并通过给实体命名来添加实体。

在我定义的每个意图中,我都添加了五到六个话语示例。我们添加的示例越多,就越有利于模型的训练并提供更好的准确性。

如果您现在查看 data.json 文件,它会自动添加更多的示例。因此,继续验证您的 data.json 文件,看看您是否有从 rasa-nlu-trainer UI 添加的所有示例。

您还会注意到,在 data.json 文件中,您可能已经使用 rasa-nlu-trainer UI 定义的实体在 common_examples 列表中被捕获为具有 startend 键,这告诉模型特定实体值在示例中的开始点和结束点。

同一个 dictionary 对象还描述了实体的值和我们定义的实体的名称。对于我们的示例,它看起来如下:

{
        "text": "19-01",
        "intent": "dob_intent",
        "entities": [
          {
            "start": 0,
            "end": 2,
            "value": "19",
            "entity": "DD"
          },
          {
            "start": 3,
            "end": 5,
            "value": "01",
            "entity": "MM"
          }
        ]
      }

训练聊天机器人模型

在本节中,我们将根据准备好的数据训练一个模型。由于我们使用 Jupyter Notebook 创建和管理文件,我们将创建一个新的。ipynb 并开始编写我们的 Python 代码,通过选择我们在本章前面讨论的管道之一来训练我们的模型。

创建配置文件

让我们使用之前使用 Jupyter 创建 json 文件的相同方法再次创建一个 JSON 文件,并将其命名为 config.json 。让我们把它放在我们的数据文件夹之外(例如,在我们的项目目录——占星 _bot 中)。

向其中添加以下配置:

{
  "pipeline":"tensorflow_embedding",
  "path":"./models/nlu",
  "data":"./data/data.json"
}

如您所见,在我们的 config.json 文件中有一些重要的配置参数。让我们试着去理解它们。

  • 管道:管道将指定使用什么样的特征化器或特征提取器来处理文本消息并提取必要的信息。在我们的例子中,我们使用了 tensorflow_embedding

  • path : path 本质上是我们在训练后保存模型的目录。我们将把我们的模型保存在/models/nlu 文件夹中。

  • 数据:数据是我们需要指定的路径;它基本上是我们的训练数据所在的地方。

当我们完成了 config.json 文件之后,让我们转到一些 Python 代码来训练我们的 ML 模型。

YAML 构型

也可以用。yml 文件作为配置文件,如下所示。您可以在 github repo 中获得示例 config.yml 文件。

  • 例 1:

  • 例 2:

language: "en"
pipeline: "tensorflow_embedding"

language: "en"
    pipeline:
    - name: "nlp_spacy"
    - name: "tokenizer_spacy"
    - name: "intent_entity_featurizer_regex"
    - name: "intent_featurizer_spacy"
    - name: "ner_crf"
    - name: "ner_synonyms"
    - name: "intent_classifier_sklearn"

所有传入的消息都按照定义的组件顺序进行处理。已定义的组件按顺序一个接一个地运行,因此被称为处理管道。不同的组件用于不同的目的,例如实体提取、意图分类、预处理等。

这种格式的好处是,我们可以通过 Rasa 以一种清晰的方式指定预定义的管道。

编写 Python 代码来训练模型和预测

让我们打开一个新的。ipynb 文件并开始编写我们的代码。让我们将 ipynb 命名为 rasa-nlu.ipynb。确保您已经成功安装了您正在使用的 Python 版本的rasa-nlu==0.13.2

下面是我们的代码在 Python 中使用我们的 data.json 和 config.json,并使用 tensorflow_embedding 管道训练一个模型的样子。

from rasa_nlu.training_data import load_data
from rasa_nlu.model import Trainer
from rasa_nlu import config
from rasa_nlu.model import Interpreter

def train_horoscopebot(data_json, config_file, model_dir):
    training_data = load_data(data_json)
    trainer = Trainer(config.load(config_file))
    trainer.train(training_data)
    model_directory = trainer.persist(model_dir, fixed_model_name = 'horoscopebot')

def predict_intent(text):
    interpreter = Interpreter.load('./models/nlu/default/horoscopebot')
    print(interpreter.parse(text))

在代码的第一部分,我们从 rasa_nlu 包中导入所有必需的库。然后,我们定义了两个方法,称为train _ 占星机器人predict_intent ,其中第一个方法在给定数据、配置文件和模型目录(存储模型的位置)的情况下训练模型,predict_intent 方法使用 rasa_nlu 的解释器模型来加载预训练的模型文件,并让用户能够预测任何新的文本示例。

训练模型

我们运行下面的代码片段,用各自的参数调用我们的 train _ astrong bot 方法

train_horoscopebot('./data/data.json', 'config.json', './models/nlu')

在我们的 rasa-nlu.ipynb 中运行这段代码后,我们将得到如下输出:

Epochs: 100%|██████████| 300/300 [00:01<00:00, 175.69it/s, loss=0.075, acc=1.000]

用于训练聊天机器人模型的代码将创建模型文件夹,您可以使用 Jupyter 或您的文件资源管理器或 finder 应用程序看到该文件夹。它将在我们提供的模型目录目的地创建一组索引、元和 pickle 文件。

从模型中预测

让我们通过传递文本来调用 predict_intent 方法,以查看我们的训练模型的执行情况。

predict_intent("I am looking for my horoscope for today. I am wondering if you can tell me that.")

该方法本身打印输出。对于上面的文本,我的输出如下所示:

INFO:tensorflow:Restoring parameters from ./models/nlu/default/horoscopebot/intent_classifier_tensorflow_embedding.ckpt

{
  "intent": {
    "name": "get_horoscope",
    "confidence": 0.9636583924293518
  },
  "entities": [],
  "intent_ranking": [
    {
      "name": "get_horoscope",
      "confidence": 0.9636583924293518
    },
    {
      "name": "dob_intent",
      "confidence": 0.03462183475494385
    },
    {
      "name": "greeting",
      "confidence": 0
    },
    {
      "name": "subscription",
      "confidence": 0
    }
  ],
  "text": "I am looking for my horoscope for today. I am wondering if you can tell me that."
}

哇!是不是很神奇?我们的模型以 96%的置信度预测了这段文字。您可以在提供的 ipynb 文件中看到,我们的模型在预测其他意图方面也做得很好。这就是 tensorflow 和 ML 整体的力量。rasa_nlu 库就不用说了,让它这么容易相信。所以,现在是你回顾过去的时候了,如果你还记得本书的第三章,那么你一定还记得每当我们添加一个新的例子时,用于重新训练模型的对话流。在幕后,它实际上和我们刚才做的一样。我们不能改变模型或调整任何参数,但我们现在可以完全控制这些。

既然我们已经使用 tensorflow 成功地构建和训练了一个模型,并对其进行了测试,我们将继续讨论对话管理的下一个主题。我会要求您测试您的机器人可能面临的所有场景,以便您知道您的模型在哪些方面表现不佳,因此,如果需要,您可以添加更多数据或调整参数。

此外,请记住,只要训练数据发生变化,您就只需要重新训练模型。如果训练数据没有变化,我们可以加载现有的训练模型来继续预测新的示例。

使用 Rasa 核心的对话管理

在这一节中,我们将通过培训另一个 Rasa 核心对话管理模型来动手实践。请记住,此时我们已经有了一个模型来预测文本的意图,我们可以编写一些 Python 代码来制定响应,并且我们可以回复客户。但是如果我们想给我们的机器人添加更多的意图呢?在具有大量特性的大型应用程序中,这种方法是否具有可伸缩性?答案是否定的。Rasa Core 的对话管理解决了这个问题。

如果你曾经尝试在任何平台上使用任何机器人,你一定会看到它在某些条件下失败。是的,我们都经历过这种情况,它仍然存在,因为今天的机器人无法悲惨地管理对话的上下文或遵循对话的规则。借助 Rasa Core 基于 ML 的对话框架,我们可以轻松解决这个问题。Rasa Core 已经为企业级应用程序提供了很好的证明,并被成千上万的开发人员使用,因为它是生产就绪的,易于使用和扩展,最重要的是,它是开源的。

更多了解 Rasa 核心和对话系统

在我们真正进入我们的对话管理模型的 Rasa 核心的编码部分之前,理解为什么和从哪里来是非常重要的。

我们将努力理解我们迄今为止是如何构建聊天机器人的,以及这将如何被永远改变。

让我们举个例子:

如果我们要构建一个简单的聊天机器人,帮助用户预订航班/公共汽车/电影/火车票,最简单的方法是创建一个状态机或决策树,写一堆 if…else,就可以完成了。这可以工作,但无法扩展。如果顾客最初对某样东西有很好的体验,他们会想更多地使用它。通过一些试探法,我们可以证明聊天机器人是聪明的,但不会持续很长时间。当代码的控制流从 try 块到 except 块,我们就开始挠头了。

图 4-2 是构建这个聊天机器人的状态机的简单表示。

img/461879_1_En_4_Fig2_HTML.jpg

图 4-2

订票聊天机器人的状态图表示

如果我们看一下我们的状态图,它可能适用于一个普通的对话,在这个对话中,用户正在寻找电影票、公共汽车票或火车票,或者在索要电影票之后想要预订一张公共汽车票。如果用户同时要公交票和电影票怎么办?你可能会说,我们可以在已经嵌套的代码中再添加几个 if…else 语句来处理这个问题。如果你是一个优秀的开发人员,从状态机写一个 in-out 或者扩展你的决策树不会花你太多时间。但是想象一下,当这些情况开始呈指数级增长时,你必须不断增加病例来处理,它们也开始相互干扰。

我们的大脑以一种学习和再学习的方式工作。如果一个孩子不知道火会对他们做什么,他们会去碰它,但是当它伤害了他们,他们不会再去做了。他们强调了一个事实,那就是它是有害的。奖励也是如此——当你做了某件事并得到某样东西时,你会联想到这样一个事实:做某件事会带来奖励或更好的奖励,然后你打算再做一次。这在 ML 中被称为强化学习,机器通过执行动作和理解结果来学习如何在特定情况下表现。强化学习有时不是最好的方法,例如在数据不足以学习的情况下,数据质量不好以学习奖励场景等。

图 4-3 是帮助您理解 Rasa 核心如何很好地适应 Rasa 堆栈及其与 Rasa NLU 的作用的图表,这是我们到目前为止一直在学习的。

img/461879_1_En_4_Fig3_HTML.jpg

图 4-3

图中显示了 Rasa NLU 和 Rasa 核心的工作情况

使用 Rasa Core,我们可以指定我们的机器人应该说或做的所有事情。这些被称为动作。一个动作可能是向用户打招呼或查询数据库,也可能是使用某种 web 服务或 API 检索某些信息。

Rasa Core 提供了训练我们的概率模型的工具,以根据用户的历史对话来预测必须采取什么行动。想象一下,在没有 ML 模型的情况下,编写数百个用例来计算应该发送或执行什么响应或动作。简单来说,Rasa Core 为你解决了这个问题。

让我们看看我们在第三章构建在线机器人时构建的用户与机器人的并行对话。

|

用户

|

网上吃饭

|
| --- | --- |
| 你好 OnlineEats | 你好!我能帮你什么吗? |
| 我想点菜 | 当然,你今天想要订购什么? |
| 一个鸡肉汉堡 | 完成了。你的最终金额是 3.99 美元 |
| 谢谢你 | 非常感谢 |

这种对话非常简单,即使我们确实使用了一个训练有素的模型来识别其中的意图和实体,也可以在没有任何 ML 模型的情况下完成。

现在,你会想到一个有趣的问题,“如果我想让我的机器人能够改变顺序,该怎么办?如果我希望我的机器人能够移除或添加更多数量的食物,该怎么办?”因此,正如所讨论的,在代码中添加更多的用例、更多的复杂性、更多的意图及其表达方式、更多的 if…else 来处理角落情况,但是当你为一个企业构建聊天机器人时,你必须扩展它以通过它产生更多的收入。所有的软件系统都是这样做的,那些没有失败的都活了下来。底线是,我们不能一直改变和部署代码。

因此,我们可以在 Rasa Stack 的帮助下,采取 ML 路线来解决这个问题,而不是在所有情况发生时处理它们并重复这样做,Rasa Stack 会根据用户的上下文和对话状态告诉我们机器人下一步应该做什么。由于模型根据之前对话数据的上下文进行自我学习,因此机器人更容易保持对话更加自然和用户友好,而不是随机选择四到五个固定的句子。

Rasa 建议数据很少或没有数据的用户使用交互式学习。在本章的后面,我们将了解更多关于互动学习的内容。

在我们真正开始使用 Rasa Stack 编写我们的 bot 的核心部分之前,首先我们需要理解几个概念。

理解 Rasa 概念

在真正尝试在代码中完全使用 Rasa 之前,理解一些与 Rasa 相关的特定概念非常重要。在这一部分,我们将学习一些重要且非常有用的拉莎·NLU 概念。请确保您完全理解这些概念,因为我们将使用 Rasa 的域文件格式来构建我们的第一个内部聊天机器人。如果我们不理解这些概念的含义,那么就很难迈出下一步。

行动

顾名思义,这是一个可以采取的具体行动。根据 Rasa 文档,它说,“Next action to be taken in response to a dialog state

例如,如果用户询问今天的星座运势,我们的机器人可以执行“GetTodaysHoroscope”动作。让我们看看一个“GetTodaysHoroscope”动作在代码中是什么样子的。

from rasa_core.actions import Action
from rasa_core.events import SlotSet

class GetTodaysHoroscope(Action):
   def name(self):
      return "get_todays_horoscope"

   def run(self, dispatcher, tracker, domain):
      # type: (Dispatcher, DialogueStateTracker, Domain) -> List[Event]

      user_horoscope_sign = tracker.get_slot('horoscope_sign')
      """Write your logic to get today’s horoscope details
         for the given Horoscope sign based on some API calls
         or retrieval from the database"""

return [SlotSet("horoscope_sign", user_horoscope_sign)]

name 方法返回动作的名称,我们将在域文件中将其称为自定义方法名称。

run 方法完成完成动作的主要工作——也就是说,核心业务逻辑驻留在这里。如你所见,它需要三个参数:分派追踪器域。

让我们逐一了解这些参数:

  • dispatcher:dispatcher 用于向我们的用户发回消息。我们可以使用dipatcher.utter_message()来达到同样的目的。

  • 跟踪器:当前用户的状态跟踪器。我们可以使用tracker.get_slot(slot_name),来访问槽值,并且可以使用tracker.latest_message.text来获取最新的用户消息。

  • 域:bot 的域。我们将在本章后面更详细地讨论这个领域。

注意

run 方法返回事件实例列表。

时间

插槽是那些让机器人负责像人类一样工作的东西。插槽就像一个存储空间,可以存储用户给出的信息,也可以使用从数据库或 API 预取的信息。

不同的使用情形有不同的插槽类型:

例如,在我们想要构建星座机器人的用例中,我们可能想要使用插槽类型作为用户提供的星座符号text

根据您想要保留的插槽类型,Rasa 提供了一些预定义的插槽类型。

除文本外,Rasa 还有以下插槽类型:

  • 布尔型用于真/假

  • 分类用于您必须选择某个值的情况

  • Float 用于连续值

  • 列表用于值列表

  • 特色化用于不影响通话的内部值存储

模板

当你在寻找发送电子邮件、准备文档、建立作品集网站或遵循流程的模板时,模板是一个你在生活中至少听过一次的词。

Rasa 中的模板用于话语。话语模板包含一组预设文本,当某个动作被触发时,这些文本将被发送给用户。通过使用与话语相同的动作名称或者使用自定义代码的动作,我们可以将格式化的消息以模板的形式发送给用户。

域文件中模板的简单表示可能如下所示:

templates:
  utter_greet:
    - "hello {name}!"   # name can be filled by a slot of same name or by custom code
  utter_goodbye:
    - "goodbye"
    - "take care bye"   # multiple templates allow the bot to randomly pick from them
  utter_default:
    - "Sorry, I didn’t get that."

现在,我们已经学习了动作、插槽和模板这三个概念,并且我们已经知道了意图和实体是什么,作为我们从第三章学习的一部分,我们现在准备深入 Rasa 并开始为我们的第一个聊天机器人编写代码。

正在为聊天机器人创建域文件

使用 Rasa stack 构建聊天机器人的首要任务是创建一个域文件。

根据 Rasa 的文档,“域定义了你的机器人运行的宇宙。它指定了你的机器人应该知道的意图、实体、插槽和动作。可选地,它还可以包括你的机器人可以说的东西的模板。”

现在,通过了解 Rasa 的核心概念,你知道为什么我们必须事先为这种情况做好准备。

让我们用 YAML 定义创建一个 DefaultDomain 文件。拉莎使用。yml 文件来定义域格式。

最初 YAML 的意思应该是Yet Another Markup Language,描述它作为一种标记语言的使用,但后来它被理解为 YAML 不是标记语言,一种递归的缩写,以区分它作为面向数据而不是文档标记语言的目的。

现在,让我们回到 rasa-nlu Jupyter 笔记本目录,开始创建文件。请注意,我们可以使用命令行在单独的文件中编写所有代码,并使用编辑器对其进行编辑。我发现 Jupyter 笔记本更具互动性,浏览文件也更容易。无论你觉得哪种都可以,但是了解 Jupyter Notebook 提供的大部分功能还是有好处的。

转到主占星 _bot 目录下,创建一个文件,姑且称之为horoscope_domain.yml

以下是我们 bot 的horoscope_domain.yml内容:

slots:
    horoscope_sign:
        type: text
    DD:
        type: text
    MM:
        type: text

    subscribe:
        type: bool

intents:
    - greeting
    - get_horoscope

    - subscription
    - dob_intent

entities:
     - horoscope_sign
     - DD
     - MM
     - subscribe
     - dob_intent

templates:
    utter_greet:
        - 'Hello! How are you doing today?'
    utter_ask_horoscope_sign:
        - 'What is your horoscope sign?'
    utter_ask_dob:
        - 'What is your DOB in DD-MM format?'
    utter_subscribe:
        - 'Do you want to subscribe for daily updates?'

actions:
  - utter_greet
  - utter_ask_horoscope_sign
  - utter_ask_dob
  - utter_subscribe
  - get_todays_horoscope
  - subscribe_user

正如您所看到的,域文件由五个重要部分组成:intents, entities, slots, templatesactions,我们在前面已经讨论过了。

注意,对于每个模板,都定义了一个 utterAction,比如utter_greet, utter_ask_horoscope_signutter_ask_dob,我们必须在模板部分定义一个同名的模板。

正如您在我们的示例中看到的,主要定义了五个动作,其中前三个动作只是为了向用户说出模板文本,但最后两个动作要求我们要么从数据库中检索数据,要么调用 API 来获取当天的星座并将其返回给用户。

对于subscribe_user动作,我们需要做一个操作,将当前用户添加到数据库的订阅列表中。这些用户定义的操作称为自定义操作。为了拥有这样的自定义动作,我们需要编写当这些动作被触发时,机器人应该做什么。

在下一节中,我们将学习如何编写自定义操作。

编写聊天机器人的自定义动作

正如我们所知,每当一个UtterAction被触发,我们的机器人会用模板中为该动作定义的完整文本进行响应。但是当一些自定义动作被触发时会发生什么呢?在这一节中,我们将编写 Python 代码来创建自定义操作,我们可以用它来进行 API 调用或几乎任何你可以用 Python 做的事情。

让我们在我们的项目目录中创建一个名为actions.py的新文件(即,在我们的例子中,在horoscope_bot文件夹中)。

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

import requests
from rasa_core_sdk import Action
from rasa_core_sdk.events import SlotSet

class GetTodaysHoroscope(Action):

    def name(self):
        return "get_todays_horoscope"

    def run(self, dispatcher, tracker, domain):
        # type: (Dispatcher, DialogueStateTracker, Domain) -> List[Event]

        user_horoscope_sign = tracker.get_slot('horoscope_sign')
        base_url = http://horoscope-api.herokuapp.com/horoscope/{day}/{sign}
        url = base_url.format(**{'day': "today", 'sign': user_horoscope_sign})
        #http://horoscope-api.herokuapp.com/horoscope/today/capricorn
        res = requests.get(url)
        todays_horoscope = res.json()['horoscope']
        response = "Your today's horoscope:\n{}".format(todays_horoscope)

        dispatcher.utter_message(response)
        return [SlotSet("horoscope_sign", user_horoscope_sign)]

正如我们所看到的,在我们的操作中有两个方法叫做 GetTodaysHoroscope。第一个方法 name 只是返回动作的名称。另一个方法是运行,正如前面讨论的,这个方法通过执行我们编写的业务逻辑来实际完成任务。

在我们的方法中,我们使用了一个开源 API,代码托管在 github [ https://github.com/tapasweni-pathak/Horoscope-API ]上

API url 如下所示:

http://horoscope-api.herokuapp.com/horoscope/today/capricorn

它以 JSON 格式返回数据:

{
  "date": "2018-08-29",
  "horoscope": "You will be overpowered with nostalgia and may long to get in touch with old pals. And as Ganesha says, chances are that you may take a liking to your ex-lover, while simultaneously strengthening your social standing. All in all, the day will be a productive one.",
  "sunsign": "capricorn"
}

正如你在 run 方法中看到的,我们将来自 API 的响应转换为 Python JSON 对象,然后从 JSON 中访问“星座”键以获得实际的星座。在从 JSON 中获得实际的星座之后,我们使用dispatcher对象及其方法 utter_message 制定一个响应并将其发送回用户。

最后,我们使用SlotSet方法设置插槽。SlotSet 就像保存您从用户的响应中发现的变量,这样您就可以在对话过程中的任何时候在代码中使用它们。

注意

使用上面的 API,我们可以通过提供星座来获得今天的星座。你可以自由使用你自己的 API 或者数据库。您只需要将 API 调用替换为您想要使用的其他资源。

就像我们在actions.py文件中添加了GetTodaysHoroscope动作一样,我们也将添加SubscribeUser动作。我们不打算使用任何数据库来存储用户的订阅偏好,但是当您为真实用户构建聊天机器人时,您可能必须拥有可以在数据库中与他们的订阅相关联的 user _ ids。

以下是 SubscribeUser 操作的外观:

class SubscribeUser(Action):
    def name(self):
        return "subscribe_user"

    def run(self, dispatcher, tracker, domain):
        # type: (Dispatcher, DialogueStateTracker, Domain) -> List[Event]

        subscribe = tracker.get_slot('subscribe')

        if subscribe == “True”:
            response = "You're successfully subscribed"
        if subscribe == “False”:
            response = "You're successfully unsubscribed"

        dispatcher.utter_message(response)
        return [SlotSet("subscribe", subscribe)]

像这样,我们可以根据需要编写任意多的自定义操作。

接下来就是数据了。Rasa 的对话管理模型是在用户和聊天机器人的实际对话中训练出来的。这里重要的一点是,这些对话必须转换成故事的形式。

故事只不过是用户和聊天机器人之间的实际对话,其中用户的输入被转换为意图和实体,而聊天机器人返回的响应被视为聊天机器人在需要时应该触发的动作。

下表给出了用户和聊天机器人之间的真实对话看起来像故事的一个例子。

情景一

|

用户

|

星座运势

|
| --- | --- |
| 你好。 | 发出问候 |
| 我想知道我今天的星座运势 | 说出星座 |
| 我的星座是摩羯 | 动作(s)。gettodayhorocscope-格达多约罗斯-格达多约罗斯-格达多约罗斯-格达多约罗斯-格达多约罗斯-格达多约罗斯-格达多约罗斯 |
| 你能帮我订阅更新吗? | 行动。订户用户 |

情景二

|

用户

|

星座运势

|
| --- | --- |
| 你好。 | 发出问候 |
| 我想知道我今天的星座运势 | 说出星座 |
| 我不知道我的星座 | 直言不讳 |
| 12-12 | 动作(s)。gettodayhorocscope-格达多约罗斯-格达多约罗斯-格达多约罗斯-格达多约罗斯-格达多约罗斯-格达多约罗斯-格达多约罗斯 |

我们还没有涵盖代码中用户不知道他的星座,但知道他的出生日期的场景。这里,我们的代码需要做一些修改,以便在找不到星座值时获得日期和月份实体。

我们可以使用 DD-MM 值来检查星座,然后显式地调用 GetTodaysHoroscope 方法,或者以这种方式训练模型。

训练机器人的数据准备

在进行任何类型的 ML 之前,拥有高质量的数据总是很重要的。为了训练我们的聊天机器人,我们也需要数据;用户和聊天机器人之间的对话是我们需要用来训练模型的数据。有时很难在网上找到一个符合我们需要的数据集。

我们应该花我们需要的时间来收集数据。我们可以要求我们的朋友和家人向我们提供示例对话文本,说明他们将如何与您正在构建的一种机器人进行交互。有些人为此创建了示例应用程序,并对数据进行了众包。所以,数据越好,模型越好,聊天机器人的反应越好。

当谈到准备数据时,Rasa 想尽一切办法,并提供了一个很酷的功能,称为互动学习。它帮助您轻松地生成故事数据,并在我们不断添加故事数据时训练对话管理模型。你可以称之为实时 ML 训练。因此,随着我们不断添加我们的故事数据,我们开始知道我们的模型是否产生正确的输出。最重要的是,当我们添加新的故事时,我们可以看到模型是在改进还是在退化。在大多数情况下,它会变得更好,因为我们会做一些强化学习,我们告诉 ML 模型去遗忘和重新学习——就像人类做的那样。

创建故事数据

正如我们所知,故事数据只是用户和聊天机器人之间的一种对话方式,讨论它将如何导致逻辑上的结束。一般来说,所有聊天机器人都是为了帮助用户完成一组预定义的事情;故事只是代表了他们是怎么做的。

我们将尝试按照 Rasa 期望的格式准备一些简单的对话。这些对话将是无状态的,也就是说,它们不依赖于以前的对话。我们将使用我们手工制作的无状态故事进行互动学习。

我们将花几分钟时间来手工整理几个我们知道的故事,以便我们适应故事数据是如何创建的。

让我们首先在我们的数据文件夹中创建一个名为stories.md的文件。

## story_001
* greeting
  - utter_greet
* get_horoscope
  - utter_ask_horoscope_sign
* get_horoscope{"horoscope_sign": "Capricorn"}
  - slot{"horoscope_sign": "Aries"}
  - get_todays_horoscope
  - utter_subscribe

## story_002
* greeting
  - utter_greet
* get_horoscope{"horoscope_sign": "Capricorn"}
  - slot{"horoscope_sign": "Cancer"}
  - get_todays_horoscope
  - utter_subscribe
* subscription
  - slot{"subscribe": "True"}
  - subscribe_user

## Horoscope query with horoscope_sign

* greeting
    - utter_greet
* get_horoscope
    - utter_ask_horoscope_sign
* get_horoscope{"horoscope_sign": "capricorn"}
    - slot{"horoscope_sign": "capricorn"}
    - get_todays_horoscope
    - slot{"horoscope_sign": "capricorn"}
    - utter_subscribe
* subscription{"subscribe": "True"}
    - slot{"subscribe": "True"}
    - subscribe_user
    - slot{"subscribe": true}

## Horoscope with sign provided
* greeting
    - utter_greet
* get_horoscope{"horoscope_sign": "leo"}
    - slot{"horoscope_sign": "leo"}
    - get_todays_horoscope
    - slot{"horoscope_sign": "leo"}
    - utter_subscribe
* subscription{"subscribe": "True"}
    - slot{"subscribe": "True"}
    - subscribe_user
    - slot{"subscribe": true}

## When user directly asks for subscription
* greeting
    - utter_greet
* subscription{"subscribe": "True"}
    - slot{"subscribe": "True"}
    - subscribe_user
    - slot{"subscribe": true}

如果你盯着这些故事看几分钟,它们会向你坦白它们的意思;弄清楚正在发生的事情应该不难。前两个故事之间的主要区别是,在第一个故事中,用户没有提到他的星座,机器人应该问星座,然后继续这个故事。

在第二个故事中,用户自己说出星座,然后用订阅对话框结束故事。我们增加了几个故事,涵盖了更多的用例。请随意在同一个文件中添加您自己的故事。

所以,基本上故事是降价文件,我们可以按照前面显示的降价格式写尽可能多的故事。手工完成这项任务似乎有点困难。因此,我们将尝试学习如何使用 Rasa 自己的互动学习工具来生成更多这样的故事。

让我们开始吧。

互动学习

到目前为止,我们一直在零零碎碎地谈论交互式学习,但现在是时候实际编写一些代码并付诸实践了。交互式学习是 Rasa 最酷的功能之一,它使 ML 部分变得有趣和简单。有两个部分:在第一部分中,我们通过使用各种策略给出我们的初始数据集来训练模型,在第二部分中,我们测试模型,修正它,并以交互的方式重新训练它。

训练聊天机器人代理模型

让我们在主项目目录中创建一个名为train_initialize.py的新文件。train_initialize.py的内容是这样的:

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

from rasa_core import utils
from rasa_core.agent import Agent
from rasa_core.policies.keras_policy import KerasPolicy
from rasa_core.policies.memoization import MemoizationPolicy
from rasa_core.policies.sklearn_policy import SklearnPolicy

if __name__ == '__main__':
    utils.configure_colored_logging(loglevel="DEBUG")

    training_data_file = './data/stories.md'
    model_path = './models/dialogue'

    agent = Agent("horoscope_domain.yml",
                  policies=[MemoizationPolicy(), KerasPolicy()])

    training_data = agent.load_data(training_data_file)

    agent.train(
            training_data,
            augmentation_factor=50,
            epochs=500,
            batch_size=10,

            validation_split=0.2
    )

    agent.persist(model_path)

这是我们写在train_initialize.py文件中的代码。现在,在我们进入下一个代码文件之前,让我们先试着理解其中的要点。

  1. 首先,我们从 future 模块中导入一些方法。Python 中的未来语句有特殊的用法,它们改变了 Python 模块的解析方式,也改变了现有方法的行为方式。

    Curious personality ? Try the below code in your python interpreter
         from __future__ import braces
    
    
  2. 从 rasa_core 模块导入utils方法来配置日志记录。

  3. 从代理模块导入代理类以创建代理对象。

  4. KerasPolicy,KerasPolicy 将作为策略参数传递给代理类。

  5. configure _ colored _ logging:utils . py 中定义的使用 Python 的 coloredlogs 包进行彩色日志记录的实用方法。

  6. Agent:Rasa 定义的一个类,提供一个接口来利用最重要的 Rasa 核心功能,比如训练、处理消息、加载对话模型、获取下一个动作、处理通道。

  7. load_data: 从给定路径加载训练数据。

  8. train: 使用提供的文件中的数据训练给定的策略/策略集合。

  9. 训练 _ 数据:加载 _ 数据方法返回的对象。DialogueStateTracker列表。这只是我们的训练数据文件。

  10. augment _ factor:告诉 Rasa 在给定初始故事集的情况下应该创建多少个虚拟故事。10x 因子是用于训练数据生成器的扩充回合的启发。

  11. 历元: 1 个历元是整个训练数据集上的完整训练周期。训练数据向前和向后传递的总数。

  12. batch_size: 告诉您每次使用的训练样本的数量。batch_size 为 10 的 100 个示例将需要 10 个历元来遍历整个数据集。

  13. validation_split: 验证模型无偏准确性的数据百分比。

  14. persist: 该方法用于将代理对象持久保存在给定的目录中,以便重用。

此时,您应该非常清楚每个方法的作用以及代码内部发生了什么。

在我们继续运行这个脚本之前,确保在执行这个脚本之前已经安装了 rasa_core 库。

您可以使用以下命令安装 rasa_core:

pip install rasa_core==0.11.1

如果你遵循本书中的聊天机器人示例,那么确保你只安装了上述版本,因为 Rasa 可能不是向后兼容的。他们正迅速提出更新更优化的方法。

最新的 rasa_core

您也可以从 github repo 安装 rasa_core 的最新版本。你只需要执行下面这组命令,这些命令会在安装之前直接从 github 获取最新的代码。

git clone https://github.com/RasaHQ/rasa_core.git
cd rasa_core
pip install -r requirements.txt
pip install -e .

让我们试着运行这个代码文件,按照给定的参数训练我们的模型。

$python train_initialize.py

您也可以使用 Jupyter 的 magic 命令从 Jupyter 笔记本本身运行该脚本,如下所示:

如果您已经为 python3 安装了 rasa,请使用 python3

在我们这样的小数据集上训练模型应该需要大约 25 到 30 秒。我在策略列表中添加了SklearnPolicy以及 MemorizationPolicy 和 KerasPolicy 来训练我的模型。不同的政策有各自的好处。阅读更多关于它们的内容,以了解哪一种可能更适合您的用例;对于我的数据集,SklearnPolicy 有时似乎比 KerasPolicy 表现得更好。

脚本执行完毕后,您应该会看到一些成功的消息,如下所示:

2018-08-30 04:24:31 INFO    rasa_core.policies.keras_policy  - Done fitting keras policy model
2018-08-30 04:24:31 INFO    rasa_core.featurizers  - Creating states and action examples from collected trackers (by MaxHistoryTrackerFeaturizer)...
Processed trackers: 100%|████████| 96/96 [00:00<00:00, 898.31it/s, # actions=75]
2018-08-30 04:24:31 INFO    rasa_core.featurizers  - Created 75 action examples.
2018-08-30 04:24:31 INFO    rasa_core.policies.sklearn_policy  - Done fitting sklearn policy model
2018-08-30 04:24:31 INFO    rasa_core.agent  - Model directory models/nlu exists and contains old model files. All files will be overwritten.
2018-08-30 04:24:31 INFO    rasa_core.agent  - Persisted model to '/Users/sumit/apress_all/Chapter IV/horoscope_bot/models/nlu'

您还会发现几个根据型号名称创建的文件夹。确保您在脚本中给出的 model_path 中有它们。以下是我在 model_path 文件夹中看到的文件夹/文件。

policy_0_MemoizationPolicy
policy_1_KerasPolicy
policy_2_SklearnPolicy
domain.json
domain.yml
Policy_metadata.json

如果您已经验证了您的模型已经成功地完成了执行,并且在您的本地系统中持久化了模型,那么我们就可以进入下一步的交互式培训了。

通过强化进行实时训练

在这一节中,我们将编写更多的代码来训练我们的对话模型,并在它给出不正确的输出时进行重新训练。

因此,当我们的机器人做错了什么,我们会立即跳出来,通过告诉它什么是正确的,让模型知道它的预测是错误的。无需停止,模型会重新训练自己,一旦我们完成,用户和机器人之间的交互就会被捕获到一个文件中,并添加到我们现有的训练数据中。它在每一步都更像一个反馈系统,而不是在最后等待一个单一的奖励。

下一步是用下面的内容创建一个名为endpoints.yml的新文件。我们将在 Python 代码文件train_online.py.中使用这个文件。通过这个配置,我们可以将 Rasa 方法公开为 HTTP APIs。

action_endpoint:
  url: http://localhost:5055/webhook

#nlg:
#  url: http://localhost:5056/nlg

core_endpoint:
  url: http://localhost:5005

现在,让我们为我们的在线/交互式培训创建train_online.py

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

import logging

from rasa_core import utils, train
from rasa_core.training import online
from rasa_core.interpreter import NaturalLanguageInterpreter

logger = logging.getLogger(__name__)

def train_agent(interpreter):
    return train.train_dialog_model(domain_file="horoscope_domain.yml",
                                      stories_file="data/stories.md",
                                      output_path="models/dialog",
                                      nlu_model_path=interpreter,
                                      endpoints="endpoints.yml",
                                      max_history=2,
                                      kwargs={"batch_size": 50,
                                              "epochs": 200,
                                              "max_training_samples": 300
                                              })

if __name__ == '__main__':
    utils.configure_colored_logging(loglevel="DEBUG")
    nlu_model_path = "./models/nlu/default/horoscopebot"
    interpreter = NaturalLanguageInterpreter.create(nlu_model_path)
    agent = train_agent(interpreter)
    online.serve_agent(agent)

max_history是模型要跟踪的状态数。

在我们继续运行我们的最终脚本train_online.py之前,我们应该了解并为 rasa-nlu-sdk 做好准备。

rasa-nlu SDK

Rasa NLU 堆栈提出了 rasa-nlu-sdk,这是一个 Python SDK,用于为 Rasa 核心开发自定义操作。至于我们的聊天机器人示例,我们需要定义一些自定义操作,比如点击 API 来获取今天的星座,或者可能是数据库写操作来将用户添加到订阅列表。

好消息是他们有一个单独的库,我们可以使用 pip 来安装它。

让我们使用以下命令来安装它:

pip install rasa-core-sdk==0.11.0

现在,我们需要转到终端的另一个选项卡或一个新的命令行,并在我们的项目目录(我们的actions.py文件所在的位置)中执行以下命令:

python -m rasa_core_sdk.endpoint --actions actions

INFO:__main__:Starting action endpoint server...
INFO:rasa_core_sdk.executor:Registered function for 'get_todays_horoscope'.
INFO:rasa_core_sdk.executor:Registered function for 'subscribe_user'.
INFO:__main__:Action endpoint is up and running. on ('0.0.0.0', 5055)

该命令将启动一个动作服务器,该服务器将监听模型预测的任何自定义动作。一旦任何动作被触发,它将执行它并根据方法给出响应。

在本地主机上,操作服务器端点的默认端口是 5055。如果你想改变它,你可以在命令行中添加 pass --port参数。

一个快速的问题浮现在脑海:为什么?为什么我需要一个单独的服务器?为什么不能用普通 Python?是的,我们可以使用普通的 Python,但是假设您要用任何其他语言来开发所需的操作,或者您已经将一些操作公开为 API。现在,您只需要转到我们已经创建的endpoints.yml,,并使用它来说明应该在哪里使用您的操作服务器以及应该在哪里使用您的 core_endpoint 服务器。在生产系统中,两者可以是具有完全不同的 URL 的不同服务器。

现在,当我们运行下一个脚本时,其中提到了我们的 endpoints.yml 文件,Rasa 将读取该文件并获取我们的 action_server 的配置,它已经按照我们之前所做的配置启动并运行。

action_endpoint:
       url: http://localhost:5055/webhook

让我们在新的命令行终端中运行train_online.py

$python3 train_online.py

在对话模型的成功训练之后,我们将得到这样的消息:

2018-08-30 07:09:37 INFO     rasa_core.policies.keras_policy  - Done fitting keras policy model
2018-08-30 07:09:37 INFO     rasa_core.agent  - Model directory models/nlu exists and contains old model files. All files will be overwritten.
2018-08-30 07:09:37 INFO     rasa_core.agent  - Persisted model to '/Users/sumit/apress_all/Chapter IV/horoscope_bot/models/nlu'
2018-08-30 07:09:37 INFO     rasa_core.training.online  - Rasa Core server is up and running on http://localhost:5005
Bot loaded. Type a message and press enter (use '/stop' to exit).
127.0.0.1 - - [2018-08-30 07:09:37] "GET /domain HTTP/1.1" 200 996 0.001847

现在,你可以开始和你刚出生的机器人说话了。从现在开始,你如何训练它完全掌握在你手中。每当它对不好的或意想不到的事情做出反应时,你都可以纠正它。

让我们这样做,看看它是否有所改善。

我输入“Hi”作为第一条消息,机器人返回以下内容:

---------------------------------------------------------------------------

Chat history:

      bot did: action_listen

      user said: hi

      whose intent is: {'confidence': 0.8472929307505297, 'name': 'greeting'}

we currently have slots: DD: None, MM: None, horoscope_sign: None, subscribe: None

------

The bot wants to [utter_greet] due to the intent. Is this correct?

      1\.      Yes
      2\.      No, intent is right but the action is wrong
      3\.      The intent is wrong
      0\.      Export current conversations as stories and quit

---------------------------------------------------------------------------

现在,机器人正在根据用户所说的话和他对它的理解告诉我它做了什么。现在,它也给了我们四个选择。我们一会儿会谈到这一点。

这里的 bot_did 是 action_listen 的意思;它只是在等待用户输入一些东西,这很好。

Bot 说出了意图{ ' confidence ':0.8472929307505297,' name': 'greeting'} ,这是正确的,所以我们会按 1,意思是 bot 正在理解并试图正确地做的事情。

1
---------------------------------------------------------------------------
Chat history:

      bot did: action_listen

      user said: hi

      whose intent is: {'confidence': 0.8472929307505297, 'name': 'greeting'}

      bot did: utter_greet

we currently have slots: DD: None, MM: None, horoscope_sign: None, subscribe: None

------
The bot wants to [action_listen]. Is this correct?

      1\.      Yes.
      2\.      No, the action is wrong.
      0\.      Export current conversations as stories and quit
---------------------------------------------------------------------------

你看,我们的机器人至少正确地问候了用户。如果你看到前面提到的回应,你实际上可以检查我们的机器人做了什么;在我们训练它的时候,它会记录所有这些。

bot did: utter_greet

现在,机器人说接下来的事情是等待并听用户将要说什么(即,等待用户输入)。这是正确的吗?是的,这是正确的,所以我们再次按 1,机器人给用户一个提示。

我输入,“我今天的星座是什么?”

---------------------------------------------------------------------------
Chat history:

      bot did: action_listen

      user said: hi

             whose intent is: {'confidence': 0.8472929307505297, 'name': 'greeting'}

      bot did: utter_greet

      bot did: action_listen

      user said: what's my horoscope for today?

      whose intent is: {'confidence': 0.8902154738608781, 'name': 'get_horoscope'}

we currently have slots: DD: None, MM: None, horoscope_sign: None, subscribe: None

------
The bot wants to [utter_ask_horoscope_sign] due to the intent. Is this correct?

      1\.      Yes
      2\.      No, intent is right but the action is wrong
      3\.      The intent is wrong
      0\.      Export current conversations as stories and quit

---------------------------------------------------------------------------

现在,机器人非常正确地识别出“获取星座”的意图,准确率达到 89%,这是非常好的。机器人还说它想说出 _ ask _ 占星 _sign,这又是正确的,因为用户还没有提到任何占星符号,槽仍然是无,如图所示。

我们再次按 1。

---------------------------------------------------------------------------

Chat history:

      bot did: action_listen

      user said: hi

      whose intent is: {'confidence': 0.8472929307505297, 'name': 'greeting'}

      bot did: utter_greet

      bot did: action_listen

      user said: what's my horoscope for today?

      whose intent is: {'confidence': 0.8902154738608781, 'name': 'get_horoscope'}

      bot did: utter_ask_horoscope_sign

we currently have slots: DD: None, MM: None, horoscope_sign: None, subscribe: None

------
The bot wants to [action_listen]. Is this correct?

      1\.      Yes.
      2\.      No, the action is wrong.
      0\.      Export current conversations as stories and quit

---------------------------------------------------------------------------

现在,机器人会询问是否到了等待用户输入的时间。是的,用户需要提供星座。

我们再次按 1,出现提示时,我们输入“摩羯”作为输入。

---------------------------------------------------------------------------

Chat history:

      bot did: action_listen

      user said: hi

      whose intent is: {'confidence': 0.8472929307505297, 'name': 'greeting'}

      bot did: utter_greet

      bot did: action_listen

      user said: what's my horoscope for today?

      whose intent is: {'confidence': 0.8902154738608781, 'name': 'get_horoscope'}

      bot did: utter_ask_horoscope_sign

      bot did: action_listen

      user said: Capricorn

      whose intent is: {'confidence': 0.8456705103362621, 'name': 'get_horoscope'}

      with horoscope_sign: capricorn

we currently have slots: DD: None, MM: None, horoscope_sign: capricorn, subscribe: None

The bot wants to [get_todays_horoscope] due to the intent. Is this correct?

      1\.      Yes
      2\.      No, intent is right but the action is wrong
      3\.      The intent is wrong
      0\.      Export current conversations as stories and quit

---------------------------------------------------------------------------

现在,正如我们所看到的,星座槽被自动设置为“摩羯座

下一步是教机器人调用get _ today _ 占星和调用get _ today _ 占星动作。到目前为止,我们的槽已经为我们在占星 _ 域. yml 中定义的占星 _ 符号变量设置好了,所以如果再次调用这个动作,聊天机器人应该会返回当天的实际占星。让我们试试。

我输入了“摩羯座”

bot 点击动作服务器的端点,并将结果返回给用户,正如我们在自定义动作中定义的那样。

Your today's horoscope:

乐观是从失败走向成功的动力。甘尼萨说,你今天会非常乐观——对你的工作、未来和一切能让你成功的东西。在处理日常工作时,你也会非常小心,会利用每一个能让你离目标更近一步的机会。决心和好运是你实现梦想所需要的一切;今天你将两者兼得。

这似乎是公平的,因为我错过了完成这一章的最后期限,现在是早上 6 点,我还没有睡觉。尽一切努力让你的钱值得花在这本书上。

好吧,让我们回去看看我们的机器人下一步要做什么。

------
The bot wants to [action_listen]. Is this correct?

      1\.      Yes.
      2\.      No, the action is wrong.
      0\.      Export current conversations as stories and quit

也许我们不想让我们的机器人在说出今天的星座之后还在听。我们希望我们的机器人要求用户根据我们的对话脚本以及我们创建的故事订阅更新。

所以,我会按 2,它会说

------
what is the next action for the bot?

         0                           action_listen    1.00
         1                          action_restart    0.00
         2                 action_default_fallback    0.00
         3                             utter_greet    0.00
         4                utter_ask_horoscope_sign    0.00
         5                           utter_ask_dob    0.00
         6                         utter_subscribe    0.00
         7                    get_todays_horoscope    0.00
         8                          subscribe_user    0.00

因为我们希望用户订阅,所以我们应该按 6,这样机器人会询问用户是否希望订阅每日更新。

机器人回答,“你想订阅每日更新吗?”

现在机器人说:

---------------------------------------------------------------------------
The bot wants to [get_todays_horoscope]. Is this correct?

      1\.      Yes.
      2\.      No, the action is wrong.
      0\.      Export current conversations as stories and quit

这里的动作不正确,所以我们按 2,训练机器人听用户这里的动作。

---------------------------------------------------------------------------
what is the next action for the bot?

         0                           action_listen    0.21
         1                          action_restart    0.01
         2                 action_default_fallback    0.01
         3                             utter_greet    0.21
         4                utter_ask_horoscope_sign    0.51
         5                           utter_ask_dob    0.01
         6                         utter_subscribe    0.02
         7                    get_todays_horoscope    0.78
         8                          subscribe_user    0.22
---------------------------------------------------------------------------

当机器人等待知道正确的下一步时,我们按 0。机器人现在将在我们的交互式学习过程中等待用户输入。

用户在这里说,“请订阅我,”我们的机器人以 80%的信心成功地识别出这是一个订阅意图,并且根据我们在 data.json 中的训练数据,很容易理解用户是在请求订阅而不是取消订阅。换句话说,它将 subscribe 的槽设置为 True,如下所示:

---------------------------------------------------------------------------

      user said: Please subscribe me

      whose intent is: {'confidence': 0.795172441763619, 'name': 'subscription'}

      with subscribe: True

we currently have slots: DD: None, MM: None, horoscope_sign: capricorn, subscribe: True
---------------------------------------------------------------------------

现在,我们的机器人已经理解了它的意图,并解析了其中的实体,是时候回复用户说“他已经成功订阅了”,然后我们从机器人那里得到一条消息:

You're successfully subscribed

这就对了。你完全可以自己成功构建自己的室内聊天机器人。作为练习的一部分,我建议你添加我们讨论过的星座机器人的所有用例,看看它是否有效。当我们到目前为止所做的一切都运行良好时,尝试添加更多的用例和更多的功能。

您可以在这里添加更多的话语信息,以便机器人在对话完成后说,“再见,祝您愉快”。我坚信你应该有能力做到这一点。一定要这样做,并让我们知道你的进展如何。

现在,最后一部分是将所有这些学习反馈给用户,这样我们就不必再次教授相同的故事,机器人会尝试从现有的故事和未来的故事中学习。

将对话导出为故事

现在,互动学习部分的下一步是按 0,将我们当前的对话导出为故事,然后退出。

为此,我们按 0,机器人会提示如下内容:

File to export to (if file exists, this will append the stories) [stories.md]:

只需输入我们的 stories.md 文件名,如果您保留了任何其他名称,请确保您给出了正确的文件名。

Rasa 为我们完成了这项艰巨的工作,并自动生成了一个 stories.md 文件,如下所示:

## Generated Story 3797421409943253925
* greeting
    - utter_greet
* I want to know my horoscope
    - utter_ask_horoscope_sign
* get_horoscope

## Generated Story 7304374603374920907
* greeting
    - utter_greet
* what is my todays horoscope?
    - utter_ask_horoscope_sign
* Cancer

## Generated Story -6877464862083507836
* greeting
    - utter_greet
* get_horoscope
    - utter_ask_horoscope_sign
* get_horoscope{"horoscope_sign": "capricorn"}
    - slot{"horoscope_sign": "capricorn"}
    - get_todays_horoscope
    - slot{"horoscope_sign": "capricorn"}
    - utter_subscribe
* subscription{"subscribe": "True"}
    - slot{"subscribe": "True"}
    - subscribe_user
    - slot{"subscribe": true}

您可以在使用上述文件训练模型时更改 stories 文件的源,也可以将新生成的故事复制并粘贴到我们的原始 stories.md 文件中。现在,我将把这些故事复制并粘贴到我们原来的 stories.md 文件中。在再次测试或进行交互式学习之前,请确保再次运行您的模型。

测试机器人

测试机器人是我们互动学习过程的一部分。我们不断检查最初为机器人想到的所有可能的场景,并相应地训练它。我测试了一些其他场景的星座机器人,并对其进行了相应的训练。下面是其中一个与我们在本章前面所做的有点不同的例子。

测试案例 1

让我们运行第一个测试:

  • 用户:你好!

  • 星座机器人:你好!能为你做什么?

  • 用户:摩羯座今天的星座是什么?

  • 星座机器人:你今天的星座:

乐观是从失败走向成功的动力。甘尼萨说,你今天会非常乐观——对你的工作、未来和一切能让你成功的东西。在处理日常工作时,你也会非常小心,会利用每一个能让你离目标更近一步的机会。决心和好运是你实现梦想所需要的一切;今天你将两者兼得。

  • 星座机器人:要订阅每日更新吗?

  • 用户:请订阅我。

  • 星座机器人:您已成功订阅。

正如你在用户和聊天机器人之间的对话中看到的,我们测试了机器人是否处理用户自己提供星座运势同时询问当天星座运势的场景。在这种情况下,机器人做得很好,并最终要求订阅,并根据用户的响应,采取适当的行动。

您应该对机器人的对话进行健全性测试,以确定正常流是否正常工作。

我还测试了我们在 stories.md 文件中提到的故事,当用户直接要求订阅时,它也工作正常。

测试案例 2

现在是第二个测试:

  • 用户:

  • 星座机器人:你好!能为你做什么?

  • 用户:请为我订阅每日更新。

  • 星座机器人:您已成功订阅。

我还会添加一些新的故事,这样机器人就可以完美地工作了。但是现在我们有了一个完全正常工作的机器人。在 github 的第二个版本中,你还会发现这个机器人正在纠正星座的拼写错误,根据用户的出生日期检索星座,说再见信息,等等。我强烈建议您检查代码,看看它是如何完成的,并提供您的反馈。但在此之前,考虑一下将如何完成以及变化将会发生在哪里。我们故意没有在本章中提到其他用例的代码,这样当你集中精力学习交易技巧时,它不会变得繁琐。

您可以从我们的 github repo 下载最新的 Python 代码和 Jupyter 笔记本,并尝试安装正确的包来运行它。你会发现在本章讨论的代码中处理了更多的用例。

摘要

在这一章中,我们了解了 Rasa-NLU,以及为什么 Rasa-NLU 比市场上任何其他开源工具都好。我们学习了如何在管道配置中使用 tensorflow、sklearn 和 keras 来配置管道。

我们学会了在本地系统上从头开始创建一切,而不依赖于任何需要您使用其 API 的服务,如 Dialogflow、wit.ai 等。

我们还学习了如何创建故事,以及如何训练 NLU 模型和对话模型,并使用 Rasa Core 通过使用最酷的功能交互式学习进行训练来构建机器人。在开源工具如 rasa-nlu-trainer 的帮助下,我们也对如何轻松地创建训练数据并轻松地进行注释有了一个相当好的想法。我希望这一章对你来说比其他任何一章都更具互动性。如果你没有成就感,那就为下一章做好准备,在那里我们将把它真实地呈现给我们的观众,并向世界展示机器人的能力。我们将学习使用我们自己的网络服务器把本章的聊天机器人集成到各种平台上,比如脸书和 Slack。

继续训练你的机器人,直到下一章我们把它投入使用。

下一章见。**

五、部署您的聊天机器人

在这一章中,我们将学习如何在网络上部署聊天机器人。人们可以通过各种方式和渠道向外界部署或公开他们的 chatbot web 应用程序。举个例子,我们可以在脸书和 Slack 上用 NLU 和对话模型来展示我们的星座机器人,因为他们已经为你提供了一个用户界面。您可能还想拥有自己的 web 应用程序,它完全运行在您自己的服务器上。在本章末尾,我们还将探索如何使用我们自己的用户界面在我们自己的服务器上部署聊天机器人。

第一步

第一步是创建一个你在第四章中创建的现有聊天机器人的副本,并制作一个新的副本,以便你有一个备份。因为,我们将通过添加一些新代码来做一些更改,所以让我们将两个项目分开。

于是,我创建了一个名为“第五章的新文件夹,并将我的horoscope_bot文件夹粘贴在那里。所以,现在我所有的模型文件、数据集和代码文件都被复制了,我可以直接使用它们进行部署。

Rasa 的凭证管理

Rasa 提供了一种在一个地方管理您所有凭据的方法。你可能有一个单一的模型,但你可能希望它被部署在各种其他平台上,如脸书,Slack,Telegram 等。所有这些第三方平台都需要一些凭据才能在连接时使用。这些凭证存储在名为credentials.yml的 YAML 文件中。

让我们在我们的项目目录horoscope_bot文件夹中创建一个名为credentials.yml file 的文件,并在那里添加我们的脸书凭证。如果你不知道如何得到它,那么现在就创建这个文件,在本章的下一节你可以找到得到脸书证书的步骤。

credentials.yml的内容将如下所示:

facebook:
  verify: "horoscope-bot"
  secret: "bfe5a34a8903e745e32asd18"
  page-access-token: "HPaCAbJJ1JmQ7qDedQKdjEAAbO4iJKr7H9nx4rEBAAuFk4Q3gPQcNT0wtD"

这些凭据是假凭据;令牌或密码的长度以及字符类型可能因您的脸书应用而异。

如果你正在做一个大项目,在这个项目中,你要在各种平台上集成你的聊天机器人,并且你想让这个项目更容易维护,那么最好使用credentials.yml。如果你是一家企业,并试图建立一个可以在各种平台上工作的机器人,如脸书、Slack、Twitter、Telegram 或你自己的网站,我强烈建议你维护一个credentials.yml。在这种情况下,管理密钥和秘密变得更加容易。

管理应用程序级密钥的一个好方法是将密钥存储为环境变量,并编写代码从操作系统环境本身读取密钥值或任何其他敏感信息。记住,在代码中保存任何类型的键都不是一个好主意。

您也可以创建一个点(。)env 文件,并从该文件中读取密钥,在您的代码存储库中没有对该文件进行跟踪。

为了简单起见,我们将在部署的独立脚本中使用访问密钥和秘密密钥。我们将使它变得简单易懂,这样你首先能够构建机器人,然后你可以尝试扩展它,最重要的是你可以考虑安全级别的问题。

如果您需要在多个平台上部署您的 bot,并希望使用 credentials.yml 来维护不同的凭证,那么您可以通过传递一个额外的参数来使用它。例如,在运行 rasa core 时使用上面名为credentials.yml的凭证文件,可以使用下面的命令。

python -m rasa_core.run -d models/dialogue -u models/nlu/current   --port 5002 --credentials credentials.yml

对于更大的企业级聊天机器人开发来说,知道这一点很好,但是正如所讨论的,我们将在即将到来的示例中直接在我们的脚本中使用凭证。

在脸书部署聊天机器人

在本节中,我们首先将使用 Heroku 在云中部署我们的聊天机器人。Heroku 是一个平台即服务(PaaS ),使开发人员能够完全在云中构建、运行和操作应用程序。Heroku 的好处是,我们可以轻松地让我们的应用程序在 https 上运行,没有太多痛苦。在我们学习和测试聊天机器人的时候,我们不需要去购买 SSL 证书。之所以需要 https,是因为脸书等一些平台不允许开发者使用非 https 的 URL 作为回调 URL。

我们将按照一系列步骤一步一步地成功地将我们的聊天机器人部署为云中的 web 服务。一旦我们成功地做到了这一点,将它与不同的平台如 Slack、Telegram 等整合起来就容易多了。那么,我们开始吧。

在 Heroku 上创建应用程序

让我们开始吧:

在 Heroku 上注册,创建一个应用程序,并将其命名为 actions,因为这将是我们的 actions 服务器应用程序。看看图 5-1 中的截图,你可以给你的动作服务器一个唯一的名字,这个名字应该在 Heroku 上可以找到。一旦该名称可用,您就可以单击 Create app 按钮来创建 actions 服务器应用程序。

如果你的名字不可用,你可以随意给它取任何你想要的名字,但是要尽量取一些有意义的名字。

img/461879_1_En_5_Fig1_HTML.jpg

图 5-1

在 Heroku 上创建名为星座机器人 1212-动作的动作服务器应用程序

在本地系统上设置 Heroku

在本地操作系统上安装 Heroku CLI。参考此链接: https://devcenter.heroku.com/articles/heroku-cli

如果您在 macOS 上,请使用以下命令:

brew install heroku/brew/heroku

在脸书创建和设置应用程序

为了能够在脸书上部署我们的聊天机器人,首先我们需要有脸书应用程序的凭证。为了获得脸书证书,我们需要设置一个脸书应用程序和一个页面,就像我们在第三章中所做的那样。

  1. Go to https://developers.facebook.com/ and create an app if you don’t have one already. We created one for our OnlineEatsBot; now we’ll create one for HoroscopeBot. Enter the details and click on Create App ID. Check Figure 5-2 to see how to enter the display name of your bot and your contact email.

    img/461879_1_En_5_Fig2_HTML.jpg

    图 5-2

    为开发者在脸书上创建应用

  2. Once your app is created, go to Basic under Settings, and click on the Show button under App Secret. This is your fb_secret. Refer Figure 5-3 to see where exactly you will get your fb_secret key.

    img/461879_1_En_5_Fig3_HTML.jpg

    图 5-3

    从脸书的应用程序中获取应用程序秘密

  3. Go to the dashboard for the app and scroll down to “Add a Product.” Click Add Product and then add Messenger (click on SetUp). Check Figure 5-4.

    img/461879_1_En_5_Fig4_HTML.jpg

    图 5-4

    将 Messenger 作为产品添加到脸书应用程序

  4. Under settings for Messenger, when you scroll down to the Token Generation section you will get a link to create a new page for your app. If you don’t have a page already, then create it or choose a page from the “Select a page” dropdown. The “Page Access Token” is your fb_access_token here. Refer Figure 5-5.

    img/461879_1_En_5_Fig5_HTML.jpg

    图 5-5

    为 Facebook Messenger 应用程序生成令牌

    您可以访问以下链接,为您的 bot 项目创建一个全新的页面:

    https://www.facebook.com/pages/creation/

  5. Right after the Token Generation section, under Webhooks, click on “Setup Webhooks.” Refer Figure 5-6.

    img/461879_1_En_5_Fig6_HTML.jpg

    图 5-6

    设置脸书 Webhooks

  6. Next, choose a verify token, which we’ll need to use later. The verify token can be any random string. This will be your fb_verify. Check Figure 5-7 to understand where to add the verification token in facebook app. Now, leave the callback URL section blank as it is. Don’t close the browser; just leave it—we’ll come back here again.

    img/461879_1_En_5_Fig7_HTML.jpg

    图 5-7

    将验证令牌添加到脸书 webhook 设置中

  7. 随身携带fb_verify, fb_secretfb_access_token将你的机器人连接到脸书。

在 Heroku 上创建和部署 Rasa Actions 服务器应用程序

在这一步中,我们将使用我们的 actions Heroku 应用程序作为 Rasa action 的服务器。我们需要两个不同的应用程序,因为我们不能在一个 Heroku 应用程序中运行两个 web 应用程序。转到命令行,按照指示从项目目录中执行以下命令。

  1. 创建一个名为 actions_app and的新文件夹,进入目录:

    mkdir actions_app

    光盘操作 _ 应用程序

  2. 将您的 actions.py 从主项目目录复制到 actions_app 目录。

  3. 用以下内容创建一个 requirements.txt 文件。会告诉 Heroku 应用程序安装软件包及其版本。

    rasa-core-sdk==0.11.0

    请求数==2.18.4

  4. 用以下内容创建一个名为 Procfile 的文件。Procfile 是 Heroku 了解如何启动应用程序的文件。

    web: python -m rasa_core_sdk.endpoint --actions actions --port $PORT
    
    
  5. 运行下面的命令集:

    $ heroku 登录

    去吧,init

    $ heroku git:remote -a

    $ heroku buildpacks:设定 heroku/python

    $ heroku config:设置端口=5055

    去给我。

    $ git commit -am "部署我的机器人"

    $ git 推出 heroku master

在最后一个命令之后,Heroku 将按照 requirements.txt 文件安装我们需要的所有包。如果您的应用程序成功部署,您应该会收到类似以下内容的日志:

remote:
remote: -----> Discovering process types
remote:        Procfile declares types -> web
remote:
remote: -----> Compressing...
remote:        Done: 48.3M
remote: -----> Launching...
remote:        Released v4
remote:        https://horoscopebot1212-actions.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/horoscopebot1212-actions.git
 * [new branch]      master -> master

此时,我们将验证我们的应用程序是否正在响应公共请求。为了做到这一点,让我们点击附加了“webhook”的应用程序 url

在我的例子中,应用程序 url 是 https://horoscopebot1212-actions.herokuapp.com/ ,因此我将检查我的操作的服务器是否有响应。

我访问这个网址 https://horoscopebot1212-actions.herokuapp.com/webhook ,不出所料,它返回说方法不允许,如图 5-8 所示,这完全没问题,意味着应用程序按照用户请求正确响应。

img/461879_1_En_5_Fig8_HTML.jpg

图 5-8

正在验证操作服务器端点

创建 Rasa 聊天机器人 API 应用程序

在这一步中,我们将遵循一些类似于我们刚才所做的步骤和命令,但这是一个我们将创建的新应用程序,它将成为我们用于对话管理的主要应用程序。所以,我们开始吧。首先回到主项目目录(即,在占星 _bot 中)并创建一个文件名( Procfile) 并向其中添加以下内容:

web: python -m spacy download en && python facebook.py

为 Facebook Messenger 聊天机器人创建独立脚本

在同一个项目目录下创建一个文件名facebook.py。Python 文件的内容应该如下所示:

from rasa_core.channels.facebook import FacebookInput
from rasa_core.agent import Agent
from rasa_core.interpreter import RasaNLUInterpreter
import os
from rasa_core.utils import EndpointConfig

# load your trained agent
interpreter = RasaNLUInterpreter("models/nlu/default/horoscopebot/")
MODEL_PATH = "models/dialog"
action_endpoint = EndpointConfig(url="https://horoscopebot1212-actions.herokuapp.com/webhook")

agent = Agent.load(MODEL_PATH, interpreter=interpreter)

input_channel = FacebookInput(
        fb_verify="YOUR_FB_VERIFY_TOKEN",
        # you need tell facebook this token, to confirm your URL
        fb_secret="YOUR_FB_SECRET",  # your app secret
        fb_access_token="YOUR_FB_ACCESS_TOKEN"
        # token for the page you subscribed to
)
# set serve_forever=False if you want to keep the server running
s = agent.handle_channels([input_channel], int(os.environ.get('PORT', 5004)), serve_forever=True)

确保用我们在步骤 3 中保留的值替换代码中的fb_verifyfb_secret,fb_access_token变量值。

创建一个新的 requirements.txt 文件,并添加这个项目所需的所有包及其版本。我的 requirements.txt 看起来是这样的;对于您的项目,需求可能会有所不同,但是如果您遵循本章中的同一个 bot 示例,这些需求应该没问题。

rasa-core==0.11.1
rasa-core-sdk==0.11.0
rasa-nlu==0.13.2
gunicorn==19.9.0
requests==2.18.4
spacy==2.0.11
sklearn-crfsuite==0.3.6

在服务器上安装我们的软件包。

现在,让我们像之前一样在 Heroku 中再次创建一个新的应用程序。转到 Heroku 仪表盘,创建一个新的应用程序,如图 5-9 所示。

img/461879_1_En_5_Fig9_HTML.jpg

图 5-9

在 Heroku 中创建对话管理应用程序

创建应用程序后,现在可以转到项目根目录,从项目文件夹中的命令行运行以下命令集:

$ git init
$ heroku git:remote -a <your-heroku-app-name>
$ heroku buildpacks:set heroku/python
$ heroku config:set PORT=5004
$ git add .
$ git commit -am "deploy my bot"
$ git push heroku master

如果您在部署后得到一个运行时错误,它可能如下所示

ValueError:您可能试图用 Python 3 读取用 Python 2 生成的 joblib pickle。joblib 不支持此功能。

如果您使用的是 Python 2.x 版本,这种情况就会发生。Heroku 默认使用 Python 3.x 版本。因此,如果您想使用 Python 2.x,您需要执行以下步骤来解决上述错误。把 Python 3.6 改成 Python-2.7.15。来做这个。

在项目的根应用程序目录下创建一个文件 runtime.txt。打开 runtime.txt,添加下面一行 python-2.7.15,然后保存。Heroku 将只使用前面提到的 Python 版本来构建您的项目。

一旦成功完成部署,您将看到 Heroku 给出的一个 url,上面写着应用程序已部署到

remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Python app detected
remote: -----> Installing requirements with pip
remote:
remote: -----> Discovering process types
remote:        Procfile declares types -> web
remote:
remote: -----> Compressing...
remote:        Done: 254M
remote: -----> Launching...
remote:        Released v17
remote:        https://horoscopebot1212.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/horoscopebot1212.git
   cd3eb1b..c0e081d  master -> master

这个部署需要一点时间,所以尽可能耐心一点——您将会看到奇迹。如果您没有收到任何错误消息,那么您已经成功地将您的聊天机器人部署到 Heroku on cloud,使其能够与 Facebook Messenger 一起工作。我们来验证一下是否有效。

在 Heroku 上验证我们的对话管理应用程序的部署

为了验证我们的对话管理应用是否成功部署在 Heroku 上,我们将执行以下步骤。

  1. 获取 Heroku 给出的 url,并将这个端点附加到它后面:/webhooks/facebook/webhook?hub.verify_token=YOUR_FB_VERIFY_TOKEN&hub.challenge=successfully_verified。确保使用您在脸书用于 webhooks 设置的正确验证令牌。对我来说,完整的网址如下: https://horoscopebot1212.herokuapp.com/webhooks/facebook/webhook?hub.verify_token=my-secret-verify-token&hub.challenge=success

  2. 转到浏览器并粘贴整个 url,如果您的 hub.verify_token 正确,它应该会返回您的 hub.challenge 值。您的完整 url 将如下所示: https://horoscopebot1212.herokuapp.com/webhooks/facebook/webhook?hub.verify_token=YOUR_FB_VERIFY_TOKEN&hub.challenge=successsfully_verified 。如果您收到消息successsfully_verif ied in the browser,那么您的应用程序已成功部署并运行。

将 Webhook 与脸书集成

现在让我们回到我们的脸书应用程序配置。我们将回到我们在步骤 3 中停止的地方,添加我们的回调 URL。确保检查订阅字段中的消息。查看图 5-10 以供参考。

img/461879_1_En_5_Fig10_HTML.jpg

图 5-10

Facebook Messenger webhooks 配置

点击“验证并保存”脸书将使用上述 url 匹配验证令牌,即服务器,或者说我们的应用程序将只响应具有正确验证令牌的请求。一旦验证令牌匹配,我们的应用程序的 webhook 订阅将被激活。

接下来,在页面的 Webhooks 部分下,选择一个页面,您可以将 webhook 订阅到该页面事件。点击订阅(见图 5-11 )。

img/461879_1_En_5_Fig11_HTML.jpg

图 5-11

为 webhook 订阅脸书页面事件

全部完成!是时候在脸书测试我们的星座机器人了。

部署后验证:脸书聊天机器人

在正常的软件开发场景中,人们构建软件,测试软件,然后部署并进行 PDV(部署后验证)。我们也将做一些类似的事情,在 Facebook Messenger 上成功部署后,我们将为我们的聊天机器人做一个 PDV。这很重要,因为正如您所了解的,聊天机器人有一部分需要连接到动作服务器,以响应用户的一些意图请求。PDV 就像是一个健全性测试,以查看应用程序的健康状况总体良好。如果您正在构建一个使用 10 到 15 个不同供应商的 API 的 bot,那么必须检查您的 bot 访问动作服务器并使用 API 将数据返回给用户的所有场景。

所以,打开你的 messenger 应用程序或电脑浏览器中的脸书,搜索你的机器人开始说话。

数字 5-12.1 到 5-12.3 显示了我的星座机器人做了什么并告诉我。

img/461879_1_En_5_Fig14_HTML.jpg

图 5-12.3

horoscope _ bot facebook

img/461879_1_En_5_Fig13_HTML.jpg

图 5-12.2

horoscope _ bot facebook

img/461879_1_En_5_Fig12_HTML.jpg

图 5-12.1

horoscope _ bot facebook

瞧啊。我们的第一个内置聊天机器人应用程序部署在网络上,可以通过 Facebook Messenger 平台访问。所以,请与你的家人、朋友、同事和全世界分享吧。

在 Slack 上部署聊天机器人

在本节中,我们将把我们的聊天机器人部署到 Slack。Slack 是一个团队协作工具,在开发人员和企业中广受欢迎。如果你不是一个社交媒体人,那么你可能需要 Slack 的帮助来使用界面与你的聊天机器人交谈。因此,让我们开始构建我们的第一个内部 Slack 聊天机器人。

为了将我们的星座聊天机器人部署到 slack,我们将编写一个独立的脚本,就像我们在脸书的例子中所做的那样。

为 Slack 聊天机器人创建独立脚本

在项目目录中创建一个名为slack.py的新文件。文件slack.py的内容如下所示:

from rasa_core.channels.slack import SlackInput
from rasa_core.agent import Agent
from rasa_core.interpreter import RasaNLUInterpreter
import os
from rasa_core.utils import EndpointConfig

# load your trained agent
interpreter = RasaNLUInterpreter("models/nlu/default/horoscopebot/")
MODEL_PATH = "models/dialogue"
action_endpoint = EndpointConfig(url="https://horoscopebot1212-actions.herokuapp.com/webhook")

agent = Agent.load(MODEL_PATH, interpreter=interpreter, action_endpoint=action_endpoint)

input_channel = SlackInput(
            slack_token="YOUR_SLACK_TOKEN",
            # this is the `bot_user_o_auth_access_token`
            slack_channel="YOUR_SLACK_CHANNEL"
            # the name of your channel to which the bot posts (optional)
    )
# set serve_forever=False if you want to keep the server running
s = agent.handle_channels([input_channel],  int(os.environ.get('PORT', 5004)), serve_forever=True)

facebook.pyslack.py的主要区别在于我们创建的input_channel对象。Rasa 提供了各种内置通道,如脸书、Slack、Mattermost、Telegram、Twilio、RocketChat 和 Microsoft Bot Framework,我们可以直接使用这些通道轻松地在各种通道上部署同一个 Bot。

如你所见,我们需要添加一个slack_tokenslack_channel到我们的脚本中。由于我们必须在脸书的开发者平台上创建一个脸书应用程序,同样我们也必须在 Slack 上创建一个应用程序。

让我们一步一步来:

  1. Got to this url https://api.slack.com/slack-apps and click on the button “Create App.” Refer Figure 5-13.

    img/461879_1_En_5_Fig15_HTML.jpg

    图 5-13

    在 Slack 中创建应用程序

  2. The next step is to create a Bot User. To create a bot user, click on Bots under “Add features and functionality.” In the new page you will get an option to “Add a Bot User.”. Check Figure 5-14 to see how to add details and add a bot user.

    img/461879_1_En_5_Fig16_HTML.jpg

    图 5-14

    在 Slack 上给你的机器人命名

  3. 根据您正在构建的聊天机器人填写详细信息。显示名称可以是您喜欢的任何名称;默认用户名必须是唯一的;你可以顺其自然。切换最后一个选项“总是将我的机器人显示为在线”就是总是将机器人显示为用户可用。这就是聊天机器人的意义所在——人类不可能全天候可用,但聊天机器人可以,所以我们打开了这个功能。确保您点击保存更改。

  4. Go back to the “Basic Information” tab. Click “Install your app to your workspace.” The app will ask to confirm the identity. Please authorize it like you do for any other app. Check Figure 5-15 which shows how the authorization would look like.

    img/461879_1_En_5_Fig17_HTML.jpg

    图 5-15

    授权您的 Slack 应用程序

你会在“添加特性和功能”下找到带有绿色勾号的“机器人和权限”选项卡,这意味着我们的机器人和应用程序集成良好。这是一个迹象,表明我们目前做得很好。

  1. 转到 OAuth & Permissions 部分,复制 Bot 用户 OAuth 访问令牌。

  2. 将复制的令牌粘贴到我们的 Python 脚本slack.py中。给一个你喜欢的频道名。如果你想让你的机器人发布到一个频道,那么你可以给一个频道名称。我已经给了@slackbot。如果不设置slack_channel关键字参数,消息将被传递回发送它们的用户。

编辑您的个人资料

在这一步中,我们不会创建任何新的 Procfile,因为我们使用的是相同的代码库。我们将对现有的 Procfile 进行如下修改,使其适用于我们的 slack bot。因此,我们只需将脚本文件的名称从facebook.py更改为slack.py,这样 Heroku 就可以使用给定的文件来启动应用程序。

web: python -m spacy download en && python slack.py

Slack Bot 在 Heroku 的最终部署

为了最终将我们的新 Slack bot 部署到 Heroku,我们将从命令行运行一组类似的 Heroku 命令来部署我们的应用程序。

$ git init
$ heroku git:remote -a <your-heroku-app-name>
$ git add .
$ git commit -am "deploy my bot"
$ git push heroku master

订阅时差事件

现在,点击“事件订阅选项卡,通过切换屏幕上的按钮激活事件订阅功能。为 Slack 输入 Heroku 应用程序的 webhook url。

如果您的应用程序使用修改后的 Procfile 正确地部署在 Heroku 上,那么您的 Slack 的 webhook url 将是app_url + /webhooks/slack/webhook,如下所示:

https://horoscopebot1212.herokuapp.com/webhooks/slack/webhook

在 Slack 向上述 URL 发送一个带有挑战参数的 HTTP POST 请求后,您将看到一个经过验证的勾号,我们的端点必须用挑战值进行响应。这类似于我们在构建脸书聊天机器人的秘密令牌时讨论的内容。查看图 5-16 了解更多信息。

img/461879_1_En_5_Fig18_HTML.jpg

图 5-16

为您的机器人激活事件订阅

订阅机器人事件

在这一步中,我们只需向下滚动事件订阅页面,转到“订阅 Bot 事件”部分,然后单击“添加 Bot 用户事件”参考图 5-17 了解导航位置。

img/461879_1_En_5_Fig19_HTML.jpg

图 5-17

订阅机器人事件

订阅机器人事件只不过是声明机器人必须回复的事件。这里我们只演示两种情况:第一,当有人提到机器人的名字时(即app _ reference),第二,当有人直接向机器人发送消息时(即 message.im )。

现在,单击保存更改,您就完成了。是时候测试我们的 Slack 聊天机器人了,就像我们在上一节为脸书做的那样。

部署后验证:Slack Bot

让我们转到我们用来创建应用程序的工作区,在左侧的应用程序下,您会找到您的机器人。试着和它说话,看看它做得好不好。我的机器人做得很好,给了我今天的星座运势,读起来很不错。如果你到现在还不能来,那么检查图 5-18 看看我的 Slack 机器人如何响应。

img/461879_1_En_5_Fig20_HTML.jpg

图 5-18

测试 Slack 聊天机器人

所以,伙计们,我们完成了我们的松弛机器人。在下一节中,我们将把我们的机器人部署到我们自己的 UI 中。构建你自己的 UI 可能需要一些前端技能,但是不要担心——我们对此有计划。

自己部署聊天机器人

这个标题听起来很酷,不是吗?到目前为止,我们一直使用脸书或 Slack 在网上部署聊天机器人,或者我们可以使用 Telegram 等。,但现在是我们自己部署一切的时候了—我们自己的服务器、我们自己的数据,以及使用我们自己的用户界面的我们自己的配置模型。如果你是一个组织或一个崭露头角的企业家,你可能会在脸书、推特或 Slack 上有你的机器人创意,但你总是希望它也能在你自己的网站上工作,这样你的品牌价值就会随着用户群的增加而越来越大。

在这一节中,我们将使用我们迄今为止的所有辛勤工作,最终构建一个聊天机器人,它具有完整的功能,并且独立于任何第三方 API 调用或工具,如 Dialogflow、wit.ai、Watson 等。你将拥有世界上所有的控制权,以你想要的方式调整你的聊天机器人,最重要的是,以你想要的方式轻松地扩展到数百万人。

那么,我们开始吧。

第一步是确保我们在前面章节中部署的两个应用程序已经启动并运行。您已经知道如何进行基本的健全性检查。要在任何平台上使用 chatbot 模型,您始终需要运行您的对话管理器应用程序和操作应用程序。

现在,在我们创建 facebook.py 和 slack.py 的同一个项目目录中,我们将创建一个名为myown_chatbot.py的新文件。之前创建的脚本,如facebook.pyslack.py,是我们创建的独立脚本,这样我们就可以在命令中告诉 Heroku 运行哪个脚本来启动应用程序。现在,我们正在创建自己的脚本,它将通过 REST APIs 公开用户和聊天机器人之间的请求/响应。

部署你自己的聊天机器人有两个部分。在第一部分中,我们将编写一个脚本来创建一个定制通道,并将其作为 REST APIs 进行部署。在第二部分,我们需要自己的用户界面,因为到目前为止,我们一直在使用脸书和 Slack 的聊天屏幕进行对话。

为您自己的聊天机器人频道编写脚本

这个脚本类似于我们到目前为止所学习和编写的内容,但是它需要我们覆盖 rasa_core 的一些现有方法,以便我们可以为 API 身份验证定义自己的规则。我在下面的代码中完成了令牌验证的基本字符串检查。对于生产级系统,这是不建议的,所以如果您正在为更大的系统构建聊天机器人,请确保小心编写该部分。

创建一个名为 myown_chatbot.py 的新文件,并向其中添加以下内容:

import os

from rasa_core.channels.rasa_chat import RasaChatInput
from rasa_core.agent import Agent
from rasa_core.interpreter import RasaNLUInterpreter
from rasa_core.utils import EndpointConfig

# load your trained agent
interpreter = RasaNLUInterpreter("models/nlu/default/horoscopebot/")
MODEL_PATH = "models/dialogue"
action_endpoint = EndpointConfig(url="https://horoscopebot1212-actions.herokuapp.com/webhook")

agent = Agent.load(MODEL_PATH, interpreter=interpreter, action_endpoint=action_endpoint)

class MyNewInput(RasaChatInput):
    def _check_token(self, token):
        if token == 'mysecret':
            return {'username': 1234}
        else:
            print("Failed to check token: {}.".format(token))
            return None

input_channel = MyNewInput(url='https://horoscopebot1212.herokuapp.com')
# set serve_forever=False if you want to keep the server running
s = agent.handle_channels([input_channel],  int(os.environ.get('PORT', 5004)), serve_forever=True)

这里需要注意几点:

  • rasa_core中的_check_token方法基本看起来如下,它进行 API 调用来获取用户对象。这主要完成用户级认证/验证的工作。在前面被覆盖的方法中,我们保持了它的简单性,以使它能够工作并理解它的用法。

    def _check_token(self, token):
            url = "{}/users/me".format(self.base_url)
            headers = {"Authorization": token}
            logger.debug("Requesting user information from auth server {}."
                         "".format(url))
            result = requests.get(url,
                                  headers=headers,
                                  timeout=DEFAULT_REQUEST_TIMEOUT)
    
            if result.status_code == 200:
                return result.json()
            else:
                logger.info("Failed to check token: {}. "
                            "Content: {}".format(token, request.data))
                return None
    
    
  • 使用 Rasa 自己的_check_token方法可能需要您编写一个 API 或 web 服务来接受请求并以指定的方式返回响应。

  • 请确保将操作的服务器端点更改为您自己的 url。

  • 请记住,代码中的mysecret字符串将在以后用于进行 API 调用。

编写概要文件并部署到

到目前为止,您一定非常熟悉为 Heroku 部署创建 Procfiles。我们将再次使用现有的 Procfile,并在那里进行修改,以将基于 API 的 chatbot 部署到 web 上。在创建现有 Procfile 的备份后,可以随意创建新的 proc file。

以下是我的 Procfile 内容的样子:

web: python -m spacy download en && python myown_chatbot.py

完成后,只需执行我们在部署 Facebook Messenger 和 Slack Bot 时已经学习过的下一组命令。

$ git init
$ heroku git:remote -a <your-heroku-app-name>
$ git add .
$ git commit -am "deploy my bot"
$ git push heroku master

在最后一个命令之后,你将从 Heroku 获得一些日志,这些日志与部署版本、对应用程序所做的更改等相关。

验证您的聊天机器人 API

在获得成功部署的消息后,让我们测试一下我们的 chatbot APIs 是否工作正常。为了快速进行健全性测试,请点击以下 url:

<your-basic-app-url>+/webhooks/rasa/

举例:

https://horoscopebot1212.herokuapp.com/webhooks/rasa/

在浏览器中打开这个 url 应该会得到如下的响应。如果它给你一个“ok”的状态,那么你就可以开始了——放松,坐下来,调试。

{"status":"ok"}

有时,仅仅是这种验证可能还不够,所以让我们通过尝试检查聊天机器人是否正在识别意图并基于此给出响应来测试它。

我将使用 POSTMAN 工具(POSTMAN 是一个非常好的基于 GUI 的工具来进行 API 测试)。你可以使用任何你觉得舒服的工具。我们只是要测试我们的聊天机器人应该理解和响应的意图之一。我测试了问候的意图,它工作得非常好。机器人返回了预期的响应,如图 5-19 所示。

img/461879_1_En_5_Fig21_HTML.jpg

图 5-19

在 POSTMAN 中测试聊天机器人 API

创建聊天机器人用户界面

正如我们之前讨论的,作为第二步的一部分,我们需要有自己的 UI,为聊天机器人和用户之间的对话提供一个用户友好的场所。如果你是一个前端开发人员,或者你的团队中有一个前端开发人员,你可以很容易地给出我们构建到这一点的 chatbot APIs,前端团队应该可以很容易地将这与他们的 chatbot UI 集成。他们可以利用常规的 HTTP 调用来使用这些 API。Websockets 是一种更好的聊天机器人方式,但这不在本书的解释范围之内。

如果你不熟悉 HTML/CSS/Javascript 之类的前端技术,那么我确实推荐 Pro HTML5 搭配 CSS、Javascript、多媒体 (Apress,2017)。

为了我们的读者——或者我应该说是学习者——的方便,我们创建了一个聊天机器人和用户对话所需的基本 UI。你可以在 github 或 Apress 的网站上找到完整的工作代码。我将告诉你使它为你的机器人工作所需要的配置。

一旦你下载了本章的代码,你会在主文件夹中找到一个名为my_own_chatbot的文件夹。进入这个文件夹,进入 assets - > js - > script.js 文件。

将下面一行 javascript 代码更改为您自己的端点 url。如果你的应用程序名称不同,那么下面的网址将是不同的。使用您自己的 url 和 javascript 代码中的标记,如下所示。

var baseUrl = "https://horoscopebot1212.herokuapp.com/webhooks/rasa/webhook?token=YOUR-SECRET";

保存文件并在浏览器中打开index.html文件,你可以很容易地看到一个聊天机器人 UI 已经准备好了。但是从本地提供的简单 HTML 进行 API 调用会引发一个 CORS 问题。因此,为了避免这种情况,我们将对现有的myown_chatbot.py稍作修改,以服务于 Heroku 应用本身的 HTML。

将您的myown_chatbot.py更改为下面的,然后我们将讨论所做的更改。

import os

from rasa_core.channels.rasa_chat import RasaChatInput
from rasa_core.channels.channel import CollectingOutputChannel, UserMessage
from rasa_core.agent import Agent
from rasa_core.interpreter import RasaNLUInterpreter
from rasa_core.utils import EndpointConfig
from rasa_core import utils

from flask import render_template, Blueprint, jsonify, request

# load your trained agent
interpreter = RasaNLUInterpreter("models/nlu/default/horoscopebot/")
MODEL_PATH = "models/dialogue"
action_endpoint = EndpointConfig(url="https://horoscopebot1212-actions.herokuapp.com/webhook")

agent = Agent.load(MODEL_PATH, interpreter=interpreter, action_endpoint=action_endpoint)

class MyNewInput(RasaChatInput):
    @classmethod
    def name(cls):
        return "rasa"

    def _check_token(self, token):
        if token == 'secret':
            return {'username': 1234}
        else:
            print("Failed to check token: {}.".format(token))
            return None

    def blueprint(self, on_new_message):
        templates_folder = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'myown_chatbot')

        custom_webhook = Blueprint('custom_webhook', __name__, template_folder = templates_folder)

        @custom_webhook.route("/", methods=['GET'])
        def health():
            return jsonify({"status": "ok"})
        @custom_webhook.route("/chat", methods=['GET'])
        def chat():
            return render_template('index.html')

        @custom_webhook.route("/webhook", methods=['POST'])
        def receive():
            sender_id = self._extract_sender(request)
            text = self._extract_message(request)
            should_use_stream = utils.bool_arg("stream", default=False)

            if should_use_stream:
                return Response(
                        self.stream_response(on_new_message, text, sender_id),
                        content_type='text/event-stream')
            else:
                collector = CollectingOutputChannel()
                on_new_message(UserMessage(text, collector, sender_id))
                return jsonify(collector.messages)

        return custom_webhook

input_channel = MyNewInput(url='https://horoscopebot1212.herokuapp.com')
# set serve_forever=False if you want to keep the server running
s = agent.handle_channels([input_channel],  int(os.environ.get('PORT', 5004)), serve_forever=True)

以下是我们所做的更改:

  • 在我们的类中覆盖现有的nameblueprint方法,这允许我们创建自己的端点,也给了我们定义它应该如何行为的自由。

  • 我们创建了一个新的端点/聊天,并提供了 index.html 文件,这只是聊天机器人的用户界面。这将是我们聊天机器人的主页链接。

  • 我们必须根据需要导入一些必要的类和方法,比如utils, CollectingOutputChannelUserMessage来使事情正常运行。

保存文件,并使用以下命令将更改再次部署到我们的 Heroku 应用程序:

$ git add .
$ git commit -am "deploy my bot"
$ git push heroku master

一旦部署成功,瞧!我们已经准备好与全世界分享我们的机器人,它使用两个 Heroku 应用程序工作:一个用于对话管理,一个用于动作。

在浏览器中打开以下 url,我们将在其中看到我们的自定义聊天机器人 UI:

https://horoscopebot1212.herokuapp.com/webhooks/rasa/chat

图 5-20.1 和 5-20.2 显示了我自己的聊天机器人在对话过程中的样子。

img/461879_1_En_5_Fig23_HTML.jpg

图 5-20.2

在你自己的网站上定制聊天机器人

img/461879_1_En_5_Fig22_HTML.jpg

图 5-20.1

在你自己的网站上定制聊天机器人

使用 Heroku 的自定义域名功能,人们可以轻松地将同一个应用程序指向自己网站的名称,如www.example.com。当你觉得你的聊天机器人足够好,可以向全世界公开,无论是盈利还是非盈利,就这么做吧。

所以,这就是所有的乡亲!这就是使用自然语言处理和机器学习用 Python 构建聊天机器人的方式。我希望这一章和前几章对你有所帮助,你可以学习学习和构建聊天机器人的实用方法。

摘要

在本章中,我们学习了如何使用 Heroku 将我们自己的应用程序部署到我们自己的服务器上。我们学会了如何使用脸书的开发平台将我们的聊天机器人与脸书集成。我们还学习了为 Slack 应用程序创建自定义聊天机器人,并对其进行了测试。最后,正如在第三章末尾所承诺的,去除所有对任何社交媒体平台的依赖,我们创建了自己的 UI,并在 Heroku 上部署和测试了它。我们看到它非常有效——在训练它的时候它就起作用了。因为我们有了一个基本的模型,现在你可以处理 chatbot 不能很好工作的情况。确定是否是与数据或培训、操作服务器或自定义代码处理相关的问题。一旦您找到了根本原因,修复它,再次部署,并检查 chatbot 是否有所改进。我们从小做起,打造大软件。

我期待着收到你的来信,并且很想知道在看完这本书之后你制作了什么样的聊天机器人。如果您在任何概念、代码执行或部署方面遇到困难,我很乐意随时为您提供帮助。

谢谢,干杯。

posted @   绝不原创的飞龙  阅读(288)  评论(0编辑  收藏  举报
编辑推荐:
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
阅读排行:
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 我与微信审核的“相爱相杀”看个人小程序副业
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
点击右上角即可分享
微信分享提示