搭建知识库-DataWhale笔记

词向量及向量知识库介绍

词向量

词向量定义

在机器学习和自然语言处理(NLP)中,词向量(Embeddings)是一种将非结构化数据,如单词、句子或者整个文档,转化为实数向量的技术。这些实数向量可以被计算机更好地理解和处理。

嵌入背后的主要想法是,相似或相关的对象在嵌入空间中的距离应该很近。

词向量优势

在RAG(Retrieval Augmented Generation,检索增强生成)方面词向量的优势主要有两点:

  • 词向量比文字更适合检索。当我们在数据库检索时,如果数据库存储的是文字,主要通过检索关键词(词法搜索)等方法找到相对匹配的数据,匹配的程度是取决于关键词的数量或者是否完全匹配查询句的;但是词向量中包含了原文本的语义信息,可以通过计算问题与数据库中数据的点积、余弦距离、欧几里得距离等指标,直接获取问题与数据在语义层面上的相似度;

  • 词向量比其它媒介的综合信息能力更强,当传统数据库存储文字、声音、图像、视频等多种媒介时,很难去将上述多种媒介构建起关联与跨模态的查询方法;但是词向量却可以通过多种向量模型将多种数据映射成统一的向量形式。

这里补充一下RAG的介绍

RAG(Retrieval Augmented Generation,检索增强生成)是一种结合了检索(Retrieval)和生成(Generation)的人工智能模型架构,旨在提高文本生成任务的性能和相关性。这种方法通过先检索相关信息,然后基于这些信息生成文本,从而允许模型在生成回答、文章或其他类型的文本内容时,利用大量的外部知识。RAG模型通常用于需要广泛背景知识的任务,如问答系统、内容推荐、文章撰写等。

一般构建词向量的方法

在搭建 RAG 系统时,我们往往可以通过使用嵌入模型来构建词向量,我们可以选择:

  • 使用各个公司的 Embedding API;

  • 在本地使用嵌入模型将数据构建为词向量。

向量数据库

向量数据库定义

向量数据库是用于高效计算和管理大量向量数据的解决方案。向量数据库是一种专门用于存储和检索向量数据(embedding)的数据库系统。它与传统的基于关系模型的数据库不同,它主要关注的是向量数据的特性和相似性。

在向量数据库中,数据被表示为向量形式,每个向量代表一个数据项。这些向量可以是数字、文本、图像或其他类型的数据。向量数据库使用高效的索引和查询算法来加速向量数据的存储和检索过程。

使用Embedding API(OpenAI)

我这里使用的是OpenAI的API,

GPT embedding mode使用的是text-embedding-3-small

def openai_embedding(text: str, model: str=None):
    # 获取环境变量 OPENAI_API_KEY
    api_key=os.environ['OPENAI_API_KEY']
    client = OpenAI(api_key=api_key)
​
    # embedding model:'text-embedding-3-small', 'text-embedding-3-large', 'text-embedding-ada-002'
    if model == None:
        model="text-embedding-3-small"
​
    response = client.embeddings.create(
        input=text,
        model=model
    )
    return response
​
response = openai_embedding(text='要生成 embedding 的输入文本,字符串形式。')

API返回格式为json,除object向量类型外还有存放数据的data、embedding model 型号model以及本次 token 使用情况usage等数据,具体如下所示:

{
  "object": "list",
  "data": [
    {
      "object": "embedding",
      "index": 0,
      "embedding": [
        -0.006929283495992422,
        ... (省略)
        -4.547132266452536e-05,
      ],
    }
  ],
  "model": "text-embedding-3-small",
  "usage": {
    "prompt_tokens": 5,
    "total_tokens": 5
  }
}

我们可以调用response的object来获取embedding的类型。

print(f'返回的embedding类型为:{response.object}')Copy to clipboardErrorCopied
返回的embedding类型为:listCopy to clipboardErrorCopied

embedding存放在data中,我们可以查看embedding的长度及生成的embedding。

print(f'embedding长度为:{len(response.data[0].embedding)}')
print(f'embedding(前10)为:{response.data[0].embedding[:10]}')Copy to clipboardErrorCopied
embedding长度为:1536
embedding(前10)为:[0.03884002938866615, 0.013516489416360855, -0.0024250170681625605, -0.01655769906938076, 0.024130908772349358, -0.017382603138685226, 0.04206013306975365, 0.011498954147100449, -0.028245486319065094, -0.00674333656206727]Copy to clipboardErrorCopied

我们也可以查看此次embedding的模型及token使用情况。

print(f'本次embedding model为:{response.model}')
print(f'本次token使用情况为:{response.usage}')Copy to clipboardErrorCopied
本次embedding model为:text-embedding-3-small
本次token使用情况为:Usage(prompt_tokens=12, total_tokens=12)

数据处理

数据读取

pdf文档

我们可以使用 LangChain 的 PyMuPDFLoader 来读取知识库的 PDF 文件。PyMuPDFLoader 是 PDF 解析器中速度最快的一种,结果会包含 PDF 及其页面的详细元数据,并且每页返回一个文档。

from langchain.document_loaders.pdf import PyMuPDFLoader
​
# 创建一个 PyMuPDFLoader Class 实例,输入为待加载的 pdf 文档路径
loader = PyMuPDFLoader("../../data_base/knowledge_db/pumkin_book/pumpkin_book.pdf")
​
# 调用 PyMuPDFLoader Class 的函数 load 对 pdf 文件进行加载
pdf_pages = loader.load()

文档加载后储存在 pages 变量中:

  • page 的变量类型为 List

  • 打印 pages 的长度可以看到 pdf 一共包含多少页

print(f"载入后的变量类型为:{type(pdf_pages)},",  f"该 PDF 一共包含 {len(pdf_pages)} 页")Copy to clipboardErrorCopied
载入后的变量类型为:<class 'list'>, 该 PDF 一共包含 196 页Copy to clipboardErrorCopied

page 中的每一元素为一个文档,变量类型为 langchain_core.documents.base.Document, 文档变量类型包含两个属性

  • page_content 包含该文档的内容。

  • meta_data 为文档相关的描述性数据。

pdf_page = pdf_pages[1]
print(f"每一个元素的类型:{type(pdf_page)}.", 
    f"该文档的描述性数据:{pdf_page.metadata}", 
    f"查看该文档的内容:\n{pdf_page.page_content}", 
    sep="\n------\n")
每一个元素的类型:<class 'langchain_core.documents.base.Document'>.
------
该文档的描述性数据:{'source': './data_base/knowledge_db/pumkin_book/pumpkin_book.pdf', 'file_path': './data_base/knowledge_db/pumkin_book/pumpkin_book.pdf', 'page': 1, 'total_pages': 196, 'format': 'PDF 1.5', 'title': '', 'author': '', 'subject': '', 'keywords': '', 'creator': 'LaTeX with hyperref', 'producer': 'xdvipdfmx (20200315)', 'creationDate': "D:20230303170709-00'00'", 'modDate': '', 'trapped': ''}
------
查看该文档的内容:
前言
……省略
md文档
from langchain.document_loaders.markdown import UnstructuredMarkdownLoader

loader = UnstructuredMarkdownLoader("../../data_base/knowledge_db/prompt_engineering/1. 简介 Introduction.md")
md_pages = loader.load()

读取出来的对象和pf文档读出来的是一致的,这里不再赘述

数据清理

我们期望知识库的数据尽量是有序的、优质的、精简的,因此我们要删除低质量的、甚至影响理解的文本数据。

不同的文本数据情况不同,所要采取的清理方法也不同,例如上文中读取的pdf文件不仅将一句话按照原文的分行添加了换行符\n,也在原本两个符号中间插入了\n,我们可以使用正则表达式匹配并删除掉\n

import re
pattern = re.compile(r'[^\u4e00-\u9fff](\n)[^\u4e00-\u9fff]', re.DOTALL)
pdf_page.page_content = re.sub(pattern, lambda match: match.group(0).replace('\n', ''), pdf_page.page_content)
print(pdf_page.page_content)

文档分割

由于单个文档的长度往往会超过模型支持的上下文,导致检索得到的知识太长超出模型的处理能力,因此,在构建向量知识库的过程中,我们往往需要对文档进行分割,将单个文档按长度或者按固定的规则分割成若干个 chunk,然后将每个 chunk 转化为词向量,存储到向量数据库中。

在检索时,我们会以 chunk 作为检索的元单位,也就是每一次检索到 k 个 chunk 作为模型可以参考来回答用户问题的知识,这个 k 是我们可以自由设定的。

Langchain 中文本分割器都根据 chunk_size (块大小)和 chunk_overlap (块与块之间的重叠大小)进行分割。

  • chunk_size 指每个块包含的字符或 Token (如单词、句子等)的数量

  • chunk_overlap 指两个块之间共享的字符数量,用于保持上下文的连贯性,避免分割丢失上下文信息

Langchain 提供多种文档分割方式,区别在怎么确定块与块之间的边界、块由哪些字符/token组成、以及如何测量块大小

  • RecursiveCharacterTextSplitter(): 按字符串分割文本,递归地尝试按不同的分隔符进行分割文本。

  • CharacterTextSplitter(): 按字符来分割文本。

  • MarkdownHeaderTextSplitter(): 基于指定的标题来分割markdown 文件。

  • TokenTextSplitter(): 按token来分割文本。

  • SentenceTransformersTokenTextSplitter(): 按token来分割文本

  • Language(): 用于 CPP、Python、Ruby、Markdown 等。

  • NLTKTextSplitter(): 使用 NLTK(自然语言工具包)按句子分割文本。

  • SpacyTextSplitter(): 使用 Spacy按句子的切割文本。

注:如何对文档进行分割,其实是数据处理中最核心的一步,其往往决定了检索系统的下限。但是,如何选择分割方式,往往具有很强的业务相关性——针对不同的业务、不同的源数据,往往需要设定个性化的文档分割方式。

搭建并使用向量数据库

明天补充

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/566142.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Unet网络架构讲解(从零到一,逐行编写并重点讲解数据维度变化)

&#x1f4da;博客主页&#xff1a;knighthood2001 ✨公众号&#xff1a;认知up吧 &#xff08;目前正在带领大家一起提升认知&#xff0c;感兴趣可以来围观一下&#xff09; &#x1f383;知识星球&#xff1a;【认知up吧|成长|副业】介绍 ❤️感谢大家点赞&#x1f44d;&…

大珩PPT助手一键颜色设置

大珩PPT助手最新推出的一键设置文字颜色和背景色功能&#xff0c;为用户在创建演示文稿时带来了更便捷、高效的体验。这一功能使用户能够轻松调整演示文稿中文字的颜色和幻灯片的背景色&#xff0c;以满足不同场合和主题的需要。 以下是该功能的几个关键特点和优势&#xff1a…

恶意游戏并非传说:它们甚至在 Steam 上也存在

三月份&#xff0c;玩家们在在线平台上遇到了热门游戏的假克隆。在受害者中&#xff0c;有一位用户购买了一款假冒游戏《最后纪元》&#xff08;Last Epoch&#xff09;&#xff0c;但玩了几个小时后却出现了 "蓝屏死机"。 在联系了技术支持后&#xff0c;Steam 将钱…

代码随想录算法训练营Day6 | 242.有效的字母异位词 ●349. 两个数组的交集 ● 202. 快乐数● 1. 两数之和

基础&#xff1a; 1.哈希表是根据关键值进行直接访问的数据结构&#xff0c;时间复杂度是O(1)&#xff0c;也就是通过数组的索引下标&#xff0c;直接访问数组中的元素哈希表的作用就是用来快速判断一个元素是否出现在集合里。 2.常见的哈希结构&#xff1a; 数组set &#…

CB2-2CARD之Debian(Bookworm)安装Gnome看CCTV

CB2-2CARD之Debian&#xff08;Bookworm&#xff09;安装Gnome看CCTV 1. 源由2. 需求3. Debian系统桌面3.1 系统安装3.2 磁盘扩容3.3 系统更新3.4 Gnome安装 4. 测试4.1 CCTV网页测试4.2 系统空闲测试4.3 Firefox CPU占用率测试 5. 总结 1. 源由 近些年来&#xff0c;随着国内…

arm架构,django4.2.7适配达梦8数据库

【Python相关包版本信息】 Django 4.2.7 django-dmPython 3.1.7 dmPython 2.5.5 【达梦数据库版本】 DM Database Server 64 V8 DB Version: 0x7000c 适配过程中发现的问题如下&#xff1a; 错误一&#xff1a;d…

Git | 分支管理

Git | 分支管理 文章目录 Git | 分支管理1、理解分支2、创建分支&&切换分支3、合并分支4、删除分支5、合并冲突6、分支管理策略合并分支模式实际工作中分支策略bug分支删除临时分支 1、理解分支 分支就类似分身。 在版本回退中&#xff0c;每次提交Git都会将修改以git…

快速部署stable diffusion@Ubuntu

Stable Diffusion可以根据文本描述生成相关的图像&#xff0c;是当前最热门的文生图模型。 在Ubuntu下&#xff0c;可以选择快速安装&#xff0c;或者手动一步步安装。 快速安装 使用文档中的方法&#xff0c;先下载一个sh文件&#xff0c;然后执行这个文件&#xff0c;就自动…

ChatGPT助力测试领域!探索人工智能编写测试用例的新前景

简介 测试用例是测试人员的核心工作内容&#xff0c;是测试人员思想的“实现类”&#xff0c;其充分体现了测试的思路&#xff0c;可以为后续的测试行为提供指导&#xff0c;是测试人员了解业务的重要根据和质量之根本。如果测试用例设计得不完成&#xff0c;出现了遗漏&#x…

git merge 和 git rebese的区别

git merge 和 git rebese的区别 拉取分支和合并代码会涉及两种选择&#xff0c;git merge 和 git rebase&#xff1a; rebase&#xff1a;变基&#xff0c;会有一个干净的分支&#xff0c;但是对于记录来源不够清楚merge&#xff1a;合并&#xff0c;git 分支看起来比较混乱&…

java-Arrays

一、Arrays的概述 Arrays是操作数组的工具类 二、Arrays的常用方法 Arrays的常用方法基本上都被static静态修饰&#xff0c;因此在使用这些方法时&#xff0c;可以直接通过类名调用 1.toString 语法&#xff1a;Arrays.toString(数组) 用于将数组的元素转换为一个字符串&a…

(mac)Prometheus监控之Node_exporter(CPU、内存、磁盘、网络等)

完整步骤 1.启动 Prometheus 普罗米修斯 prometheus --config.file/usr/local/etc/prometheus.yml 浏览器访问 http://localhost:9090/targets 2.启动Node_exporter node_exporter 访问&#xff1a;http://localhost:9100 3.启动grafana brew services start grafana 访问…

Redis - Redisson tryLock 函数参数分析

这里有三个参数&#xff1a; waitTime&#xff1a;等待时间leaseTime&#xff1a;超时施放时间TimeUnit&#xff1a;时间单位 等待时间 如果 ABC… 多个线程去抢夺一把锁&#xff0c;A 成功了&#xff0c;如果设置的是 -1&#xff0c;那么 BCD... 就不等待&#xff0c;直接返…

计算机工作者学习平台

给大家分享了几个非常有用的学习平台&#xff0c;可以作为参考&#xff0c;具体为&#xff1a; 1.中国大学MOOC 中国大学MOOC_优质在线课程学习平台 2.牛客 牛客网 - 找工作神器|笔试题库|面试经验|实习招聘内推&#xff0c;求职就业一站解决_牛客网 3.CSDN https://www…

气压计LPS22HB开发(1)----轮询获取气压计数据

气压计LPS22HB开发----1.轮询获取气压计数据 概述硬件准备视频教学样品申请源码下载产品特性通信模式速率生成STM32CUBEMX串口配置IIC配置CS和SA0地址设置串口重定向参考程序SA0设置模块地址获取ID复位操作BDU设置设置低通滤波器设置速率轮询读取数据演示 概述 最近在弄ST的课…

[Algorithm][二分查找][山峰数组的峰顶索引][寻找峰值][寻找旋转排序数组中的最小值][0~n-1中缺失的数字]详细讲解

目录 1.山脉数组的峰顶索引1.题目链接2.算法原理详解3.代码实现 2.寻找峰值1.题目链接2.算法原理详解3.代码实现 3.寻找旋转排序数组中的最小值1.题目链接2.算法原理详解3.代码实现 4.0〜n-1 中缺失的数字1.题目链接2.算法原理详解3.代码实现 1.山脉数组的峰顶索引 1.题目链接…

TaskWeaver使用记录

TaskWeaver使用记录 1. 基本介绍2. 总体结构与流程3. 概念细节3.1 Project3.2 Session3.3 Memory3.4 Conversation3.5 Round3.6 Post3.7 Attachment3.8 Plugin3.9 Executor 4. 代码特点5. 使用过程5.1 api调用5.2 本地模型使用5.3 添加插件 6. 存在的问题与使用体验6.1 判别模型…

模板初阶

泛型编程&#xff1a; 泛型编程&#xff1a;编写与类型无关的通用代码&#xff0c;模板是泛型编程的基础 class Test { public:void Swap(int& left, int& right){int tmp left;left right;right tmp;}void Swap(double& left, double& right){double tmp…

一句话或一张图讲清楚系列之——ISERDESE2的原理

主要参考&#xff1a; https://blog.csdn.net/weixin_50810761/article/details/137383681 xilinx原语详解及仿真——ISERDESE2 作者&#xff1a;电路_fpga https://blog.csdn.net/weixin_45372778/article/details/122036112 Xilinx ISERDESE2应用笔记及仿真实操 作者&#x…

鸿蒙OpenHarmony【小型系统编写“Hello World”程序】 (基于Hi3516开发板)

编写“Hello World”程序 下方将展示如何在单板上运行第一个应用程序&#xff0c;其中包括新建应用程序、编译、烧写、运行等步骤&#xff0c;最终输出“Hello World&#xff01;”。 前提条件 已参考[创建工程并获取源码]&#xff0c;创建Hi3516开发板的源码工程。 鸿蒙开发…