
内容参考于图灵AI大模型全栈向量存储是VectorStore官网地址https://developers.llamaindex.ai/python/framework-api-reference/storage/vector_store/它默认的是SingleStoreVectorStore如下图一个是上一个内容中文档存储时创建的json文件一个是本次向量存储创建的json文件文档存储的时候就没有向量的内容如下图根据向量里的id可以找到原始文档下方代码中如下图红框使用了 llm 和 embed_model如下图base_llm里的内容后续跟上图红框一样引入的base_llm都是下图里的代码代码# 导入句子分割器用于按语义边界将长文档切分为独立的文本节点 from llama_index.core.node_parser import SentenceSplitter # 从自定义模块导入预先初始化好的大模型实例与嵌入模型实例 # llm大语言模型实例用于后续问答生成 # embed_model嵌入模型实例负责将文本转换为向量是向量检索的核心依赖 from base_llm import llm, embed_model # 导入目录文件加载器用于读取本地文件并封装为标准 Document 对象 from llama_index.core import SimpleDirectoryReader # 导入基础内存向量存储类 # 类全称SimpleVectorStore # 定位LlamaIndex 内置的轻量级内存向量存储无外部数据库依赖 # 特点向量数据保存在运行内存中支持本地持久化与加载适合小型 Demo、开发调试 # 局限采用暴力相似度计算不适合大规模向量生产环境建议替换为专业向量数据库 from llama_index.core.vector_stores import SimpleVectorStore # 导入向量查询标准数据结构 # 作用封装向量检索的请求参数查询向量、召回数量、过滤条件等是向量检索的标准入参格式 from llama_index.core.vector_stores.types import VectorStoreQuery # 导入存储上下文容器统一管理文档存储、向量存储、索引存储等所有存储组件 from llama_index.core import StorageContext # 1. 加载本地文档 # 读取指定的单个文本文件返回 Document 对象列表 # input_files直接指定目标文件路径无需扫描整个目录适合精准加载少量文件 documents SimpleDirectoryReader(input_files[./data_file/小说.txt]).load_data() # 2. 初始化内存向量存储 # 创建最基础的内存型向量存储实例无参实例化默认空存储所有向量数据保存在进程内存中 vector_store SimpleVectorStore() # 3. 构建存储上下文容器 # 通过 from_defaults 工厂方法创建存储上下文将自定义向量存储注册进去统一管理 # 未显式指定的 docstore文档存储、index_store索引存储会自动使用默认的内存实现 # 核心作用屏蔽各类存储的差异提供统一的持久化、加载、读写入口 storage_context StorageContext.from_defaults(vector_storevector_store) # 4. 文档切分为文本节点 # 使用默认配置的句子分割器chunk_size1024、chunk_overlap200将完整文档切分为多个 TextNode # 每个节点包含独立文本片段、元数据、唯一节点ID等属性 nodes SentenceSplitter().get_nodes_from_documents(documents) # 5. 手动为每个节点生成向量嵌入 # 说明正常使用 VectorStoreIndex 等高层 API 时框架会自动完成向量生成与写入 # 此处手动循环赋值是拆解演示底层原理节点必须先携带 embedding才能存入向量存储 # 调用嵌入模型的 get_text_embedding 方法将节点文本转为向量数组赋值给节点的 embedding 属性 for node in nodes: node.embedding embed_model.get_text_embedding(node.text) # 6. 批量写入向量存储 # 将携带向量的节点存入向量存储 # 向量存储仅保存「节点ID 向量数组」不保存完整文本实现向量与业务数据解耦 storage_context.vector_store.add(nodes) # 7. 批量写入文档存储 # 将节点的完整信息文本内容、元数据、节点关系等写入文档存储 # 文档存储保存节点的完整业务数据检索时先通过向量库查到节点ID再从文档库获取完整文本 storage_context.docstore.add_documents(nodes) # 8. 持久化存储到本地磁盘 # 将存储上下文中的所有组件向量存储、文档存储、索引存储序列化为本地文件 # 入参目标目录路径目录不存在会自动创建 # 持久化后可直接加载复用无需重新切分、向量化避免重复计算 storage_context.persist(./storage)存储到Chroma首先安装下方两个库pip install llama-index-vector-stores-chroma pip install chromadb下方的代码并没有跟上方代码一样写向量生成的代码代码# 导入 LlamaIndex 核心向量索引类、目录文件加载器 # VectorStoreIndex向量索引核心类一站式完成文档切分、向量化、索引构建、检索查询全流程 # SimpleDirectoryReader本地文件加载器将文件内容封装为 Document 对象 from llama_index.core import VectorStoreIndex, SimpleDirectoryReader # 导入 Chroma 向量存储适配类用于将 Chroma 数据库接入 LlamaIndex 标准向量存储体系 # 所属扩展包llama-index-vector-stores-chroma需单独安装 from llama_index.vector_stores.chroma import ChromaVectorStore # 导入存储上下文容器统一管理向量存储、文档存储、索引存储等各类存储组件 from llama_index.core import StorageContext # 从自定义模块导入预初始化的大语言模型实例、嵌入模型实例 # llm用于后续问答生成 # embed_model用于文本向量化构建索引和检索时必须使用同一款嵌入模型 from base_llm import llm, embed_model # 导入 Chroma 官方 Python SDK用于操作 Chroma 向量数据库 import chromadb # 1. 加载本地文档 # 读取指定的单个文本文件返回 Document 对象列表 # input_files直接指定目标文件路径无需扫描整个目录 documents SimpleDirectoryReader(input_files[./data_file/小说.txt]).load_data() print(---------------使用chroma进行存储向量--------------------) # 2. 初始化 Chroma 客户端与集合 # Chroma 支持两种客户端模式 # 1. EphemeralClient纯内存模式进程结束数据立即丢失适合临时测试、快速验证 # chroma_client chromadb.EphemeralClient() # 2. PersistentClient持久化模式数据写入本地磁盘目录重启可复用是生产/常用场景的选择 # 入参为本地持久化目录路径目录不存在会自动创建 chroma_client chromadb.PersistentClient(./chroma_db) # 获取或创建集合Collection # 集合是 Chroma 的数据单元相当于关系型数据库的表用于存放向量、元数据、文档ID # get_or_create_collection集合存在则直接获取不存在则创建避免重复创建报错 chroma_collection chroma_client.get_or_create_collection(quickstart) # 3. 封装为 LlamaIndex 兼容的向量存储 # 将 Chroma 原生集合对象包装为 LlamaIndex 标准的 VectorStore 实现 # 作用屏蔽 Chroma 原生接口差异让 LlamaIndex 索引可以像操作通用向量存储一样读写 Chroma vector_store ChromaVectorStore(chroma_collectionchroma_collection) # 4. 构建存储上下文 # 将自定义的 Chroma 向量存储注册到存储上下文中统一管理 # 未显式指定的 docstore、index_store 会自动使用默认的内存实现 storage_context StorageContext.from_defaults(vector_storevector_store) # 5. 一键构建向量索引 # VectorStoreIndex.from_documents 是 LlamaIndex 高层一站式 API内部自动完成 # 1. 使用默认 SentenceSplitter 将文档切分为文本节点 # 2. 调用传入的 embed_model 为每个节点生成向量 # 3. 将向量写入 Chroma 向量存储将节点完整信息写入文档存储 # 4. 构建完整的向量索引结构 # 入参说明 # documents待入库的原始文档列表 # storage_context存储上下文指定使用 Chroma 作为向量存储 # embed_model指定嵌入模型必须和后续检索时使用的模型完全一致 index VectorStoreIndex.from_documents( documents, storage_contextstorage_context, embed_modelembed_model ) # 打印 Chroma 集合中的向量总数验证数据是否成功写入 # 数量等于切分后的文本节点总数 print(chroma_collection.count()) # 6. 向量检索测试 # 从索引创建检索器默认是向量相似度检索模式 # 可通过 similarity_top_k 参数自定义召回节点数量 query_retriever index.as_retriever() # 执行检索传入用户查询文本 # 内部流程将查询文本转为向量 → 在 Chroma 中做相似度匹配 → 返回 TopK 个带得分的相关节点 # 返回值List[NodeWithScore]每个元素包含 node节点完整信息和 score相似度得分 response query_retriever.retrieve(萧炎的妹妹是谁) print(response) # 以下为加载已有 Chroma 索引的标准写法已注释 # 适用场景服务重启、已有向量数据无需重新切分和向量化直接加载复用 # print(---------------使用chroma获取存储向量--------------------) # # 1. 重新初始化持久化客户端指向同一个本地目录 # chroma_client chromadb.PersistentClient(./chroma_db) # # 2. 获取已存在的集合必须和创建时的集合名完全一致 # chroma_collection_new chroma_client.get_collection(quickstart) # # 3. 包装为 LlamaIndex 向量存储 # vector_store_new ChromaVectorStore(chroma_collectionchroma_collection_new) # # 4. 从已有向量存储恢复索引不会重新写入数据 # # 注意embed_model 必须和构建索引时完全一致否则向量语义空间不匹配检索结果会异常 # index_new VectorStoreIndex.from_vector_store( # vector_storevector_store_new, # embed_modelembed_model # ) # # # 恢复后即可正常使用检索、查询能力 # query_retriever index_new.as_retriever() # response query_retriever.retrieve(萧炎的妹妹是谁) # print(response)接下来跟一下代码看看LLama_Index怎么做的首先按着CTRL鼠标左键单击下图红框然后下图红框位置设置断点它cls调用的是类中__init__方法不断点跟追不到断点会进入下图红框的代码然后它又调用了父类的__init__方法下图红框的build_index_from_nodes然后再进入下图红框下图蓝框是通过上方红框进入的代码在进入_add_nodes_to_index然后就可以看到向量处理的方法了如下图红框_get_node_with_embedding如下图进入_get_node_with_embedding如下图红框就是转向量的代码现在的值蓝框是分片后的文档数据红框是我们传递进来的向量模型如下图调用_get_text_embeddings方法生成向量索引IndexStore官网地址https://developers.llamaindex.ai/python/framework-api-reference/storage/index_store/simple/这个索引是比如向量数据库存了很多文档比如物理、化学、计算机然后我们的问题都是围绕计算机的但是向量数据库里存了物理、化学、计算机我们不能把物理、化学、计算机都检索一遍当我们知道问题数据计算机那么物理、化学我们就不应该去检索只需要检索计算机这个索引IndexStore存放的就是结构索引存放的是向量数据是怎样存的存储的逻辑是怎样的如下图索引存放的东西json的说明{ // 根键index_store 的数据分区存储所有索引的元数据定义 // index_store 是 LlamaIndex 存储体系的核心组件之一负责管理索引的结构与归属关系 index_store/data: { // 键名单个索引的全局唯一IDUUID格式与内部 index_id 字段完全一致 // 一个 index_store 可存放多个不同的索引通过该ID做唯一区分与定位 d6fbe516-1cf0-4c43-b60b-00c154dbac62: { // 序列化类型标记LlamaIndex 反序列化加载时的类型标识符 // 值为 vector_store 表示这是一个向量存储索引VectorStoreIndex // 框架会根据此字段自动匹配对应的索引类完成实例化 __type__: vector_store, // 索引的实际数据载荷包含该索引的所有核心元数据 __data__: { // 索引全局唯一标识与外层键的UUID一一对应 // 用于多索引路由、跨组件关联、索引增删等场景的精准定位 index_id: d6fbe516-1cf0-4c43-b60b-00c154dbac62, // 索引摘要描述 // 默认为 null可手动为索引添加文本描述 // 主要用于多索引检索场景帮助路由检索器识别该索引的内容主题与用途 summary: null, // 节点归属字典记录该索引包含的所有文本节点NodeID // 键和值均为节点的UUID一一对应本质是集合的JSON兼容写法 // 每个UUID对应一个经过文档切分后的文本块节点 // 检索时框架会通过这些ID去 DocStore 中拉取节点的原始文本与元数据 // 本示例中共包含 11 个文本节点 nodes_dict: { 82d952d1-86d1-4564-988e-78621865d66d: 82d952d1-86d1-4564-988e-78621865d66d, 9ad38a43-1b6c-492c-9543-b432630fcddf: 9ad38a43-1b6c-492c-9543-b432630fcddf, e1215612-b2bd-48a6-ab0d-42b9cc3c382d: e1215612-b2bd-48a6-ab0d-42b9cc3c382d, 5ada2216-95fc-41c5-8bdd-e9fc1991f068: 5ada2216-95fc-41c5-8bdd-e9fc1991f068, 675cfc67-ec59-489c-a275-7798e0c764c0: 675cfc67-ec59-489c-a275-7798e0c764c0, 7b9e52e0-dfbb-497a-9618-b9c60362d6d2: 7b9e52e0-dfbb-497a-9618-b9c60362d6d2, 4668fbaa-1090-43c5-b3bb-1fb8ffdb7827: 4668fbaa-1090-43c5-b3bb-1fb8ffdb7827, 7348173f-148c-4f36-bd49-c3aa5dfb17ea: 7348173f-148c-4f36-bd49-c3aa5dfb17ea, fcf3a124-81e4-41a6-854f-61b62680b18b: fcf3a124-81e4-41a6-854f-61b62680b18b, ef43dfcb-c7f8-4762-9ac9-9bab46617c6a: ef43dfcb-c7f8-4762-9ac9-9bab46617c6a, f8945e1d-04ad-47cd-a1ad-519d6e29954f: f8945e1d-04ad-47cd-a1ad-519d6e29954f }, // 文档-节点映射字典记录「源文档ID - 该文档下属所有节点ID列表」的映射 // 当前为空对象常见原因 // 1. 直接通过 Node 列表构建索引未传入源 Document 对象 // 2. 构建索引时未开启文档ID关联配置 // 正常从 Document 构建的索引会填充此字段用于支持按文档维度增删、管理节点 doc_id_dict: {}, // 嵌入向量字典预留兼容字段 // 当前为空是正常现象VectorStoreIndex 的向量数据默认存储在独立的 VectorStore 组件中 // 如本地 SimpleVectorStore、Chroma、Pinecone 等向量数据库不存放在索引元数据内 // 该字段仅用于兼容极轻量的内存索引场景正式持久化时向量数据单独存储 embeddings_dict: {} } } } }代码# 导入本地目录文件加载器负责读取本地文件并封装为标准 Document 对象 from llama_index.core import SimpleDirectoryReader # 导入存储上下文类、从存储加载索引的工具函数 # StorageContext统一管理向量存储、文档存储、索引存储的容器 # load_index_from_storage从已有的存储上下文中重建索引对象无需重新切分与向量化 from llama_index.core import StorageContext, load_index_from_storage # 导入向量索引核心类一站式完成文本切分、向量化、索引构建、语义检索全流程 from llama_index.core import VectorStoreIndex # 从自定义基础配置模块导入预初始化的大语言模型与嵌入模型 # llm用于后续问答生成本示例未直接调用检索阶段不依赖大模型 # embed_model嵌入模型构建索引和检索时必须使用同一款保证向量空间一致 from base_llm import llm, embed_model # 1. 加载本地文档 # 读取指定的单个文本文件返回 Document 对象列表 documents SimpleDirectoryReader(input_files[./data_file/小说.txt]).load_data() # 2. 一键构建向量索引 # 使用 from_documents 高层 API内部自动完成 # 1. 默认调用 SentenceSplitter 将文档切分为文本节点 # 2. 调用 embed_model 为每个节点生成向量 # 3. 自动创建默认的内存型存储上下文SimpleVectorStore SimpleDocumentStore # 4. 构建完整的向量索引结构 # 未显式指定 storage_context 时框架默认使用内存级轻量存储 index VectorStoreIndex.from_documents(documents, embed_modelembed_model) # 3. 索引持久化到本地磁盘 # 通过索引的 storage_context 属性调用 persist 方法 # 将存储上下文中的所有数据向量数据、文档节点、索引元数据全部序列化写入本地目录 # 目录不存在会自动创建生成的核心文件包括 # - vector_store.json所有节点的向量数据 # - docstore.json所有节点的文本、元数据、节点关系 # - index_store.json索引结构元数据 index.storage_context.persist(./vector_store_index) # 4. 基于索引创建检索器并测试检索 # as_retriever() 创建默认向量相似度检索器默认召回 Top2 节点 retriever index.as_retriever() # 执行语义检索返回与查询最相关的节点列表 print(retriever.retrieve(萧炎父亲是谁)) # 5. 从本地磁盘加载已持久化的索引 # 第一步从持久化目录重建存储上下文 # 读取本地目录下的所有存储文件还原向量存储、文档存储、索引存储的完整数据 new_storage_context StorageContext.from_defaults(persist_dir./vector_store_index) # 第二步从存储上下文中加载重建索引对象 # load_index_from_storage 会自动识别索引类型还原为对应的索引实例 # 必须传入 embed_model存储中仅保存向量数据不保存嵌入模型检索时需要同款模型生成查询向量 # 嵌入模型必须和构建索引时完全一致否则向量空间不匹配检索结果会完全失效 new_index load_index_from_storage(new_storage_context, embed_modelembed_model) # 6. 使用加载后的索引执行检索 # 加载后的索引和原索引功能完全一致可直接创建检索器、查询引擎使用 print(new_index.as_retriever().retrieve(古河是谁?))索引存储到Redis首先安装下方两个库pip install llama-index-storage-docstore-redis pip install llama-index-storage-index-store-redis效果图代码# 导入 Chroma 官方 Python SDK用于操作 Chroma 向量数据库 import chromadb # 导入 LlamaIndex 核心组件目录文件加载器、从存储重建索引的工具函数 from llama_index.core import SimpleDirectoryReader, load_index_from_storage # 导入句子分割器用于按语义边界将长文档切分为文本节点 from llama_index.core.node_parser import SentenceSplitter # 导入存储上下文容器统一管理向量存储、文档存储、索引存储三类存储组件 from llama_index.core import StorageContext # 导入 Redis 实现的索引存储、文档存储组件 # RedisIndexStore基于 Redis 存储索引元数据索引类型、配置、节点映射关系等 # RedisDocumentStore基于 Redis 存储文本节点的完整内容文本、元数据、节点关系等 # 两者均属于生产级存储实现利用 Redis 高性能读写特性提升访问效率 from llama_index.storage.index_store.redis import RedisIndexStore from llama_index.storage.docstore.redis import RedisDocumentStore # 导入向量索引核心类负责向量化、索引构建、语义检索全流程 from llama_index.core import VectorStoreIndex # 导入 Chroma 向量存储适配类将 Chroma 接入 LlamaIndex 标准向量存储体系 from llama_index.vector_stores.chroma import ChromaVectorStore # 从自定义基础配置模块导入预初始化的大语言模型、嵌入模型 # llm用于问答生成阶段 # embed_model用于文本向量化构建与检索时必须使用同一款模型保证向量空间一致 from base_llm import llm, embed_model # 1. 初始化 Chroma 向量存储 # 创建 Chroma 持久化客户端数据写入本地磁盘目录服务重启可复用 # 入参为本地持久化目录路径目录不存在会自动创建 chroma_client chromadb.PersistentClient(./chroma_test) # 获取或创建向量集合Collection相当于向量数据的表 # get_or_create_collection集合存在则直接复用不存在则新建避免重复创建报错 chroma_collection chroma_client.get_or_create_collection(test) # 将 Chroma 原生集合包装为 LlamaIndex 标准兼容的向量存储对象 # 封装后可直接接入 LlamaIndex 的存储上下文与索引体系 vector_store ChromaVectorStore(chroma_collectionchroma_collection) # 2. 加载并切分文档 # 加载本地指定文本文件返回 Document 对象列表 documents SimpleDirectoryReader(input_files[./data_file/小说.txt]).load_data() # 使用默认配置的句子分割器将完整文档切分为多个独立文本节点TextNode nodes SentenceSplitter().get_nodes_from_documents(documents) # 3. 构建完整存储上下文三类存储分离部署 # 这是生产级典型的分层存储架构 # - 向量数据 → Chroma专业向量检索引擎负责相似度计算 # - 文档节点 → Redis高性能KV负责低延迟读取文本内容与元数据 # - 索引元数据 → Redis高性能KV负责索引结构元数据的快速读写 storage_context StorageContext.from_defaults( # 索引存储基于 Redis保存索引的元信息索引ID、类型、配置、节点映射关系等 # from_host_and_port通过主机地址端口方式连接 Redis # namespace命名空间给 Redis Key 加统一前缀实现同一 Redis 实例下多业务数据隔离 index_storeRedisIndexStore.from_host_and_port( host127.0.0.1, port6379, namespacenovel_index ), # 文档存储基于 Redis保存所有文本节点的完整数据文本、元数据、节点关系、起止位置等 docstoreRedisDocumentStore.from_host_and_port( host127.0.0.1, port6379, namespacenovel_docs ), # 向量存储使用前面初始化的 Chroma 实现 vector_storevector_store ) # 4. 手动将节点写入 Redis 文档存储 # 补充说明标准流程中VectorStoreIndex 初始化时会自动将节点写入 docstore无需手动调用 # 此处手动写入属于显式演示操作效果与自动写入一致重复写入相同节点ID会覆盖原有数据 storage_context.docstore.add_documents(nodes) # 5. 构建向量索引 # 直接传入切分好的节点列表、存储上下文、嵌入模型构建索引 # 内部自动完成为每个节点生成向量 → 写入 Chroma 向量库 → 索引元数据写入 Redis index VectorStoreIndex(nodes, storage_contextstorage_context, embed_modelembed_model) # 打印索引唯一 ID验证索引创建成功 print(f索引创建并存储完成ID: {index.index_id}) # 6. 功能测试 # 测试纯向量检索召回 Top5 最相关的节点 print(index.as_retriever(similarity_top_k5).retrieve(小说中古河是个什么样的人)) # 测试完整问答检索 大模型生成答案 response index.as_query_engine(llmllm).query(小说中古河是个什么样的人) print(f加载成功查询结果: {response}) # 以下为从已有存储中加载索引的标准流程已注释 # 适用场景服务重启、数据已持久化无需重新切分、向量化直接加载复用 # 核心要求所有存储组件的配置Chroma集合名、Redis namespace、嵌入模型必须和创建时完全一致 # # # 1. 重新初始化 Chroma 客户端与集合指向同一个持久化目录与集合 # chroma_client chromadb.PersistentClient(./chroma_db) # chroma_collection_new chroma_client.get_collection(quickstart) # vector_store_new ChromaVectorStore(chroma_collectionchroma_collection_new) # # # 2. 重新构建完全相同配置的存储上下文 # storage_context StorageContext.from_defaults( # index_storeRedisIndexStore.from_host_and_port( # host127.0.0.1, port6379, namespacenovel_index # ), # docstoreRedisDocumentStore.from_host_and_port( # host127.0.0.1, port6379, namespacenovel_docs # ), # vector_storevector_store_new # ) # # # 3. 从存储上下文加载重建索引无需重新切分和向量化 # # 必须传入与构建时一致的 embed_model否则向量空间不匹配检索完全失效 # loaded_index load_index_from_storage(storage_context, embed_modelembed_model) # # # 4. 加载后的索引可直接用于问答 # response loaded_index.as_query_engine(llmllm).query(萧炎父亲是谁?) # print(f加载成功查询结果: {response})