马尔科夫链聊天机器人是如何工作的?

75

我打算使用马尔可夫链之类的东西创建一个聊天机器人,但我不确定如何使其正常工作。据我所知,您可以从给定单词和后续单词的数据中创建表格。在训练机器人时是否可能附加任何概率或计数器?这是个好主意吗?

问题的第二部分涉及关键字。假设我已经能够从用户输入中识别关键字,那么我该如何生成使用该关键字的句子呢?我并不总是想以关键字开头,那么我应该如何为马尔可夫链进行初始设置呢?


1
二维表格数据对于人工智能来说并不是很有用,而图形则更加有益。要获取接下来的单词,贝叶斯网络是最佳解决方案。要形成句子,需要语言处理,而基本逻辑(如马尔可夫链)无法完成此任务。 - AbiusX
2
你不能用马尔可夫链做吗?虽然有一些机器人使用了马尔可夫链,但它们只是把句子拼在一起,我想它们并不总是有意义的。 - Jordan
@AbiusX:你说的“只是找出最可能的句子”是什么意思?类似贝叶斯网络的东西会给我带来什么,而马尔可夫链没有?我该处理什么?马尔可夫链不就有点像贝叶斯网络吗?我的意思是,你仍然在处理概率和类似有向图的东西,只不过它存储在表格中。在每个单词处,你仍然会根据给定的概率选择下一个要跟随的单词,对吧?有什么区别?而且,我可以先使用马尔可夫链,然后添加其他逻辑吗?有什么建议吗?谢谢! - Jordan
1
@Jordan:AI是一个广泛的话题。我曾经用贝叶斯网络、语义网和一些创意做了一个聊天机器人,听起来不错。如果你对AI不太了解,就坚持创意吧。贝叶斯网络会让你的机器人说出像“are you peruel?”这样的话,虽然不是正确的句子,但让你感觉它很聪明!(在单词的字母选择上应用贝叶斯网络,可以制造新单词,这就是CAPTCHA算法所做的,你在CAPTCHA图像中看到的是无意义但漂亮的单词) - AbiusX
@Jordan:马尔可夫链可以帮助你在一维事物集合中进行选择,贝叶斯网络则可以帮助你在二维事物集合中进行选择(两个因素)。在你的情况下,使用马尔可夫链即可。 - AbiusX
显示剩余8条评论
3个回答

142
我几年前用Python为IRC创建了一个Markov链聊天机器人,可以分享一下我是如何做的。生成的文本不一定有意义,但阅读起来可能非常有趣。我们可以分步骤来看。假设你有一个固定的输入文本文件(可以使用聊天文本或歌词或想象),那么你可以通过以下步骤来构建字典:
1. 循环遍历文本并制作字典,即键值容器。将所有成对的单词作为键,其后跟随的单词作为值。例如:如果你有一个文本"a b c a b k",你从"a b"作为键开始,"c"作为值,然后是"b c"和"a"作为值......值应该是一个列表或任何收集0..多个'项'的集合,因为对于给定的一组单词,你可以有多个值。在上面的例子中,你会发现两次 "a b",第一次后面跟着 "c",最后跟着 "k"。因此,你最终会得到一个类似这样的字典/哈希表:{'a b': ['c','k'], 'b c': ['a'], 'c a': ['b']} 2. 现在,你已经拥有了需要构建奇妙文本的结构。你可以选择随机选择一个键或一个固定位置来开始!所以,给定我们拥有的结构,我们可以从保存“a b”开始,然后随机从值中取一个单词,即c或k。这样,在循环中,第一次保存"a b k"(如果"k"是随机选择的值),然后继续向右移动一个步骤,在我们的例子中是 "b k",如果你有一个随机值对于那个键,则将其保存,否则跳出循环(或者你可以决定其他事情,比如重新开始)。当循环完成时,你就可以打印你保存的文本字符串了。
输入越大,你的键(一组单词)就会有更多的值,因此你将拥有一个更聪明的机器人,因此你可以通过添加更多文本(也许是聊天)来“训练”你的机器人。如果你有一本书作为输入,你可以构造一些漂亮的随机句子。请注意,你不必只选一个跟在一对单词后面的单词作为值,你也可以选2个或10个。区别在于,如果使用“更长”的建筑块,你的文本将显得更准确。从一对单词作为键开始,选择其后跟的单词作为值。
因此,你可以基本上有两步,首先制作一个结构,你随机选择一个键来开始,然后拿取该键并打印该键的一个随机值,并继续进行,直到没有值或某些其他条件。如果你想要,你可以从你的键-值结构中用聊天输入"播种"一对单词,以便有一个开端。如何开始你的链取决于你的想象力。
真实单词示例:
"hi my name is Al and i live in a box that i like very much and i can live in there as long as i want"

"hi my" -> ["name"]

"my name" -> ["is"]

"name is" -> ["Al"]

"is Al" -> ["and"]

........

"and i" -> ["live", "can"]

........

"i can" -> ["live"]

......
现在构建一个循环:选取一个随机的键,比如说“hi my”,并随机选择一个值,这里只有一个值,所以是“name”(将“hi my name”保存)。现在向右移动一步,以“my name”作为下一个键并选择一个随机值……“is”(将“hi my name is”保存)。现在继续移动并选取“name is”……“Al”(将“hi my name is AL”保存)。现在选取“is Al”……“and”(将“hi my name is Al and”保存)。
当你到达“and i”时,你会随机选择一个值,比如说“can”,那么就形成了“i can”的单词等等。当你达到停止条件或者没有值时,在我们的例子中打印出构建好的字符串:“hi my name is Al and i can live in there as long as i want”。
如果你有更多的值,你可以跳转到任何键。值越多,组合就越多,文本就越随机、趣味性就越强。

1
如果您将聊天文本作为输入,您必须有大量的内容来让机器人“变得更智能”。当某人提到机器人名称时,会触发一个响应。我获取整个字符串并首先检查是谁写的,然后以该名称开始我的回复,例如:“Jordan:bla bla”,然后我选择一对词语并从那里开始回复。我也可以编造两个以“和(随机单词)”开头的句子。我还随机选择我的回复长度,可能是5-50个单词。我还拥有多个“大脑”,其中有更多结构可供我使用。大脑基本上就是一个文本文件。 - Nocker
1
忘了说,如果你使用聊天输入,由于人们往往会犯很多拼写错误和使用缩写,那么你的机器人也会变成那样。如果你有时间,还可以研究自然语言处理,这里有一个 Python 的链接(http://www.nltk.org/)。 - Nocker
如果你仍然有源代码,请将其上传到Github上。 - user1943442
我曾经做过类似这样的事情,我让程序扫描奥利弗·特威斯特(Oliver Twist),并提取每个由4个单词组合而成的组合及其出现频率。生成频率图花费了很长时间,只输出了接近无意义的垃圾文本字符串。我真希望当时知道这种方法! - Carcigenicate
2
我认为这里缺少了一部分,因为马尔可夫链是基于概率做出决策的,所以当涉及到“and i”时,系统应该能够重新评估整个字符串(而不仅仅是最后一个键值对)直到那里来确定下一个单词。系统应该告诉你“live”应该是下一个单词,但不是凭空猜测。 - Juan Zamora
这是有关每个州权重的额外信息 https://www.youtube.com/watch?v=L97yQMT0jn8 - Juan Zamora

9
机器人从您的输入中选择一个随机单词,并通过选择另一个已被视为其保留单词的后继单词来生成响应。然后,它通过依次找到该单词的后继者并进行迭代来重复此过程,直到认为已经说够了为止。它通过在训练文本中停在标点符号之前的单词来停止,并返回输入模式以让您做出回应,如此循环。

虽然不是非常逼真,但我在此挑战任何人在71行代码内完成更好的工作!!这对于任何初学Python的人来说都是一个很好的挑战,我只希望我能将挑战开放给比访问此博客的少数访客更广泛的受众。编写一个始终保证语法正确的机器人肯定更接近几百行,我简化了很多,只是试图想出最简单的规则,让计算机尝试有话可说。

它的响应至少可以说是印象主义!此外,您必须用单引号表达您的话。

我使用《战争与和平》作为我的“语料库”,这需要几个小时的训练运行时间。如果您不耐烦,请使用较短的文件...

这是训练器

#lukebot-trainer.py
import pickle
b=open('war&peace.txt')
text=[]
for line in b:
    for word in line.split():
        text.append (word)
b.close()
textset=list(set(text))
follow={}
for l in range(len(textset)):
    working=[]
    check=textset[l]
    for w in range(len(text)-1):
        if check==text[w] and text[w][-1] not in '(),.?!':
            working.append(str(text[w+1]))
    follow[check]=working
a=open('lexicon-luke','wb')
pickle.dump(follow,a,2)
a.close()

以下是机器人:

#lukebot.py
import pickle,random
a=open('lexicon-luke','rb')
successorlist=pickle.load(a)
a.close()
def nextword(a):
    if a in successorlist:
        return random.choice(successorlist[a])
    else:
        return 'the'
speech=''
while speech!='quit':
    speech=raw_input('>')
    s=random.choice(speech.split())
    response=''
    while True:
        neword=nextword(s)
        response+=' '+neword
        s=neword
        if neword[-1] in ',?!.':
            break
    print response

你会在它说出某些部分有意义的话时感到一种神秘的感觉。

0
你可以这样做: 创建一个一阶马尔可夫链生成器,使用单词而不是字母。 每当有人发布内容时,他所发布的内容将被添加到机器人数据库中。 此外,机器人会保存他何时进入聊天室以及某个人发布第一篇帖子的时间(以10秒的倍数),然后他将保存同一人等待再次发布的时间量(以10秒的倍数)... 这第二部分将用于查看该人何时发布帖子,因此他加入聊天并在基于“一个人加入聊天后多少个10秒钟之后发布”的表格上经过一定时间后,他将继续使用相同的表格发布帖子,并思考“在使用X秒钟思考和编写后发布的帖子之后,他使用的时间量是多少”。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接