智能问答机器人是 自然语言处理领域一个很经典的问题,它用于回答人们以自然语言形式提出的问题,有着广泛的应用。其经典应用场景包括:智能语音交互、在线客服、知识获取、情感类聊天等。常见的分类有:生成型、检索型问答系统;单轮问答、多轮问答系统;面向开放领域、特定领域的问答系统。
在过去,客服机器人的搭建通常需要将相关领域的知识(Domain Knowledge),转化为一系列的规则和知识图谱。构建过程中重度依赖“人工”智能,换个场景,换个用户都需要大量的重复劳动。随着深度学习在自然语言处理(NLP)中的应用,机器阅读可以直接自动从文档中找到匹配问题的答案。深度语言模型会将问题和文档转化为语义向量,从而找到最后的匹配答案。特别是ChatGPT以文字方式互动,除了可以透过人类自然对话方式进行交互,还可以用于相对复杂的语言工作,包括自动文本生成、自动问答、自动摘要等在内的多种任务。
ChatGPT 是由 OpenAI 最先进的语言模型 gpt-3.5-turbo 提供支持, GPT-3.5-turbo 模型是以一系列消息作为输入,并将模型生成的消息作为输出。
# Note: you need to be using OpenAI Python v0.27.0 for the code below to work
import openai
openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Who won the world series in 2020?"},
{"role": "assistant", "content": "The Los Angeles Dodgers won the World Series in 2020."},
{"role": "user", "content": "Where was it played?"}
]
)
消息是一个对象数组,其中每个对象都有一个角色,一共有三种角色。
- 系统 消息有助于设置助手的行为。在上面的例子中,助手被指示 “你是一个得力的助手”。
- 用户 消息有助于指导助手。 就是用户说的话,向助手提的问题。
- 助手 消息有助于存储先前的回复。这是为了持续对话,提供会话的上下文。
我们调用的ChatGPT的API是无状态的,意味着你需要自己去维持会话状态,保存上下文,每次请求的时候将之前的历史消息全部发过去,但是这里面有两个问题:
1. 为了建立持续会话,请求内容会越来越大,这些内容前后的关联关系并不是很大;
2. 语言模型以称为 tokens 的块读取文本,需要为为每个 token 支付费用,这样Token 费用很高。
3. 为了保证API调用的有效性,令牌总数必须是 低于模型的最大限制(gpt-3.5-turbo-0301 为 4096 个令牌)
我们借助OpenAI的embedding模型和自己的数据库,先在本地搜索数据获得上下文,然后在调用ChatGPT的API的时候,加上本地数据库中的相关内容,这样就可以让ChatGPT从你自己的数据集获得了上下文 ,再结合ChatGPT自己庞大的数据集给出一个更相关的理想结果。
| 整体架构
本文通过语义相似度匹配来实现一个问答系统,大致的构建过程:
- 获取某一特定领域里大量的带有答案的中文或者英文问题(本文将之称为标准问题集),把它变成CSV或者Json这样易于处理的格式,并且分成小块(chunks),每块不要超过8191个Tokens,因为这是OpenAI embeddings模型的输入长度限制。
- 使用OpenAI的embedding模型将这些问题转化为特征向量,需要将转换后的结果保存到本地数据库。 注意一般的关系型数据库是不支持这种向量数据的,需要使用向量数据库,这里使用Milvus,同时Milvus将给这些特征向量分配一个向量ID。
- 当然你保存的时候,可以把原始的文本块和数字向量一起存储,这样可以根据数字向量反向获得原始文本。也可以将这些代表问题的ID和其对应的答案存储在关系数据库SQL Server/Postgresql中, 这一步有点类似于全文索引中给数据建索引。
当用户提出一个问题时:
- 通过OpenAI的embedding模型将之转化为特征向量
- 在Milvus中对特征向量做相似度检索,得到与该问题最相似的标准问题的id, 拿到这个数字向量后,再去自己的数据库进行检索,那么就可以得到一个结果集,这个结果集会根据匹配的相似度有个打分,分越高说明越匹配, 这样就可以按照匹配度倒序返回一个相关结果。
- 在PostgreSQL得出对应的结果集。然后根据拿到的结果集,将结果集加入到请求ChatGPT的prompt中。
比如说用户提了一个问题:“What's the makers's schedule?”,从数据库中检索到相关的文字段落是:“What I worked on...”和"Taste for Makers...",那么最终的prompt看起来就像这样:
```js
[
{
role: "system",
content: "You are a helpful assistant that accurately answers queries using Paul Graham's essays. Use the text provided to form your answer, but avoid copying word-for-word from the essays. Try to use your own words when possible. Keep your answer under 5 sentences. Be accurate, helpful, concise, and clear."
},
{
role: "user",
content: `Use the following passages to provide an answer
to the query: "What's the makers's schedule?"
1. What I worked on...
2. Taste for Makers...`
}
]
```
这样ChatGPT在返回结果的时候,就会加上你的数据集。
系统交互图来自宝玉的微博(https://m.weibo.cn/status/4875446737175262)如下:
参考项目地址:https://github.com/mckaywrigley/paul-graham-gpt
在搭建之前您需要安装Milvus、SQL Server,具体安装步骤请参考官网。
1.数据准备
本文中的实验数据来自:https://github.com/SophonPlus/ChineseNlpCorpus。该项目下的FAQ问答系统中的金融数据集,我们从中一共整理了33万条数据。结合这组数据,我们可以快速搭建一个xx银行智能客服机器人。
2.生成特征向量
本系统使用OpenAI的embedding模型,使用该模型将问题库转化为特征向量,以用于后续的相似度检索。更多embedding 模型的内容请参考 https://platform.openai.com/docs/guides/embeddings/what-are-embeddings。
3.导入Milvus和SQL Server将上述产生的特征向量归一化处理后导入Milvus中存储,然后将Milvus返回的id以及该id对应的问题的答案导入SQL Server中。
4.获取答案用户输入一个问题,通过OpenAI的embedding产生特征向量后,在Milvus库中找出与之最相似的一个问题。本文采用的余弦距离来表示两个句子间的相似度,由于所有向量都进行了归一化,因此两个特征向量的余弦距离越接近1表示相似度也高越高。库中可能没有与用户给定问题比较相似的问题,所以在实践中我们可以设定了一个阈值0.9,当检索出来的最相似的距离小于该阈值时,则返回本系统未收录相关问题的提示。
5. 将结果集加入到请求ChatGPT的prompt中,向 OpenAI Chat completion API 发起请求,返回的结果中进一步进行无害化处理,返回给用户。
相关文章:
- Milvus 图形化管理工具 Attu 来袭!
- 基于云原生向量数据库 Milvus 的云平台设计实践
- Understanding Neural Network Embeddings