知识库的创建(5) - FaissKBService

news2025/2/27 14:16:56

文章目录

  • 前言
  • 一、追踪代码
  • 二、源码分析
  • 三、详解kb_faiss_pool类的load_vector_store
    • 1. 方法定义
    • 2. 方法实现
    • 3. 优点
    • 4. 再看看self.new_vector_store
  • 总结


前言

上一篇文章,我们追到了这里,了解了kb是通过KBServiceFactory产生的一个对象,而且这个对象根据类型不同,分别会实例化出类似 FaissKBService和ChromaKBService这样的向量数据库对象。
在这里插入图片描述
之前在向量索引的文章里,我们讲过Faiss和Chroma这两种向量数据库,并且简易写了运用他们的代码。今天我们看看langchain-chatchat是 怎么封装的


一、追踪代码

沿着kb_doc_api.py 的update_docs 往下,我们可以看到如图所示的地方在使用kb里的方法
在这里插入图片描述
追踪kb.update_doc(kb_file, not_refresh_vs_cache=True) ,点进去
在这里插入图片描述
可以看到,实际上是调用了 FaissKBService继承的KBService里的 update_doc方法,它往下会调用 FaissKBService继承的KBService的add_doc

继续追踪,可以看到这个方法调用了 do_add_doc
在这里插入图片描述
do_add_doc 是 一个抽象方法,它需要被实现。那么我们进入FaissKBService 看看是怎么实现它的
在这里插入图片描述
我们选择方框所示的一条
在这里插入图片描述

二、源码分析

根据上面的步骤,我们可以看到如下的代码

def do_add_doc(self,
               docs: List[Document],
               **kwargs,
               ) -> List[Dict]:
    data = self._docs_to_embeddings(docs) # 将向量化单独出来可以减少向量库的锁定时间

    with self.load_vector_store().acquire() as vs:
        ids = vs.add_embeddings(text_embeddings=zip(data["texts"], data["embeddings"]),
                                metadatas=data["metadatas"],
                                ids=kwargs.get("ids"))
        if not kwargs.get("not_refresh_vs_cache"):
            vs.save_local(self.vs_path)
    doc_infos = [{"id": id, "metadata": doc.metadata} for id, doc in zip(ids, docs)]
    torch_gc()
    return doc_infos

1. 把文档制作成向量

data = self._docs_to_embeddings(docs)

这一步,调用选择的embedding模型,将docs转换成向量数据

2.with self.load_vector_store().acquire() as vs:
这一段就很眼熟了,我们之前研究过with的用法,它的主要作用就是可以让某些操作,例如清零缓存关闭连接的操作可以在后续自动执行。
这里的self.load_vector_store 是用来创建或读取向量对象的。
它的代码如下,调用了kb_faiss_pool的load_vector_store

def load_vector_store(self) -> ThreadSafeFaiss:
    return kb_faiss_pool.load_vector_store(kb_name=self.kb_name,
                                           vector_name=self.vector_name,
                                           embed_model=self.embed_model)

acquire()里有with需要的try和finally,还记得吗?with代码块会让代码阻塞在yield 这一行,finally就是with代码块执行完成之后要做的事情。这里就是 先把对象给到 vs变量,然后在代码块执行之后做一个解锁的操作。

................
    yield self._obj
finally:
    if log_verbose:
        logger.info(f"{owner} 结束操作:{self.key}{msg}")
    self._lock.release()

3. vs.add_embeddings
将上面将转换成向量数据的知识存入向量数据库里

三、详解kb_faiss_pool类的load_vector_store

KBFaissPool 是一个继承自 _FaissPool 的类,用于处理知识库中的向量存储操作。它的主要功能是加载或创建特定知识库的向量存储。

1. 方法定义

load_vector_store 方法的定义如下:

def load_vector_store(
        self,
        kb_name: str,
        vector_name: str = None,
        create: bool = True,
        embed_model: str = EMBEDDING_MODEL,
        embed_device: str = embedding_device(),
) -> ThreadSafeFaiss:

这个方法接受五个参数:

  • kb_name: 知识库的名称,是一个必需的字符串参数。
  • vector_name: 向量存储的名称,是一个可选字符串参数。如果未提供,则使用 embed_model 作为默认值。
  • create: 一个布尔值,指示是否在向量存储不存在时创建一个新的向量存储,默认值为 True
  • embed_model: 嵌入模型的名称,默认值为 EMBEDDING_MODEL
  • embed_device: 嵌入设备,默认值为调用 embedding_device() 的结果。

2. 方法实现

方法实现的主要步骤如下:

1) 获取互斥锁:
python self.atomic.acquire()
这是为了确保在多线程环境下对共享资源的安全访问。

2) 确定 vector_name:
python vector_name = vector_name or embed_model
如果 vector_name 未提供,则使用 embed_model 作为默认值。

3) 检查缓存:
python cache = self.get((kb_name, vector_name)) if cache is None:
检查是否已有对应的向量存储。如果没有,则创建一个新的 ThreadSafeFaiss 对象。

4) 初始化向量存储:
python item = ThreadSafeFaiss((kb_name, vector_name), pool=self) self.set((kb_name, vector_name), item) with item.acquire(msg="初始化"): self.atomic.release() logger.info(f"loading vector store in '{kb_name}/vector_store/{vector_name}' from disk.") vs_path = get_vs_path(kb_name, vector_name)
创建并设置一个新的 ThreadSafeFaiss 对象,并记录日志。

5) 加载或创建向量存储:
python if os.path.isfile(os.path.join(vs_path, "index.faiss")): embeddings = self.load_kb_embeddings(kb_name=kb_name, embed_device=embed_device, default_embed_model=embed_model) vector_store = FAISS.load_local(vs_path, embeddings, normalize_L2=True, distance_strategy="METRIC_INNER_PRODUCT") elif create: if not os.path.exists(vs_path): os.makedirs(vs_path) vector_store = self.new_vector_store(embed_model=embed_model, embed_device=embed_device) vector_store.save_local(vs_path) else: raise RuntimeError(f"knowledge base {kb_name} not exist.")
- 如果向量存储文件存在,加载现有的向量存储。
- 如果向量存储文件不存在且 createTrue,则创建一个新的向量存储。
- 如果向量存储文件不存在且 createFalse,则抛出错误。

6) 设置和完成加载:
python item.obj = vector_store item.finish_loading()

设置向量存储对象,并标记加载完成。

7) 返回结果:
python return self.get((kb_name, vector_name))

返回相应的向量存储对象。

3. 优点

load_vector_store 方法的设计非常合理,确保了在多线程环境下对向量存储的安全加载和创建。它通过检查缓存来避免重复加载,并提供了创建新向量存储的功能。该方法对于需要高效管理大规模知识库向量存储的应用场景非常适用。

4. 再看看self.new_vector_store

这句话的 self指代的是如下一段

class _FaissPool(CachePool):
    def new_vector_store(
        self,
        embed_model: str = EMBEDDING_MODEL,
        embed_device: str = embedding_device(),
    ) -> FAISS:
        embeddings = EmbeddingsFunAdapter(embed_model)
        doc = Document(page_content="init", metadata={})
        vector_store = FAISS.from_documents([doc], embeddings, normalize_L2=True,distance_strategy="METRIC_INNER_PRODUCT")
        ids = list(vector_store.docstore._dict.keys())
        vector_store.delete(ids)
        return vector_store

这里面最重要的就是 下面这一句

vector_store = FAISS.from_documents([doc], embeddings, normalize_L2=True, distance_strategy="METRIC_INNER_PRODUCT")

这句话的作用是利用 FAISS 库创建一个新的向量存储,并将一个文档的向量嵌入存储在其中。
关键组成部分

1) FAISS.from_documents:

  • 这是 FAISS 库中的一个方法,用于从文档创建向量存储。
  • FAISS(Facebook AI Similarity Search)是一种高效的相似度搜索库,广泛应用于向量搜索和相似度匹配任务。

2) [doc]:

  • 这是一个包含单个文档的列表。doc 通常是一个表示文本或其他信息的对象。
  • 通过将文档放入列表中,可以传递一个或多个文档以创建向量存储。

3) embeddings:

  • 这是用于将文档转换为向量的嵌入模型。
  • 嵌入模型可以将文本或其他信息表示为高维向量,便于进行相似度计算和搜索。

4) normalize_L2=True:

  • 这是一个参数,指示是否对向量进行 L2 正则化。
  • L2 正则化可以将向量的长度归一化,使得向量的范数为 1,有助于提高相似度计算的准确性。

5) distance_strategy="METRIC_INNER_PRODUCT":

  • 这是一个参数,指定向量之间距离的计算策略。
  • "METRIC_INNER_PRODUCT" 表示使用内积作为相似度度量方式,内积可以高效计算向量之间的相似度。

总结

通过上面的封装,我们可以大致了解到langchain-chatchat的封装风格,因为代码呈树状分支一层一层的往下调用,所以不太容易看明白。大家可以多看几次

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机网络-BGP路由优选原则八

一、优选到Next_Hop的IGP度量值最小的路由。 查看BGP路由详细信息: [AR1]dis bgp routing-table 192.168.1.0BGP local router ID : 1.1.1.1Local AS number : 100Paths: 2 available, 1 best, 1 selectBGP routing table entry information of 192.168.1.0/24:Fr…

ADOP带你了解:数据中心的高速互联解决方案

随着大语言模型和AIGC的飞速发展,数据中心对于高速、高可靠性的网络连接需求日益增长。ADOP系列产品正是在这样的背景下应运而生,为现代数据中心提供了全面的连接解决方案。 ADOP系列产品概览 ADOP系列产品旨在为云、高性能计算、Web 2.0、企业、电信、…

Python | Leetcode Python题解之第167题两数之和II-输入有序数组

题目&#xff1a; 题解&#xff1a; class Solution:def twoSum(self, numbers: List[int], target: int) -> List[int]:low, high 0, len(numbers) - 1while low < high:total numbers[low] numbers[high]if total target:return [low 1, high 1]elif total <…

吴恩达机器学习 第二课 week4 决策树

目录 01 学习目标 02 实现工具 03 问题描述 04 构建决策树 05 总结 01 学习目标 &#xff08;1&#xff09;理解“熵”、“交叉熵&#xff08;信息增益&#xff09;”的概念 &#xff08;2&#xff09;掌握决策树的构建步骤与要点 02 实现工具 &#xff08;1&#xff09;…

格式化数据恢复,4个方法,恢复文件好帮手

“由于电脑病毒的原因&#xff0c;我不得已将磁盘格式化了&#xff0c;不知道大家有没有方法恢复格式化的数据呢&#xff1f;” 在数字时代的浪潮中&#xff0c;我们每个人的生活都如同被数据编织成的一幅幅绚丽画卷。然而&#xff0c;有时这幅画卷可能会因为一次意外的格式化操…

【科研基础】通感一体化讲座

通信和感知在硬件结构上相似&#xff0c;高效地利用资源&#xff0c;实现相互的增益&#xff1b; 感知是基于不同的任务&#xff0c;比如

Python联动Mysql

首先配置pip源(不然在安装库的时候会很慢!!!) pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/安装必要库: mysql.connector MySQL 连接器/ODBC 是 MySQL ODBC 驱动程序&#xff08;以前称为 MyODBC 驱动程序&#xff09;系列的名称&#xff0c;它使…

计算机网络:运输层 - TCP 流量控制 拥塞控制

计算机网络&#xff1a;运输层 - TCP 流量控制 & 拥塞控制 滑动窗口流量控制拥塞控制慢开始算法拥塞避免算法快重传算法快恢复算法 滑动窗口 如图所示&#xff1a; 在TCP首部中有一个窗口字段&#xff0c;该字段就基于滑动窗口来辅助流量控制和拥塞控制。所以我们先讲解滑…

kotlin集合框架

1、集合框架的接口类型对比 2、不可变和可变List fun main() {// 不可变List - 不能删除或添加元素val intList: List<Int> listOf(1,2,3)intList.forEach{println(it) // 1 2 3}println("")// 可变List - 可以删除或添加元素val mutableList mutableListO…

为什么要学Java?

想要自己教会自己java&#xff0c;从小白成长到架构师。实现硬实力就业&#xff01; 因为Java是全球排名第一的编程语言&#xff0c;Java工程师也是市场需求最大的软件工程师&#xff0c;选择Java&#xff0c;就是选择了高薪。 为什么Java应用最广泛&#xff1f; 从互联网到…

[Linux] 文件系统

UNIX操作系统将文件组织成一个有层次的树形结构&#xff1a; 标准目录&#xff1a; 根目录&#xff1a; /tmp目录 主目录&#xff1a; 这就是主目录 一般与系统有关的信息都存放在etc目录下 注意&#xff1a; /etc/passwd存放的是用户账户信息&#xff0c;不是密码信息&#xf…

适用于所有 Android 手机的 8 大 Android 解锁工具

有时您无法解锁手机&#xff0c;因为您忘记了密码或设备停止响应解锁图案。不要惊慌。我们在这里为您列出了最好的 Android 解锁工具。只需选择一个您喜欢的。 为了保护重要数据&#xff0c;许多手机用户倾向于使用图案锁、密码、指纹甚至面部识别来锁定设备。但有时&#xff…

抉择与未来:高考后专业与学校的深度选择思考

引言 随着2024年高考的尘埃落定&#xff0c;数百万考生及其家庭正面临一个至关重要的决策&#xff1a;在有限的分数条件下&#xff0c;是优先选择专业还是学校&#xff1f;这一选择不仅影响着个人的未来职业道路&#xff0c;也关系到大学生活的质量和个人综合素质的培养。本文将…

Mysten Labs宣布推出Walrus:一种去中心化存储和数据可用性协议

Walrus是为区块链应用和自主代理提供的创新去中心化存储网络。Walrus存储系统今天以开发者预览版的形式发布&#xff0c;面向Sui开发者征求反馈意见&#xff0c;并预计很快会向其他Web3社区广泛推广。 通过采用纠删编码创新技术&#xff0c;Walrus能够快速且稳健地将非结构化数…

功能测试 之 单模块测试----添加会员

1.需求分析 点击【添加会员】按钮后&#xff0c;页面跳转至添加会员详细页面。 说明&#xff1a; 会员昵称&#xff1a;必填&#xff0c;长度在20个字符&#xff08;除去空格&#xff09;以内&#xff0c;&#xff08;会员昵称&#xff09;可以重复&#xff1b;登录密码&#x…

Druid未授权访问漏洞修复

前言 安全组针对系统漏扫发现系统存在Druid未授权访问&#xff0c;会引发泄露系统敏感信息&#xff0c;漏洞链接为ip:端口/druid/index.html&#xff0c;可以清楚的查看数据库的相关连接信息&#xff0c;如下图所示&#xff1a; 漏洞修复 1、关闭Druid监控页面 在Druid的配…

【Linux】基础IO_1

文章目录 六、基础IO1. C语言的文件接口2. 系统文件I/O 未完待续 六、基础IO 1. C语言的文件接口 我们知道 文件 文件内容 文件属性 。即使是一个空文件&#xff0c;仍然会在磁盘中占据空间。那打开文件是什么意思呢&#xff1f;其实文件打开的意思就是&#xff1a;将文件从…

LightGBM算法详解

LightGBM算法详解 LightGBM&#xff08;Light Gradient Boosting Machine&#xff09;是由微软开发的高效梯度提升决策树&#xff08;GBDT&#xff09;实现。它以速度和效率著称&#xff0c;特别适用于大规模数据集和高维特征的场景。本文将详细介绍LightGBM的原理、特点、常用…

研究Redis源码的一些前期准备

一 背景 Redis数据结构讲完后&#xff0c;觉得还是有点不过瘾&#xff0c;想研究一下Redis的底层实现。找了一些相关资料&#xff0c;准备借鉴和学习其他各位大佬钻研Redis底层的方法和经验&#xff0c;掌握Redis实现的基本原理。 二 源码归类 网上有大佬已经总结了…