使用 Oscova 在 C# 中创建本地离线机器人





5.00/5 (6投票s)
使用 Oscova 和 Oryzer FBP 平台,我们将构建一个设备上的餐桌预订机器人,以理解当今离线机器人开发标准背后的概念。
引言
之前(不久前),我解释了如何通过机器人界面与数据库进行交互。在本文中,我们将通过最少的后端编码开销,浏览离线(设备上/本地)机器人的通用概念。
我们将创建一个餐桌预订机器人,为此,我将使用免费提供的工具,特别是名为 Oryzer Studio 的免费流式编程平台,并将尝试一步一步地引导读者理解概念。不过,我会尽量避免在此直接发布链接,所以您可能需要自己搜索一下。尽管我会尽量减少这种情况。
尽管读者可能对当今机器人架构的工作原理有一般的了解,但我仍将尝试介绍一些现在在机器人开发平台中广泛确立的基本概念。
背景
在深入研究之前,我强烈建议读者回顾我上一篇关于创建用于与数据库交互的机器人的文章。该文章重点介绍了本文中使用的许多基本概念。
本文相当全面,它将带您了解机器人开发、WPF GUI 的基础知识,设置数据库实用程序类并将机器人的操作绑定到数据库。
必备组件
要启动并运行,您需要具备以下技能,或者可能需要稍作完善才能快速完成本文。
- 了解流式编程结构(组件/节点、端口和连接)
- 了解在 Visual Studio 中工作
- C#/.NET 编程基础知识
- 机器人架构基础知识
对于本文,您只需要以下内容
- Visual Studio 2019 社区版或更高版本
- Oryzer Studio 用于工作区 - 免费的流式编程平台
术语
我可能会在本文中一直使用以下术语及其缩写,为了更好地理解,我建议您熟悉它们。
- 知识库 (KB) - 机器人可以进行对话的集合。
- 组件/节点 - 本文中可以互换使用这些术语。
- 流式编程 (FBP) - 一种通过连接功能组件来构建逻辑的编程结构。
- 工作区 - 类似于图画布,您可以在其中放置节点并与其他节点连接。
文章方法
为了简洁起见并介绍流式编程,我们将使用 Oryzer Studio 来开发机器人基本交互的骨架知识库,而不是用任何编程语言进行脚本编写或硬编码。
一旦我们成功构建了机器人的知识库 (KB),我们将在 Oryzer Studio 中对其进行测试,然后将 KB 导入一个简单的 C# 控制台应用程序。
由于本文可能涉及大量 FBP,我将采用以下方法进行阐述
- 解释正在添加/使用的组件
- 口头解释连接组件的步骤(初期)
- 提供截图以显示组件的连接方式。
机器人开发的行业和研究正在变得更加标准化。在本文中,我们将学习一些机器人开发中常见的术语。例如对话、意图、上下文和实体。
开始吧
假设您已从上述链接下载了Oryzer Studio,让我们首先创建一个对话。
为了创建此机器人,我们将在对话流程中从用户那里收集以下信息
- 预订的日期
- 时间(早餐、午餐或晚餐)
- 预订餐桌的人数
- 用于确认预订的用户号码
对话 (greet_dialog)
对话是意图的集合,更像是谈话的主题。例如,如果您的机器人需要说“你好”、“哈喽”、“嘿”,您会将其分组到一个名为问候的对话中。对话是按唯一标识符对相似意图进行分组的好方法。
创建对话
- 启动 Oryzer Studio。
- 展开右侧节点浏览器中的Oscova类别。
- 选择对话节点并将其拖到工作区。
- 如果您不小心拖入了错误的节点,只需按Delete键即可将其删除。
您刚刚拖动的是一个节点,将其拖动到的地方称为工作区。
Oryzer Studio 中的节点是执行专门任务的功能单元。节点包括
- 输入端口 - 左侧的蓝色框
- 输出端口 - 右侧的蓝色框
输入端口通常存储某些变量值,这些值使节点能够执行其专门任务。
另一方面,输出端口是节点完成任务后返回的值。在某些情况下,输出端口也可以是节点本身。
因此,我们现在已经创建了一个对话节点,它将帮助我们与用户开始对话,并提供预订餐桌的第一组选项。
您可以看到对话节点有几个输入和输出端口
- 输入端口 -
名称
、意图别名
、领域
和意图
- 输出端口 -
(self)
- 将节点本身作为输出返回
我们将此对话称为 greet_dialog
,并将 2 个意图连接到它。要在 Name
端口命名对话,只需键入 greet_dialog
。
按CTRL+S保存此工作区,并将文件命名为 table-reservation-bot.west。
意图 (greet_intent)
意图是将用户查询与响应以及可选操作绑定的东西,当给定的意图表达式(用户查询示例)匹配时。为了开始我们的对话,我们将向 greet_dialog
添加一个名为 greet_intent
的意图。
我们的 greet_intent
将问候用户,简单介绍自己,并收集我们继续预订所需的初始信息。
要向对话添加意图,我们将执行以下操作
- 从节点浏览器(右侧)拖动一个意图节点。
- 从意图节点的(self)输出端口单击并拖动到对话节点的意图输入端口。
我们现在已经创建了一个对话,并将其与一个意图连接。
表达式
在机器人开发领域,表达式是用户查询示例的集合,可帮助机器人引擎进行训练,以查找用于相似性检测的模式。您提供的表达式示例越多,机器人检测相似用户查询的能力就越强。
表达式将用户查询映射到意图,该意图再将其映射到响应或操作。为了简洁起见,我们不会在此添加太多表达式,而只添加几个以阐明概念。
我们将继续添加 4 个表达式示例(请记住,这些是用户查询的示例)。
- 你好
- 哈喽
- 嘿,我能预订一张桌子吗
- 我想预订一张桌子,谢谢
现在让我们将表达式节点添加到工作区,并将它们连接到上述意图节点
- 从节点浏览器拖动表达式节点。
- 在值端口的文本框中,为每个新的表达式节点输入上述表达式样本。
- 将表达式节点的输出端口连接到
greet_intent
,如下图所示
既然我们已经向机器人系统提供了一些用户查询样本,我们就必须指定当匹配了表达式的用户查询时,机器人的响应是什么。
响应
响应是当用户查询匹配与意图关联的表达式时调用的操作的一部分。我们已经添加了 4 个表达式,所以现在让我们添加一个响应,以防用户查询匹配我们添加的表达式之一。
我们的响应将执行以下操作
- 发送一条文本消息,问候用户并要求用户提供一些信息
- 为用户提供选项,以便快速选择机器人消息的后续响应
- 设置一个上下文以创建流程(我们将在下一节中学习)
现在,让我们拖动一个 响应
节点并将其连接到 greet_intent
,如下所示
由于我们的第一个任务是添加文本消息,我们将再拖入一个名为输入文本的节点,并将其连接到 响应
节点的 文本
端口。
文本节点的内容将是
文本部分
你好!我在这里帮助您预订餐桌。
那么,让我们开始吧,告诉我您想何时预订餐桌?
我们还将在 响应
节点的提示框中添加 2 个输入选项显示给用户,并用竖线分隔它们
提示部分
今天|明天
除了询问用户何时需要预订外,我们还需要准备另一个意图来准备接收用户对我们开场白问题的回答。
我们将放下上下文添加节点并将其连接到响应节点。因此,当调用响应时,将添加相关的上下文。
上下文 (table-date-con)
在机器人开发中,上下文通常是一个字符串标签,添加到称为聊天会话的内容中,以创建对话的层次结构。这些上下文字符串的存在或不存在决定了意图的激活。
如下所示,我已经拖放了一个上下文添加节点,并将其连接到响应节点的输出端口。每当意图生成响应时,此节点将执行,并将上下文项 table-date-con
添加到会话中,并存在于接下来的 2 个用户查询中。因为我们选择了 生命周期
值为 2
。
意图 (table_date_intent)
如果您还记得我们在 greet_intent
的响应中,询问了用户何时希望预订餐桌。那么,如果用户随后指定一个日期,例如今天 或明天, 我们需要一个意图来捕获这一点。
此意图有几个任务需要完成
- 捕获用户指定的日期。
- 将用户指定的日期值存储在称为用户变量的内容中。
- 提示用户指定用餐类型/时间(早餐、午餐或晚餐)
- 创建另一个名为
table-time-con
的上下文,以帮助启用后续意图。
既然您知道如何拖动、放下和连接节点,我就不需要冗余地重新解释这些步骤了。
上下文和表达式
让我们继续指定此意图需要上下文项 table-date-con
存在于用户聊天会话中,然后我们将指定一个表达式,该表达式确保它仅从用户输入中捕获日期值。
在上面的截图中,您可以看到我指定了一个名为 table-date-con
的上下文,如果您还记得,这个上下文是由我们的 greet_intent
添加的。
现在,通过在此意图中指定上下文名称,我们告诉机器人系统,仅当用户聊天会话中存在上下文 table-date-con
时,才匹配此意图的表达式。
表达式 @sys.date
是一个预构建的系统实体,用于匹配日期。有关此的更多信息可在 Oscova 的开发者门户中找到。现在您只需在 Google 上搜索即可。
响应
此意图的响应包含三个部分
- 将日期值存储到某个用户变量中(我们将在响应中使用该值)。
- 创建新的后续上下文
table-time-con
,以便下一个意图可以捕获用餐类型。 - 提示用户指定用餐类型。
为此
- 拖动一个
响应
节点并将其连接到意图
首先,我们将存储用户指定的日期部分。请注意,此意图仅在用户在 greet_intent
之后指定日期值时调用。
为此
- 拖动实体获取节点并将实体类型指定为
sys.date
- 然后拖动变量设置节点,并将实体获取节点的值端口连接到变量设置节点的变量值输入端口。
- 将变量名指定为
table-date
确保在实体获取节点的 获取
属性中,您已将 值
设置为获取类型,并在变量设置节点中选择用户作为目标。
瞧!我们现在准备就绪。每当调用此响应节点时,名为 table-date
的变量将保存在用户变量中。
上下文和文本响应
我们需要为下一个捕获用餐时间或时间的意图添加一个新上下文。所以,让我们继续拖动并连接一个上下文添加节点到响应节点的 调用
输出端口。
我们将上下文设置为 table-time-con
,如下面的截图所示
除了为下一个后续意图添加上下文外,我们还将提供一个文本响应,显示类似以下的消息
好的,餐桌定在午餐时间,您想来吃哪一餐?(如果用户指定午餐作为用餐类型/时间)
请注意,我们在响应文本中使用了 $sys.user.table-date
。这是一个特殊参数,它告诉机器人系统用名为 table-date
的已存储用户变量替换该值。
如果您出于某种原因将变量存储在机器人的变量集合中,那么参数将是 $sys.bot.table-date
。
实体创建
在上一个意图中,我们为用户提供了早餐|午餐|晚餐的用餐时间选项。当用户输入上述值之一时,我们需要捕获它。
一个简单的解决方法是将它们转换为已知的实体类型。为了创建例如 @meal-type
类型的实体,我们将按照以下步骤操作
- 拖放一个实体识别器节点。
- 将此节点的 (self)
- 在实体类型端口编辑器中,将实体类型指定为
meal-type
。
接下来,让我们通过以下方式为此实体识别器节点指定 3 个条目值
- 拖动 3 个条目节点。
- 将早餐、午餐和晚餐指定为它们的条目值。
- 将它们的(self)输出端口连接到实体识别器节点的条目输入端口。
测试机器人
到目前为止一切顺利。现在我们的 2 个意图已准备就绪,我们可以尝试与机器人进行交互。为了测试机器人,我们首先需要将 对话
节点连接到一个Oscova Bot节点,然后将这个Oscova Bot
节点连接到一个Oscova Test Panel节点。
将您的 greet_dialog
节点连接到Oscova Bot节点
- 只需将Oscova Bot
- 将对话节点的(self)输出端口连接到Oscova Bot节点的
对话
输入端口。
Oscova Bot节点是实际代表整个机器人的节点。此节点有几个输入端口,您可以将其他节点类型连接到这些端口。
现在,让我们将其连接到Oscova Test Panel节点以测试我们机器人的响应。
连接Oscova Bot
和Oscova Test Panel
节点后
- 按训练机器人以完成训练过程。
- 键入你好 ,您应该会看到带有选项的第一个响应。
- 选择或键入今天,将显示第二个意图的响应。
继续
现在您已经(很可能)看到并测试了您机器人的响应,在下一阶段,我们将转向其他重要的意图,以捕获一些额外的用户信息。
所以我们已经获取了日期,现在要求用户提供用餐时间。我们的接下来的 2 个意图将很简单。它们手头的任务是:
- 捕获我们先前意图请求的用餐时间。
- 请求用户提供预订餐桌的人数。
在这 2 个意图之后,将是我们的最终确认意图,它将向用户显示最终消息。
为了保持内容的易懂性,我们将限制将任何进一步的信息存储在变量中,因为您已经知道如何做到这一点。因此,添加这样的额外层不会为我们的学习过程做出贡献。
对话 (table_config_dialog)
从现在开始会更简单。同样,让我们向工作区添加一个 对话
节点,将其(self)输出端口连接到Oscova Bot节点的对话输入端口。
在名称端口编辑器中,将 table_config_dialog
指定为名称。
意图 (table_time_intent)
添加一个新的意图节点,将意图命名为 table_time_intent
。此意图将捕获我们先前意图请求的用餐类型(早餐、午餐或晚餐),并将提示用户指定预订餐桌的人数。
- 拖放一个意图节点
- 在节点的名称端口编辑器中,将
table_time_intent
指定为名称 - 将其连接到
table_config_dialog
对话节点。
由于之前的意图添加了一个 table-time-con
上下文项。我们将指定此意图需要该上下文存在,并且我们还将添加一个表达式节点,该节点将捕获 @meal-type
类型的实体。
所以,请继续
- 拖放一个上下文节点并将其(self)输出端口连接到意图节点。
- 将上下文名称指定为
table-time-con
。 - 拖放一个表达式节点,并在
值
端口编辑器中指定@meal-type
。这是因为我们希望每当用户指定早餐、午餐或晚餐作为响应时,此意图都能被调用。
接下来,让我们简单添加一个响应和一个上下文项,用于我们的下一个后续意图,该意图将捕获预订餐桌的人数。
- 添加一个新的响应节点,将其连接到意图。
- 添加一个新的上下文添加节点,将
table-num-con
指定为上下文名称 - 添加一个输入文本节点,将好的!我将为您预订 人的餐桌。我们一切都准备好了。您能分享一下您的号码,以便我确认您的预订吗?作为文本值。
- 将输入文本节点连接到
响应
节点。
意图 (table_num_intent)
现在在这个意图中,让我们捕获用户对我们询问预订餐桌人数问题的回答。
- 添加一个意图节点,将意图命名为
table_num_intent
。 - 添加一个上下文节点和一个表达式节点,并将它们连接到意图节点的输入端口。
- 将
table-num-con
设置为上下文名称。 - 将
@sys.number
设置为表达式节点的值。
我想您现在应该已经掌握了我们一直在捣鼓的所有连接和节点背后的原理。
让我们添加一个响应节点,存储人数的值,并为我们最终的确认意图设置上下文。
- 添加一个新的
响应
节点并将其连接到意图节点 - 放下新的
上下文添加
节点,将table-phone-con
指定为上下文名称,并将其连接到响应节点。 - 放下新的
实体获取
和变量设置
节点。配置它们以存储@sys.number
实体。 - 添加一个
输入文本
节点,其响应文本为:太棒了!我将为您预订 $sys.number 人。我们一切都准备好了。您能分享您的号码,以便我确认您的预订吗。
响应包含 $sys.number
参数,该参数将被用户指定的餐桌预订人数的值替换。
对话 (confirm_dialog) - 结局!
我们与用户的最后一次对话是显示关于预订的确认消息。以下是我们的最终 confirm_dialog
设置。
- 添加一个新的
意图
节点并将其命名为confirm_intent
。 - 我们添加一个
上下文
来指定应该存在的上下文项。 - 我们使用
@sys.number
预构建的实体类型捕获一个数字。 - 最后,发送一条文本响应,内容为:非常感谢!您 $sys.user.table-date 的餐桌预订,共 $sys.user.table-num 人,现已确认。您将很快收到您手机号码 $sys.number 的通知。 我们使用两个参数:
$sys.user.table-date
和$sys.user.table-num
,它们将被用户指定的日期和餐桌数量替换。
让我们来测试一下
去吧,再次点击Oscova Test Panel节点上的训练机器人,然后遵循对话流程。如果一切顺利,那么您与机器人的对话应该看起来像这样:您还可以看到一个短视频,显示了它对我来说最终是什么样子的。
导入到控制台应用
既然我们机器人的知识库 (KB) 已经准备就绪,为什么不看看如何将这样的 KB 导入应用程序呢?当然,仅仅在 Oryzer 中创建 KB 而将其放在那里是没有意义的。
创建 C# 控制台项目
在您的机器上启动 Visual Studio 2019 或更高版本。
- 启动 Visual Studio 2019。
- 选择控制台应用 (.NET Core)作为项目类型。
- 您可以为项目命名。我碰巧选择了
TableReservationBot
作为项目名称。
导入 NuGet 包
到目前为止,我们开发的知识库是针对名为Oscova的机器人开发平台,它是 Syn.Bot
框架的一部分,该框架在 NuGet 上可用。
导入 NuGet 包
- 项目打开后
- 单击工具,选择NuGet 包管理器,然后选择程序包管理器控制台
- 键入
Install-Package Syn.Bot
以安装所需的程序包及其引用。
将 Program.cs 类文件中的代码替换为以下内容
using System;
using Syn.Bot.Oscova;
namespace TableReservationBot
{
class Program
{
static void Main(string[] args)
{
var bot = new OscovaBot();
bot.ImportWorkspace(@"C:\Users\Workstation\Documents\table-reservation-bot.west");
bot.Trainer.StartTraining();
bot.MainUser.ResponseReceived += (sender, eventArgs) =>
{
Console.WriteLine($"Bot: {eventArgs.Response.Text}");
};
while (true)
{
var request = Console.ReadLine();
var evaluationResult = bot.Evaluate(request);
evaluationResult.Invoke();
}
}
}
}
在上面的代码中,我们创建了 OscovaBot
类的实例,调用了 ImportWorskspace
方法,并传入了我们的工作区基于知识库文件的位置。
在接下来的几行中,我们只是获取用户输入,处理它,并显示机器人的输出消息。
构建并运行项目,然后在第一个输入中键入你好,让对话继续。
成功了!我们已经成功创建了一个餐桌预订机器人,在 Oryzer 中对其进行了测试,甚至将其导入了控制台应用程序。啊,这真是一段漫长的旅程!:)
关注点
好的!我个人认为我只是触及了表面。与我以前以代码为中心的文章相比,这篇文章采用了不同的方法。我没有使用任何后端 C# 代码,这与我以前的文章不同,因为我想完全坚持使用流式编程结构。
在实际逻辑中,确实会有后端代码来处理机器人收集的信息。让许多人惊讶的是,我使用节点创建的任何逻辑也可以使用纯 C# 后端代码创建。
为了简洁起见,我不得不克制自己不去详细介绍 Oryzer Studio 的工作原理,而是选择专注于我们的机器人开发。当然,任何人都可以自由地试用该平台,随心所欲地构建任何东西。
历史
- 2020 年 3 月 10 日:初始发布