Python聊天机器人构建指南全绝不原创的飞龙

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

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

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

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

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

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

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

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

图1-1

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

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

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

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

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

—蒂姆·彼得斯

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

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

Python2.7.15(default,May12018,16:44:08)[GCC4.2.1CompatibleAppleLLVM9.1.0(clang-902.0.39.1)]ondarwinType"help","copyright","credits"or"license"formoreinformation.>>>importthisTheZenofPython,byTimPetersBeautifulisbetterthanugly.Explicitisbetterthanimplicit.Simpleisbetterthancomplex.Complexisbetterthancomplicated.Flatisbetterthannested.Sparseisbetterthandense.Readabilitycounts.Specialcasesaren'tspecialenoughtobreaktherules.Althoughpracticalitybeatspurity.Errorsshouldneverpasssilently.Unlessexplicitlysilenced.Inthefaceofambiguity,refusethetemptationtoguess.Thereshouldbeone—andpreferablyonlyone—obviouswaytodoit.Althoughthatwaymaynotbeobviousatfirstunlessyou'reDutch.Nowisbetterthannever.Althoughneverisoftenbetterthan*right*now.Iftheimplementationishardtoexplain,it'sabadidea.Iftheimplementationiseasytoexplain,itmaybeagoodidea.Namespacesareonehonkinggreatidea—let'sdomoreofthose!你可能无法理解以上所有关于聊天机器人的观点,但你肯定能理解其中的大部分。

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

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

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

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

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

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

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

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

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

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

图1-2

聊天机器人带来收入

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

图1-3

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

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

图1-4

顾客更喜欢聊天机器人

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

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

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

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

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

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

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

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

图1-5

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

—杰克·多西

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

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

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

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

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

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

图1-6

常见问题聊天机器人示例

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

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

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

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

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

—维基百科

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

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

图1-7

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

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

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

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

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

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

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

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

图1-8

通过设计解决用例的例子

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

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

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

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

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

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

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

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

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

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

这里可能有两个实体:

类别:鞋子

尺寸:8

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

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

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

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

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

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

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

下一章见。

本章旨在让你开始使用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,清理数据,然后准备采取适当的行动。

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

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

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

图2-1

空间基准测试结果

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

!python3-mspacydownloaden使用JupyterNotebook下载Python3的空间模型时,您可能会遇到权限问题。转到您的终端,运行以下命令:

sudopython3–mdownloaden参见图2-4进行参考。

图2-4

下载空间模型

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

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

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

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

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

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

例1:

nlp=spacy.load('en')#Loadsthespacyenmodelintoapythonobjectdoc=nlp(u'Iamlearninghowtobuildchatbots')#Createsadocobjectfortokenindoc:print(token.text,token.pos_)#printsthetextandPOS输出:

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

doc=nlp(u'IamgoingtoLondonnextweekforameeting.')fortokenindoc: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'Googlerelease"MoveMirror"AIexperimentthatmatchesyourposefrom80,000images')fortokenindoc: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万|Eightythousand|全国矿工联合会|激光唱片|nummod|dd,ddd|错误的|错误的||图像|图像|名词|非营养性吸吮|比吉|电影站|真实的|错误的|

例4:

doc=nlp(u'Iamlearninghowtobuildchatbots')fortokenindoc:print(token.text,token.lemma_,token.pos_,token.tag_,token.dep_,token.shape_,token.is_alpha,token.is_stop)输出:

||---|---|---|---|---|---|---|---||我|PRON|代词|富含血小板血浆|nsubj|X|真实的|错误的||上午|是|动词|文件|去吧|xx|真实的|真实的||学习|学习|动词|静脉全血葡萄糖|根|电影站|真实的|错误的||如何|怎么|副词|warrefugeeboard战时难民事务委员会|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没有任何内置的词干分析器,因为词汇化被认为更加正确和有效。

词干化和词汇化的区别

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

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

fromspacy.lemmatizerimportLemmatizerfromspacy.lang.enimportLEMMA_INDEX,LEMMA_EXC,LEMMA_RULESlemmatizer=Lemmatizer(LEMMA_INDEX,LEMMA_EXC,LEMMA_RULES)lemmatizer('chuckles','NOUN')#2ndparamistoken'spart-of-speechtag输出:

[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”的词干,这更有意义,也更正确。

fromnltk.stem.porterimport*fromnltk.stem.snowballimportSnowballStemmerporter_stemmer=PorterStemmer()snowball_stemmer=SnowballStemmer("english")print(porter_stemmer.stem("fastest"))print(snowball_stemmer.stem("fastest"))fastestfastest注意在尝试运行这段代码之前,确保使用pip3安装nltk包。

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

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

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

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

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

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

my_string=u"GooglehasitsheadquartersinMountainView,Californiahavingrevenueamountedto109.65billionUSdollars"doc=nlp(my_string)forentindoc.ents:print(ent.text,ent.label_)输出:

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

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

例2:

my_string=u"MarkZuckerbergbornMay14,1984inNewYorkisanAmericantechnologyentrepreneurandphilanthropistbestknownforco-foundingandleadingFacebookasitschairmanandCEO."doc=nlp(my_string)forentindoc.ents:print(ent.text,ent.label_)输出:

('MarkZuckerberg','PERSON')('May14,1984','DATE')('NewYork','GPE')('American','NORP')('Facebook','ORG')例3:

my_string=u"Iusuallywakeupat9:00AM.90%ofmydaytimegoesinlearningnewthings."doc=nlp(my_string)forentindoc.ents:print(ent.text,ent.label_)输出:

类型

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

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

my_string1=u"ImagineDragonsarethebestband."my_string2=u"Imaginedragonscomeandtakeoverthecity."doc1=nlp(my_string1)doc2=nlp(my_string2)forentindoc1.ents:print(ent.text,ent.label_)上面的for循环遍历doc1对象给出一个输出:

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

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

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

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

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

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

fromspacy.lang.en.stop_wordsimportSTOP_WORDSprint(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属性。

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

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

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

doc=nlp(u'BookmeaflightfromBangaloretoGoa')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)的祖先。您可以尝试更多这样的例子,以便更好地理解依赖解析和祖先概念。

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

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

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

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

doc=nlp(u'Bookatableattherestaurantandthetaxitothehotel')tasks=doc[2],doc[8]#(table,taxi)tasks_target=doc[5],doc[11]#(restaurant,hotel)fortaskintasks_target:fortokintask.ancestors:iftokintasks:print("Bookingof{}belongsto{}".format(tok,task))break输出:

BookingoftablebelongstorestaurantBookingoftaxibelongstohotel依存解析中的子元素是什么?子代是该标记的直接语法依赖项。我们可以像使用ancestors一样使用children属性来查看单词的子单词。

list(doc[3].children)将输出

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

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

图2-5

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

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

图2-6

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

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

图2-7

依存解析示例

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

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

doc=nlp(u"WhataresomeplacestovisitinBerlinandstayinLubeck")现在,我们得到了正在谈论的地点和用户想要的动作:

places=[doc[7],doc[11]]#[Berlin,Lubeck]actions=[doc[5],doc[9]]#[visit,stay]因为您已经知道了词性标注和实体提取,所以您可以很容易地自动获得位置和动作。

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

forplaceinplaces:fortokinplace.ancestors:iftokinactions:print("Userisreferring{}to{}").format(place,tok)break输出:

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

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

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

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

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

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

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

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

doc=nlp(u"BostonDynamicsisgearinguptoproducethousandsofrobotdogs")list(doc.noun_chunks)输出:

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

doc=nlp(u"DeeplearningcracksthecodeofmessengerRNAsandprotein-codingpotential")forchunkindoc.noun_chunks:print(chunk.text,chunk.root.text,chunk.root.dep_,chunk.root.head.text)输出:

根。正文

根。DEP_

根。头.正文

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

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

意为

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

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

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

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

doc=nlp(u'Howareyoudoingtoday')fortokenindoc: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))看到这个输出,没有太大的意义和意义。从应用程序的角度来看,最重要的是不同单词的向量有多相似——也就是单词本身的意思。

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

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))输出:

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

代码:

GoT_str1=nlp(u"WhenwillnextseasonofGameofThronesbereleasing")GoT_str2=nlp(u"GameofThronesnextseasonreleasedate")GoT_str1.similarity(GoT_str2)输出:

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

example_doc=nlp(u"cartruckgoogle")fort1inexample_doc:fort2inexample_doc:similarity_perc=int(t1.similarity(t2)*100)print"Word{}is{}%similartoword{}".format(t1.text,similarity_perc,t2.text)输出:

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

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

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

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

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

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

doc=nlp(u'BrexitistheimpendingwithdrawaloftheU.K.fromtheEuropeanUnion.')fortokenindoc:print(token.text)输出:

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

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

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

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

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

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

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

代码如下:

sentence1="BookmeametrofromAirportStationtoHongKongStation."sentence2="BookmeacabtoHongKongAirportfromAsiaWorld-Expo."importrefrom_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)iffrom_to_matchandfrom_to_match.groups():_from=from_to_match.groups()[0]_to=from_to_match.groups()[1]print("from_topatternmatchedcorrectly.Printingvalues\n")print("From:{},To:{}".format(_from,_to))elifto_from_matchandto_from_match.groups():_to=to_from_match.groups()[0]_from=to_from_match.groups()[1]print("to_frompatternmatchedcorrectly.Printingvalues\n")print("From:{},To:{}".format(_from,_to))输出:

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

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

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

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

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

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

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

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

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

图3-1

Dialogflow架构的工作图

事情是这样的:

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

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

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

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

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

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

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

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

意图

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

实体

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

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

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

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

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

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

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

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

图3-4

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

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

图3-5

测试Dialogflow中的欢迎意图

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

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

我想要食物

我想尽快点餐

你能帮我点菜吗?

请为我点餐

我想点中餐

我想下订单

请你帮我点餐好吗?

你能帮我点餐吗?

我想点餐

我想点泰国菜

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

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

当然,你今天想吃什么?

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

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

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

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

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

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

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

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

{"food_items":{"chickendumpling":1,"Springrolls":2}}项目说明意图和所属实体我们可以选择一个和两个,并将其定义为@sys.number,它只不过是数据类型。我们将创建一个名为food_items_entity的新实体来标识食品。

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

图3-6

项目描述意图

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

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

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

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

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

图3-7

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

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

一份鸡肉饺子和两份春卷

意向响应:

{"id":"e8cf4a44-6ec9-49ae-9da8-a5542a80d742","timestamp":"2018-04-01T21:22:42.846Z","lang":"en","result":{"source":"agent","resolvedQuery":"Onechickendumplingandtwospringrolls","action":"","actionIncomplete":false,"parameters":{"quantity1":1,"food_items_entity1":"chickendumpling","quantity2":2,"food_items_entity2":"springrolls"},"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":"chickendumpling","quantity2":2,"food_items_entity2":"springrolls"}我们可以轻松地编写一些Python代码,将JSON转换成我们讨论过的预期格式。

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

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

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

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

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

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

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

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

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

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

图3-8

创建订单状态意图

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

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

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

图3-9

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

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

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

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

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

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

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

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

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

图3-10

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

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

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

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

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

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

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

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

图3-11

定义用户说谢谢时的意图

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

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

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

图3-12

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

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

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

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

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

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

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

图3-13

“安静”web演示链接

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

图3-14.4

OnlineEatsBot演示对话屏幕IV

图3-14.3

OnlineEatsBot演示对话屏幕III

图3-14.2

OnlineEatsBot演示对话屏幕II

图3-14.1

OnlineEatsBot演示对话屏幕I

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

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

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

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

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

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

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

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

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

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

以下是步骤:

图3-17

使用FacebookMessenger设置和集成Dialogflow】

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

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

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

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

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

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

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

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

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

图3-18

在脸书为Dialogflowbot设置webhooks

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

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

图3-20

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

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

图3-21.4

FacebookMessenger在线版演示屏幕四

图3-21.3

FacebookMessenger在线版演示屏幕III

图3-21.2

FacebookMessenger在线版演示屏幕II

图3-21.1

FacebookMessenger在线EatsBot演示屏幕I

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

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

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

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

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

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

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

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

在这里找到代码:flask_onlineeats_demo.zip

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

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

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

图3-22

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

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

图3-23

在Dialogflow中为实现设置webhook

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

图3-24

为特定目的启用webhook调用

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

图3-25

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

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

图3-26

Dialogflow需要来自webhookURL的响应

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

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

{"fulfillmentText":"OrderID:9999\.It'sontheway","payload":{"facebook":{"text":"OrderID:9999\.It'sontheway"}}}当我再次尝试点击相同的API时,我得到了不同的订单状态文本,但格式与Dialogflow引擎预期的相同。

{"fulfillmentText":"OrderID:9999\.Riderhaspickedupyourfood,pleasewaitforanother10-15minutes","payload":{"facebook":{"text":"OrderID:9999\.Riderhaspickedupyourfood,pleasewaitforanother10-15minutes"}}}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模型可能工作得很好,以至于你根本不需要任何启发。但是根据我的经验,当你继续销售你的聊天机器人或者将它们商业化的时候,你必须小心一点。没有功能总比有一个没有意义的功能好。

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

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

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

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

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

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

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

pipinstallrasa-nlu==0.13.2RasaNLU有多个用于分类意图和识别实体的组件。Rasa的不同组件有自己的依赖集。

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

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

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

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

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

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

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

可能的意图

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

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

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

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

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

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

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

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

RasaNLU期望的数据的JSON格式有一个名为rasa_nlu_data的顶层对象,键为common_examples、entity_synonyms、regex_features。

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

{"rasa_nlu_data":{"common_examples":[],"regex_features":[],"entity_synonyms":[]}}JSON数据中的common_examples键是用于训练我们的模型的中心位置。我们将在common_examples数组中添加我们所有的训练示例。

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

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

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

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

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

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

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

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

[fsevents]Success:"/usr/local/lib/node_modules/rasa-nlu-trainer/node_modules/fsevents/lib/binding/Release/node-v57-darwin-x64/fse.node"alreadyinstalledPass--update-binarytoreinstallor--build-from-sourcetorecompilenpmWARNslick-carousel@1.8.1requiresapeerofjquery@>=1.8.0butnoneisinstalled.Youmustinstallpeerdependenciesyourself.+rasa-nlu-trainer@0.2.7added492packagesin10.14s即使您的消息看起来不像这样,只要它没有抛出任何错误,也不用担心。我们很快就会知道我们的rasa-nlu-trainer是否安装成功并且运行良好。

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

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

图4-1

本地主机中的rasa-nlu-trainer

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

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

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

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

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

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

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

{"text":"19-01","intent":"dob_intent","entities":[{"start":0,"end":2,"value":"19","entity":"DD"},{"start":3,"end":5,"value":"01","entity":"MM"}]}训练聊天机器人模型在本节中,我们将根据准备好的数据训练一个模型。由于我们使用JupyterNotebook创建和管理文件,我们将创建一个新的。ipynb并开始编写我们的Python代码,通过选择我们在本章前面讨论的管道之一来训练我们的模型。

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

向其中添加以下配置:

{"pipeline":"tensorflow_embedding","path":"./models/nlu","data":"./data/data.json"}如您所见,在我们的config.json文件中有一些重要的配置参数。让我们试着去理解它们。

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

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

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以一种清晰的方式指定预定义的管道。

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

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

fromrasa_nlu.training_dataimportload_datafromrasa_nlu.modelimportTrainerfromrasa_nluimportconfigfromrasa_nlu.modelimportInterpreterdeftrain_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')defpredict_intent(text):interpreter=Interpreter.load('./models/nlu/default/horoscopebot')print(interpreter.parse(text))在代码的第一部分,我们从rasa_nlu包中导入所有必需的库。然后,我们定义了两个方法,称为train_占星机器人和predict_intent,其中第一个方法在给定数据、配置文件和模型目录(存储模型的位置)的情况下训练模型,predict_intent方法使用rasa_nlu的解释器模型来加载预训练的模型文件,并让用户能够预测任何新的文本示例。

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

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("Iamlookingformyhoroscopefortoday.Iamwonderingifyoucantellmethat.")该方法本身打印输出。对于上面的文本,我的输出如下所示:

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

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

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

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

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

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

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

让我们举个例子:

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

图4-2

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

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

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

图4-3

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

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

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

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

用户

网上吃饭

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

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

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

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

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

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

顾名思义,这是一个可以采取的具体行动。根据Rasa文档,它说,“Nextactiontobetakeninresponsetoadialogstate”

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

fromrasa_core.actionsimportActionfromrasa_core.eventsimportSlotSetclassGetTodaysHoroscope(Action):defname(self):return"get_todays_horoscope"defrun(self,dispatcher,tracker,domain):#type:(Dispatcher,DialogueStateTracker,Domain)->List[Event]user_horoscope_sign=tracker.get_slot('horoscope_sign')"""Writeyourlogictogettoday’shoroscopedetailsforthegivenHoroscopesignbasedonsomeAPIcallsorretrievalfromthedatabase"""return[SlotSet("horoscope_sign",user_horoscope_sign)]name方法返回动作的名称,我们将在域文件中将其称为自定义方法名称。

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

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

run方法返回事件实例列表。

插槽是那些让机器人负责像人类一样工作的东西。插槽就像一个存储空间,可以存储用户给出的信息,也可以使用从数据库或API预取的信息。

不同的使用情形有不同的插槽类型:

例如,在我们想要构建星座机器人的用例中,我们可能想要使用插槽类型作为用户提供的星座符号的text。

根据您想要保留的插槽类型,Rasa提供了一些预定义的插槽类型。

除文本外,Rasa还有以下插槽类型:

当你在寻找发送电子邮件、准备文档、建立作品集网站或遵循流程的模板时,模板是一个你在生活中至少听过一次的词。

Rasa中的模板用于话语。话语模板包含一组预设文本,当某个动作被触发时,这些文本将被发送给用户。通过使用与话语相同的动作名称或者使用自定义代码的动作,我们可以将格式化的消息以模板的形式发送给用户。

域文件中模板的简单表示可能如下所示:

templates:utter_greet:-"hello{name}!"#namecanbefilledbyaslotofsamenameorbycustomcodeutter_goodbye:-"goodbye"-"takecarebye"#multipletemplatesallowthebottorandomlypickfromthemutter_default:-"Sorry,Ididn’tgetthat."现在,我们已经学习了动作、插槽和模板这三个概念,并且我们已经知道了意图和实体是什么,作为我们从第三章学习的一部分,我们现在准备深入Rasa并开始为我们的第一个聊天机器人编写代码。

使用Rasastack构建聊天机器人的首要任务是创建一个域文件。

根据Rasa的文档,“域定义了你的机器人运行的宇宙。它指定了你的机器人应该知道的意图、实体、插槽和动作。可选地,它还可以包括你的机器人可以说的东西的模板。”

现在,通过了解Rasa的核心概念,你知道为什么我们必须事先为这种情况做好准备。

让我们用YAML定义创建一个DefaultDomain文件。拉莎使用。yml文件来定义域格式。

最初YAML的意思应该是YetAnotherMarkupLanguage,描述它作为一种标记语言的使用,但后来它被理解为YAML不是标记语言,一种递归的缩写,以区分它作为面向数据而不是文档标记语言的目的。

现在,让我们回到rasa-nluJupyter笔记本目录,开始创建文件。请注意,我们可以使用命令行在单独的文件中编写所有代码,并使用编辑器对其进行编辑。我发现Jupyter笔记本更具互动性,浏览文件也更容易。无论你觉得哪种都可以,但是了解JupyterNotebook提供的大部分功能还是有好处的。

转到主占星_bot目录下,创建一个文件,姑且称之为horoscope_domain.yml。

以下是我们bot的horoscope_domain.yml内容:

slots:horoscope_sign:type:textDD:type:textMM:type:textsubscribe:type:boolintents:-greeting-get_horoscope-subscription-dob_intententities:-horoscope_sign-DD-MM-subscribe-dob_intenttemplates:utter_greet:-'Hello!Howareyoudoingtoday'utter_ask_horoscope_sign:-'Whatisyourhoroscopesign'utter_ask_dob:-'WhatisyourDOBinDD-MMformat'utter_subscribe:-'Doyouwanttosubscribefordailyupdates'actions:-utter_greet-utter_ask_horoscope_sign-utter_ask_dob-utter_subscribe-get_todays_horoscope-subscribe_user正如您所看到的,域文件由五个重要部分组成:intents,entities,slots,templates和actions,我们在前面已经讨论过了。

注意,对于每个模板,都定义了一个utterAction,比如utter_greet,utter_ask_horoscope_sign和utter_ask_dob,我们必须在模板部分定义一个同名的模板。

正如您在我们的示例中看到的,主要定义了五个动作,其中前三个动作只是为了向用户说出模板文本,但最后两个动作要求我们要么从数据库中检索数据,要么调用API来获取当天的星座并将其返回给用户。

对于subscribe_user动作,我们需要做一个操作,将当前用户添加到数据库的订阅列表中。这些用户定义的操作称为自定义操作。为了拥有这样的自定义动作,我们需要编写当这些动作被触发时,机器人应该做什么。

在下一节中,我们将学习如何编写自定义操作。

正如我们所知,每当一个UtterAction被触发,我们的机器人会用模板中为该动作定义的完整文本进行响应。但是当一些自定义动作被触发时会发生什么呢?在这一节中,我们将编写Python代码来创建自定义操作,我们可以用它来进行API调用或几乎任何你可以用Python做的事情。

让我们在我们的项目目录中创建一个名为actions.py的新文件(即,在我们的例子中,在horoscope_bot文件夹中)。

APIurl如下所示:

它以JSON格式返回数据:

{"date":"2018-08-29","horoscope":"Youwillbeoverpoweredwithnostalgiaandmaylongtogetintouchwitholdpals.AndasGaneshasays,chancesarethatyoumaytakealikingtoyourex-lover,whilesimultaneouslystrengtheningyoursocialstanding.Allinall,thedaywillbeaproductiveone.","sunsign":"capricorn"}正如你在run方法中看到的,我们将来自API的响应转换为PythonJSON对象,然后从JSON中访问“星座”键以获得实际的星座。在从JSON中获得实际的星座之后,我们使用dispatcher对象及其方法utter_message制定一个响应并将其发送回用户。

最后,我们使用SlotSet方法设置插槽。SlotSet就像保存您从用户的响应中发现的变量,这样您就可以在对话过程中的任何时候在代码中使用它们。

使用上面的API,我们可以通过提供星座来获得今天的星座。你可以自由使用你自己的API或者数据库。您只需要将API调用替换为您想要使用的其他资源。

以下是SubscribeUser操作的外观:

classSubscribeUser(Action):defname(self):return"subscribe_user"defrun(self,dispatcher,tracker,domain):#type:(Dispatcher,DialogueStateTracker,Domain)->List[Event]subscribe=tracker.get_slot('subscribe')ifsubscribe==“True”:response="You'resuccessfullysubscribed"ifsubscribe==“False”:response="You'resuccessfullyunsubscribed"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的文件。

在第二个故事中,用户自己说出星座,然后用订阅对话框结束故事。我们增加了几个故事,涵盖了更多的用例。请随意在同一个文件中添加您自己的故事。

所以,基本上故事是降价文件,我们可以按照前面显示的降价格式写尽可能多的故事。手工完成这项任务似乎有点困难。因此,我们将尝试学习如何使用Rasa自己的互动学习工具来生成更多这样的故事。

让我们开始吧。

到目前为止,我们一直在零零碎碎地谈论交互式学习,但现在是时候实际编写一些代码并付诸实践了。交互式学习是Rasa最酷的功能之一,它使ML部分变得有趣和简单。有两个部分:在第一部分中,我们通过使用各种策略给出我们的初始数据集来训练模型,在第二部分中,我们测试模型,修正它,并以交互的方式重新训练它。

让我们在主项目目录中创建一个名为train_initialize.py的新文件。train_initialize.py的内容是这样的:

from__future__importabsolute_importfrom__future__importdivisionfrom__future__importprint_functionfrom__future__importunicode_literalsfromrasa_coreimportutilsfromrasa_core.agentimportAgentfromrasa_core.policies.keras_policyimportKerasPolicyfromrasa_core.policies.memoizationimportMemoizationPolicyfromrasa_core.policies.sklearn_policyimportSklearnPolicyif__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文件中的代码。现在,在我们进入下一个代码文件之前,让我们先试着理解其中的要点。

此时,您应该非常清楚每个方法的作用以及代码内部发生了什么。

在我们继续运行这个脚本之前,确保在执行这个脚本之前已经安装了rasa_core库。

您可以使用以下命令安装rasa_core:

pipinstallrasa_core==0.11.1如果你遵循本书中的聊天机器人示例,那么确保你只安装了上述版本,因为Rasa可能不是向后兼容的。他们正迅速提出更新更优化的方法。

您也可以从githubrepo安装rasa_core的最新版本。你只需要执行下面这组命令,这些命令会在安装之前直接从github获取最新的代码。

$pythontrain_initialize.py您也可以使用Jupyter的magic命令从Jupyter笔记本本身运行该脚本,如下所示:

如果您已经为python3安装了rasa,请使用python3

在我们这样的小数据集上训练模型应该需要大约25到30秒。我在策略列表中添加了SklearnPolicy以及MemorizationPolicy和KerasPolicy来训练我的模型。不同的政策有各自的好处。阅读更多关于它们的内容,以了解哪一种可能更适合您的用例;对于我的数据集,SklearnPolicy有时似乎比KerasPolicy表现得更好。

脚本执行完毕后,您应该会看到一些成功的消息,如下所示:

2018-08-3004:24:31INFOrasa_core.policies.keras_policy-Donefittingkeraspolicymodel2018-08-3004:24:31INFOrasa_core.featurizers-Creatingstatesandactionexamplesfromcollectedtrackers(byMaxHistoryTrackerFeaturizer)...Processedtrackers:100%|████████|96/96[00:00<00:00,898.31it/s,#actions=75]2018-08-3004:24:31INFOrasa_core.featurizers-Created75actionexamples.2018-08-3004:24:31INFOrasa_core.policies.sklearn_policy-Donefittingsklearnpolicymodel2018-08-3004:24:31INFOrasa_core.agent-Modeldirectorymodels/nluexistsandcontainsoldmodelfiles.Allfileswillbeoverwritten.2018-08-3004:24:31INFOrasa_core.agent-Persistedmodelto'/Users/sumit/apress_all/ChapterIV/horoscope_bot/models/nlu'您还会发现几个根据型号名称创建的文件夹。确保您在脚本中给出的model_path中有它们。以下是我在model_path文件夹中看到的文件夹/文件。

policy_0_MemoizationPolicypolicy_1_KerasPolicypolicy_2_SklearnPolicydomain.jsondomain.ymlPolicy_metadata.json如果您已经验证了您的模型已经成功地完成了执行,并且在您的本地系统中持久化了模型,那么我们就可以进入下一步的交互式培训了。

在这一节中,我们将编写更多的代码来训练我们的对话模型,并在它给出不正确的输出时进行重新训练。

因此,当我们的机器人做错了什么,我们会立即跳出来,通过告诉它什么是正确的,让模型知道它的预测是错误的。无需停止,模型会重新训练自己,一旦我们完成,用户和机器人之间的交互就会被捕获到一个文件中,并添加到我们现有的训练数据中。它在每一步都更像一个反馈系统,而不是在最后等待一个单一的奖励。

下一步是用下面的内容创建一个名为endpoints.yml的新文件。我们将在Python代码文件train_online.py.中使用这个文件。通过这个配置,我们可以将Rasa方法公开为HTTPAPIs。

from__future__importabsolute_importfrom__future__importdivisionfrom__future__importprint_functionfrom__future__importunicode_literalsimportloggingfromrasa_coreimportutils,trainfromrasa_core.trainingimportonlinefromrasa_core.interpreterimportNaturalLanguageInterpreterlogger=logging.getLogger(__name__)deftrain_agent(interpreter):returntrain.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做好准备。

RasaNLU堆栈提出了rasa-nlu-sdk,这是一个PythonSDK,用于为Rasa核心开发自定义操作。至于我们的聊天机器人示例,我们需要定义一些自定义操作,比如点击API来获取今天的星座,或者可能是数据库写操作来将用户添加到订阅列表。

好消息是他们有一个单独的库,我们可以使用pip来安装它。

让我们使用以下命令来安装它:

pipinstallrasa-core-sdk==0.11.0现在,我们需要转到终端的另一个选项卡或一个新的命令行,并在我们的项目目录(我们的actions.py文件所在的位置)中执行以下命令:

python-mrasa_core_sdk.endpoint--actionsactionsINFO:__main__:Startingactionendpointserver...INFO:rasa_core_sdk.executor:Registeredfunctionfor'get_todays_horoscope'.INFO:rasa_core_sdk.executor:Registeredfunctionfor'subscribe_user'.INFO:__main__:Actionendpointisupandrunning.on('0.0.0.0',5055)该命令将启动一个动作服务器,该服务器将监听模型预测的任何自定义动作。一旦任何动作被触发,它将执行它并根据方法给出响应。

在本地主机上,操作服务器端点的默认端口是5055。如果你想改变它,你可以在命令行中添加pass--port参数。

一个快速的问题浮现在脑海:为什么?为什么我需要一个单独的服务器?为什么不能用普通Python?是的,我们可以使用普通的Python,但是假设您要用任何其他语言来开发所需的操作,或者您已经将一些操作公开为API。现在,您只需要转到我们已经创建的endpoints.yml,,并使用它来说明应该在哪里使用您的操作服务器以及应该在哪里使用您的core_endpoint服务器。在生产系统中,两者可以是具有完全不同的URL的不同服务器。

现在,当我们运行下一个脚本时,其中提到了我们的endpoints.yml文件,Rasa将读取该文件并获取我们的action_server的配置,它已经按照我们之前所做的配置启动并运行。

$python3train_online.py在对话模型的成功训练之后,我们将得到这样的消息:

让我们这样做,看看它是否有所改善。

我输入“Hi”作为第一条消息,机器人返回以下内容:

---------------------------------------------------------------------------Chathistory:botdid:action_listenusersaid:hiwhoseintentis:{'confidence':0.8472929307505297,'name':'greeting'}wecurrentlyhaveslots:DD:None,MM:None,horoscope_sign:None,subscribe:None------Thebotwantsto[utter_greet]duetotheintent.Isthiscorrect1\.Yes2\.No,intentisrightbuttheactioniswrong3\.Theintentiswrong0\.Exportcurrentconversationsasstoriesandquit---------------------------------------------------------------------------现在,机器人正在根据用户所说的话和他对它的理解告诉我它做了什么。现在,它也给了我们四个选择。我们一会儿会谈到这一点。

这里的bot_did是action_listen的意思;它只是在等待用户输入一些东西,这很好。

Bot说出了意图{'confidence':0.8472929307505297,'name':'greeting'},这是正确的,所以我们会按1,意思是bot正在理解并试图正确地做的事情。

1---------------------------------------------------------------------------Chathistory:botdid:action_listenusersaid:hiwhoseintentis:{'confidence':0.8472929307505297,'name':'greeting'}botdid:utter_greetwecurrentlyhaveslots:DD:None,MM:None,horoscope_sign:None,subscribe:None------Thebotwantsto[action_listen].Isthiscorrect1\.Yes.2\.No,theactioniswrong.0\.Exportcurrentconversationsasstoriesandquit---------------------------------------------------------------------------你看,我们的机器人至少正确地问候了用户。如果你看到前面提到的回应,你实际上可以检查我们的机器人做了什么;在我们训练它的时候,它会记录所有这些。

botdid:utter_greet现在,机器人说接下来的事情是等待并听用户将要说什么(即,等待用户输入)。这是正确的吗?是的,这是正确的,所以我们再次按1,机器人给用户一个提示。

我输入,“我今天的星座是什么?”

---------------------------------------------------------------------------Chathistory:botdid:action_listenusersaid:hiwhoseintentis:{'confidence':0.8472929307505297,'name':'greeting'}botdid:utter_greetbotdid:action_listenusersaid:what'smyhoroscopefortodaywhoseintentis:{'confidence':0.8902154738608781,'name':'get_horoscope'}wecurrentlyhaveslots:DD:None,MM:None,horoscope_sign:None,subscribe:None------Thebotwantsto[utter_ask_horoscope_sign]duetotheintent.Isthiscorrect1\.Yes2\.No,intentisrightbuttheactioniswrong3\.Theintentiswrong0\.Exportcurrentconversationsasstoriesandquit---------------------------------------------------------------------------现在,机器人非常正确地识别出“获取星座”的意图,准确率达到89%,这是非常好的。机器人还说它想说出_ask_占星_sign,这又是正确的,因为用户还没有提到任何占星符号,槽仍然是无,如图所示。

我们再次按1。

我们再次按1,出现提示时,我们输入“摩羯”作为输入。

---------------------------------------------------------------------------Chathistory:botdid:action_listenusersaid:hiwhoseintentis:{'confidence':0.8472929307505297,'name':'greeting'}botdid:utter_greetbotdid:action_listenusersaid:what'smyhoroscopefortodaywhoseintentis:{'confidence':0.8902154738608781,'name':'get_horoscope'}botdid:utter_ask_horoscope_signbotdid:action_listenusersaid:Capricornwhoseintentis:{'confidence':0.8456705103362621,'name':'get_horoscope'}withhoroscope_sign:capricornwecurrentlyhaveslots:DD:None,MM:None,horoscope_sign:capricorn,subscribe:NoneThebotwantsto[get_todays_horoscope]duetotheintent.Isthiscorrect1\.Yes2\.No,intentisrightbuttheactioniswrong3\.Theintentiswrong0\.Exportcurrentconversationsasstoriesandquit---------------------------------------------------------------------------现在,正如我们所看到的,星座槽被自动设置为“摩羯座”

下一步是教机器人调用get_today_占星和调用get_today_占星动作。到目前为止,我们的槽已经为我们在占星_域.yml中定义的占星_符号变量设置好了,所以如果再次调用这个动作,聊天机器人应该会返回当天的实际占星。让我们试试。

我输入了“摩羯座”

bot点击动作服务器的端点,并将结果返回给用户,正如我们在自定义动作中定义的那样。

Yourtoday'shoroscope:乐观是从失败走向成功的动力。甘尼萨说,你今天会非常乐观——对你的工作、未来和一切能让你成功的东西。在处理日常工作时,你也会非常小心,会利用每一个能让你离目标更近一步的机会。决心和好运是你实现梦想所需要的一切;今天你将两者兼得。

这似乎是公平的,因为我错过了完成这一章的最后期限,现在是早上6点,我还没有睡觉。尽一切努力让你的钱值得花在这本书上。

好吧,让我们回去看看我们的机器人下一步要做什么。

------Thebotwantsto[action_listen].Isthiscorrect1\.Yes.2\.No,theactioniswrong.0\.Exportcurrentconversationsasstoriesandquit也许我们不想让我们的机器人在说出今天的星座之后还在听。我们希望我们的机器人要求用户根据我们的对话脚本以及我们创建的故事订阅更新。

所以,我会按2,它会说

------whatisthenextactionforthebot0action_listen1.001action_restart0.002action_default_fallback0.003utter_greet0.004utter_ask_horoscope_sign0.005utter_ask_dob0.006utter_subscribe0.007get_todays_horoscope0.008subscribe_user0.00因为我们希望用户订阅,所以我们应该按6,这样机器人会询问用户是否希望订阅每日更新。

机器人回答,“你想订阅每日更新吗?”

现在机器人说:

---------------------------------------------------------------------------Thebotwantsto[get_todays_horoscope].Isthiscorrect1\.Yes.2\.No,theactioniswrong.0\.Exportcurrentconversationsasstoriesandquit这里的动作不正确,所以我们按2,训练机器人听用户这里的动作。

---------------------------------------------------------------------------whatisthenextactionforthebot0action_listen0.211action_restart0.012action_default_fallback0.013utter_greet0.214utter_ask_horoscope_sign0.515utter_ask_dob0.016utter_subscribe0.027get_todays_horoscope0.788subscribe_user0.22---------------------------------------------------------------------------当机器人等待知道正确的下一步时,我们按0。机器人现在将在我们的交互式学习过程中等待用户输入。

用户在这里说,“请订阅我,”我们的机器人以80%的信心成功地识别出这是一个订阅意图,并且根据我们在data.json中的训练数据,很容易理解用户是在请求订阅而不是取消订阅。换句话说,它将subscribe的槽设置为True,如下所示:

---------------------------------------------------------------------------usersaid:Pleasesubscribemewhoseintentis:{'confidence':0.795172441763619,'name':'subscription'}withsubscribe:Truewecurrentlyhaveslots:DD:None,MM:None,horoscope_sign:capricorn,subscribe:True---------------------------------------------------------------------------现在,我们的机器人已经理解了它的意图,并解析了其中的实体,是时候回复用户说“他已经成功订阅了”,然后我们从机器人那里得到一条消息:

You'resuccessfullysubscribed这就对了。你完全可以自己成功构建自己的室内聊天机器人。作为练习的一部分,我建议你添加我们讨论过的星座机器人的所有用例,看看它是否有效。当我们到目前为止所做的一切都运行良好时,尝试添加更多的用例和更多的功能。

您可以在这里添加更多的话语信息,以便机器人在对话完成后说,“再见,祝您愉快”。我坚信你应该有能力做到这一点。一定要这样做,并让我们知道你的进展如何。

现在,最后一部分是将所有这些学习反馈给用户,这样我们就不必再次教授相同的故事,机器人会尝试从现有的故事和未来的故事中学习。

现在,互动学习部分的下一步是按0,将我们当前的对话导出为故事,然后退出。

为此,我们按0,机器人会提示如下内容:

Filetoexportto(iffileexists,thiswillappendthestories)[stories.md]:只需输入我们的stories.md文件名,如果您保留了任何其他名称,请确保您给出了正确的文件名。

Rasa为我们完成了这项艰巨的工作,并自动生成了一个stories.md文件,如下所示:

##GeneratedStory3797421409943253925*greeting-utter_greet*Iwanttoknowmyhoroscope-utter_ask_horoscope_sign*get_horoscope##GeneratedStory7304374603374920907*greeting-utter_greet*whatismytodayshoroscope-utter_ask_horoscope_sign*Cancer##GeneratedStory-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文件中。在再次测试或进行交互式学习之前,请确保再次运行您的模型。

测试机器人是我们互动学习过程的一部分。我们不断检查最初为机器人想到的所有可能的场景,并相应地训练它。我测试了一些其他场景的星座机器人,并对其进行了相应的训练。下面是其中一个与我们在本章前面所做的有点不同的例子。

让我们运行第一个测试:

乐观是从失败走向成功的动力。甘尼萨说,你今天会非常乐观——对你的工作、未来和一切能让你成功的东西。在处理日常工作时,你也会非常小心,会利用每一个能让你离目标更近一步的机会。决心和好运是你实现梦想所需要的一切;今天你将两者兼得。

正如你在用户和聊天机器人之间的对话中看到的,我们测试了机器人是否处理用户自己提供星座运势同时询问当天星座运势的场景。在这种情况下,机器人做得很好,并最终要求订阅,并根据用户的响应,采取适当的行动。

您应该对机器人的对话进行健全性测试,以确定正常流是否正常工作。

我还测试了我们在stories.md文件中提到的故事,当用户直接要求订阅时,它也工作正常。

现在是第二个测试:

我还会添加一些新的故事,这样机器人就可以完美地工作了。但是现在我们有了一个完全正常工作的机器人。在github的第二个版本中,你还会发现这个机器人正在纠正星座的拼写错误,根据用户的出生日期检索星座,说再见信息,等等。我强烈建议您检查代码,看看它是如何完成的,并提供您的反馈。但在此之前,考虑一下将如何完成以及变化将会发生在哪里。我们故意没有在本章中提到其他用例的代码,这样当你集中精力学习交易技巧时,它不会变得繁琐。

您可以从我们的githubrepo下载最新的Python代码和Jupyter笔记本,并尝试安装正确的包来运行它。你会发现在本章讨论的代码中处理了更多的用例。

在这一章中,我们了解了Rasa-NLU,以及为什么Rasa-NLU比市场上任何其他开源工具都好。我们学习了如何在管道配置中使用tensorflow、sklearn和keras来配置管道。

我们学会了在本地系统上从头开始创建一切,而不依赖于任何需要您使用其API的服务,如Dialogflow、wit.ai等。

我们还学习了如何创建故事,以及如何训练NLU模型和对话模型,并使用RasaCore通过使用最酷的功能交互式学习进行训练来构建机器人。在开源工具如rasa-nlu-trainer的帮助下,我们也对如何轻松地创建训练数据并轻松地进行注释有了一个相当好的想法。我希望这一章对你来说比其他任何一章都更具互动性。如果你没有成就感,那就为下一章做好准备,在那里我们将把它真实地呈现给我们的观众,并向世界展示机器人的能力。我们将学习使用我们自己的网络服务器把本章的聊天机器人集成到各种平台上,比如脸书和Slack。

继续训练你的机器人,直到下一章我们把它投入使用。

下一章见。**

在这一章中,我们将学习如何在网络上部署聊天机器人。人们可以通过各种方式和渠道向外界部署或公开他们的chatbotweb应用程序。举个例子,我们可以在脸书和Slack上用NLU和对话模型来展示我们的星座机器人,因为他们已经为你提供了一个用户界面。您可能还想拥有自己的web应用程序,它完全运行在您自己的服务器上。在本章末尾,我们还将探索如何使用我们自己的用户界面在我们自己的服务器上部署聊天机器人。

第一步是创建一个你在第四章中创建的现有聊天机器人的副本,并制作一个新的副本,以便你有一个备份。因为,我们将通过添加一些新代码来做一些更改,所以让我们将两个项目分开。

于是,我创建了一个名为“第五章的新文件夹,并将我的horoscope_bot文件夹粘贴在那里。所以,现在我所有的模型文件、数据集和代码文件都被复制了,我可以直接使用它们进行部署。

Rasa提供了一种在一个地方管理您所有凭据的方法。你可能有一个单一的模型,但你可能希望它被部署在各种其他平台上,如脸书,Slack,Telegram等。所有这些第三方平台都需要一些凭据才能在连接时使用。这些凭证存储在名为credentials.yml的YAML文件中。

让我们在我们的项目目录horoscope_bot文件夹中创建一个名为credentials.ymlfile的文件,并在那里添加我们的脸书凭证。如果你不知道如何得到它,那么现在就创建这个文件,在本章的下一节你可以找到得到脸书证书的步骤。

credentials.yml的内容将如下所示:

facebook:verify:"horoscope-bot"secret:"bfe5a34a8903e745e32asd18"page-access-token:"HPaCAbJJ1JmQ7qDedQKdjEAAbO4iJKr7H9nx4rEBAAuFk4Q3gPQcNT0wtD"这些凭据是假凭据;令牌或密码的长度以及字符类型可能因您的脸书应用而异。

如果你正在做一个大项目,在这个项目中,你要在各种平台上集成你的聊天机器人,并且你想让这个项目更容易维护,那么最好使用credentials.yml。如果你是一家企业,并试图建立一个可以在各种平台上工作的机器人,如脸书、Slack、Twitter、Telegram或你自己的网站,我强烈建议你维护一个credentials.yml。在这种情况下,管理密钥和秘密变得更加容易。

管理应用程序级密钥的一个好方法是将密钥存储为环境变量,并编写代码从操作系统环境本身读取密钥值或任何其他敏感信息。记住,在代码中保存任何类型的键都不是一个好主意。

您也可以创建一个点(。)env文件,并从该文件中读取密钥,在您的代码存储库中没有对该文件进行跟踪。

为了简单起见,我们将在部署的独立脚本中使用访问密钥和秘密密钥。我们将使它变得简单易懂,这样你首先能够构建机器人,然后你可以尝试扩展它,最重要的是你可以考虑安全级别的问题。

如果您需要在多个平台上部署您的bot,并希望使用credentials.yml来维护不同的凭证,那么您可以通过传递一个额外的参数来使用它。例如,在运行rasacore时使用上面名为credentials.yml的凭证文件,可以使用下面的命令。

python-mrasa_core.run-dmodels/dialogue-umodels/nlu/current--port5002--credentialscredentials.yml对于更大的企业级聊天机器人开发来说,知道这一点很好,但是正如所讨论的,我们将在即将到来的示例中直接在我们的脚本中使用凭证。

我们将按照一系列步骤一步一步地成功地将我们的聊天机器人部署为云中的web服务。一旦我们成功地做到了这一点,将它与不同的平台如Slack、Telegram等整合起来就容易多了。那么,我们开始吧。

让我们开始吧:

在Heroku上注册,创建一个应用程序,并将其命名为actions,因为这将是我们的actions服务器应用程序。看看图5-1中的截图,你可以给你的动作服务器一个唯一的名字,这个名字应该在Heroku上可以找到。一旦该名称可用,您就可以单击Createapp按钮来创建actions服务器应用程序。

如果你的名字不可用,你可以随意给它取任何你想要的名字,但是要尽量取一些有意义的名字。

图5-1

在Heroku上创建名为星座机器人1212-动作的动作服务器应用程序

如果您在macOS上,请使用以下命令:

brewinstallheroku/brew/heroku在脸书创建和设置应用程序为了能够在脸书上部署我们的聊天机器人,首先我们需要有脸书应用程序的凭证。为了获得脸书证书,我们需要设置一个脸书应用程序和一个页面,就像我们在第三章中所做的那样。

在这一步中,我们将使用我们的actionsHeroku应用程序作为Rasaaction的服务器。我们需要两个不同的应用程序,因为我们不能在一个Heroku应用程序中运行两个web应用程序。转到命令行,按照指示从项目目录中执行以下命令。

在最后一个命令之后,Heroku将按照requirements.txt文件安装我们需要的所有包。如果您的应用程序成功部署,您应该会收到类似以下内容的日志:

图5-8

正在验证操作服务器端点

在这一步中,我们将遵循一些类似于我们刚才所做的步骤和命令,但这是一个我们将创建的新应用程序,它将成为我们用于对话管理的主要应用程序。所以,我们开始吧。首先回到主项目目录(即,在占星_bot中)并创建一个文件名(Procfile)并向其中添加以下内容:

web:python-mspacydownloaden&&pythonfacebook.py为FacebookMessenger聊天机器人创建独立脚本在同一个项目目录下创建一个文件名facebook.py。Python文件的内容应该如下所示:

创建一个新的requirements.txt文件,并添加这个项目所需的所有包及其版本。我的requirements.txt看起来是这样的;对于您的项目,需求可能会有所不同,但是如果您遵循本章中的同一个bot示例,这些需求应该没问题。

rasa-core==0.11.1rasa-core-sdk==0.11.0rasa-nlu==0.13.2gunicorn==19.9.0requests==2.18.4spacy==2.0.11sklearn-crfsuite==0.3.6在服务器上安装我们的软件包。

现在,让我们像之前一样在Heroku中再次创建一个新的应用程序。转到Heroku仪表盘,创建一个新的应用程序,如图5-9所示。

图5-9

在Heroku中创建对话管理应用程序

创建应用程序后,现在可以转到项目根目录,从项目文件夹中的命令行运行以下命令集:

$gitinit$herokugit:remote-a$herokubuildpacks:setheroku/python$herokuconfig:setPORT=5004$gitadd.$gitcommit-am"deploymybot"$gitpushherokumaster如果您在部署后得到一个运行时错误,它可能如下所示

ValueError:您可能试图用Python3读取用Python2生成的joblibpickle。joblib不支持此功能。

如果您使用的是Python2.x版本,这种情况就会发生。Heroku默认使用Python3.x版本。因此,如果您想使用Python2.x,您需要执行以下步骤来解决上述错误。把Python3.6改成Python-2.7.15。来做这个。

在项目的根应用程序目录下创建一个文件runtime.txt。打开runtime.txt,添加下面一行python-2.7.15,然后保存。Heroku将只使用前面提到的Python版本来构建您的项目。

一旦成功完成部署,您将看到Heroku给出的一个url,上面写着应用程序已部署到。

为了验证我们的对话管理应用是否成功部署在Heroku上,我们将执行以下步骤。

现在让我们回到我们的脸书应用程序配置。我们将回到我们在步骤3中停止的地方,添加我们的回调URL。确保检查订阅字段中的消息。查看图5-10以供参考。

图5-10

FacebookMessengerwebhooks配置

点击“验证并保存”脸书将使用上述url匹配验证令牌,即服务器,或者说我们的应用程序将只响应具有正确验证令牌的请求。一旦验证令牌匹配,我们的应用程序的webhook订阅将被激活。

接下来,在页面的Webhooks部分下,选择一个页面,您可以将webhook订阅到该页面事件。点击订阅(见图5-11)。

图5-11

为webhook订阅脸书页面事件

全部完成!是时候在脸书测试我们的星座机器人了。

在正常的软件开发场景中,人们构建软件,测试软件,然后部署并进行PDV(部署后验证)。我们也将做一些类似的事情,在FacebookMessenger上成功部署后,我们将为我们的聊天机器人做一个PDV。这很重要,因为正如您所了解的,聊天机器人有一部分需要连接到动作服务器,以响应用户的一些意图请求。PDV就像是一个健全性测试,以查看应用程序的健康状况总体良好。如果您正在构建一个使用10到15个不同供应商的API的bot,那么必须检查您的bot访问动作服务器并使用API将数据返回给用户的所有场景。

所以,打开你的messenger应用程序或电脑浏览器中的脸书,搜索你的机器人开始说话。

数字5-12.1到5-12.3显示了我的星座机器人做了什么并告诉我。

图5-12.3

horoscope_botfacebook

图5-12.2

图5-12.1

在本节中,我们将把我们的聊天机器人部署到Slack。Slack是一个团队协作工具,在开发人员和企业中广受欢迎。如果你不是一个社交媒体人,那么你可能需要Slack的帮助来使用界面与你的聊天机器人交谈。因此,让我们开始构建我们的第一个内部Slack聊天机器人。

为了将我们的星座聊天机器人部署到slack,我们将编写一个独立的脚本,就像我们在脸书的例子中所做的那样。

在项目目录中创建一个名为slack.py的新文件。文件slack.py的内容如下所示:

如你所见,我们需要添加一个slack_token和slack_channel到我们的脚本中。由于我们必须在脸书的开发者平台上创建一个脸书应用程序,同样我们也必须在Slack上创建一个应用程序。

让我们一步一步来:

你会在“添加特性和功能”下找到带有绿色勾号的“机器人和权限”选项卡,这意味着我们的机器人和应用程序集成良好。这是一个迹象,表明我们目前做得很好。

在这一步中,我们不会创建任何新的Procfile,因为我们使用的是相同的代码库。我们将对现有的Procfile进行如下修改,使其适用于我们的slackbot。因此,我们只需将脚本文件的名称从facebook.py更改为slack.py,这样Heroku就可以使用给定的文件来启动应用程序。

web:python-mspacydownloaden&&pythonslack.pySlackBot在Heroku的最终部署为了最终将我们的新Slackbot部署到Heroku,我们将从命令行运行一组类似的Heroku命令来部署我们的应用程序。

$gitinit$herokugit:remote-a$gitadd.$gitcommit-am"deploymybot"$gitpushherokumaster订阅时差事件现在,点击“事件订阅选项卡,通过切换屏幕上的按钮激活事件订阅功能。为Slack输入Heroku应用程序的webhookurl。

如果您的应用程序使用修改后的Procfile正确地部署在Heroku上,那么您的Slack的webhookurl将是app_url+/webhooks/slack/webhook,如下所示:

在Slack向上述URL发送一个带有挑战参数的HTTPPOST请求后,您将看到一个经过验证的勾号,我们的端点必须用挑战值进行响应。这类似于我们在构建脸书聊天机器人的秘密令牌时讨论的内容。查看图5-16了解更多信息。

图5-16

为您的机器人激活事件订阅

在这一步中,我们只需向下滚动事件订阅页面,转到“订阅Bot事件”部分,然后单击“添加Bot用户事件”参考图5-17了解导航位置。

图5-17

订阅机器人事件

现在,单击保存更改,您就完成了。是时候测试我们的Slack聊天机器人了,就像我们在上一节为脸书做的那样。

让我们转到我们用来创建应用程序的工作区,在左侧的应用程序下,您会找到您的机器人。试着和它说话,看看它做得好不好。我的机器人做得很好,给了我今天的星座运势,读起来很不错。如果你到现在还不能来,那么检查图5-18看看我的Slack机器人如何响应。

图5-18

测试Slack聊天机器人

所以,伙计们,我们完成了我们的松弛机器人。在下一节中,我们将把我们的机器人部署到我们自己的UI中。构建你自己的UI可能需要一些前端技能,但是不要担心——我们对此有计划。

这个标题听起来很酷,不是吗?到目前为止,我们一直使用脸书或Slack在网上部署聊天机器人,或者我们可以使用Telegram等。,但现在是我们自己部署一切的时候了—我们自己的服务器、我们自己的数据,以及使用我们自己的用户界面的我们自己的配置模型。如果你是一个组织或一个崭露头角的企业家,你可能会在脸书、推特或Slack上有你的机器人创意,但你总是希望它也能在你自己的网站上工作,这样你的品牌价值就会随着用户群的增加而越来越大。

在这一节中,我们将使用我们迄今为止的所有辛勤工作,最终构建一个聊天机器人,它具有完整的功能,并且独立于任何第三方API调用或工具,如Dialogflow、wit.ai、Watson等。你将拥有世界上所有的控制权,以你想要的方式调整你的聊天机器人,最重要的是,以你想要的方式轻松地扩展到数百万人。

那么,我们开始吧。

第一步是确保我们在前面章节中部署的两个应用程序已经启动并运行。您已经知道如何进行基本的健全性检查。要在任何平台上使用chatbot模型,您始终需要运行您的对话管理器应用程序和操作应用程序。

现在,在我们创建facebook.py和slack.py的同一个项目目录中,我们将创建一个名为myown_chatbot.py的新文件。之前创建的脚本,如facebook.py和slack.py,是我们创建的独立脚本,这样我们就可以在命令中告诉Heroku运行哪个脚本来启动应用程序。现在,我们正在创建自己的脚本,它将通过RESTAPIs公开用户和聊天机器人之间的请求/响应。

部署你自己的聊天机器人有两个部分。在第一部分中,我们将编写一个脚本来创建一个定制通道,并将其作为RESTAPIs进行部署。在第二部分,我们需要自己的用户界面,因为到目前为止,我们一直在使用脸书和Slack的聊天屏幕进行对话。

这个脚本类似于我们到目前为止所学习和编写的内容,但是它需要我们覆盖rasa_core的一些现有方法,以便我们可以为API身份验证定义自己的规则。我在下面的代码中完成了令牌验证的基本字符串检查。对于生产级系统,这是不建议的,所以如果您正在为更大的系统构建聊天机器人,请确保小心编写该部分。

创建一个名为myown_chatbot.py的新文件,并向其中添加以下内容:

到目前为止,您一定非常熟悉为Heroku部署创建Procfiles。我们将再次使用现有的Procfile,并在那里进行修改,以将基于API的chatbot部署到web上。在创建现有Procfile的备份后,可以随意创建新的procfile。

以下是我的Procfile内容的样子:

web:python-mspacydownloaden&&pythonmyown_chatbot.py完成后,只需执行我们在部署FacebookMessenger和SlackBot时已经学习过的下一组命令。

在获得成功部署的消息后,让我们测试一下我们的chatbotAPIs是否工作正常。为了快速进行健全性测试,请点击以下url:

+/webhooks/rasa/举例:

在浏览器中打开这个url应该会得到如下的响应。如果它给你一个“ok”的状态,那么你就可以开始了——放松,坐下来,调试。

{"status":"ok"}有时,仅仅是这种验证可能还不够,所以让我们通过尝试检查聊天机器人是否正在识别意图并基于此给出响应来测试它。

我将使用POSTMAN工具(POSTMAN是一个非常好的基于GUI的工具来进行API测试)。你可以使用任何你觉得舒服的工具。我们只是要测试我们的聊天机器人应该理解和响应的意图之一。我测试了问候的意图,它工作得非常好。机器人返回了预期的响应,如图5-19所示。

图5-19

在POSTMAN中测试聊天机器人API

正如我们之前讨论的,作为第二步的一部分,我们需要有自己的UI,为聊天机器人和用户之间的对话提供一个用户友好的场所。如果你是一个前端开发人员,或者你的团队中有一个前端开发人员,你可以很容易地给出我们构建到这一点的chatbotAPIs,前端团队应该可以很容易地将这与他们的chatbotUI集成。他们可以利用常规的HTTP调用来使用这些API。Websockets是一种更好的聊天机器人方式,但这不在本书的解释范围之内。

如果你不熟悉HTML/CSS/Javascript之类的前端技术,那么我确实推荐ProHTML5搭配CSS、Javascript、多媒体(Apress,2017)。

为了我们的读者——或者我应该说是学习者——的方便,我们创建了一个聊天机器人和用户对话所需的基本UI。你可以在github或Apress的网站上找到完整的工作代码。我将告诉你使它为你的机器人工作所需要的配置。

一旦你下载了本章的代码,你会在主文件夹中找到一个名为my_own_chatbot的文件夹。进入这个文件夹,进入assets->js->script.js文件。

将下面一行javascript代码更改为您自己的端点url。如果你的应用程序名称不同,那么下面的网址将是不同的。使用您自己的url和javascript代码中的标记,如下所示。

将您的myown_chatbot.py更改为下面的,然后我们将讨论所做的更改。

保存文件,并使用以下命令将更改再次部署到我们的Heroku应用程序:

在浏览器中打开以下url,我们将在其中看到我们的自定义聊天机器人UI:

图5-20.1和5-20.2显示了我自己的聊天机器人在对话过程中的样子。

图5-20.2

在你自己的网站上定制聊天机器人

图5-20.1

使用Heroku的自定义域名功能,人们可以轻松地将同一个应用程序指向自己网站的名称,如www.example.com。当你觉得你的聊天机器人足够好,可以向全世界公开,无论是盈利还是非盈利,就这么做吧。

所以,这就是所有的乡亲!这就是使用自然语言处理和机器学习用Python构建聊天机器人的方式。我希望这一章和前几章对你有所帮助,你可以学习学习和构建聊天机器人的实用方法。

我期待着收到你的来信,并且很想知道在看完这本书之后你制作了什么样的聊天机器人。如果您在任何概念、代码执行或部署方面遇到困难,我很乐意随时为您提供帮助。

THE END
1.首页曲线人生八字算命人生曲线首页,曲线人生网是以图形化直观明了的方式将人一生的运气表示出来,结合现代人生测试技术智商、情商、财商、心理、职业等,使人们真正地了解自己,把握自己,抓住机遇,趋利避害,让人生更美好!http://www.quxian123.net/
2.Luka大叔星座馆一周健康运势曲线图 最近身体的免疫力提高,健康运势有上升,但还是要规律作息哦~本命星盘免费解读!每个人不止有一个星座~ 认识自我 破解格局 仅供娱乐 广告x陕ICP备19010446号-23X2024/12/07星期六(Sat.) 天秤座青色60 水星正在逆行 自我·潜力·寸有所长幸运总是倾向那些忠于自己长处的人,找到身上的优点,将其http://pro.luka.xingtazhuman.com/pages/index/index?cid=1&tab=2
3.准生肖预知2025运势吉凶 运势性格配对测测 2024-12-11 · 星期三农历:二零二四年冬月十一今日明日本周本月本年“ 心情低落的一天 ”3.4综合运势事业爱情健康财运牛贵人生肖褐色幸运颜色10、35幸运数字东北桃花方位东北喜神方位正北财神方位沐浴/ 理发 / 除虫 / 打猎 / 美甲浴足祈福/ 冠带 / 结婚 / 收养 / 搬家八字https://zsx.linggx365.cn/index?tab_type=luck&zodiac_id=0&channel=sw_whxl_00001
4.十年运势曲线(十年运程车免费)免费紫微运势曲线算命,紫微斗数运势曲线图请输入您的生日性别男女出生年出生月出生日运势曲线图(大限变化图)十年运势曲线图(流年变化图)一年运势曲线。 1、八字人生运势起伏图 免费测八字运势旺衰图八字免费测运势用八字看一生,一生运势高低曲线图一生的运势性格分析1月9日出生的人很强硬、很难对付。他们对自己或是对https://www.16757.com/ysh/yunshi/3751.html
5.星盘免费在线占星命盘查询分析新浪星座新浪星盘,好用的免费在线占星命盘,提供本命盘,双人盘,推运盘,生理曲线,双人比较盘,组合中点盘,时空中点盘,三限盘,次限盘,太阳弧,运行盘等全面的星盘查询分析。http://product.astro.sina.com.cn/swe/
6.天蝎座这一周的运势图曲线天蝎座这一周的运势图曲线,解读天蝎座这一周的运势图曲线知识,想了解学习天蝎座这一周的运势图曲线,请参与天蝎座这一周的运势图曲线话题讨论。http://yi.fsrdz.com/explore/98249
7.日式占卜:手相中隐藏的性格与运势感情线智慧线是标准的倾斜(平缓的曲线) 客観的でバランスの取れた考えができる。失敗しそうなことは回避するため、冒険や挑戦は少ない。平穏さを好み、不正やハラスメントを指摘できず見過ごしがち。 比较客观,能权衡各方面来思考。为了避免发生失败,很少进行冒险和挑战。喜欢稳定,不会指出不正行为或扰乱行为http://m.hujiang.com/jp/p754839/
8.八字怎么看一生的运势,八字怎么看运势提起八字人生运势曲线图,大家都知道,有人问怎样从八字看出自己的一生运势,另外,还有人想问易奇八字免费测算运程曲线图黑点代表的年份是什么意思?你知道这是怎么回事?其实从这个时辰出生的人的八字,人生运势的具体分析,下面就一起来看看怎样从八字看出自己的一生运势,希望能够帮助到大家! http://www.jiadechem.com/yxarticle/520n15.html
9.运势高低曲线图在线测一生大运运势图关注 本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报。 打开APP,阅读全文并永久保存 查看更多类似文章 类似文章 四拳八势图说 使用一分钟K线轻松把握高低点 学习K线在高低位有属不同 《60分钟曲线图》 涨停股后的表现 怎样通过一根线知道明日的高低点 https://www.360doc.cn/article/58393483_885933926.html
10.紫微看运势现在,有很多在线平台提供紫微运势曲线的免费查询服务。用户只需要输入自己的出生日期和时间,就可以得到一份详细的紫微运势曲线图。这份曲线图会显示出你在不同年份的运势变化趋势,包括事业、财运、健康等方面的情况。还有不少专业的紫微斗数网站或应用,提供了更加详细和个性化的运势分析服务,但可能需要支付一定的费用。 http://semyishu.com/ziweidoushu/192308473.html
11.十年大运免费查询,免费八字详批流年大运2025运势 八字合婚 命主性别: 男 女 出生日期: 出生时辰: 付费精批 八字排盘 五行查询 测喜用神 测身强身弱 测八字阴阳 测正缘 财运测试 称骨算命 子平排盘 大运排盘 流年排盘 八字命盘 免费测试十年大运 十年大运是什么意思? 八字命理学把十年分成一大运、一大运分成十流年,十年大运是https://m.k366.com/cbz/shiniandayun.htm
12.星座运势今日算命2024年运势免费Luka大叔星座馆,一周健康运势曲线图也许是因为最近熬夜太多口腔会有上火现象出现牙疼或喉咙痛要调整作息多休息哦本命星盘免费解读!每个人不止有一个星座认识自我破解格局仅供娱乐。新浪星座运势每日每日星座运势查询星座运势吧,星座运势查询每日星座运势新浪星座运势今日运势蝎座今日运势狮子座今日运势双鱼座今日运势双子座今日https://www.wansudu.com/meida/yunshi/3677.html
13.八字十二宫免费算(八字免费算八字)八字己丑年十一月初六日亥时。一生运势高低起伏图。 属牛[生肖以农历立春节气为准] 乾命(西四命) 八字排盘 比印日元杀免费算一生财运运势图。 乾造己丙己乙(日空午、未) 丑子丑亥免费八字一生运势起伏图。 干癸辛己癸癸辛己甲壬运势曲线图测算。 https://www.ynysb.com/news/13993.html
14.幸运芝麻好运密码八字预测人生曲线本网站是最直观、超准的算命网站,测算结果全部是图形化曲线表示,简单明了,一目了然。全方位展示了人生的各种运气和人生命运。基础运、财运、官运、桃花运以及各种改运尽在其中。运气曲线,人生指南。https://www.quxian123.com/
15.八字流年运程测算免费流年运势详批汉程网八字流年运程,免费分析最近几年流年运势详批、犯太岁分析、流年十二宫神煞、流年意外/官非/是非/破财等流年运程测算!https://life.httpcn.com/baziyear.asp
16.属鼠今年的运气运势,属鼠72年出生今天财运如何内容导航:属鼠今年运势属鼠2024年的每月运势?2024年属鼠人的全年运势?今年属鼠的运气如何20241977属蛇的和1972年属鼠的男人婚姻财运怎样?83年属猪和72年属鼠财运两口子Q1:属鼠今年运势属鼠今年运势吉凶参半,有很多期待,也需要不断的努力。对于2024年属鼠人来说整体运势排名:第11名,会有吉星三台与将星的庇佑,两http://www.finaint.com/swift_code/sabrrum3.html
17.流年运程免费测算查询流年运程免费测算查询 关于流年运程 流年运程也被称为每年运势,人的每年的运势都是在不停的变动的,流年代表以每年农历正月初一为起始来计算,到除夕日为结束。到了第二年正月初一又会是一个新的流年。紫微排盘中,流年会依照十二地支的宫位顺序来发生轮转(十二宫位即子宫、丑宫、寅宫、卯宫、辰宫、巳宫、午宫、https://services.shen88.cn/ziweidoushu/liunian.html
18.八字运程2024生辰八字五行运势查询八字运程测试,通过周易八字算命的理论,查询您的生辰八字五行,并免费测试您的生辰八字命理、2024年日柱运势、生辰八字运程详批十年大运https://www.buyiju.com/yuncheng/
19.免费算命在线算命今日运程明日运程本周运程本月运程今年金牛座 04/20 - 05/20 爱情运势: 综合运势: 工作状况: 理财投资: 健康指数: 70% 商谈指数: 83% 幸运数字: 5 速配星座: 射手座 工作与人际关系上都因跟你搭档的人能言善道你也间接受惠喔。 今天颇有沾别人光的好运呢,跟那些口才溜的人搭配颇有互补作用哩。像是与朋友长时间的电话聊天也是很好的气氛转http://www.168luck.com/sm/astro/xzyc.asp?type=nextday&xz=2
20.生肖算命免费生辰八字自动算命生肖算命免费2024 健康运气:注意身体状况、潜在疾病和健康建议。 运势曲线:展示未来一段时间整体运势起伏。 破解吉凶,趋吉避凶 免费生肖算命可以帮助人们大致了解自己的性格特征和运势。通过了解好运和坏运,我们可以积极寻求好运,避免坏运气,抓住机会,规避风险。例如: http://hn21z.com/view/263800
21.1991年属羊2023年全年运势运势及运程详解八字运程算命人的运势有起有落,人们渴望的好运气也只是让这条曲线平稳一些,不要出现强烈的波动。那么,1991年属羊2023年全年运势 运势及运程详解如下: 进入2023年,对于91年属羊人来说,他们已经32岁了。在合太岁的年份中,一定要牢牢把握住机遇,否则一旦错失好机会,会让自己感到追悔莫及。属羊人应该让自己变得勇敢大胆一些,可以https://www.bgyfdcgw.com/bzsm/bzyc/1674.html
22.紫微曲线免费算命理想股票技术论坛紫微曲线免费算命,通过专业的命理分析,为你提供个性化的运势预测。了解你的命运走势、事业发展、财富状况、感情婚姻等方面的信息,助你做出更好的人生规划。 ,理想股票技术论坛https://www.55188.com/tag-8435180.html