C#使用词嵌入向量与向量数据库为大语言模型(LLM)赋能长期记忆实现私域问答机器人落地
本文将探讨如何使用c#开发基于大语言模型的私域聊天机器人落地。大语言模型(Large Language Model,LLM 这里主要以chatgpt为代表的的文本生成式人工智能)是一种利用深度学习方法训练的能够生成人类语言的模型。这种模型可以处理大量的文本数据,并学习从中获得的模式,以预测在给定的文本上下文中最可能出现的下一个词。 在一般场景下LLM可以理解用户提出的问题并生成相应的回答。然而由于其训练时的数据限制LLM无法处理特定领域的问题。因此我们需要探索一种方法让LLM能够获取并利用长期记忆来提高问答机器人的效果。
这里我们主要是用到了词嵌入向量表示以及对应的向量数据库持久化存储,并且通过相似度计算得到长期记忆用于模型对特定领域的特定问题进行作答。词嵌入是自然语言处理(NLP)中的一个重要概念,它是将文本数据转换成数值型的向量,使得机器可以理解和处理。词嵌入向量可以捕获词语的语义信息,如相似的词语会有相似的词嵌入向量。而向量数据库则是一种专门用来存储和检索向量数据的数据库,它可以高效地对大量的向量进行相似性搜索。
目标:如何利用C#,词嵌入技术和向量数据库,使LLM实现长期记忆,以落地私域问答机器人。基于以上目的,我们需要完成以下几个步骤,从而实现将大语言模型与私域知识相结合来落地问答机器人。
一、私域知识的构建与词嵌入向量的转换
首先我们应该收集私域知识的文本语料,通过清洗处理得到高质量的语意文本。接着我们将这些文本通过调用OpenAI的词嵌入向量接口转化为词嵌入向量表示的数组
这里我们以ChatGLM为例,ChatGLM是清华大学开源的文本生成式模型,其模型开源于2023年。所以在ChatGPT的知识库中并不会包含相关的领域知识。当直接使用ChatGPT进行提问时,它的回答是这样的
由于只是演示这里我们只准备一条关于chatglm的知识。通过调用openai的接口,将它转化成词嵌入向量
原始语料:ChatGLM是一个开源的清华技术成果转化的公司智谱AI研发的支持中英双语的对话机器人它支持中英双语问答的对话语言模型,基于 General Language Model (GLM) 架构,具有 62 亿参数。结合模型量化技术,用户可以在消费级的显卡上进行本地部署(INT4 量化级别下最低只需 6GB 显存)。ChatGLM-6B 使用了和 ChatGLM 相同的技术,针对中文问答和对话进行了优化。经过约 1T 标识符的中英双语训练,辅以监督微调、反馈自助、人类反馈强化学习等技术的加持,62 亿参数的 ChatGLM-6B 已经能生成相当符合人类偏好的回答。
接着准备好一个openai的开发者key,我们将这段文本转化成词嵌入,这里我使用Betalgo.OpenAI.GPT3这个Nuget包,具体代码如下:
var embeddings = await new OpenAiOptions() { ApiKey = key }.Embeddings.CreateEmbedding(new EmbeddingCreateRequest()
{
InputAsList = inputs.ToList(),
Model = OpenAI.GPT3.ObjectModels.Models.TextEmbeddingAdaV2
});
return embeddings.Data.Select(x => x.Embedding).ToList();
这里的inputs就是你的句子数组,由于这个接口可以一次处理多条句子,所以这里可以传入句子数组来实现批处理。
接着这里会返回词嵌入向量结果,类似如下的list<double>:
[-0.0020597207,-0.012355088,0.0037828966,-0.032127112,-0.04815184,0.016633095,-0.01277577,........]
二、对词嵌入向量的理解和使用
接着我们需要使用一个向量数据库,这里由于只是演示,我就是用elasticsearch这样的支持向量存储的搜索引擎来保存。这里我使用NEST作为操作ES的包
首先我们构建一个对应的实体用于读写ES,这里的向量维度1536是openai的词嵌入向量接口的数组长度,如果是其他词嵌入技术,则需要按需定义维度
public class ChatGlmVector
{
public ChatGlmVector()
{
Id = Id ?? Guid.NewGuid().ToString();
}
[Keyword]
public string Id { get; set; } [Text]
public string Text { get; set; } [DenseVector(Dimensions = 1536)]
public IList<double> Vector { get; set; }
}
接着我们使用NEST创建一个索引名(IndexName)并存储刚才得到的文本和向量表示,这里的item就是上文的ChatGlmVector实例。
if (!elasticClient.Indices.Exists(IndexName).Exists)
elasticClient.Indices.Create(IndexName, c => c.Map<ChatGlmVector>(m => m.AutoMap()));
await elasticClient.IndexAsync(item, idx => idx.Index(IndexName));
三、用户问题的处理与相似度计算
用户问题的处理和知识处理相似,将用户问题转化成词嵌入向量。这里主要讲一下如何基于ES做相似度搜索,以下是原始的请求es的json表示
POST /my_index/_search
{
"size": 3, // 返回前3个最相似的文档
"query": {
"function_score": {
"query": {
"match_all": {}
},
"functions": [
{
"script_score": {
"script": {
"source": "def cosineSim = cosineSimilarity(params.queryVector, 'vector'); if (cosineSim > 0.8) return cosineSim; else return 0;",
"params": {
"queryVector": [1.0, 2.0, 3.0] // 要查询的向量
}
}
}
}
],
"boost_mode": "replace"
}
}
}
我们在c#中使用NEST的表示可以通过如下代码来完成,这里我们以0.8作为一个阈值来判断相似度最低必须高于这个数字,否则可以判断用户问题与知识没有关联性。当然这个值可以根据实际情况调整。
var scriptParams = new Dictionary<string, object>
{
{"queryVector", new double[]{1.0, 2.0, 3.0}}
}; var script = new InlineScript("def cosineSim = cosineSimilarity(params.queryVector, 'vector'); if (cosineSim > 0.8) return cosineSim; else return 0;")
{
Params = scriptParams
}; var searchResponse = client.Search<object>(s => s
.Size(3)
.Query(q => q
.FunctionScore(fs => fs
.Query(qq => qq
.MatchAll()
)
.Functions(fu => fu
.ScriptScore(ss => ss
.Script(sc => script)
)
)
.BoostMode(FunctionBoostMode.Replace)
)
)
);
四、构建精巧的prompt与OpenAI的chat接口的使用
这里我们就可以通过一些混合一些提示+长记忆+用户问题作为完整的prompt喂给chatgpt得到回答
return (await GetOpenAIService().ChatCompletion.CreateCompletion(new ChatCompletionCreateRequest()
{
Messages=new List<ChatMessage>() {
ChatMessage.FromUser("你是一个智能助手,你需要根据下面的事实依据回答问题。如果用户输入不在事实依据范围内,请说\"抱歉,这个问题我不知道。\""),
ChatMessage.FromUser($"事实依据:{这里需要从ES查询出相似度最高的文本作为LLM的长期记忆}"),
ChatMessage.FromUser($"用户输入:{这里是用户的原始问题}")
},
Model = OpenAI.GPT3.ObjectModels.Models.ChatGpt3_5Turbo
})).Choices.FirstOrDefault().Message;
当我们使用新的提示词提问后,chatgpt就可以准确的告诉你相关的回答:
写在最后
ChatGPT的出现已经彻底改变了这个世界,作为一个开发人员,我们能做的只能尽量跟上技术的脚步。在这个结合C#、词嵌入技术和向量数据库将大语言模型成功应用到私域问答机器人的案例中只是大语言模型落地的冰山一角,这仅仅是开始,我们还有许多可能性等待探索........
C#使用词嵌入向量与向量数据库为大语言模型(LLM)赋能长期记忆实现私域问答机器人落地的更多相关文章
- 词嵌入向量WordEmbedding
词嵌入向量WordEmbedding的原理和生成方法 WordEmbedding 词嵌入向量(WordEmbedding)是NLP里面一个重要的概念,我们可以利用WordEmbedding将一个单 ...
- 词向量 词嵌入 word embedding
词嵌入 word embedding embedding 嵌入 embedding: 嵌入, 在数学上表示一个映射f:x->y, 是将x所在的空间映射到y所在空间上去,并且在x空间中每一个x有y ...
- 词向量表示:word2vec与词嵌入
在NLP任务中,训练数据一般是一句话(中文或英文),输入序列数据的每一步是一个字母.我们需要对数据进行的预处理是:先对这些字母使用独热编码再把它输入到RNN中,如字母a表示为(1, 0, 0, 0, ...
- cips2016+学习笔记︱简述常见的语言表示模型(词嵌入、句表示、篇章表示)
在cips2016出来之前,笔者也总结过种类繁多,类似词向量的内容,自然语言处理︱简述四大类文本分析中的"词向量"(文本词特征提取)事实证明,笔者当时所写的基本跟CIPS2016一 ...
- DeepLearning.ai学习笔记(五)序列模型 -- week2 自然语言处理与词嵌入
一.词汇表征 首先回顾一下之前介绍的单词表示方法,即one hot表示法. 如下图示,"Man"这个单词可以用 \(O_{5391}\) 表示,其中O表示One_hot.其他单词同 ...
- DLNg序列模型第二周NLP与词嵌入
1.使用词嵌入 给了一个命名实体识别的例子,如果两句分别是“orange farmer”和“apple farmer”,由于两种都是比较常见的,那么可以判断主语为人名. 但是如果是榴莲种植员可能就无法 ...
- NLP领域的ImageNet时代到来:词嵌入「已死」,语言模型当立
http://3g.163.com/all/article/DM995J240511AQHO.html 选自the Gradient 作者:Sebastian Ruder 机器之心编译 计算机视觉领域 ...
- 2.keras实现-->字符级或单词级的one-hot编码 VS 词嵌入
1. one-hot编码 # 字符集的one-hot编码 import string samples = ['zzh is a pig','he loves himself very much','p ...
- ng-深度学习-课程笔记-16: 自然语言处理与词嵌入(Week2)
1 词汇表征(Word representation) 用one-hot表示单词的一个缺点就是它把每个词孤立起来,这使得算法对词语的相关性泛化不强. 可以使用词嵌入(word embedding)来解 ...
- [DeeplearningAI笔记]序列模型2.10词嵌入除偏
5.2自然语言处理 觉得有用的话,欢迎一起讨论相互学习~Follow Me 2.10词嵌入除偏 Debiasing word embeddings Bolukbasi T, Chang K W, Zo ...
随机推荐
- mysql对汉字排序
问题: 编写order by排序时,如果字段是汉字的话,排序会失效. 如: SELECT * FROM user ORDER BY age ASC,username DESC 此时按照username ...
- linux 打包各种后缀的命令
01-.tar格式解包:[*******]$ tar xvf FileName.tar打包:[*******]$ tar cvf FileName.tar DirName(注:tar是打包,不是压缩! ...
- win10试安装docker部署hyperf
一:部署虚拟机,这里使用的win系统带的Hyper-V虚拟机,其它虚拟机也行 1.win+R打开命令行 2.安装Hyper-V . 失败放弃安装,选择其它吧 3.win10安装VMware 这里参考 ...
- 【VSC】ERROR:GDB exited unexpectedly.
[VSC]ERROR:GDB exited unexpectedly. 记录一次调试所遇bug的查找历程 问题描述 ERROR: GDB exited unexpectedly. Debugging ...
- 服务器资源监测脚本(网卡、MEM、CPU)
#-*- coding: utf-8 -*- #!/usr/bin/python ''' 用法: sar [ 选项 ] [ <时间间隔> [ <次数> ] ] 主选项和报告: ...
- 新版TinyCore Linux系统安装
1.设置软件仓库源echo "https://mirrors.163.com/tinycorelinux">/opt/tcemirror 2.安装启动加载器及其依赖tce-l ...
- Spring Bean 的生命周期(详细解读)
Spring Bean 的生命周期简单易懂.在一个 bean 实例被初始化时,需要执行一系列的初始化操作以达到可用的状态.同样的,当一个 bean 不再被调用时需要进行相关的析构操作,并从 bean ...
- Linux Redhat ens33不显示IP问题
[第一步]:查看系统网卡设备 : ip addr show
- C++内存重叠
内存重叠是指在内存中存在两个或多个区域,它们的地址范围有交叉部分.在 C++ 中,内存重叠可能会导致程序出现不可预期的行为,因此我们需要了解它的原因和如何避免. 内存重叠的原因 内存重叠的主要原因是指 ...
- 音质效果不错的Pcie声卡之CM8828听歌声卡
CM8828芯片是cmedia骅讯公司生产的,采用这个芯片的声卡价格不一,便宜的100多,贵一点的500多.价位在100多买到这款声卡还是比较实惠的,再高一点的声卡都是堆料的.CM8828声卡是原生的 ...