随着一众国内外大模型免费开放API,零本钱构建一些性能不是那么强的大模型运用成为了可能。作为Digital IDE的作者,锦恢在完成学业的同时也须要卖力掩护一些自己的开源项目。
在掩护一个产品的时候,为了得到更好的用户反馈,我们每每会建立一个***群来和用户直接互动。
不过随着韶光的推移,群内会有很多的问题变得重复,或者很多问题都可以从我们供应的官方文档中找到答案。当然,我们知道,大部分的人都是
于是我就想着能不能开拓一个用于进行问题办理的QA机器人,这样就可以解放我的双手了,让我每天有更多韶光和朋友打星际争霸。通过5天的开拓,我上线了我的QA机器人,我取名为Tiphereth,是卡巴拉生命之树最中央的节点,希伯来文意为“俏丽、光彩”。目前已经在群内稳定运行了一个月。

项目目前已经开源,欢迎各位点个star:Lagrange.RagBot
这篇文章,我就分享一下我在开拓QA机器人中的心得,以及个中最核心的模块“意图识别”模块是如何基于深度学习和单元测试的进行迭代的。
项目架构&流程讲解
由于这个项目是一个将机器人接入***的项目,涉及到比较多的环节,项目整体有一定的繁芜性。本着先感性再理性的认知原则,以是我打算先讲讲系统的整体的比较粗略的架构,先让我的不雅观众大概知道QA机器人的整理架构和大致的一个事理。
项目的整体架构如下图所示:
个中最上层的Lagrange.Core卖力全体***的鉴权和底层通信,包括登录注册,和***的做事器直接发起安全连接和信息发送接管。此处感谢Lagrange.Core项目组的无私奉献,也希望大家可以去点个star。
中间层的Lagrange.onebot则是全体***的后端框架,卖力编写对付不同的群聊和私聊的逻辑函数,这个项目完备由我开拓完成,官方文档在这里Lagrange.onebot文档。
在逻辑层面,当一个用户在在群内发言后,onebot层在将转换为更加规整的文本信息后,会交给意图识别模块,也便是Intent Recogition进行意图分类,该模块会将用户输入的一段话分类成如下几个种别之一:
·bug讯问
·usage讯问
·表达情绪
·others
对付99%的群内的谈天内容,都属于others,当意图识别模块将others识别返回给onebot后,onebot就会自动谢绝回答当前的。这么做会让我们的QA机器人显得很乖,不会胡乱插嘴。这在客服机器人和QA机器人的开拓中是非常主要的。实际上,由于深度学习上数据不敷造成的out of distribution问题,我在系统上还加上了我今年提出的一个深度学习可信打算的算法,阁下暂时不须要理解它的事理,理解它须要阁下去复习高档数学和多元统计剖析的知识。阁下只须要知道,这个模型能返回当前意图分类的不愿定性。下图是我对Tiphereth进行的一个意图识别测试。
可以看到,它很好地完成了意图的识别,并返回了对应的不愿定度,不愿定度如果太高了(>0.3),那么,系统也会谢绝回答用户的问题。这样就能很好地办理out of distribution的问题。
如果意图识别模块返回的是内容是bug讯问,那么onebot层就会去讯问大模型,从而得到对应的回答结果。不过这么做太大略了,对付我们自己的项目或者公司内部的技能文档,大模型肯定不知道个中的技能。因此,我们须要引入知识库来让大模型“更理解我们的内部资料”。详细做法为,将我们的内部资料切成一个个小块扔进向量数据库中,等到用户讯问干系问题时,利用用户的讯问语句去向量数据库的语义空间中找出topk靠近的小块,将小块作为prompt再去讯问大模型,从而得到具备内部知识库的回答。而且最棒的是,我们的程序在讯问大模型时是可以获取到从向量数据库中返回的切块的来源的(比如来源于某个网址),这样我们的QA机器人在回答时就能像new bing一样返回答案的参考链接了,这对付须要专业信息咨询的用户而言,是非常主要的:
对付其他的意图,用户完备可以自己去接入一些其他的第三方做事,比如google搜索,wiki知识库等等。总之,我设计的这套QA机器人框架目前可以知足我自己的需求,如果阁下对付当前框架的设计有其他建议,欢迎在评论区提出。只有在工业界受过足够多的迭代升级,才能得到效果更好的QA机器人。
TDD意图识别开拓
好啦,接下来,非常有必要讲讲开拓中非常主要的一些细节。
QA机器人的设计边界
我在一年前,实在开拓过一款基于大模型的谈天机器人,当时我对这类产品的定位还没有一个清晰的认知,算是乐趣>实用代价。一年后的现在,我认识到以目前的深度学习技能,想要开拓一个QA机器人,最主要的并不是把机器人的回答做得更加像人,OpenAI的首席实行官Sam在今年4月份的一次演讲中也提到了:
我不看好任何视图通过大模型向外部供应感情代价的项目,这些项目终将以失落败告终;我们推动大模型的方向永久是让它成为一个解放大脑,提升生产力的工具。
事实上,在Chatgpt推出的一年多之前,就发生过类似的项目,该项目后来由于openai的阻力而破产。因此,我们设计的QA机器人不应该把“说话像猫娘”作为提升方向,而是该当给它设计更加明确的利用场景,提前设计好它能做什么,它不能做什么。在软件工程学中,这被我们称为一款软件的设计边界(design boundary)。
那么QA机器人的设计边界是什么呢?在我的场景中,便是根据用户的问题,回答有关我的开源软件利用方面的问题(usage intent),或者回答有关软件可能存在的bug干系的问题(bug intent)。
而对付这样有明确设计边界的问答系统,意图识别模块基本是必不可少的。虽然大模型自身也能在一定程度上进行意图识别,但是大模型的返回结果的稳定性极差,且条件实行效果也非常差(目前最好的GPT4,条件实行的准确率也只有86%)。想要做到比较低的缺点率且可控性极佳,方便让程序的其他模块更加风雅地掌握QA机器人的行为,一个意图识别模块险些是必不可少的。
意图识别的开拓
在讲解TDD(test driven development,测试驱动的开拓)的意图识别之前,首先须要给意图识别的IPO进行大略的定义。在我们的场景中,意图识别的输入是一段话,卖力输出意图的分类结果,当前意图是属于usage,bug,expression还是others,相称于是一个文本四分类问题。
为了预防数据不敷导致的out of distribution的问题,我们还须要给模型的输出增加一个不愿定率,这个过程采取了最新的可信打算技能EDL(证据神经网络,evidential deep learning)结合了我在今年提出的新的改进方法完成。有关EDL的详细事理,欢迎阁下去阅读我的往期博客:EDL(Evidential Deep Learning)事理与代码实现。
有的非资深深度学习工程师可能对付网络到底要搭建多少层,一贯没有一个感性的认知,我虽然也不是资深的深度学习工程师(毕竟咱还没有毕业,笑),但是关于如何布局网络的深度大小,我还是有点履历的。最大略的方法便是先利用t-SNE,将数据在特色空间上进行可视化。此处我采取了网易开源的BCEmebedding作为中英稠浊文本的嵌入层,大略说便是这玩意儿能把一段话变成一个512维向量。那么我们先把演习集全部扔进去,然后利用t-SNE在二维平面上进行可视化这些512维向量:
我们比较关心的是usage,bug,expression和others这几个量,那么我根据上图右上角的标签,去找这四个种别对应的颜色的散点。我们须要通过这四个种别是不是足够好分,来判断我们须要布局多么繁芜的模型,越是繁芜的模型,能做出的决策边界可以越繁芜,最大略的单层线性模型只能用切蛋糕的办法,通过给上面的图“划几刀”的办法来直接划定楚汉两界。比如,在线左边的便是usage,在右边的便是bug。
我们的例子中,上面的图中四个种别对应的散点并不算非常难以区分,结合业界对付意图模型的通用做法,我终极采纳了单层MLP+ELU激活函数的办法进行网络布局。
假设我们通过预演习的得到了上述的模型(详细请参考Lagrange.RagBot的./notebook/experiment.ipynb文件中的实验结果),loss丢失函数低落得非常舒畅:
解释演习收敛了。
我们可以写个程序和对应的test suite来测试一下准确率,这实在就相称于深度学习模型在测试集上的准确率:
test_suite=[
#input代表输入值,expect代表模型输出的目标值
{'input':'如何利用digital ide这个插件?','expect':'usage'},
#此处的expect利用逗号进行分隔,代表只要符合个中的某一个就行。这是由于很多时候,问题的意图并不明显,很可能某几个值都知足哀求
{'input':'我本日打开vscode,创造自动补全失落效了,我是哪里没有配置好吗?','expect':'usage,bug'},
{'input':'path top.v is not a hdlFile叨教报这个缺点大概是啥缘故原由啊','expect':'usage,bug'},
{'input':'我同学在学习强国看到小麦收割了,然后就买相应的股就赚了','expect':'others'},
{'input':'我平时写代码就喜好喝茶','expect':'others'},
{'input':'叨教报这个缺点大概是啥缘故原由啊','expect':'usage,bug'},
{'input':'觉得现在啥都在往AI靠','expect':'others'},
{'input':'别人设置切实其实定有点不得当自己的','expect':'others'},
{'input':'在企业里面最大的问题是遇见傻逼怎么办?','expect':'others'},
{'input':'险些完备不喝牛奶2333','expect':'others'},
{'input':'command not found:python','expect':'usage,bug,others'},
{'input':'兄弟们有没有C措辞绘图库推举','expect':'usage'},
{'input':'我早上开着机去打论文回来创造我电脑切换到Linux了','expect':'usage,bug,others'},
{'input':'我在Windows下碰着的只要问题便是对付C程序,包管理和编译管理器偶尔会不认识彼此但除此之外,都很安稳(win11除外)','expect':'usage,others'},
{'input':'我的反撤回还能用','expect':'others'},
{'input':'由于这是养蛊的虚拟机,放了些国产垃圾软件,得用国产泼皮之王才能镇得住他们','expect':'others'},
{'input':'你咋装了个360','expect':'others'},
{'input':'???','expect':'expression'},
]
for test in test_suite:
embd=model.embed_documents([test['input']])
embd=torch.FloatTensor(embd)
with torch.no_grad():
evidence,prob=enn_model(embd)
e=evidence
alpha=e+1
S=alpha.sum(1)
b=e/S
u=out_dim/S
pre_label=prob.argmax(1)
name=engine.id2intent[pre_label[0].item()]
ok='√'if name in test['expect']else'×'
print(name,test['expect'],ok,u)
输出:
usage usage√tensor([0.0501])
bug usage,bug√tensor([0.0773])
bug usage,bug√tensor([0.0758])
others others√tensor([0.1678])
others others√tensor([0.0887])
bug usage,bug√tensor([0.0902])
others others√tensor([0.0453])
others others√tensor([0.0424])
others others√tensor([0.1416])
others others√tensor([0.1441])
bug usage,bug,others√tensor([0.1615])
usage usage√tensor([0.0562])
others usage,bug,others√tensor([0.0820])
others usage,others√tensor([0.0798])
others others√tensor([0.1282])
others others√tensor([0.1034])
others others√tensor([0.0967])
expression expression√tensor([0.0802])
可以看到,全都答对了。
但是此时,并不能直接参与支配的,请听我娓娓道来。
QA机器人是须要不断迭代的
这里须要阁下理解一个关于QA机器人开拓的基本流程,QA机器人的开拓(其他很多深度学习运用也一样)一定是一个不断迭代的过程,由于你的无法在一开始就制作出一个能够cover所有问题的数据集,在QA机器人上线测试的过程中,用户一定会不断地提出问题,或是闲聊,这些数据是非常非常宝贵的!
以是!
QA机器人能跑,能说人话了,只是第一步,最最主要的是须要设计出一套机制,能够网络用户数据,并周期性田主动利用这些数据去更新模型,从而终极趋于完美。
如果阁下运行了我的项目,会创造在项目的根目录下,涌现了一个logs文件夹,它里面就存储了我的系统自动保存的用户的对话和模型将该对话识别成的意图。
在./notebook/clear-logs.ipynb中,给出了一个例程,该例程会自动将logs下识别意图不是others的对话内存展示出来,你可以自己进行干预,重新审核这些非others的意图是否精确,如果禁绝确,它的意图该当是什么。然后基于这些信息,可以快速更新我们的演习集。新增的数据会自动录入到./config/***.story.yml中(这个文件我并没有开源,由于里面涉及到了用户的个人隐私),然后我们重新演习模型即可。由于模型只有一层,以是就算利用CPU,也能在超短韶光内瞬间演习完成。
迭代后的测试
在重新演习完成后,我们须要知道更新参数后的模型是不是还能把之前的问题答对,我将这一部分逻辑写成了单元测试。启动项目后,在项目中输入npm run test即可开启单元测试:
开拓者只须要根据单元测试的反馈,就能大致理解到重新演习后的模型的性能,从而做出判断,到底是连续上线,还是连续添加数据,让不知足条件的测试样例通过。
很多做深度学习的工程师都没有做单元测试的习气,这是非常不好的。由于实际场景下,是须要担保模型在特定例子上一定能通过,测试集的精确率并不能反应这一点。
如此,反复迭代,就能够在终极得到一个很乖的AI啦!
在我稳定运行的1个月以来,大概迭代到第二代时,意图识别模块就足够稳定了。对了,每次演习完后,你还可以用curl工具先将模型重新加载到做事中:
curl-X POST http://127.0.0.1:8081/intent/reload-embedding-mapping
返回:
{"code":200,"data":"load model from./model/intent.enn.pth","msg":200}
这么做最大的好处便是不须要重启做事,然后我们可以利用单个例子来测试上线的模型:
curl-X POST-H"Content-Type:application/json"-d'{"query":"本日吃不吃猖獗星期四?"}'http://127.0.0.1:8081/intent/get-intent-reco
gition
输出:
{"code":200,"data":{"id":6,"name":"others","uncertainty":0.2645169198513031},"msg":200}
可以看到,输出结果为others,不愿定度也非常高,代表当前的语句是闲聊。当然,你也可以拿更多的例子来测试。
这样,一个稳定的意图识别模块就搞定了,至于后面如何结合向量数据库和大模型给出带有参考链接的回答,这就不属于本篇文章的内容了。感兴趣的朋友可以参考./bot/services/intent.ts这个文件的内容。
各位,玩得愉快点!
总结
本文大略讲解了一下我的QA机器人的设计与开拓履历,特殊是关于TDD模式下的意图识别模块的迭代。除了意图识别,也便是文本分类,对付其他的须要基于深度学习进行的精准任务而言,这套开拓流程也是具有一定的参考代价的,特殊是对付深度学习同行而言,一定不要想着一个很鲁棒的算法+数据集就能一招解千愁,一个精良的深度学习运用一定是要在测试中反复迭代升级的,毕竟,对付深度学习而言,算法>数据>算法。
文末了,我约请你进入我们的软件测试学习互换群,大家可以一起磋商互换软件测试,共同学习软件测试技能、口试等软件测试方方面面,理解测试行业的最新趋势,助你快速进阶Python自动化测试/测试开拓,稳住当前职位同时走向高薪之路。
末了:1)关注+私信回答:“测试”,可以免费领取一份10G软件测试工程师口试宝典文档资料。以及相对应的***学习教程免费分享!
2)关注+私信回答:"入群" 就可以约请你进入软件测试群学习互换~~