使用 Neo4j 和 Qdrant 构建 GraphRAG Agent
时长:30 分钟 | 级别:中级 | 输出:GitHub |
---|
为了让人工智能 (AI) 系统更加智能和可靠,我们面临一个悖论:大型语言模型 (LLMs) 拥有卓越的推理能力,但在连接信息方面却难以做到人类直观的方式。尽管具有开创性,但检索增强生成 (RAG) 方法在处理复杂信息合成任务时常常力不从心。当要求连接不相关的信息碎片或理解大型文档中的整体概念时,这些系统经常会遗漏人类专家显而易见的关键联系。
为了解决这些问题,微软引入了 GraphRAG,它使用知识图谱 (KGs) 而非向量作为 LLMs 的上下文。GraphRAG 主要依赖 LLMs 来创建和查询 KG。然而,这种对 LLMs 的依赖可能导致许多问题。我们将通过结合向量数据库和基于图的数据库来解决这些挑战。
本教程将演示如何使用 Neo4j 和 Qdrant 构建一个带有向量搜索功能的 GraphRAG 系统。
附加材料 |
---|
本高级教程基于我们的原始集成文档:Neo4j - Qdrant 集成 |
本教程的输出在我们 GitHub 的示例仓库中:Python 中的 Neo4j - Qdrant Agent |
观看视频
RAG 及其挑战
RAG 结合了基于检索和生成式 AI,通过知识库(如向量数据库)中的相关最新信息来增强 LLMs。然而,RAG 面临一些挑战:
- 理解上下文: 模型可能会误解查询,特别是在上下文复杂或模糊时,导致不正确或不相关的答案。
- 平衡相似性与相关性: RAG 系统难以确保检索到的信息既相似又具有上下文相关性。
- 答案完整性: 传统的 RAG 可能无法捕获复杂查询的所有相关细节,这些查询需要 LLMs 在上下文中找到那些未明确呈现的关系。
GraphRAG 简介
与通常依赖文档检索的 RAG 不同,GraphRAG 构建知识图谱 (KGs) 来捕获实体及其关系。对于要求 AI 系统达到人类智能水平的数据集或用例,GraphRAG 提供了一个有前景的解决方案:
- 它可以遵循关系链来回答复杂查询,使其适用于超越简单文档检索的更好推理。
- 图结构能够更深入地理解上下文,从而产生更准确和相关的响应。
GraphRAG 的工作流程如下:
- LLM 分析数据集以识别实体(人物、地点、组织)及其关系,创建一个全面的知识图谱,其中实体是节点,它们的连接形成边。
- 自下而上的聚类算法将 KG 组织成层次化的语义组。这创建了相关的有意义的信息段,从而能够在不同抽象级别上进行理解。
- GraphRAG 使用 KG 和语义聚类来为 LLM 回答查询时选择相关的上下文。
图 1:GraphRAG 摄取和检索的完整视图
GraphRAG 的挑战
尽管有其优点,但以 LLM 为中心的 GraphRAG 方法面临几个挑战:
- 使用 LLMs 构建 KG: 由于 LLM 负责构建知识图谱,存在不一致性、偏差或错误的传播以及对所用本体缺乏控制等风险。然而,在我们的实现中,我们使用了一个 LLM 来提取本体。
- 使用 LLMs 查询 KG: 图谱构建完成后,LLM 将人类查询转换为 Cypher(Neo4j 的声明式查询语言)。然而,在 Cypher 中编写复杂查询可能导致结果不准确。
- 可伸缩性与成本考量: 要实用,应用程序必须既可伸缩又具有成本效益。依赖 LLMs 会增加成本并降低可伸缩性,因为每次添加、查询或生成数据时都会使用它们。
为了解决这些挑战,GraphRAG 需要一个更受控且结构化的知识表示系统才能在大规模运行时达到最佳效果。
架构概览
该架构有两个主要组成部分:摄取和检索与生成。摄取将原始数据处理为结构化知识和向量表示,而检索和生成则支持高效的查询和响应生成。
这个过程分为两个步骤:摄取,即准备和存储数据;以及检索和生成,即查询和利用准备好的数据。让我们从摄取开始。
摄取
GraphRAG 摄取管道结合了图数据库和向量数据库,以改进 RAG 工作流程。
图 2:摄取管道概览
让我们分解一下:
- 原始数据: 作为基础,包含非结构化或结构化内容。
- 本体创建: 一个 LLM 将原始数据处理成本体,构建实体、关系和层次结构。存在更好的方法可以从原始数据中提取更结构化的信息,例如使用 NER 识别人物、组织和地点的名称。与 LLMs 不同,这种方法会创建。
- 图数据库: 本体存储在图数据库中,以捕获复杂关系。
- 向量嵌入: 嵌入模型将原始数据转换为捕获语义相似性的高维向量。
- 向量数据库: 这些嵌入存储在向量数据库中,用于基于相似性的检索。
- 数据库互联: 图数据库(例如 Neo4j)和向量数据库(例如 Qdrant)共享唯一 ID,从而能够对基于本体和基于向量的结果进行交叉引用。
检索与生成
检索和生成过程旨在通过利用语义搜索和基于图的上下文提取来处理用户查询。
图 3:检索与生成管道概览
该架构可以分解为以下步骤:
- 查询向量化: 嵌入模型将用户查询转换为高维向量。
- 语义搜索: 该向量在向量数据库中执行基于相似性的搜索,检索相关的文档或条目。
- ID 提取: 从语义搜索结果中提取的 ID 用于查询图数据库。
- 图上下文检索: 图数据库提供上下文信息,包括与提取的 ID 链接的关系和实体。
- 响应生成: 从图谱中检索到的上下文被传递给 LLM,以生成最终响应。
- 结果: 生成的响应返回给用户。
这种架构结合了两种数据库的优势:
- 使用向量数据库进行语义搜索: 用户查询首先经过语义处理,以识别最相关的数据点,而无需明确的关键字匹配。
- 使用图数据库进行上下文扩展: 从向量数据库检索到的 ID 或实体用于查询图数据库以获取详细关系,从而用结构化上下文丰富检索到的数据。
- 增强生成: 该架构结合了语义相关性(来自向量数据库)和基于图谱的上下文,使 LLM 能够生成更具信息量、更准确且上下文丰富的响应。
实现
我们将逐步介绍一个完整的管道,该管道将数据摄取到 Neo4j 和 Qdrant 中,检索相关数据,并基于检索到的图上下文使用 LLM 生成响应。
该管道的主要组成部分包括数据摄取(到 Neo4j 和 Qdrant)、检索和生成步骤。
先决条件
这些是本教程的先决条件,分为设置、导入以及两个数据库的初始化。
设置
我们先从设置 Qdrant 和 Neo4j 实例开始。
Qdrant 设置
要创建 Qdrant 实例,您可以使用其托管服务 (Qdrant Cloud) 或设置自托管集群。为简单起见,我们将使用 Qdrant Cloud
- 前往 Qdrant Cloud 并注册或登录。
- 登录后,点击“创建新集群”。
- 按照屏幕上的说明创建您的集群。
- 集群创建后,您将获得集群 URL 和 API 密钥,您将在客户端中使用它们与 Qdrant 进行交互。
Neo4j 设置
要设置 Neo4j 实例,您可以使用 Neo4j Aura(云服务)或自行托管。我们将使用 Neo4j Aura
- 前往 Neo4j Aura 并注册/登录。
- 设置后,如果这是第一次,将创建一个实例。
- 数据库设置后,您将收到连接 URI、用户名和密码。
出于安全考虑,我们可以在 .env 文件中添加以下内容。
导入
首先,我们导入与 Neo4j、Qdrant、OpenAI 以及其他实用函数一起工作所需的库。
from neo4j import GraphDatabase
from qdrant_client import QdrantClient, models
from dotenv import load_dotenv
from pydantic import BaseModel
from openai import OpenAI
from collections import defaultdict
from neo4j_graphrag.retrievers import QdrantNeo4jRetriever
import uuid
import os
- Neo4j: 用于存储和查询图数据库。
- Qdrant: 用于语义相似性搜索的向量数据库。
- dotenv: 加载凭据和 API 密钥的环境变量。
- Pydantic: 确保在与图数据交互时数据结构正确。
- OpenAI: 与 OpenAI API 交互以生成响应和嵌入。
- neo4j_graphrag: 一个帮助程序包,用于从 Qdrant 和 Neo4j 中检索数据。
设置环境变量
在初始化客户端之前,我们从环境变量加载必要的凭据。
# Load environment variables
load_dotenv()
# Get credentials from environment variables
qdrant_key = os.getenv("QDRANT_KEY")
qdrant_url = os.getenv("QDRANT_URL")
neo4j_uri = os.getenv("NEO4J_URI")
neo4j_username = os.getenv("NEO4J_USERNAME")
neo4j_password = os.getenv("NEO4J_PASSWORD")
openai_key = os.getenv("OPENAI_API_KEY")
这确保敏感信息(如 API 密钥和数据库凭据)安全地存储在环境变量中。
初始化 Neo4j 和 Qdrant 客户端
现在,我们使用凭据初始化 Neo4j 和 Qdrant 客户端。
# Initialize Neo4j driver
neo4j_driver = GraphDatabase.driver(neo4j_uri, auth=(neo4j_username, neo4j_password))
# Initialize Qdrant client
qdrant_client = QdrantClient(
url=qdrant_url,
api_key=qdrant_key
)
- Neo4j: 我们设置与 Neo4j 图数据库的连接。
- Qdrant: 我们初始化与 Qdrant 向量存储的连接。
这将连接 Neo4j 和 Qdrant,我们现在可以开始进行摄取。
摄取
我们将遵循架构部分介绍的摄取管道工作流程。让我们从实现的角度来检查它。
定义输出解析器
single 和 GraphComponents 类将 LLM 的响应结构化为可用格式。
class single(BaseModel):
node: str
target_node: str
relationship: str
class GraphComponents(BaseModel):
graph: list[single]
这些类有助于确保来自 OpenAI LLM 的数据被正确解析为图组件(节点和关系)。
定义 OpenAI 客户端和 LLM 解析器函数
现在我们初始化 OpenAI 客户端,并定义一个函数来向 LLM 发送提示并解析其响应。
client = OpenAI()
def openai_llm_parser(prompt):
completion = client.chat.completions.create(
model="gpt-4o-2024-08-06",
response_format={"type": "json_object"},
messages=[
{
"role": "system",
"content":
""" You are a precise graph relationship extractor. Extract all
relationships from the text and format them as a JSON object
with this exact structure:
{
"graph": [
{"node": "Person/Entity",
"target_node": "Related Entity",
"relationship": "Type of Relationship"},
...more relationships...
]
}
Include ALL relationships mentioned in the text, including
implicit ones. Be thorough and precise. """
},
{
"role": "user",
"content": prompt
}
]
)
return GraphComponents.model_validate_json(completion.choices[0].message.content)
此函数向 LLM 发送提示,要求它从提供的文本中提取图组件(节点和关系)。响应被解析为结构化的图数据。
提取图组件
函数 extract_graph_components 处理原始数据,将节点和关系提取为图组件。
def extract_graph_components(raw_data):
prompt = f"Extract nodes and relationships from the following text:\n{raw_data}"
parsed_response = openai_llm_parser(prompt) # Assuming this returns a list of dictionaries
parsed_response = parsed_response.graph # Assuming the 'graph' structure is a key in the parsed response
nodes = {}
relationships = []
for entry in parsed_response:
node = entry.node
target_node = entry.target_node # Get target node if available
relationship = entry.relationship # Get relationship if available
# Add nodes to the dictionary with a unique ID
if node not in nodes:
nodes[node] = str(uuid.uuid4())
if target_node and target_node not in nodes:
nodes[target_node] = str(uuid.uuid4())
# Add relationship to the relationships list with node IDs
if target_node and relationship:
relationships.append({
"source": nodes[node],
"target": nodes[target_node],
"type": relationship
})
return nodes, relationships
此函数接受原始数据,使用 LLM 将其解析为图组件,然后为节点和关系分配唯一 ID。
将数据摄取到 Neo4j
函数 ingest_to_neo4j 将提取的图数据(节点和关系)摄取到 Neo4j 中。
def ingest_to_neo4j(nodes, relationships):
"""
Ingest nodes and relationships into Neo4j.
"""
with neo4j_driver.session() as session:
# Create nodes in Neo4j
for name, node_id in nodes.items():
session.run(
"CREATE (n:Entity {id: $id, name: $name})",
id=node_id,
name=name
)
# Create relationships in Neo4j
for relationship in relationships:
session.run(
"MATCH (a:Entity {id: $source_id}), (b:Entity {id: $target_id}) "
"CREATE (a)-[:RELATIONSHIP {type: $type}]->(b)",
source_id=relationship["source"],
target_id=relationship["target"],
type=relationship["type"]
)
return nodes
在这里,我们在 Neo4j 图数据库中创建节点和关系。节点是实体,关系连接这些实体。
这将把数据摄取到 Neo4j 中,在示例数据集上看起来是这样的:
图 4:知识图谱可视化
让我们探索如何将节点与其 ID 进行映射,并将这些信息以及向量集成到 Qdrant 中。首先,让我们创建一个 Qdrant Collection。
创建 Qdrant Collection
设置好 Qdrant 实例后,您可以创建一个 Collection。Qdrant 中的 Collection 存储用于搜索和检索的向量。
def create_collection(client, collection_name, vector_dimension):
try
# Try to fetch the collection status
try:
collection_info = client.get_collection(collection_name)
print(f"Skipping creating collection; '{collection_name}' already exists.")
except Exception as e:
# If collection does not exist, an error will be thrown, so we create the collection
if 'Not found: Collection' in str(e):
print(f"Collection '{collection_name}' not found. Creating it now...")
client.create_collection(
collection_name=collection_name,
vectors_config=models.VectorParams(size=vector_dimension, distance=models.Distance.COSINE)
)
print(f"Collection '{collection_name}' created successfully.")
else:
print(f"Error while checking collection: {e}")
- Qdrant 客户端: QdrantClient 用于连接到 Qdrant 实例。
- 创建 Collection: create_collection 函数检查是否存在 Collection。如果不存在,则使用指定的向量维度和距离度量(在本例中为余弦相似度)创建一个。
生成嵌入
接下来,我们定义一个函数,用于使用 OpenAI 的 API 为文本生成嵌入。
def openai_embeddings(text):
response = client.embeddings.create(
input=text,
model="text-embedding-3-small"
)
return response.data[0].embedding
此函数使用 OpenAI 的嵌入模型将输入文本转换为向量表示。
摄取到 Qdrant
让我们将数据摄取到向量数据库中。
def ingest_to_qdrant(collection_name, raw_data, node_id_mapping):
embeddings = [openai_embeddings(paragraph) for paragraph in raw_data.split("\n")]
qdrant_client.upsert(
collection_name=collection_name,
points=[
{
"id": str(uuid.uuid4()),
"vector": embedding,
"payload": {"id": node_id}
}
for node_id, embedding in zip(node_id_mapping.values(), embeddings)
]
)
函数 ingest_to_qdrant 为原始数据中的每个段落生成嵌入,并将其存储在 Qdrant Collection 中。它将每个嵌入与一个唯一 ID 及其来自 node_id_mapping 字典的相应节点 ID 相关联,确保为以后的检索提供适当的链接。
检索与生成
在本节中,我们将创建系统的检索和生成引擎。
构建检索器
该检索器集成了向量搜索和图数据,支持使用 Qdrant 进行语义相似性搜索,并从 Neo4j 中获取相关的图数据。这丰富了 RAG 过程,并支持生成更具信息量的响应。
def retriever_search(neo4j_driver, qdrant_client, collection_name, query):
retriever = QdrantNeo4jRetriever(
driver=neo4j_driver,
client=qdrant_client,
collection_name=collection_name,
id_property_external="id",
id_property_neo4j="id",
)
results = retriever.search(query_vector=openai_embeddings(query), top_k=5)
return results
QdrantNeo4jRetriever 处理向量搜索和图数据获取,结合使用 Qdrant 进行基于向量的检索和 Neo4j 进行基于图的查询。
向量搜索
qdrant_client
连接到 Qdrant,进行高效的向量相似性搜索。collection_name
指定向量的存储位置。id_property_external="id"
映射外部实体的 ID 进行检索。
图数据获取
neo4j_driver
连接到 Neo4j,查询图数据。id_property_neo4j="id"
确保来自 Qdrant 的实体 ID 与 Neo4j 中的图节点匹配。
查询 Neo4j 获取相关的图数据
检索器提供相关 ID 后,我们需要根据特定的实体 ID 从 Neo4j 数据库中获取子图数据。
def fetch_related_graph(neo4j_client, entity_ids):
query = """
MATCH (e:Entity)-[r1]-(n1)-[r2]-(n2)
WHERE e.id IN $entity_ids
RETURN e, r1 as r, n1 as related, r2, n2
UNION
MATCH (e:Entity)-[r]-(related)
WHERE e.id IN $entity_ids
RETURN e, r, related, null as r2, null as n2
"""
with neo4j_client.session() as session:
result = session.run(query, entity_ids=entity_ids)
subgraph = []
for record in result:
subgraph.append({
"entity": record["e"],
"relationship": record["r"],
"related_node": record["related"]
})
if record["r2"] and record["n2"]:
subgraph.append({
"entity": record["related"],
"relationship": record["r2"],
"related_node": record["n2"]
})
return subgraph
函数 fetch_related_graph 接受一个 Neo4j 客户端和一个 entity_ids 列表。它运行一个 Cypher 查询,根据给定的实体 ID 查找相关的节点(实体)及其关系。该查询匹配实体 (e:Entity),并通过任何关系 [r] 查找相关节点。该函数返回一个子图数据列表,其中每条记录包含实体、关系和 related_node。
这个子图对于生成用于回答用户查询的上下文至关重要。
设置图上下文
实现的第二部分涉及准备图上下文。我们将从 Neo4j 数据库中获取相关的子图数据,并将其格式化以供模型使用。让我们分解一下。
def format_graph_context(subgraph):
nodes = set()
edges = []
for entry in subgraph:
entity = entry["entity"]
related = entry["related_node"]
relationship = entry["relationship"]
nodes.add(entity["name"])
nodes.add(related["name"])
edges.append(f"{entity['name']} {relationship['type']} {related['name']}")
return {"nodes": list(nodes), "edges": edges}
函数 format_graph_context 处理 Neo4j 查询返回的子图。它提取图的实体(节点)和关系(边)。nodes 集合确保每个实体只添加一次。edges 列表以可读格式捕获关系:实体1 关系 实体2。
与 LLM 集成
既然我们已经有了图上下文,我们需要为像 GPT-4 这样的语言模型生成一个提示。这就是检索增强生成 (RAG) 的核心所在——我们将图数据和用户查询结合起来,为模型生成一个全面的提示。
def graphRAG_run(graph_context, user_query):
nodes_str = ", ".join(graph_context["nodes"])
edges_str = "; ".join(graph_context["edges"])
prompt = f"""
You are an intelligent assistant with access to the following knowledge graph:
Nodes: {nodes_str}
Edges: {edges_str}
Using this graph, Answer the following question:
User Query: "{user_query}"
"""
try:
response = client.chat.completions.create(
model="gpt-4",
messages=[
{"role": "system", "content": "Provide the answer for the following question:"},
{"role": "user", "content": prompt}
]
)
return response.choices[0].message
except Exception as e:
return f"Error querying LLM: {str(e)}"
函数 graphRAG_run 接受图上下文(节点和边)和用户查询,并将它们组合成 LLM 的结构化提示。节点和边被格式化为可读字符串,构成 LLM 输入的一部分。然后,LLM 会收到生成的提示,要求它使用图上下文细化用户查询并提供答案。如果模型成功生成响应,则返回答案。
端到端管道
最后,让我们将所有内容集成到一个端到端管道中,我们在其中摄取一些样本数据,运行检索过程,并查询语言模型。
if __name__ == "__main__":
print("Script started")
print("Loading environment variables...")
load_dotenv('.env.local')
print("Environment variables loaded")
print("Initializing clients...")
neo4j_driver = GraphDatabase.driver(neo4j_uri, auth=(neo4j_username, neo4j_password))
qdrant_client = QdrantClient(
url=qdrant_url,
api_key=qdrant_key
)
print("Clients initialized")
print("Creating collection...")
collection_name = "graphRAGstoreds"
vector_dimension = 1536
create_collection(qdrant_client, collection_name, vector_dimension)
print("Collection created/verified")
print("Extracting graph components...")
raw_data = """Alice is a data scientist at TechCorp's Seattle office.
Bob and Carol collaborate on the Alpha project.
Carol transferred to the New York office last year.
Dave mentors both Alice and Bob.
TechCorp's headquarters is in Seattle.
Carol leads the East Coast team.
Dave started his career in Seattle.
The Alpha project is managed from New York.
Alice previously worked with Carol at DataCo.
Bob joined the team after Dave's recommendation.
Eve runs the West Coast operations from Seattle.
Frank works with Carol on client relations.
The New York office expanded under Carol's leadership.
Dave's team spans multiple locations.
Alice visits Seattle monthly for team meetings.
Bob's expertise is crucial for the Alpha project.
Carol implemented new processes in New York.
Eve and Dave collaborated on previous projects.
Frank reports to the New York office.
TechCorp's main AI research is in Seattle.
The Alpha project revolutionized East Coast operations.
Dave oversees projects in both offices.
Bob's contributions are mainly remote.
Carol's team grew significantly after moving to New York.
Seattle remains the technology hub for TechCorp."""
nodes, relationships = extract_graph_components(raw_data)
print("Nodes:", nodes)
print("Relationships:", relationships)
print("Ingesting to Neo4j...")
node_id_mapping = ingest_to_neo4j(nodes, relationships)
print("Neo4j ingestion complete")
print("Ingesting to Qdrant...")
ingest_to_qdrant(collection_name, raw_data, node_id_mapping)
print("Qdrant ingestion complete")
query = "How is Bob connected to New York?"
print("Starting retriever search...")
retriever_result = retriever_search(neo4j_driver, qdrant_client, collection_name, query)
print("Retriever results:", retriever_result)
print("Extracting entity IDs...")
entity_ids = [item.content.split("'id': '")[1].split("'")[0] for item in retriever_result.items]
print("Entity IDs:", entity_ids)
print("Fetching related graph...")
subgraph = fetch_related_graph(neo4j_driver, entity_ids)
print("Subgraph:", subgraph)
print("Formatting graph context...")
graph_context = format_graph_context(subgraph)
print("Graph context:", graph_context)
print("Running GraphRAG...")
answer = graphRAG_run(graph_context, query)
print("Final Answer:", answer)
以下是其工作原理:
- 首先,定义用户查询(“Bob 如何与纽约连接?”)。
- QdrantNeo4jRetriever 根据用户查询的嵌入,在 Qdrant 向量数据库中搜索相关实体。它检索前 5 个结果 (top_k=5)。
- 从检索结果中提取 entity_ids。
- fetch_related_graph 函数从 Neo4j 数据库中检索相关实体及其关系。
- format_graph_context 函数以 LLM 可以理解的格式准备图数据。
- 最后,调用 graphRAG_run 函数来生成和查询语言模型,基于检索到的图上下文产生答案。
至此,我们成功创建了 GraphRAG,这是一个能够捕获复杂关系并提供比基线 RAG 方法更高性能的系统。
Qdrant + Neo4j GraphRAG 的优势
在 GraphRAG 架构中将 Qdrant 与 Neo4j 结合提供了几个显著优势,尤其是在召回率和精度组合、上下文理解、对复杂查询的适应性以及更佳的成本和可伸缩性方面。
- 提高召回率和精度: 通过利用高效的向量搜索引擎 Qdrant 以及 Neo4j 强大的图数据库,系统同时受益于语义搜索和基于关系的检索。Qdrant 识别相关向量并捕获查询与存储数据之间的相似性。同时,Neo4j 通过其图结构增加了一层连接性,确保检索到相关且上下文链接的信息。这种结合提高了召回率(检索更广泛的相关结果)和精度(提供更准确且上下文相关的结果),解决了传统基于检索的 AI 系统中的常见挑战。
- 增强上下文理解: Neo4j 通过将信息表示为图来增强上下文理解,其中实体及其关系被自然建模。与 Qdrant 集成后,系统可以根据向量嵌入检索相似的项目,以及符合所需关系上下文的项目,从而产生更细致和有意义的响应。
- 适应复杂查询: 将 Qdrant 和 Neo4j 结合使系统能够高度适应复杂查询。Qdrant 处理相关数据的向量搜索,而 Neo4j 的图能力则通过关系实现复杂的查询。这支持多跳推理以及处理传统搜索引擎难以应对的复杂结构化查询。
- 更佳的成本和可伸缩性: GraphRAG 本身需要大量资源,因为它依赖 LLMs 构建和查询知识图谱。它还采用聚类算法来创建用于局部搜索的语义聚类。这些都会阻碍可伸缩性并增加成本。Qdrant 通过向量搜索解决了局部搜索的问题,而 Neo4j 的知识图谱则用于获取更精确的答案,从而提高了效率和准确性。此外,使用命名实体识别 (NER) 技术代替 LLM 可以进一步降低成本,但这主要取决于数据集。
结论
结合 Neo4j 和 Qdrant 的 GraphRAG 是检索增强生成领域向前迈出的重要一步。这种混合方法通过结合向量搜索和图数据库带来了显著优势。Qdrant 的语义搜索能力增强了召回精度,而 Neo4j 的关系建模则提供了更深入的上下文理解。
我们探索的实现模板为您的项目提供了基础。您可以根据自己的特定需求进行调整和定制,无论是用于文档分析、知识管理还是其他信息检索任务。
随着 AI 系统的发展,这种技术的组合展示了我们如何构建更智能、更高效的解决方案。我们鼓励您尝试这种方法,探索它如何增强您的应用程序。