
Jerry Liu • 2023-08-11
Zep 和 LlamaIndex:向量存储演练
编者按:本文由 Zep 的 Daniel 为 LlamaIndex 博客撰写。
Zep 是一个 用于 LLM 应用的长期记忆存储。借助 Zep,开发者可以轻松地将相关文档、聊天历史记忆和丰富的用户数据添加到 LLM 应用的提示中。文档和聊天历史的存储、嵌入、丰富等都由 Zep 服务处理。
在本文中,我们演示了如何将 Zep 新推出的文档向量存储与(同样是新的)适用于 LlamaIndex 的 ZepVectorStore 结合使用。
安装 Zep 及一些重要概念
Zep 是开源的,可以通过 Docker 安装,也可以安装到 Kubernetes 和 Render 等托管平台。提供了 Python 和 TypeScript 的 SDK,并且 LangChain 和 LlamaIndex 等框架也内置了对 Zep 的支持。
Zep 将文档存储在 Collection 中,文档文本、嵌入和元数据都放在一起。这使得可以在 Collection 上进行混合语义搜索,并通过针对文档元数据的 JSONPath 查询来过滤结果。将 Zep 与 LlamaIndex 一起使用时,LlamaIndex 的过滤器会被翻译供 Zep 使用。
一个文档或文档块相当于一个 LlamaIndex TextNode 或 NodeWithEmbedding。
Collection 可以选择设置为使用 OpenAI 等服务自动嵌入文本,或者在本地使用您选择的嵌入模型。然而,将 Zep 与 LlamaIndex 一起使用时,我们依赖 LlamaIndex 与嵌入服务和库的集成。
创建 ZepVectorStore 和文档 Collection
您需要安装 Zep,并准备好您的 API URL,如果需要,还需要身份验证密钥。
from llama_index.vector_stores import ZepVectorStore
zep_api_url = "http://localhost:8000"
zep_api_key = "<optional_jwt_token>"
collection_name = "babbage" # The name of a new or existing collection
embedding_dimensions = 1536 # the dimensions of the embedding model you intend to use
vector_store = ZepVectorStore(
api_url=zep_api_url,
api_key=zep_api_key,
collection_name=collection_name,
embedding_dimensions=embedding_dimensions
)
Collection 名称是您的向量索引的唯一标识符,应只包含字母数字字符。如果 Collection 不存在,Zep 会自动为您创建一个。
创建和填充索引
下面我们将使用 LlamaIndex 加载内容并将其添加到索引的常用模式。加载文本数据后,我们创建一个由 ZepVectorStore 支持的 StorageContext。
然后,我们使用已加载的文档和由 Zep 支持的存储上下文创建索引。
from llama_index import VectorStoreIndex, SimpleDirectoryReader
from llama_index.storage.storage_context import StorageContext
documents = SimpleDirectoryReader("./babbages_calculating_engine/").load_data()
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex.from_documents(documents, storage_context=storage_context)
query = "the sun and stars"
query_engine = index.as_query_engine()
response = query_engine.query(query)
print(str(response))
But one of the most signal examples of this kind, of which we are aware, is related by Mr Baily. The catalogue of stars published by the Astronomical Society was computed by two separate and independent persons, and was afterwards compared and examined with great care and attention by Mr Stratford. On examining this catalogue, and recalculating a portion of it, Mr Baily discovered an error in the case of the star
最后,我们对索引运行一个简单的文本查询,并打印结果节点的文本。
带元数据过滤器的混合搜索
如上所述,Zep 还支持将丰富的元数据与文档关联。此元数据可以是任意深度的 JSON 结构。与 LlamaIndex 一起使用时,我们当前支持基于映射中的顶级键进行过滤。
以下代码演示了如何在索引上运行向量搜索,并使用 LlamaIndex 的 MetadataFilters 对元数据进行过滤。我们打印匹配结果及其归一化余弦相似度。
from llama_index.schema import TextNode
from llama_index.vector_stores.types import ExactMatchFilter, MetadataFilters
nodes = [
TextNode(
text="Not aware that tables of these squares existed, Bouvard, who calculated the tides for Laplace, underwent the labour of calculating the square of each individual sine in every case in which it occurred.",
metadata={
"topic": "math",
"entities": "laplace",
},
),
TextNode(
text="Within the limits of the lunar orbit there are not less than one thousand stars, which are so situated as to be in the moon's path, and therefore to exhibit, at some period or other, those desirable occultations.",
metadata={
"topic": "astronomy",
"entities": "moon",
},
),
]
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex(nodes, storage_context=storage_context)
filters = MetadataFilters(filters=[ExactMatchFilter(key="topic", value="astronomy")])
retriever = index.as_retriever(filters=filters)
result = retriever.retrieve("What is the structure of our galaxy?")
for r in result:
print("\n", r.node.text, r.score)
Within the limits of the lunar orbit there are not less than one thousand stars, which are so situated as to be in the moon's path, and therefore to exhibit, at some period or other, those desirable occultations. 0.6456785674
总结
Zep 为文档和聊天历史的向量搜索提供了一个统一的 API,允许开发者使用这两种形式的长期记忆来填充提示。LlamaIndex 使得从广泛的文档和数据源中填充内容到 Zep 并为 LLM 应用构建提示及其他功能时查询这些来源变得极其容易。