打造个人助理-1

Database and Ruby, Python, History


最近自己做了一个个人版的“小爱同学”,能够进行 NLP 处理,并进行对应的操作。之前做过一个版本,是依托 ChatGPT 的 API 做的聊天功能,但这次,我们可以让它干活了!

比如,我提问”what’s the value of jdbc_database_url for the deployment order-service in PROD”,它就会识别我的意图是想要查到生产环境上 order-service 的 jdbc_database_url 是什么,并自动连接 Kubernetes 集群查询 jdbc_database_url 的值。

问题拆解

  1. 需要识别 NLP 的意图。比如上面的例子里面,我们的意图是要查询 jdbc_database_url 的值。
  2. 需要找到句子里面的关键词(也叫槽位),比如,我们需要知道 PROD 的意思是生产环境,order-service 是部署名字,以及我们需要查询的字段是什么。

Bert

通过 Bert 模型,以及阿里达摩院的这篇[论文][3],我们可以轻松实现上面的两件事。

相关代码在[这里][2],以及[中文介绍][1]。

简单而言,通过 Bert 的能力,我们可以识别出语句的意图是什么,以及每个槽位是什么,进而我们可以做下一步的操作。举个例子,“what’s the value of jdbc_database_url for the deployment order-service in PROD”这句话,对应的槽位就是O O O O B-env-var-name O O O B-deployment-name O B-environment,进而得到env-var-namejdbc_database_urlorder-servicedeployment-namePRODenvironment

需要做哪些

训练语料

基于 Bert 的预训练模型,我们可以进行简单的微调,就可以完成很多 NLP 任务。但是,这里“简单的微调”并不是说没什么工作。相反,相当繁杂的人工任务是在准备语料上面,包括对意图识别打标,和槽位打标。

在实例代码中,大概有 4000 多条训练数据,都需要人工一条条处理。“what’s the value of jdbc_database_url for the deployment order-service in PROD”这句话,我们需要打一个意图的标签kubernetes_pod_env_value,以及对应的槽位就是O O O O B-env-var-name O O O B-deployment-name O B-environment

顺便吐槽一句,网上各种流行的开源 LLM 模型,却没有一家开源了自己的语料。所以,核心才是语料,而语料的背后是人工和业务知识。

实现逻辑

这个无需多言,每个意图都需要实现一边。当然现在有 ChatGPT 可以帮忙实现,但需要有 debug 的能力,毕竟 ChatGPT 生成的代码还需要调试和修改才能够用。

我这里需要连接 Kubernetes,ChatGPT 提供的代码是用自己本地的kube config文件,但没有谁会真的把自己的kube config文件提交到代码仓库,然后部署上去的,太危险了。所以,真实的实现还是需要额外的考虑。

Bert 是如何做到的

还是这个例子,当输入是

what's the value of jdbc_database_url for the deployment order-service in PROD

输出是

O O O O B-env-var-name O O O B-deployment-name O B-environment

这里只有槽位(slot)的信息,还缺失意图。实际上,输入会先进行 Tokenizer。

tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
tokenizer.tokenize('value')

然后再在一头一尾分别加上[CLS][SEP],并补齐成 50 个字符(Bert 要求统一输入长度),[CLS]就是用来做意图识别的。

最后输出大概是这样,101就是[CLS], 102就是[SEP]

[ 101, 2054, 2003, 1996, 2783, 2544, 1997, 5310, 6337, 2326, 2006, 4013, 2094,  102,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0]

再将上面的数据喂入模型,输出的结果就是lossintent_logitsslot_logits

我们不需要处理loss,因为这个是训练的时候才会用到的。

对于intent_logits,如果我有 3 个意图(unknown, play_music, turn_off_light),那么这个输出就是每个意图的可能性,取最高值对应的 index 就行了。 对于slot_logits,slot 有多个可能性(PAD, UNK, O, B-deployment-name, B-environment),输出的是每个 slot label 的可能性,取最高值对应的 index 就行了。

1 2 3