GraphRA应用:Neo4j GenAI Python包的混合检索指南

2024年09月09日 由 alex 发表 172 0

简介

在本文我们将探讨如何使用全文索引来增强 GraphRAG 应用程序。我们将展示如何将全文索引与矢量索引相结合,通过检索矢量检索可能会遗漏的信息来提高这些应用程序的检索性能。此外,我们还将介绍如何使用 Neo4j GenAI Python 库构建一个同时利用全文索引和矢量索引的 GraphRAG 应用程序。


安装

首先,确保已安装 Neo4j GenAI 软件包、Neo4j Python 驱动程序和 OpenAI Python 软件包:


pip install neo4j neo4j_genai openai


我们将使用Neo4j 演示数据库。该数据库模拟了电影推荐知识图谱。


你可以使用 “recommendations ”作为用户名和密码,通过浏览器访问数据库,网址是 https://demo.neo4jlabs.com:7473/browser/。在应用程序中使用以下代码段连接数据库:


from neo4j import GraphDatabase
# Demo database credentials
URI = "neo4j+s://demo.neo4jlabs.com"
AUTH = ("recommendations", "recommendations")
# Connect to Neo4j database
driver = GraphDatabase.driver(URI, auth=AUTH)


此外,确保导出 OpenAI 密钥:


import os
os.environ["OPENAI_API_KEY"] = "sk-…"


矢量搜索的局限性

矢量搜索通常是 RAG 应用程序的基本组成部分。它使应用程序能够在数据库中找到与用户查询含义相似(语义相似)的信息,并将这些信息作为相关上下文提供给 LLM,以便生成响应。在之前,我们在 GraphRAG 应用程序中使用了矢量搜索,以返回在意义上与用户查询非常匹配的电影情节,从而回答用户关于电影的问题。例如,如果用户问:“关于恐龙主题公园的电影叫什么名字?”矢量搜索将检索到电影《侏罗纪公园》。这是因为电影情节 “在一次预览参观中,主题公园发生了重大电力故障,导致克隆恐龙展品失控 ”与用户查询的意思相似。


然而,语义相似性并不总是为每个查询检索最相关信息的最佳衡量标准。例如,当搜索缺乏广泛语义或在更广泛的语境中具有不同含义的特定领域术语时,矢量搜索可能无法检索到相关信息,或者可能返回不相关的信息。出现这种情况的原因是,这些术语在用于向量搜索的嵌入模型的训练数据中可能没有得到很好的体现。此外,当用户查询包含特定字符串(如姓名或日期)时,语义相似性也不是一个可靠的衡量标准,因为这些字符串需要完全匹配才能得到准确的结果。使用 VectorRetriever 查询在特定地点和日期拍摄的电影名称(如 1375 年在帝国中国拍摄的电影)就是一个例子:


from neo4j import GraphDatabase
from neo4j_genai.embeddings.openai import OpenAIEmbeddings
from neo4j_genai.retrievers import VectorRetriever
driver = GraphDatabase.driver(URI, auth=AUTH)
embedder = OpenAIEmbeddings(model="text-embedding-ada-002")
retriever = VectorRetriever(
    driver,
    index_name="moviePlotsEmbedding",
    embedder=embedder,
    return_properties=["title", "plot"],
)
query_text = "What is the name of the movie set in 1375 in Imperial China?"
retriever_result = retriever.search(query_text=query_text, top_k=3)
print(retriever_result)


为了准确匹配这个查询,VectorRetriever 的匹配算法需要在电影的情节描述中找到 1375 年的确切日期,但它无法做到这一点。因此,VectorRetriever 无法为该查询返回正确的电影(《勇士穆萨》)。相反,它检索到了以中国为背景或与中国有关的电影,但没有一部是以 1375 年为具体背景的。


items = [
    RetrieverResultItem(
        content="{'title': 'Once Upon a Time in China (Wong Fei Hung)', 'plot': \"Set in late 19th century Canton this martial arts film depicts the stance taken by the legendary martial arts hero Wong Fei-Hung (1847-1924) against foreign forces' (English, French and ...\"}",
        metadata={"score": 0.9209008812904358, "nodeLabels": None, "id": None},
    ),
    RetrieverResultItem(
        content="{'title': 'Once Upon a Time in China II (Wong Fei-hung Ji Yi: Naam yi dong ji keung)', 'plot': 'In the sequel to the Tsui Hark classic, Wong Fei-Hung faces The White Lotus society, a fanatical cult seeking to drive the Europeans out of China through violence, even attacking Chinese ...'}",
        metadata={"score": 0.9179003834724426, "nodeLabels": None, "id": None},
    ),
    RetrieverResultItem(
        content="{'title': 'Red Cliff Part II (Chi Bi Xia: Jue Zhan Tian Xia)', 'plot': 'In this sequel to Red Cliff, Chancellor Cao Cao convinces Emperor Xian of the Han to initiate a battle against the two Kingdoms of Shu and Wu, who have become allied forces, against all ...'}",
        metadata={"score": 0.91493159532547, "nodeLabels": None, "id": None},
    ),
]
metadata = {"__retriever": "VectorRetriever"}


全文索引

幸运的是,这个问题有了解决方案:全文索引。与根据语义相似性匹配字符串的矢量索引不同,全文索引根据词法相似性匹配文本片段,这意味着它们会比较文本的确切措辞或结构。例如,考虑句子 “蝙蝠飞了 ”和 “蝙蝠断了”。这两个句子在词性上相似,因为它们只差一个词,但在语义上却截然不同:前者描述的是动物飞起来,而后者描述的是物体断裂。全文索引使我们能够精确匹配日期和名称等字符串。


混合寻回犬


11


通过使用 Neo4j GenAI Python 库中的 HybridRetriever 类,我们可以在 GraphRAG 应用程序中使用全文索引。这种检索器在混合搜索过程中同时利用了矢量索引和全文索引。它使用用户查询来搜索这两个索引,检索节点及其相应的分数。在对每组结果的得分进行归一化处理后,它会合并这些结果,按得分对合并后的结果进行排序,并返回匹配度最高的结果。


from neo4j import GraphDatabase
from neo4j_genai.embeddings.openai import OpenAIEmbeddings
from neo4j_genai.retrievers import HybridRetriever
driver = GraphDatabase.driver(URI, auth=AUTH)
embedder = OpenAIEmbeddings(model="text-embedding-ada-002")
retriever = HybridRetriever(
    driver=driver,
    vector_index_name="moviePlotsEmbedding",
    fulltext_index_name="movieFulltext",
    embedder=embedder,
    return_properties=["title", "plot"],
)
query_text = "What is the name of the movie set in 1375 in Imperial China?"
retriever_result = retriever.search(query_text=query_text, top_k=3)
print(retriever_result)


在这里,我们再次使用电影情节的向量索引(moviePlotsEmbedding),以及每部电影标题和情节的全文索引(movieFulltext)。使用这种检索器可以返回正确的电影:


items = [
    RetrieverResultItem(
        content="{'title': 'Musa the Warrior (Musa)', 'plot': '1375. Nine Koryo warriors, envoys exiled by Imperial China, battle to protect a Chinese Ming Princess from Mongolian troops.'}",
        metadata={"score": 1.0},
    ),
    RetrieverResultItem(
        content="{'title': 'Once Upon a Time in China (Wong Fei Hung)', 'plot': \"Set in late 19th century Canton this martial arts film depicts the stance taken by the legendary martial arts hero Wong Fei-Hung (1847-1924) against foreign forces' (English, French and ...\"}",
        metadata={"score": 1.0},
    ),
    RetrieverResultItem(
        content="{'title': 'Once Upon a Time in China II (Wong Fei-hung Ji Yi: Naam yi dong ji keung)', 'plot': 'In the sequel to the Tsui Hark classic, Wong Fei-Hung faces The White Lotus society, a fanatical cult seeking to drive the Europeans out of China through violence, even attacking Chinese ...'}",
        metadata={"score": 0.9967417798386851},
    ),
]
metadata = {"__retriever": "HybridRetriever"}


要将其转化为完整的 GraphRAG 管道,我们只需添加以下代码即可:


from neo4j_genai.llm import OpenAILLM
from neo4j_genai.generation import GraphRAG
# LLM
# Note: the OPENAI_API_KEY must be in the env vars
llm = OpenAILLM(model_name="gpt-4o", model_params={"temperature": 0})
# Initialize the RAG pipeline
rag = GraphRAG(retriever=retriever, llm=llm)
# Query the graph
query_text = "What is the name of the movie set in 1375 in Imperial China?"
response = rag.search(query_text=query_text, retriever_config={"top_k": 3})
print(response.answer)


这就是我们期待的答案:


The name of the movie set in 1375 in Imperial China is "Musa the Warrior (Musa)."


总结

我们演示了如何使用 neo4j-genai 软件包中的 HybridRetriever 类构建 GraphRAG 应用程序。我们展示了该类如何将矢量搜索和全文搜索结合起来,为用户查询检索正确的上下文,而单靠矢量搜索可能无法做到这一点。


文章来源:https://medium.com/neo4j/hybrid-retrieval-for-graphrag-applications-using-the-neo4j-genai-python-package-fddfafe06ff3
欢迎关注ATYUN官方公众号
商务合作及内容投稿请联系邮箱:bd@atyun.com
评论 登录
热门职位
Maluuba
20000~40000/月
Cisco
25000~30000/月 深圳市
PilotAILabs
30000~60000/年 深圳市
写评论取消
回复取消