张子阳的博客

首页 读书 技术 店铺 关于
张子阳的博客 首页 读书 技术 关于

LlamaIndex 构建本地文件向量数据库

2025-04-28 张子阳 分类: 大语言模型

LlamaIndex 使用大语言模型 这篇文章中,我们介绍了使用LlamaIndex直接对大模型进行提问,并输出结果。在本篇以及后续文章中,我们发挥LlamaIndex的专长,构建RAG,来对本地的私有文档进行提问。这篇文章中,我们先进行第一个步骤:构建本地的文件向量数据库。

基本概念

LlamaIndex官方文档 已经很详尽了,所以我再就各种概念进行详细讲述。只结合代码将相关的概念串联起来,主要还是实现一个个的代码实例。

假设有一个 player.txt,其中包含了一款游戏的玩家信息,文件内容大致如下:

​玩家信息列表 ​昵称​​:剑影随风 ​​区服​​:青云峰 ​​出生日期​​:2002-08-15 ​​年龄​​:22 ​​注册日期​​:2023-05-20 ​​注册时长​​:708天 ​​注册方式​​:微信 ​​昵称​​:ShadowBlade_007 ​​区服​​:赤霄谷 ​​出生日期​​:1989-11-03 ​​年龄​​:35 ​​注册日期​​:2021-09-12 ​​注册时长​​:1324天 ​​注册方式​​:手机号 ... 省略若干

那么如何让大语言模型在处理数据时,参考这个文件呢?其遵循的流程如下:

构建向量数据库:

  1. 加载(loading):将需要查询的文件,本例中是 player.txt,加载到程序中
  2. 索引(indexing):基于文件,创建向量嵌入(vector embeddings)
  3. 存储(storing):将上一步创建好的向量嵌入,存储到向量数据库中

查询:

查询(querying):用户发起针对文件内容的查询,此时会先检索 向量数据库,然后从中找出,和查询内容最相关的部分。然后将这一部分内容,作为上下文,连同用户的原始查询,一并发送到LLM,然后返回响应结果。

这个流程是不必要连贯的,可以一次构建,多次查询。

向量数据库,有点类似 Sql数据库。player.txt是非结构化的文本数据,如果我们要查询注册>=100天的玩家,并不是很方便。但如果在Sql数据库中,创建一张 player 表,然后将数据从txt导入到player表中,转为结构化数据,那么如果再要查询注册>=100天的玩家,就可以执行SQL:where register_days >=100了。

与Sql数据库不同的是,向量数据库,存储的是文本的相似度信息。player.txt可能很大,比如说,包含了1000万的玩家数据,大小超过200MB,我们不可能将所有这些数据,连带查询信息发送给LLM。而是先从player.txt 中检索相关数据。向量化,即是将文本转为数字化表达,并且提供相似性信息,从而方便进行相关性检索。向量数据库,即用来保存转换后的向量信息。

例如:

文本 “仙侠游戏”,经过向量化之后,表示为:[0.3, -1.2, 5.0];
文本 “武侠小说”,表示为:[0.4, -1.0, 4.8];
文本 “股票分析”,表示为:[0.8, 2.5, 1.0]

可以看到,仙侠游戏 和 武侠小说 的相似度更高,和 股票分析 相似度更小。

向量数据库,有类似MySql这样的专门软件,例如 Chroma,也可以存在文件系统中。接下来,我们逐步编码,将 player.txt 创建为一个本地的文件向量数据库:

构建向量数据库

在工作目录下,创建文件:txt_vector_file.py

from dotenv import load_dotenv load_dotenv() # 配置模型 from llama_index.core import Settings from llama_index.embeddings.openai import OpenAIEmbedding Settings.embed_model = OpenAIEmbedding(model="text-embedding-3-large") # 1. 加载 from llama_index.core import SimpleDirectoryReader documents = SimpleDirectoryReader(input_files=["./player.txt"]).load_data() # 2. 索引 from llama_index.core import VectorStoreIndex vector_index = VectorStoreIndex.from_documents(documents) # 3. 存储 vector_index.storage_context.persist(persist_dir="./vector")

这段代码首先配置了 embedding模型,这个模型用于将文本(也有针对图片、视频的模型),转换为向量数据。不同的模型适用于不同的场景,其算法设计 和 训练数据集不同。在本例中,用的是 text-embedding-3-large。类似地,还有 text-embedding-3-small,相对于 text-embedding-3-smalltext-embedding-3-large 对于多语音的处理更好一些。因为我们的文本是中文,所以我用了这个。

需要注意,当文本量很大的时候,在后台,会自动将大的文本集,切分成小的段落,再发送给OpanAI的接口进行处理。这个过程往往会反复执行多次,且耗时比较久。

上面的 加载、索引、存储,3个步骤,每个步骤都可以进行更进一步的细化和调优,这里作为演示,仅用最基础和默认的配置进行。

执行完上面的代码后,会在工作目录下,创建一个 vector 文件夹,其中包含了向量数据库的相关文件。结构如下:

vector ├── default__vector_store.json ├── docstore.json ├── graph_store.json ├── image__vector_store.json └── index_store.json

这里包含了原始的 player.txt,以及对应的向量信息。

查询向量数据库

前面说过,如果文件很大,构建向量库需要反复请求openai的接口,耗时也比较久。所以通常的模式是:一次构建,多次查询。在上面步骤中构建好向量库之后,接下来我们就可以对它进行查询。

在工作目录下,创建一个新的文件:txt_vector_file_query.py

# 配置模型 from llama_index.core import Settings, StorageContext, load_index_from_storage from llama_index.llms.openai import OpenAI from llama_index.embeddings.openai import OpenAIEmbedding Settings.embed_model = OpenAIEmbedding(model="text-embedding-3-large") Settings.llm = OpenAI(model="gpt-4o") # 加载本地文件向量数据库./vector storage_context = StorageContext.from_defaults(persist_dir="./vector") # 加载索引 vector_index = load_index_from_storage(storage_context) # 2. 构建查询引擎 query_engine = vector_index.as_query_engine() response = query_engine.query("ShadowBlade_007 注册了多久了?") # 3. 打印结果 print(response)

上面代码的说明如下:

运行结果如下:

D:\codes\llamaindex\rag_txt> py .\txt_vector_file_query.py ShadowBlade_007 注册了 1324 天。

至此,我们就完成了一个简单的实例,对本地的一个文本文件构建了向量数据库,并对它进行了查询。

感谢阅读,希望这篇文章能给你带来帮助!