上手实操!使用Facebook Messenger构建聊天机器人,只用了不到60分钟

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"italic"},{"type":"size","attrs":{"size":10}},{"type":"strong"}],"text":"本文最初发表于 Towards Data Science 博客,经原作者 Mandy Gu 授权,InfoQ 中文站翻译并分享。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/rasa.com\/?fileGuid=EoE2UeNK8n0kAwJZ","title":"","type":null},"content":[{"type":"text","text":"Rasa"}]},{"type":"text","text":"是一种开源的对话式人工智能框架,它使用机器学习来构建聊天机器人和人工智能助手。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"今天,我将向大家展示如何使用 Rasa 构建自己的简单聊天机器人,并将其作为机器人部署到 Facebook messenger 上,一小时之内就可以完成。而你所需要的,只是一些简单的 Python 编程和可用的 Internet 连接。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"完整的代码可以在我的"},{"type":"link","attrs":{"href":"https:\/\/github.com\/happilyeverafter95\/demo-bot?fileGuid=EoE2UeNK8n0kAwJZ","title":"","type":null},"content":[{"type":"text","text":"GitHub "}]},{"type":"text","marks":[{"type":"strong"}],"text":"仓库找到。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我的代码是在 Python 3.7 中开发和测试的。Rasa 目前只支持 Python 3.8 以下的版本 ("},{"type":"link","attrs":{"href":"https:\/\/rasa.com\/docs\/rasa\/installation\/?fileGuid=EoE2UeNK8n0kAwJZ","title":"","type":null},"content":[{"type":"text","text":"更新"}]},{"type":"text","text":"请看这里:"},{"type":"link","attrs":{"href":"https:\/\/rasa.com\/docs\/rasa\/installation\/?fileGuid=EoE2UeNK8n0kAwJZ","title":"","type":null},"content":[{"type":"text","text":"https:\/\/rasa.com\/docs\/rasa\/installation\/"}]},{"type":"text","text":")。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"要构建的机器人非常简单,无需深入研究任何高级自然语言处理应用。不过,Rasa 确实提供了对更复杂应用的充分支持。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"为了了解更多关于自然语言处理的知识,我推荐 DeepLearning.AI 开设的这门 Coursera 课程《"},{"type":"link","attrs":{"href":"https:\/\/www.coursera.org\/learn\/sequence-models-in-nlp?fileGuid=EoE2UeNK8n0kAwJZ","title":"","type":null},"content":[{"type":"text","text":"基于序列模型的自然语言处理"}]},{"type":"text","text":"》("},{"type":"text","marks":[{"type":"italic"}],"text":"Natural Language Processing with Sequence Models"},{"type":"text","text":")。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"让我们开始吧"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"“克隆”我的"},{"type":"link","attrs":{"href":"https:\/\/github.com\/happilyeverafter95\/demo-bot?fileGuid=EoE2UeNK8n0kAwJZ","title":"","type":null},"content":[{"type":"text","text":"仓库"}]},{"type":"text","text":"获取完整的代码。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/resource\/image\/e5\/ed\/e58e42e93fae2ae8882e7e1d87e451ed.jpg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"依赖关系"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"确保所有的依赖关系都已安装。我们的简单机器人只需要两个库:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"bash"},"content":[{"type":"text","text":"rasa==2.2.0\nspacy==2.2.4\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果已经“克隆”了我的仓库,就可以运行"},{"type":"codeinline","content":[{"type":"text","text":"pip install -r requirements.txt"}]},{"type":"text","text":"从根目录来安装这两个库。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"spacy 语言模型需要在单独的步骤中安装。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"bash"},"content":[{"type":"text","text":"python3 -m spacy download en_core_web_md\npython3 -m spacy link en_core_web_md en\n"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"仓库攻略"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在展示如何训练和部署助手之前,先通过每个组件来了解它们是如何结合在一起的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这些文件大部分可以通过运行"},{"type":"codeinline","content":[{"type":"text","text":"rasa init"}]},{"type":"text","text":"来生成,"},{"type":"codeinline","content":[{"type":"text","text":"rasa init"}]},{"type":"text","text":"会创建一个带有训练数据、动作和配置文件示例的新项目。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首先来看一下配置文件。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"配置文件"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"endpoints.yml"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这是助手的所有端点的位置。为了支持"},{"type":"link","attrs":{"href":"https:\/\/rasa.com\/docs\/rasa\/next\/custom-actions?fileGuid=EoE2UeNK8n0kAwJZ","title":"","type":null},"content":[{"type":"text","text":"自定义动作"}]},{"type":"text","text":"(基本就是你可以编写用于调用其他 API、查询数据库或访问你构建的其他服务的自定义代码),我们需要创建动作服务器。要做到这一点,请在这个文件中包含"},{"type":"codeinline","content":[{"type":"text","text":"action_endpoint"}]},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其他端点也可以在这里定义,如,使用 Kafka 发送事件,或将对话存储在 Redis 中而不是内存中。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这就是 endpoints 文件的样子:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"yaml"},"content":[{"type":"text","text":"action_endpoint:\n url: \"http:\/\/localhost:5055\/webhook\"\n"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"config.yml"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"配置文件定义了如何训练模型,这是你可以发挥创造力的地方。第一行用于指定聊天机器人的语言。在这里,它将是英语:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"yaml"},"content":[{"type":"text","text":"language: \"en\"\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下一个组件配置自然语言理解管道。我们使用的是 Rasa 推荐的“sensible”启动管道之一。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"yaml"},"content":[{"type":"text","text":"pipeline: \n - name: SpacyNLP\n - name: SpacyTokenizer\n - name: SpacyFeaturizer\n...\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接下来是"},{"type":"codeinline","content":[{"type":"text","text":"policies"}]},{"type":"text","text":"。这些是 Rasa 将遵循的响应用户信息的策略。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"yaml"},"content":[{"type":"text","text":"policies: \n - name: MemoizationPolicy\n - name: RulePolicy\n core_fallback_threshold: 0.3\n core_fallback_action_name: action_default_fallback \n...`\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"MemoizationPolicy 会记住训练故事中的最后 X 个事件。可通过将"},{"type":"codeinline","content":[{"type":"text","text":"max_history"}]},{"type":"text","text":"添加到策略配置来指定 X。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"RulePolicy 利用我们为机器人编写的硬性规则(稍后会介绍)来生成响应。即使 RulePolicy 被指定在第二位,它也会优先于其他策略。因为 RulePolicy 在缺省情况下具有最高优先级:也可以配置这些优先级。根据策略配置,机器人首先要检查适用的规则,否则就会转向训练故事。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们的策略还配置了默认的回退机制。当一个动作置信度分数低于"},{"type":"codeinline","content":[{"type":"text","text":"core_fallback_threshold"}]},{"type":"text","text":"0.3 时,它将发送一个名为"},{"type":"codeinline","content":[{"type":"text","text":"utter_default"}]},{"type":"text","text":"的预定义响应,并恢复到触发回退之前的状态。这在用户说一些完全没有意义的内容时是很有用的。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"credentials.yml"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果代码托管在像 GitHub 这样的地方,你应该在发布该文件前仔细考虑。需要使用此文件进行身份验证,我们会用它与 Facebook Messenger 机器人相连。现在,我暂时隐去了密码,但是稍后会介绍如何从 Facebook 生成此文件。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"注意"},{"type":"text","text":":我的 GitHub 仓库中并没有包含此文件。你需要创建这个文件,然后用稍后生成的令牌对其进行填充。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"yaml"},"content":[{"type":"text","text":"facebook:\n verify: \"[this is your custom verification token]\"\n secret: \"[this is generated from facebook]\"\n page-access-token: \"[this is generated from facebook]\"\n"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"domain.yml"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"来自 RASA 的官方"},{"type":"link","attrs":{"href":"https:\/\/rasa.com\/docs\/rasa\/domain\/?fileGuid=EoE2UeNK8n0kAwJZ","title":"","type":null},"content":[{"type":"text","text":"文档"}]},{"type":"text","text":":"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"领域定义了助手操作的范围。它指定了你的机器人应该知道的意图、实体、槽、响应、形式和动作。它还定义了对话会话的配置。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"domain.yml 文件被分解为意图、实体、槽、响应、动作和会话配置。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"训练机器人识别定义的意图,并根据检测到的意图采取不同的行为。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果在管道中指定了一个实体提取器,它将提取这个文件中定义的所有实体;实体可以用来进一步控制对话流程。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"槽是机器人将信息存储到内存中的键值对;槽可以在对话期间的任何时候被设置、重置和检索。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"响应是预先定义的响应模板,用于机器人发送消息;当机器人达到该状态时,默认回退将始终发送与"},{"type":"codeinline","content":[{"type":"text","text":"utter_default"}]},{"type":"text","text":"相关联的消息。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"动作包括任何已定义的自定义动作。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在会话配置中,可以定义会话过期时间,以及是否应该将槽引入到新的会话中。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"训练数据"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"将训练数据分成三个文件夹:nlu、rules 和 stories。在 nlu 文件夹中,定义了意图和实体。在 rules 文件夹中,定义了通过 RulePolicy 进行操作的规则。stories 文件夹中包含了模拟对话,这些对话被用作额外的训练数据,以了解如何管理对话。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"nlu.yml"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 NLU 设置中,定义了一些非常基本的意图。下面是“greet”意图的一个例子,它使用了以下的训练数据:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"yaml"},"content":[{"type":"text","text":"nlu:\n - intent: greet \n examples: | \n - hey \n - hello \n - hiya\n...\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/rasa.com\/docs\/rasa\/nlu-training-data\/?fileGuid=EoE2UeNK8n0kAwJZ","title":"","type":null},"content":[{"type":"text","text":"官方文档"}]},{"type":"text","text":"更详细地介绍了如何改进 NLU 组件,例如加入实体、同义词和查找表。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"rules.yml"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"rules 定义了机器人应该始终遵循的小型对话模式。RulePolicy 利用这些 rules 来管理对话流程。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这里定义了一个简单的规则“always greet the user”。当机器人遇到“greet”意图时(它根据上面提供的数据学习识别问候意图),它会用自定义动作"},{"type":"codeinline","content":[{"type":"text","text":"action_greet"}]},{"type":"text","text":"来跟进。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"yaml"},"content":[{"type":"text","text":"- rule: always greet the user \n steps: \n - intent: greet \n - action: action_greet\n"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"stories.yml"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"stories 是“真实”对话的例子,用于进一步训练机器人的对话管理模型。它们被写成用户和机器人之间的对话交流。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们将包括一个非常简单的故事。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"yaml"},"content":[{"type":"text","text":"version: \"2.0\"\nstories:\n - story: generic happy path\nsteps:\n - intent: greet\n - action: action_greet\n - intent: select_price\n - action: action_select_upper_price\n - intent: select_purpose\n - action: action_select_purpose\n - intent: select_brand\n - action: action_select_brand\n"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"自定义动作"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"自定义动作对于更复杂的机器人来说非常有用,它们可以用来调用其他内部自然语言处理服务或公共 API 来改善对话体验。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"自定义动作存储在"},{"type":"codeinline","content":[{"type":"text","text":"actions\/actions.py"}]},{"type":"text","text":"中。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面是自定义动作"},{"type":"codeinline","content":[{"type":"text","text":"action_greet"}]},{"type":"text","text":"的一个例子,它可以向用户问候。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"class ActionGreet(Action):\ndef name(self) -> Text:\nreturn 'action_greet'\ndef run(self, dispatcher: CollectingDispatcher,\ntracker: Tracker,\ndomain: Dict[Text, Any]) -> List[Dict[Text, Any]]:\ndispatcher.utter_message(template='utter_greet')\ndispatcher.utter_message(template='utter_price')\nreturn []`\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"每个自定义操作都遵循一个非常标准的格式。有一个"},{"type":"codeinline","content":[{"type":"text","text":"name"}]},{"type":"text","text":"方法返回自定义动作的名称,这个名称必须与 domain.yml 中提供的名称一致。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"run"}]},{"type":"text","text":"方法需要接受调度器、跟踪器和域。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"调度器用于生成响应(在这里,它将发出两条消息)。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"追踪器指的是对话追踪器,可以利用它调出槽值、当前和过去的状态。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"返回值是一个在动作结束时执行的事件列表。下面是一些我们可以包含在其中的常用事件:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"SlotSet:用于设置槽值。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"FollowupAction:触发一个后续行动。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Restarted:结束当前对话。"}]}]}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"训练和启动机器人"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一旦准备好以上所有的文件,就可以训练机器人了。在根目录下运行"},{"type":"codeinline","content":[{"type":"text","text":"rasa train"}]},{"type":"text","text":"来开始这个过程。根据数据有多少,管道有多复杂,这可能需要一段时间。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果能够看到这条消息,就说明模型已经成功训练并保存。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/resource\/image\/26\/7d\/26dd896df4c82bbdd0f2aa887913ab7d.jpg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"需要运行两个命令来启动机器人:一个用于动作服务器,一个用于机器人本身。在这里,我把它合并成一行。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"注意"},{"type":"text","text":":这将在本地启动机器人。稍后,将需要用 Facebook 生成的令牌来填充我们的凭据文件,以便将其部署到 Messenger。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"bash"},"content":[{"type":"text","text":"rasa run -m models --enable-api --cors \"*\" --debug & rasa run actions\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这是我的终端在该命令运行完成后的样子。每次服务器进行对话时,都会有额外的日志。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/resource\/image\/3e\/80\/3eee1aa83ddc4461f9d2ea0f56fc2d80.jpg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在运行上述操作时,动作服务器将占用 5055 端口,机器人将占用 5005 端口。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以通过 ping http:\/\/localhost:5005 来测试服务器是否在运行。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/resource\/image\/e9\/fa\/e90ff67ce7d4d5a4eb172daa39d46ffa.jpg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"与机器人交互"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"有几种方式可以让你开始与机器人交互。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"REST API"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以通过 REST API 与机器人进行交互。当 RASA 服务器运行时,发送这个请求,以用户身份发送消息:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"shell"},"content":[{"type":"text","text":"curl --request POST \\\n --url http:\/\/localhost:5005\/webhooks\/rest\/webhook \\\n --header 'content-type: application\/json' \\\n --data '{\"sender\": \"sender_id\", \"message\": \"hi\"}'\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"sender 字段是对话的唯一 ID。当同一 sender 字段下连续发送消息时,服务器将识别它是一个对话的一部分。message 字段是要发送的文本。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"RASA shell"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以运行"},{"type":"codeinline","content":[{"type":"text","text":"rasa shell"}]},{"type":"text","text":",通过命令行与机器人开始对话。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Facebook Messenger 设置"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我对部署 Rasa 服务器的偏好是通过"},{"type":"link","attrs":{"href":"https:\/\/ngrok.com\/?fileGuid=EoE2UeNK8n0kAwJZ","title":"","type":null},"content":[{"type":"text","text":"ngrok"}]},{"type":"text","text":"来完成,这将使你的本地端口暴露在公共互联网上。另外,你也可以使用像 Heroku 这样的服务,但是 Rasa 镜像的大小让它很难在大多数免费服务保持应用的运行。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"ngrok 设置"}]},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"创建 ngrok 账户。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"按照这些说明在计算机上设置 ngrok:https:\/\/ngrok.com\/download。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"在单独的终端中运行"},{"type":"codeinline","content":[{"type":"text","text":".\/ngrok http 5005"}]},{"type":"text","text":",在端口 5005 上启动 HTTP 隧道。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"确保终端在任何时候都能运行,只要终端被中止,那么隧道就会停止,机器人在 Messenger 上就会没有反应。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"记下生成的 URL。需要向 Facebook 提供安全的 URL(带 https 的那个)。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"在 Facebook 上创建应用程序"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Facebook 机器人需要连接到 Facebook 页面。需要一个 Facebook 账户来"},{"type":"link","attrs":{"href":"https:\/\/www.facebook.com\/pages\/create\/?ref_type=site_footer&fileGuid=EoE2UeNK8n0kAwJZ","title":"","type":null},"content":[{"type":"text","text":"创建一个页面"}]},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一旦页面创建完毕,请访问 https:\/\/developers.facebook.com\/apps。点击绿色的“Create App”按钮,创建一个新的应用程序。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/resource\/image\/56\/19\/56e49d71cbd74ed6f0f81705c1899819.jpg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"选择第一个选项,然后按照说明创建应用程序。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/resource\/image\/51\/73\/511aa45e362407c7yy76949a04214873.jpg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"点击下方的“Set Up”按钮,将“Messenger”添加到应用中。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/resource\/image\/ea\/2d\/ea751c2c867574675d235027d903b12d.jpg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"在 Facebook 上设置应用程序"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一旦应用程序被创建,它应该引导你到 Messenger 下的“Setting”页面。如果没有自动进入那里,请导航到应用程序仪表板,然后进入“Messengers”→“Settings”。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/resource\/image\/9f\/81\/9f451f33aceba9962eaf8d39dafd9981.jpg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首先,将 Facebook 页面链接到应用程序。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/resource\/image\/42\/a2\/42005a7170d8679ae1eaba867d528ca2.jpg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在链接页面旁边,添加订阅允许 messages。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/resource\/image\/28\/07\/28cd0543c43a1091e38e32c249aa8907.jpg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一旦页面被链接,点击页面旁边的“generate token”。追踪这个令牌(token),因为它将需要包含在你的 Rasa 项目中。我们将此标记称为“页面访问令牌”."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接下来,在仪表板上导航到 settings→basic,找到应用密码(app secret)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/resource\/image\/b5\/f7\/b563f0fa21bf6364e44803b01942a0f7.jpg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"然后,向下滚动到“webhooks”来添加一个新的回调 URL。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/resource\/image\/67\/3e\/674d86fdb15899b2406b641db256a43e.jpg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在填写回调细节之前,在 Rasa 项目中创建 credentials.yml。这个文件应该是这样的:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"yaml"},"content":[{"type":"text","text":"facebook:\n verify: \"\"\n secret: \"\"\n page-access-token: \"\"\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面是如何填充字段:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"verify"},{"type":"text","text":":创建一个你选择的安全验证令牌。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"sectet"},{"type":"text","text":":这是应用程序的密码,从 basic settings 中获取。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"page-access-token"},{"type":"text","text":":使用之前为页面生成的页面访问令牌。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通过运行以下命令再次启动 Rasa 服务器。这与之前的命令略有不同,因为我们现在利用了凭据标志。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"bash"},"content":[{"type":"text","text":"rasa run -m models --enable-api --cors \"*\" --debug --credentials credentials.yml & rasa run actions\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"取出作为 credentials.yml 一部分创建的验证令牌,并在 Webhooks 部分的回调 URL 一起输入。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"回调 URL 是 https:\/\/{ngrok_url}\/webhooks\/facebook\/webhook。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/resource\/image\/9b\/a7\/9bf9a9f407523545ceb4e5d14f7ce3a7.jpg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"注意"},{"type":"text","text":":在任何时候,如果 ngrok 隧道停止,都必须重新启动它,并更新 Facebook 上的回调 URL。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"验证应用程序是否已启动并运行"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"导航到你的页面并尝试给机器人发消息。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/resource\/image\/16\/c7\/16107db8843aeb6562294fd7aa48d2c7.jpg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/resource\/image\/8b\/c0\/8b00011153b81d794aa05cca177305c0.jpg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"太棒了,都准备好了!实际上,在目前的状态下,机器人并不会就笔记本计算机的推荐话题做出有意义的对话……也许有一天它会 😆"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"作者介绍:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Mandy Gu,Wealthsimple 数据科学家。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"原文链接:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"https:\/\/towardsdatascience.com\/build-a-chatbot-with-facebook-messenger-in-under-60-minutes-f4c8b8046a91"}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章