聊天机器人教程






4.85/5 (81投票s)
关于制作人工智能聊天机器人的教程
概述
这是一个逐步实现你自己的人工智能聊天机器人的指南。
目录
- 引言 - 聊天机器人描述(第一个例子)
- 引入关键词和刺激-响应
- 预处理用户输入和重复控制
- 一种更灵活的输入匹配方式
- 使用类实现更好的功能
- 控制用户造成的重复
- 使用“状态”表示不同的事件
- 关键词边界概念
- 使用登录消息
- “关键词排名”概念
- 关键词等效概念
- 转置和模板响应
- 关键词位置概念
- 处理上下文
- 使用文本转语音
- 使用平面文件存储数据库
- 一种更好的重复处理算法
- 用新关键词更新数据库
- 保存对话日志
- 学习能力
引言
基本上,聊天机器人是一个计算机程序,当你用自然语言(英语、法语...)提供一些输入时,它会用相同的语言做出有意义的响应。这意味着聊天机器人的强度可以直接通过机器人为响应用户而选择的输出质量来衡量。通过前面的描述,我们可以推断出一个非常基本的聊天机器人可以用几行特定编程语言的代码来编写。让我们制作我们的第一个聊天机器人(请注意,本教程中使用的所有代码都将用 C++ 编写。此外,假设读者熟悉 STL 库。)本教程也提供以下语言版本:Java、Visual Basic、C#、Pascal、Prolog 和 Lisp。
//
// Program Name: chatterbot1
// Description: This is a very basic example of a chatterbot program
//
// Author: Gonzales Cenelia
//
#include <iostream>
#include <string>
#include <ctime>
int main()
{
std::string Response[] = {
"I HEARD YOU!",
"SO, YOU ARE TALKING TO ME.",
"CONTINUE, I’M LISTENING.",
"VERY INTERESTING CONVERSATION.",
"TELL ME MORE..."
};
srand((unsigned) time(NULL));
std::string sInput = "";
std::string sResponse = "";
while(1) {
std::cout << ">";
std::getline(std::cin, sInput);
int nSelection = rand() % 5;
sResponse = Response[nSelection];
std::cout << sResponse << std::endl;
}
return 0;
}
如你所见,编写一个可以与用户交互的非常基本的程序不需要很多代码,但要编写一个真正能够解释用户实际所说的话,并在此之后生成适当响应的程序,可能会非常困难。这些自始至终,甚至在第一台计算机创建之前,就一直是长期目标。1951 年,英国数学家艾伦·图灵提出了“**机器能思考吗**”这个问题,他还提出了一项现在被称为**图灵测试**的测试。在这项测试中,一个计算机程序和一个真人与第三方(评委)交谈,评委必须判断他们中哪一个是真人。如今,有一项名为**勒布纳奖**的比赛,在此比赛中,成功欺骗大多数评委至少 5 分钟的机器人将赢得 10 万美元的奖金。到目前为止,还没有计算机程序能够成功通过这项测试。其中一个主要原因是,为这类竞赛编写的计算机程序自然倾向于犯很多打字错误(它们通常脱离对话上下文)。这意味着,一般来说,评委很容易判断他是在与“计算机程序”还是真人交谈。此外,所有这些试图模仿人与人之间对话的程序的直接祖先是 **Eliza**,该程序的第一版由麻省理工学院教授 Joseph Weizenbaum 于 1966 年编写。
聊天机器人通常被认为属于弱人工智能领域(弱人工智能),与强人工智能的目标(创造与人类一样智能或更智能的程序)相对。但这并不意味着聊天机器人没有任何真正的潜力。能够创造一个像人类一样交流的程序将是人工智能领域的一大进步。聊天机器人是人工智能中更容易被爱好者接触的部分(成为一名聊天机器人程序员只需要一些一般的编程技能)。所以,那些想创造真正人工智能或某种人工智能的程序员们,编写智能聊天机器人是一个很好的起点!
现在,让我们回到我们之前的程序,它有什么问题?
嗯,有很多。首先,我们可以清楚地看到程序并没有真正尝试理解用户在说什么,而只是每次用户在键盘上输入一些句子时,它都从数据库中随机选择一个响应。而且,我们还可以注意到程序经常重复自己。其中一个原因是因为数据库的大小非常小(5个句子)。第二个解释重复的原因是我们没有实现任何机制来控制这种不必要的行为。
我们如何从一个只随机选择响应的程序,无论用户在键盘上输入什么,转变为一个对输入表现出更多理解的程序呢?
这个问题的答案很简单;我们只需要使用关键词。
关键词只是程序可能从用户输入中识别出来的一个句子(不一定是完整的)甚至一个词,然后程序就可以对此做出反应(例如:通过在屏幕上打印一个句子)。对于下一个程序,我们将编写一个知识库或数据库,它将由关键词和与每个关键词相关的一些响应组成。
所以,现在我们知道如何改进“我们的第一个聊天机器人”并使其更智能。让我们继续编写“我们的第二个机器人”,我们将它命名为 chatterbot2
。
//
// Program Name: chatterbot2
// Description: this is an improved version
// of the previous chatterbot program "chatterbot1"
// this one will try a little bit more to understand what the user is trying to say
//
// Author: Gonzales Cenelia
//
#pragma warning(disable: 4786)
#include <iostream>
#include <string>
#include <vector>
#include <ctime>
const int MAX_RESP = 3;
typedef std::vector<std::string> vstring;
vstring find_match(std::string input);
void copy(char *array[], vstring &v);
typedef struct {
char *input;
char *responses[MAX_RESP];
}record;
record KnowledgeBase[] = {
{"WHAT IS YOUR NAME",
{"MY NAME IS CHATTERBOT2.",
"YOU CAN CALL ME CHATTERBOT2.",
"WHY DO YOU WANT TO KNOW MY NAME?"}
},
{"HI",
{"HI THERE!",
"HOW ARE YOU?",
"HI!"}
},
{"HOW ARE YOU",
{"I'M DOING FINE!",
"I'M DOING WELL AND YOU?",
"WHY DO YOU WANT TO KNOW HOW AM I DOING?"}
},
{"WHO ARE YOU",
{"I'M AN A.I PROGRAM.",
"I THINK THAT YOU KNOW WHO I'M.",
"WHY ARE YOU ASKING?"}
},
{"ARE YOU INTELLIGENT",
{"YES,OFCORSE.",
"WHAT DO YOU THINK?",
"ACTUALY,I'M VERY INTELLIGENT!"}
},
{"ARE YOU REAL",
{"DOES THAT QUESTION REALLY MATERS TO YOU?",
"WHAT DO YOU MEAN BY THAT?",
"I'M AS REAL AS I CAN BE."}
}
};
size_t nKnowledgeBaseSize = sizeof(KnowledgeBase)/sizeof(KnowledgeBase[0]);
int main() {
srand((unsigned) time(NULL));
std::string sInput = "";
std::string sResponse = "";
while(1) {
std::cout << ">";
std::getline(std::cin, sInput);
vstring responses = find_match(sInput);
if(sInput == "BYE") {
std::cout << "IT WAS NICE TALKING TO YOU USER, SEE YOU NEXTTIME!" << std::endl;
break;
}
else if(responses.size() == 0) {
std::cout << "I'M NOT SURE IF I UNDERSTAND WHAT YOU ARE TALKING ABOUT."
<< std::endl;
}
else {
int nSelection = rand() % MAX_RESP;
sResponse = responses[nSelection]; std::cout << sResponse << std::endl;
}
}
return 0;
}
// make a search for the user's input
// inside the database of the program
vstring find_match(std::string input) {
vstring result;
for(int i = 0; i < nKnowledgeBaseSize; ++i) {
if(std::string(KnowledgeBase[i].input) == input) {
copy(KnowledgeBase[i].responses, result);
return result;
}
}
return result;
}
void copy(char *array[], vstring &v) {
for(int i = 0; i < MAX_RESP; ++i) {
v.push_back(array[i]);
}
}
现在,程序可以理解一些句子,比如“**你叫什么名字**”、“**你聪明吗**”等等。它还可以从其响应列表中为给定句子选择一个合适的响应,并将其显示在屏幕上。与程序的先前版本(chatterbot1
)不同,Chatterbot2
能够根据给定的用户输入选择合适的响应,而不会选择不考虑用户实际试图说什么的随机响应。
我们还在这些新程序中添加了一些新技术:当程序无法为当前用户输入找到匹配的关键词时,它只会回答说它不理解,这非常像人类。
我们可以在这些之前的聊天机器人上进行哪些改进,使其变得更好?
我们可以改进的地方很多,首先是由于聊天机器人倾向于重复,我们可以创建一个机制来控制这些重复。我们可以简单地将聊天机器人的上一个响应存储在一个 `string` `sPrevResponse` 中,并在选择下一个机器人响应时进行一些检查,看它是否与上一个响应不同。如果是这样,我们就从可用响应中选择一个新的响应。
我们可以改进的另一个方面是聊天机器人处理用户输入的方式,目前如果你输入一个全小写的输入,即使机器人的数据库中有匹配的输入,聊天机器人也无法理解任何内容。此外,如果输入包含额外的空格或标点符号(!;, .),这也会阻止聊天机器人理解输入。这就是为什么我们将尝试引入一些新机制,在用户输入被搜索到聊天机器人数据库之前对其进行预处理。我们可以有一个函数将用户输入转换为大写,因为数据库中的关键词都是大写,还可以有另一个程序来删除用户输入中可能存在的所有标点符号和额外空格。话虽如此,我们现在有足够的材料来编写我们的下一个聊天机器人:“`Chattebot3`”。
当前版本的程序有什么弱点?
显然,这个版本的程序仍然有很多局限性。最明显的一点是,程序使用“精确句子匹配”来查找对用户输入的响应。这意味着,如果你问它“你叫什么名字再来一次”,程序将根本不理解你想对它说什么,这是因为它无法为这个输入找到匹配项。考虑到程序能理解“你叫什么名字”这个句子,这听起来确实有点令人惊讶。
我们如何克服这个问题?
至少有两种方法可以解决这个问题,最明显的方法是使用一种稍微灵活的方式来匹配数据库中的关键词与用户输入。我们所要做的就是简单地允许在输入中找到关键词,这样我们就不再有之前的限制。
另一种可能性要复杂得多,它使用了**模糊字符串搜索**的概念。要应用这种方法,最初可能有助于将输入和当前关键词分解成单独的单词,之后我们可以创建两个不同的向量,第一个可以用来存储输入的单词,另一个可以存储当前关键词的单词。完成此操作后,我们可以使用**莱文斯坦距离**来测量两个单词向量之间的距离。(请注意,为了使此方法有效,我们还需要一个额外的关键词来表示当前关键词的主题)。
所以,你有两种不同的方法来改进聊天机器人。实际上,我们可以将两种方法结合起来,并根据情况选择使用哪一种。
最后,您可能还注意到之前的聊天机器人还有一个问题,您可以一遍又一遍地重复同一个句子,而程序对此没有任何反应。我们还需要纠正这个问题。
因此,我们现在准备编写我们的第四个聊天机器人,我们将简单地称之为 `chatterbot4`。查看 Chatterbot4 的代码。
如您所见,“`chatterbot4`”的代码与“`chatterbot3`”的代码非常相似,但其中也有一些关键更改。特别是,在数据库中搜索关键词的函数现在变得更加灵活。**那么,接下来呢?**别担心;还有很多东西需要介绍。
我们如何在 Chatterbot4 中进行改进,使其变得更好?
这里有一些想法
- 由于聊天机器人的代码已经开始增长,因此使用类来封装下一个聊天机器人的实现将是一件好事。
- 此外,数据库仍然太小,无法处理与用户的真实对话,所以我们需要在其中添加更多条目。
- 有时用户可能会在键盘上未输入任何内容的情况下按下回车键,我们也需要处理这种情况。
- 用户也可能试图通过稍加修改来重复他之前的句子,从而欺骗聊天机器人,我们需要将其视为用户的重复。
- 最后,很快您也会注意到,当给定输入有多个关键词选择时,我们可能需要一种对关键词进行排名的方法,我们需要一种方法来选择其中最好的一个。
话虽如此,我们现在将开始编写 chatterbot5
的实现。下载 Chatterbot5。
在继续本教程的下一部分之前,建议您尝试编译并运行“`chatterbot5`”的代码,以便您了解其工作原理并验证其中所做的更改。如您所见,“当前聊天机器人”的实现现在已封装到一个类中,此外,新版本的程序中还添加了一些新函数。
我们现在将尝试讨论“Chatterbot5”的实现
select_response()
: 此函数从响应列表中选择一个响应,程序中添加了一个新的辅助函数 shuffle,此新函数在调用seed_random_generator()
后随机打乱一个 `string` 列表。save_prev_input()
: 此函数只是在从用户那里获取新输入之前,将当前用户输入保存到变量 (m_sPrevInput
) 中。void save_prev_response()
: 函数save_prev_response()
在机器人开始搜索当前输入的响应之前保存聊天机器人的当前响应,当前响应保存在变量 (m_sPrevResponse
) 中。void save_prev_event()
: 此函数只是将当前事件 (m_sEvent
) 保存到变量 (m_sPrevEvent
) 中。事件可以是程序检测到用户输入为空,或者用户重复自己,甚至聊天机器人重复自己等。void set_event(std::string str)
: 设置当前事件 (m_sEvent
)void save_input()
: 将当前输入 (m_sIntput
) 备份到变量m_sInputBackup
中。void set_input(std::string str)
: 设置当前输入 (m_sInput
)void restore_input()
: 恢复已保存到变量m_sInputBackup
中的当前输入 (m_sInput
) 的值。void print_response()
: 在屏幕上打印聊天机器人选择的响应。void preprocess_input()
: 此函数对输入进行一些预处理,例如删除标点符号、多余的空格字符,并将其转换为大写。bool bot_repeat()
: 验证聊天机器人是否开始重复自己。bool user_repeat()
: 验证用户是否重复了自己。bool bot_understand()
: 验证机器人是否理解当前用户输入 (m_sInput
)。bool null_input()
: 验证当前用户输入 (m_sInput
) 是否为空。bool null_input_repetition()
: 验证用户是否重复了空输入。bool user_want_to_quit()
: 检查用户是否想要退出当前与聊天机器人的会话。bool same_event()
: 验证当前事件 (m_sEvent
) 是否与上一个事件 (m_sPrevEvent
) 相同。bool no_response()
: 检查程序是否对当前输入没有响应。bool same_input()
: 验证当前输入 (m_sInput
) 是否与上一个输入 (m_sPrevInput
) 相同。bool similar_input()
: 检查当前输入和上一个输入是否相似,如果其中一个输入是另一个输入的子字符串(例如:*你好吗*和*你过得怎么样*将被视为相似,因为*你好吗*是*你过得怎么样*的子字符串),则两个输入被视为相似。void get_input()
: 获取用户的输入。void respond()
: 处理聊天机器人的所有响应,无论是针对事件还是仅仅是当前用户输入。所以,基本上,这个函数控制程序的行为。find_match()
: 为当前输入查找响应。void handle_repetition()
: 处理程序产生的重复。handle_user_repetition()
: 处理用户造成的重复。void handle_event(std::string str)
: 此函数处理一般事件。
你可以清楚地看到,“`chatterbot5`”比“`chatterbot4`”具有更多的功能,并且每个功能都封装在 CBot
类的成员方法(函数)中,但仍有许多改进需要进行。
Chattebot5
引入了“state
”的概念,在这个新版本的 Chatterbot
中,我们将不同的“state
”与对话中可能发生的一些事件关联起来。例如,当用户输入一个 null
输入时,聊天机器人会将其自身设置为“NULL INPUT**
”状态;当用户重复相同的句子时,它会进入“REPETITION T1**
”状态,等等。
此外,这些新聊天机器人使用的数据库比我们目前看到的之前的聊天机器人更大:chatterbot1
、chatterbot2
、chatterbot3
...但即便如此,这仍然微不足道,因为当今使用的大多数聊天机器人(非常流行的那些)至少拥有 10000 行或更多的数据库。因此,这无疑是我们可能在聊天机器人的下一版本中努力实现的主要目标之一。
但是现在,我们将集中讨论一个与当前`聊天机器人`有关的小问题。
这到底会是什么问题呢?
嗯,这都与关键词边界有关,假设用户在与聊天机器人对话时输入了句子:“`I think not`”,程序自然会在其数据库中查找与该句子匹配的关键词,它可能会找到关键词:“`Hi`”,而这也是“`think`”这个词的子字符串,显然这是不希望发生的行为。
我们如何避免这种情况?
只需在数据库中找到的关键词前后加上一个空格字符,或者我们可以在“`find_match()`函数”中的匹配过程中直接应用这些更改。
“Chatterbot5”还有哪些可以改进的地方?
当然有。到目前为止,聊天机器人在对话开始时没有说任何话,就开始与用户进行“聊天会话”。如果聊天机器人能在对话开始时说些什么来启动对话,那会很好。这可以通过在程序中引入“登录消息”轻松实现。我们只需在聊天机器人的“知识库”中创建一个新状态,并添加一些与其相关联的适当消息。这个新状态可以命名为“`SIGNON**`”。
引入“关键词排名”概念
如您所见,在聊天机器人的每个新版本中,我们都在逐步添加新功能,以使聊天机器人更逼真。现在,在本节中,我们将在 `Chatterbot` 中引入“关键词排名”的概念。关键词排名是程序在数据库中有多个关键词与用户输入匹配时选择最佳关键词的一种方式。例如:如果当前用户输入是:你叫什么名字,通过查看其数据库,聊天机器人会有一个匹配此输入的两个关键词列表:“`WHAT`”和“`WHAT IS YOUR NAME`”。哪一个最好?答案很简单,显然是:“你叫什么名字”,仅仅因为它最长。这个新功能已在程序的新版本 `Chatterbot7` 中实现。
等效关键词
在之前所有的 `Chatterbot` 中,数据库记录只允许我们为每组响应使用一个关键词,但有时为每组响应关联多个关键词可能会很有用。特别是当这些关键词具有相同含义时,例如:“你叫什么名字”和“你能告诉我你的名字吗”都具有相同含义?因此无需为这些关键词使用不同的记录,我们可以简单地修改记录结构,使其允许每个记录有多个关键词。
关键词转置和模板响应
聊天机器人众所周知的机制之一是它能够通过一些基本的动词变位来重新表述用户的输入。例如,如果用户输入:“YOU ARE A MACHINE”,聊天机器人可能会回答:“So, you think that I'm a machine.”
我们是如何实现这种转换的?我们可能通过两个步骤完成的
-
我们确保聊天机器人有一个响应模板列表,该列表链接到相应的关键词。响应模板是一种构建聊天机器人新响应的骨架。通常,我们在响应中使用通配符来表示它是一个模板。在前面的例子中,我们使用了模板:(so, you think that*) 来构建我们的响应。在重组过程中,我们只需将通配符替换为原始输入的一部分。在同一个例子中,我们使用了:You are a machine,这实际上是用户完整的原始输入。在用用户输入替换通配符后,我们得到以下句子:So, you think that you are a machine,但我们不能直接使用这个句子,在此之前我们需要对其进行一些代词反转。
- 我们主要使用的转置是将第一人称代词替换为第二人称代词,例如:you -> me,I'm -> you are,等等。在前面的例子中,通过将用户输入中的“YOU ARE”替换为“I'M”,应用这些更改后,原始句子变为:I'm a machine。现在我们可以用这个新句子替换模板中的通配符,这就得到了聊天机器人的最终响应:So, you think that I'm a machine。
请注意,在对话中过多地使用转置并不是一件好事,这种机制会变得过于明显,并可能导致重复。
关键词位置概念
有些关键词可以在给定输入中的任何位置找到,而另一些则只能在用户输入中的某些特定位置找到,否则就没有意义。像“Who are you”这样的关键词可以在用户输入中的任何位置找到,而不会对其含义造成任何问题。
使用“WHO ARE YOU”的句子的一些例子是
- 你是谁?
- 顺便问一下,你是谁?
- 那么告诉我,你到底是谁?
但是像“who is”这样的关键词只能在给定句子的开头或中间找到,而不能在句子的末尾或单独出现。
使用关键词“who is”的句子示例
- 你最喜欢的歌手是谁?
- 你知道谁是史上最伟大的数学家吗?
- 告诉我,你知道谁是吗?(这显然没有任何意义)
我们如何确保聊天机器人能够区分这些关键词以及它们允许出现在句子中的特定位置?我们将简单地引入一些关键词的新表示法
- 只能在句子开头或中间找到的关键词将表示为:`_KEYWORD` (例如:_WHO IS)
- 只能在句子结尾或中间找到的关键词将表示为:`KEYWORD_` (WHAT ARE YOU_)
- 只应在句子中单独出现的关键词将表示为:`_KEYWORD_` (例如:_WHAT)
- 最后,可以在句子中任何位置甚至单独找到的关键词将简单地表示为:`KEYWORD` (例如:I UNDERSTAND)
一个关键词根据其在给定句子中的位置可以有不同的含义。
处理上下文
上下文是聊天机器人跟踪其之前所说内容的一种方式,并能够在选择下一个响应时考虑到这一点。到目前为止,聊天机器人在对话中选择的每个响应都只基于当前用户输入。但有时,我们可能需要更多数据才能正确响应给定输入,这就是我们需要使用上下文的时候。
为了说明这个概念,我们将查看以下对话日志
用户:你最喜欢的电影是什么?
聊天机器人:是《终结者2》。
用户:你为什么喜欢这部电影?(现在,如果我们对聊天机器人之前的回复一无所知,我们该如何回答这个问题?)
因此,显然,有些输入需要使用“上下文”才能形成正确的答案。在前面的例子中,它简单地是:是《终结者2》。现在机器人知道它之前在说什么,它可以更容易地为用户输入形成一个好的答案。
我们现在可以继续之前的对话记录
(上下文:是《终结者2》)
聊天机器人:因为它是一部科幻电影,我喜欢科幻。
上下文还允许我们控制聊天机器人的不当反应。例如,如果用户在对话中输入句子:“你为什么喜欢这些电影?”而`聊天机器人`甚至没有谈论这些话题。它可能只是回答:“你在说什么?”
上下文功能已在 Chatterbot11
中实现。
另一个很有趣的特性,如果能在`聊天机器人`中实现,那就是预测用户下一次响应的能力,这会让聊天机器人在对话中看起来更智能。
使用文本转语音
如果你的电脑在你命令它做某事时能回应你,那不是很好吗?我们已经在程序的最新版本“`Chatterbot12`”中实现了这一点。现在程序可以根据用户输入选择的每个答案说出来。我们使用了微软的 SAPI 库,以便在程序中添加“**文本转语音**”功能。在实现部分,程序中添加了三个新函数来实现“**文本转语音**”功能:Initialize_TTS_Engine()
、speak(const std::string text)
、Release_TTS_Engine()
。
Initialize_TTS_Engine()
:顾名思义,此函数初始化“**文本转语音引擎**”,即我们首先初始化“**COM 对象**”,因为 SAPI 是基于 ATL 库构建的。如果初始化成功,我们然后通过使用 `CoCreateInstance` 函数创建 `ISpVoice` 对象的一个实例,该对象控制 SAPI 库中的“**文本转语音**”机制。如果这也成功了,则表示我们的“**文本转语音引擎**”已正确初始化,我们现在已准备好进入下一个阶段:说出“**响应字符串**”。- `speak (const std::string text)`:所以,这是用于在程序中实现“**文本转语音**”的主要函数,它基本上获取转换为宽字符 (`WCHAR`) 的“**响应字符串**”,然后将其传递给“`ISpVoice`”对象的“**Speak 方法**”,该方法随后说出“机器人的响应”。
- `Release_TTS_Engine()`:一旦我们使用完“**SAPI 文本转语音引擎**”,我们就会释放在此过程中分配的所有资源。
使用平面文件存储数据库
到目前为止,数据库总是内置在程序中,这意味着无论何时修改数据库,都必须重新编译程序。这不是很方便,因为有时我们可能只想编辑数据库并保持程序的其余部分不变。出于这个原因和许多其他原因,拥有一个单独的文件来存储数据库可能是一个好主意,这样我们就可以只编辑数据库,而无需重新编译程序中的所有文件。为了存储数据库,我们基本上可以使用一个简单的文本文件,其中包含一些特定的符号来区分数据库的不同元素(关键词、响应、转置、上下文等)。在当前程序中,我们将使用之前在 Pascal 中实现 Eliza 聊天机器人时使用过的以下符号。
- 数据库中以“K”开头的行表示关键词。
- 以“R”开头的行表示响应
- 以“S”开头的行表示登录消息
- 以“T”开头的行表示转置
- 以“E”开头的行表示在转置用户输入后可能进行的更正
- 以“N”开头的行表示用户空输入的响应
- 以“X”开头的行表示聊天机器人未找到与当前用户输入匹配的任何关键词时的响应。
- 以“W”开头的行表示用户重复自身时的响应。
- 以“C”开头的行表示聊天机器人当前响应的上下文。
- 以“#”开头的行表示注释
我们现在拥有了一个完整的数据库架构,我们只需要在下一版聊天机器人 (Chatterbot13
) 中实现这些功能。
更好的重复处理算法
为了防止聊天机器人重复过多,之前我们使用了一个非常基本简单的算法,该算法包括将当前聊天机器人的响应与之前的响应进行比较。如果当前响应选择与之前的响应相同,我们简单地丢弃该响应,并从可用响应列表中查找下一个候选响应。该算法在控制聊天机器人的即时重复方面非常有效。然而,在避免更长期的重复方面却不那么好。在聊天会话期间,相同的响应可能会出现多次。使用新算法,我们控制聊天机器人重新选择相同响应所需的时间。实际上,我们确保它已使用完对应关键词的所有可用响应,然后才能重复相同的响应。这反过来可以提高对话交流的质量。以下是算法工作原理的解密:在聊天机器人和用户之间的对话过程中,我们会列出聊天机器人之前选择的所有响应。在选择新响应时,我们从列表末尾开始搜索当前选定的响应。如果在列表中找到当前候选响应,我们然后将该位置与可用响应的总数进行比较。如果位置加一小于可用响应的总数,我们认为这是一个重复,因此我们必须丢弃当前响应并选择另一个响应。
用新关键词更新数据库
有时,在向数据库添加新关键词时,很难选择真正相关的关键词。然而,有一个非常简单的解决方案。在与聊天机器人聊天时,我们只需确保每次聊天机器人无法找到与当前输入匹配的关键词时,都将用户输入存储在一个文件中(例如:*unknown.txt*)。之后,当我们需要在数据库中进行关键词更新时,只需查看我们用于保存之前对话中发现的未知句子的文件。通过持续使用这些程序添加新关键词,我们可以创建一个非常好的数据库。
保存对话日志
为什么要保存用户和聊天机器人之间的对话?因为这可以帮助我们找出聊天机器人在给定对话中的弱点。然后我们可以决定对数据库进行哪些修改,以使未来的对话交流更自然。我们基本上可以保存时间和日期,以帮助我们确定聊天机器人应用新更新后的进展。保存日志有助于我们确定聊天机器人对话技能的拟人程度。
学习能力
到目前为止,聊天机器人在聊天时无法从用户那里学习新数据,在聊天机器人中拥有此功能将非常有用。它基本上意味着,无论何时聊天机器人遇到没有相应关键词的输入,它都会提示用户。作为回报,用户将能够向聊天机器人的数据库添加一个新关键词和相应的响应,这样做可以显著改善聊天机器人的数据库。以下是算法的工作方式:
- 未找到此输入的关键词,请输入关键词
- 所以关键词是:**(key)**
- **(如果响应为否)**请重新输入关键词(返回第2步)
- 未找到此关键词的响应:**(key)**,请输入响应
- 所以,响应是:**(resp)**
- **(如果响应为否)**请重新输入响应(返回第4步)
- 关键词和响应学习成功
- 我还有其他需要学习的关键词吗?
- (**如果回答是肯定的,否则继续聊天**):请输入关键词(**返回第2步**)