ObjectBox 向量存储演示¶
本笔记本将展示如何将 ObjectBox 作为高效的本地设备向量存储与 LlamaIndex 结合使用。我们将通过一个简单的 RAG(检索增强生成)用例进行演示:给定文档后,用户可以用自然语言提问,并从大型语言模型(LLM)获取相关答案。该 RAG 流水线将按照以下模块进行配置:
- LlamaIndex 内置的
SimpleDirectoryReader
读取器 - LlamaIndex 内置的
SentenceSplitter
节点解析器 - 采用 HuggingFace 模型作为嵌入提供者
- 使用 ObjectBox 作为 NoSQL 和向量数据存储
- 采用谷歌的 Gemini 作为远程 LLM 服务
1) 安装依赖项¶
我们将安装与LlamaIndex配套使用的HuggingFace和Gemini集成组件
In [ ]:
Copied!
!pip install llama_index_vector_stores_objectbox --quiet
!pip install llama-index --quiet
!pip install llama-index-embeddings-huggingface --quiet
!pip install llama-index-llms-gemini --quiet
!pip install llama_index_vector_stores_objectbox --quiet
!pip install llama-index --quiet
!pip install llama-index-embeddings-huggingface --quiet
!pip install llama-index-llms-gemini --quiet
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/1.6 MB ? eta -:--:-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╺━━ 1.5/1.6 MB 40.2 MB/s eta 0:00:01 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.6/1.6 MB 25.4 MB/s eta 0:00:00 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4.0/4.0 MB 44.0 MB/s eta 0:00:00 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.5/1.5 MB 38.9 MB/s eta 0:00:00 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.1/1.1 MB 37.5 MB/s eta 0:00:00 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 76.4/76.4 kB 5.2 MB/s eta 0:00:00 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 77.9/77.9 kB 4.9 MB/s eta 0:00:00 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 49.3/49.3 kB 3.1 MB/s eta 0:00:00 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 58.3/58.3 kB 3.4 MB/s eta 0:00:00
2) 下载文档¶
In [ ]:
Copied!
!mkdir -p 'data/paul_graham/'
!wget 'https://raw.githubusercontent.com/run-llama/llama_index/main/docs/docs/examples/data/paul_graham/paul_graham_essay.txt' -O 'data/paul_graham/paul_graham_essay.txt'
!mkdir -p 'data/paul_graham/'
!wget 'https://raw.githubusercontent.com/run-llama/llama_index/main/docs/docs/examples/data/paul_graham/paul_graham_essay.txt' -O 'data/paul_graham/paul_graham_essay.txt'
In [ ]:
Copied!
from llama_index.llms.gemini import Gemini
import getpass
gemini_key_api = getpass.getpass("Gemini API Key: ")
gemini_llm = Gemini(api_key=gemini_key_api)
from llama_index.llms.gemini import Gemini
import getpass
gemini_key_api = getpass.getpass("Gemini API Key: ")
gemini_llm = Gemini(api_key=gemini_key_api)
In [ ]:
Copied!
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
hf_embedding = HuggingFaceEmbedding(model_name="BAAI/bge-base-en-v1.5")
embedding_dim = 384
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
hf_embedding = HuggingFaceEmbedding(model_name="BAAI/bge-base-en-v1.5")
embedding_dim = 384
5) 准备文档与节点¶
在 RAG(检索增强生成)流程中,第一步是读取给定的文档。我们使用 SimpleDirectoryReader
工具,该工具会通过检查目录中文件的扩展名来自动选择最佳的文件阅读器。
接下来,我们将 SimpleDirectoryReader
从文档中读取的内容分割成文本块(即文本子序列)。SentenceSplitter
是一种文本分割器,它能在将文本分割成指定 chunk_size
大小的块时,完整保留句子边界。
In [ ]:
Copied!
from llama_index.core import SimpleDirectoryReader
from llama_index.core.node_parser import SentenceSplitter
reader = SimpleDirectoryReader("./data/paul_graham")
documents = reader.load_data()
node_parser = SentenceSplitter(chunk_size=512, chunk_overlap=20)
nodes = node_parser.get_nodes_from_documents(documents)
from llama_index.core import SimpleDirectoryReader
from llama_index.core.node_parser import SentenceSplitter
reader = SimpleDirectoryReader("./data/paul_graham")
documents = reader.load_data()
node_parser = SentenceSplitter(chunk_size=512, chunk_overlap=20)
nodes = node_parser.get_nodes_from_documents(documents)
6) 配置 ObjectBoxVectorStore
¶
ObjectBoxVectorStore
可通过以下选项进行初始化:
embedding_dim
(必填):向量数据库将存储的嵌入维度distance_type
:可选值包括COSINE
(余弦)、DOT_PRODUCT
(点积)、DOT_PRODUCT_NON_NORMALIZED
(非标准化点积)和EUCLIDEAN
(欧几里得)db_directory
:用于创建.mdb
ObjectBox 数据库文件的目录路径clear_db
:若db_directory
路径已存在数据库文件则删除do_log
:启用 ObjectBox 集成的日志记录功能
In [ ]:
Copied!
from llama_index.vector_stores.objectbox import ObjectBoxVectorStore
from llama_index.core import StorageContext, VectorStoreIndex, Settings
from objectbox import VectorDistanceType
vector_store = ObjectBoxVectorStore(
embedding_dim,
distance_type=VectorDistanceType.COSINE,
db_directory="obx_data",
clear_db=False,
do_log=True,
)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
Settings.llm = gemini_llm
Settings.embed_model = hf_embedding
index = VectorStoreIndex(nodes=nodes, storage_context=storage_context)
from llama_index.vector_stores.objectbox import ObjectBoxVectorStore
from llama_index.core import StorageContext, VectorStoreIndex, Settings
from objectbox import VectorDistanceType
vector_store = ObjectBoxVectorStore(
embedding_dim,
distance_type=VectorDistanceType.COSINE,
db_directory="obx_data",
clear_db=False,
do_log=True,
)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
Settings.llm = gemini_llm
Settings.embed_model = hf_embedding
index = VectorStoreIndex(nodes=nodes, storage_context=storage_context)
7) 与文档对话¶
In [ ]:
Copied!
query_engine = index.as_query_engine()
response = query_engine.query("Who is Paul Graham?")
print(response)
query_engine = index.as_query_engine()
response = query_engine.query("Who is Paul Graham?")
print(response)
In [ ]:
Copied!
retriever = index.as_retriever()
response = retriever.retrieve("What did the author do growing up?")
for node in response:
print("Retrieved chunk text:\n", node.node.get_text())
print("Retrieved chunk metadata:\n", node.node.get_metadata_str())
print("\n\n\n")
retriever = index.as_retriever()
response = retriever.retrieve("What did the author do growing up?")
for node in response:
print("Retrieved chunk text:\n", node.node.get_text())
print("Retrieved chunk metadata:\n", node.node.get_metadata_str())
print("\n\n\n")
可选操作:使用 delete_nodes
删除与单个查询关联的文本块¶
我们可以通过 ObjectBoxVectorStore.delete_nodes
方法从向量数据库中移除文本块(节点),只需将包含节点 ID 的列表作为参数传入即可。
In [ ]:
Copied!
response = retriever.retrieve("What did the author do growing up?")
node_ids = []
for node in response:
node_ids.append(node.node_id)
print(f"Nodes to be removed: {node_ids}")
print(f"No. of vectors before deletion: {vector_store.count()}")
vector_store.delete_nodes(node_ids)
print(f"No. of vectors after deletion: {vector_store.count()}")
response = retriever.retrieve("What did the author do growing up?")
node_ids = []
for node in response:
node_ids.append(node.node_id)
print(f"Nodes to be removed: {node_ids}")
print(f"No. of vectors before deletion: {vector_store.count()}")
vector_store.delete_nodes(node_ids)
print(f"No. of vectors after deletion: {vector_store.count()}")
可选操作:从向量数据库中删除单个文档¶
ObjectBoxVectorStore.delete
方法可用于删除与指定文档关联的块(节点),该文档的 id_
需作为参数传入。
In [ ]:
Copied!
document = documents[0]
print(f"Document to be deleted {document.id_}")
print(f"No. of vectors before deletion: {vector_store.count()}")
vector_store.delete(document.id_)
print(f"No. of vectors after document deletion: {vector_store.count()}")
document = documents[0]
print(f"Document to be deleted {document.id_}")
print(f"No. of vectors before deletion: {vector_store.count()}")
vector_store.delete(document.id_)
print(f"No. of vectors after document deletion: {vector_store.count()}")