你是否曾在探索检索增强生成(RAG)系统时遇到过“GraphRAG”这个术语?如果是这样,你并不孤单。这个术语正在引起广泛关注,但其含义可能令人困惑。有时,它是一种特定的检索方法;而其他时候,它则是一个完整的软件套件,比如微软的GraphRAG“数据管道和转化套件”。由于使用方式多种多样,即使是最专注于RAG讨论的追随者也可能感到有些迷失。
那么,GraphRAG到底是什么呢?对我们来说,它是一组利用图结构进行检索的RAG模式。每种模式都需要一个独特的数据结构或图模式才能有效运行。感兴趣吗?在这篇文章中,我们将深入探讨GraphRAG模式的细节,分解每种模式的属性和策略。
如果你想了解RAG的入门知识,可以查看《什么是检索增强生成(RAG)?——图数据库与分析》或参加11月7日的NODES大会。这是一个为期24小时的免费在线活动,来自世界各地的演讲者将分享关于知识图谱和AI的内容。
我们介绍的每个模式都直接链接到其GraphRAG模式目录条目。这是一个开源项目,旨在实时更新最新的模式演变。我们刚刚开始收集模式,肯定还缺少很多。请帮助我们构建一个全面的GraphRAG模式目录,并加入GraphRAG Discord频道的讨论。
为了让你更清楚地了解,我们在本文中解释的模式包括:
基础 GraphRAG 模式:
中级 GraphRAG 模式:
高级 GraphRAG 模式:
让我们从一些背景信息开始。
RAG有三种范式:朴素RAG、高级RAG和模块化RAG(Gao等人):
RAG范式(Gao等人)
在高级RAG范式中,朴素RAG范式中增加了预检索和后检索阶段。模块化RAG系统包含更复杂的模式,这些模式需要对用户查询进行编排和路由。
高级RAG系统的阶段:
在这里,我们想专注于检索阶段,并对最常被引用的GraphRAG检索模式及其所需的图模式进行调查。请注意,这里的模式并不是详尽列表。
当我们深入研究检索模式时,我们注意到最先进的技术依赖于数据中的连接。无论是元数据过滤,比如按特定作者或特定主题搜索文章,还是父子检索器,它们通过回溯文本块的父节点为大语言模型(LLM)提供上下文丰富的答案,这些方法都_利用了要检索数据之间的关系_。
通常,这些实现严重依赖于客户端数据结构和大量的Python代码。然而,在图数据库中,建立真实的关系并通过简单的模式进行查询更加高效。
如果你想使用LangChain实现本文讨论的检索器,可以使用其Neo4j向量实现。我们不会在这里讨论如何设置你的Python项目以支持基于Neo4j的检索器,因为这些内容在其他地方有详细记录(例如,Neo4j GraphAcademy:使用Python构建一个基于Neo4j的聊天机器人或将Neo4j集成到LangChain生态系统中)。
相反,我们将重点放在有趣的部分:使用retrieval_query参数来实现我们将讨论的GraphRAG模式。每个模式的细节将包括相应的查询。
请记住,在编写查询时,有一个隐形的“第一部分”,它在你指定的节点标签和属性上执行向量搜索(请参阅from_existing_graph方法中的node_label和embedding_node_property参数)。可以在Neo4j向量文档中找到一个示例。第一部分返回找到的节点及其相似度分数作为node和score,然后你可以在检索查询中使用这些节点和分数来执行进一步的遍历。你还可以使用自定义参数以及$embedding参数来表示问题的嵌入。下面是一个可能的示例(来自LangChain Neo4j向量文档的示例):
retrieval_query = """
RETURN "Name:" + node.name AS text, score, {foo:"bar"} AS metadata
"""
retrieval_example = Neo4jVector.from_existing_index(
OpenAIEmbeddings(),
url=url,
username=username,
password=password,
index_name="person_index",
retrieval_query=retrieval_query,
)
retrieval_example.similarity_search("Foo", k=1)
在上述示例中,使用用户输入“Foo”在现有索引person_index上执行向量相似性搜索,并返回与最佳匹配的节点的名称、分数和一些元数据(k=1)。
在几乎每个模式的图模式中,你都会看到块节点。它们是大多数GraphRAG模式的基础,至少具有以下两个属性:文本和嵌入,其中文本包含块的可读文本字符串,嵌入包含计算出的文本嵌入。
具有最小属性的块节点。图片由作者提供。
现在让我们深入探讨各种GraphRAG模式。
你可能已经遇到过这些RAG模式——它们是处理非结构化数据时的常见模式。尽管通常展示在向量数据库中,但这些模式实际上依赖于数据中的关系。
名称: 基础检索器
又名: 朴素检索器,基线RAG,典型RAG
背景: 在创建嵌入时,将大型文档分块是有用的。嵌入是文本的语义表示,捕捉文本的含义。如果给定的文本很长且包含太多不同的主题,其嵌入的有效信息量会下降。
所需预处理: 将文档拆分为块,并使用嵌入模型对块的文本内容进行嵌入。
所需图模式: 基础词汇图
基础词汇图。图片由作者提供。
描述: 使用与之前创建块嵌入时相同的嵌入器对用户问题进行嵌入。在块嵌入上执行向量相似性搜索,以检索_k_(由开发者/用户预先配置的数量)个最相似的块。
用法: 如果用户询问有关某个主题的具体信息,而该主题存在于一个或多个(但不太多)的块中,则此模式非常有用。问题不应要求复杂的聚合或对整个数据集的知识。由于该模式仅包含向量相似性搜索,因此易于理解、实现并开始使用。
检索查询: 不需要额外的查询,因为Neo4j向量检索器默认会检索相似的块。
资源: 改进你的RAG的高级检索技术,使用Neo4j实现高级RAG策略
GraphRAG模式目录: 基础检索器
现有实现: LangChain检索器:基于向量存储的检索器,LangChain:Neo4jVector
示例实现: LangChain模板:Neo4j高级RAG
名称: 父子检索器
又名: 父文档检索器
背景: 如前所述,嵌入表示文本的语义含义。更狭窄的文本片段将产生更有意义的向量表示,因为来自多个主题的噪音较少。然而,如果LLM只接收到一个小片段的信息来生成答案,可能会缺乏上下文。检索包含找到的信息的更广泛的周围文本可以解决这个问题。
所需预处理: 将文档拆分为(较大的)块(父块),并进一步将这些块拆分为较小的块(子块)。使用嵌入模型对子块的文本内容进行嵌入。请注意,不需要对父块进行嵌入,因为它们仅用于答案生成,而不是用于相似性搜索。
所需图模式: 父子词汇图
父子词汇图。图片由作者提供。
描述: 使用与创建块嵌入时相同的嵌入器对用户问题进行嵌入。在子块嵌入上执行向量相似性搜索,以找到_k_(由开发者/用户预先配置的数量)个最相似的块。然后检索找到的子块的父块。
用法: 该模式是基础检索器的有益演进。当一个块中涵盖多个主题时,这会对嵌入质量产生负面影响,而较小的块将具有更有意义的向量表示,从而导致更好的相似性搜索结果。通过有限的额外努力,可以获得更好的结果。
检索查询:
retrieval_query = """
MATCH (node)<-[:HAS_CHILD]-(parent)
WITH parent, max(score) AS score
RETURN parent.text AS text, score, {} AS metadata
"""
资源: 改进你的RAG的高级检索技术,使用Neo4j实现高级RAG策略
GraphRAG模式目录: Graphr.ag:父子检索器
现有实现: LangChain检索器:父文档检索器
示例实现: LangChain模板:Neo4j高级RAG
类似的模式可以在具有兄弟结构的词汇图或具有层次结构的词汇图上实现,其中额外的上下文不仅来自检索父文档,还来自兄弟文档或预设深度的结构。具有兄弟结构的词汇图目前已在Neo4j的LLM知识图构建器中实现。
请注意,在具有层次结构的词汇图上有两种可能的检索器:
具有兄弟结构的词汇图。图片由作者提供。
具有层次结构的词汇图。图片由作者提供。
名称: 假设问题检索器
背景: 问题的嵌入与适当答案或文本源的文本嵌入之间的向量相似性可能非常低。如果我们有问题-块对,可以在问题嵌入上执行向量相似性搜索,这可能会比在原始文本块上执行向量相似性搜索产生更好的结果。
所需预处理: 使用LLM生成块内回答的问题。使用嵌入模型对问题进行嵌入。记录问题与包含其答案的块之间的关系。
所需图模式: 具有假设问题的词汇图
具有假设问题的词汇图。图片由作者提供。
描述: 使用与创建问题嵌入时相同的嵌入器对用户问题进行嵌入。对先前生成的问题执行向量相似性搜索。找到_k_(由开发者/用户预先配置的数量)个最相似的问题,并检索它们相关的块。
用法: 该模式是对上述模式的补充。它可以在向量相似性搜索中产生更好的结果。然而,它还需要更多的预处理工作和LLM调用的成本来生成问题。
检索查询:
retrieval_query = """
MATCH (node)<-[:HAS_QUESTION]-(chunk)
WITH chunk, max(score) AS score
RETURN chunk.text AS text, score, {} AS metadata
"""
资源: 使用Neo4j实现高级RAG策略
GraphRAG模式目录: Graphr.ag:假设问题检索器
现有实现: 多向量检索器:假设问题
示例实现: LangChain模板:Neo4j高级RAG
假设问题检索器在某种程度上与假设文档嵌入(HyDE)检索器非常相似(参见《使用LangChain进行RAG:第5部分——假设文档嵌入》)。它们的主要思想是增加用户问题与可用文本之间的相似性。在假设问题检索器中,我们生成假设问题,并将用户问题与这些问题进行匹配,而在HyDE检索器中,LLM生成用户问题的假设答案(不使用基础数据库),然后将假设答案与数据库中的实际块进行匹配,以找到最佳匹配。我们不详细讨论HyDE检索器,因为它属于RAG的预处理阶段,而不是检索阶段,并且也不需要特定的底层图模式。
领域图包含你的业务领域知识。它包含实体及其之间的关系。经常使用的领域图示例包括电影图或Northwind图。
由于领域图会根据底层领域的不同而有所差异,因此不可能提供一个通用的蓝图。只需记住,它们包含遵循某种架构的结构化数据。
在自然语言查询导致(确定性的)结构化数据检索的问题回答应用中,可以通过几种方式提供领域图中的信息。
名称: Cypher 模板
背景: 为了检索结构化数据,我们需要将用户问题翻译为可以在数据库上执行的查询。一个基本的方法是让领域专家编写预定义的查询,以便将用户问题映射到这些查询。
所需预处理: 提供多个领域特定的Cypher查询(包含参数)及其功能描述给LLM。
所需图模式: 领域图
描述: 给定用户问题,LLM决定使用哪个Cypher模板。LLM可以从用户问题中提取参数,并将它们插入到模板中。查询在数据库上执行,结果返回给LLM以生成答案。
用法: 当用户对领域图提出的问题类型是已知的时,可以创建这些模板。这种方法的一个缺点是只能使用给定的模板查询。如果用户提出的问题会导致一个不存在于模板中的查询,该怎么办?
资源: 增强语言模型与图数据库之间的交互,通过语义层GraphRAG模式目录: Graphr.ag:Cypher模板
名称: 动态 Cypher 生成
背景: 用户对结构化数据的问题中通常包含多个过滤条件,但并不总是相同的。让我们用电影图的例子来说明。可能会提出几个相关的问题:
- 史蒂文·斯皮尔伯格导演了哪些电影?
- 史蒂文·斯皮尔伯格在2000年至2010年间导演了哪些电影?
- 史蒂文·斯皮尔伯格在2000年至2010年间导演了哪些包含[示例]的电影?
这个列表可以无限延续。你不会想为每一个问题创建一个Cypher模板。解决方案是根据用户问题中实际给出的参数(部分)动态生成Cypher查询。
所需预处理: 提供参数化的Cypher查询片段及其功能描述给LLM。
所需图模式: 领域图
描述: 给定用户问题,LLM决定使用哪个片段。LLM从用户问题中提取参数,将它们插入到片段中,并将它们组合成一个完整的查询。查询在数据库上执行,结果返回给LLM以生成答案。
用法: 该模式是Cypher模板的有益演进。它更加灵活,允许回答更多样化的用户问题。然而,问题的范围仍然受到提供的片段的限制。
资源: 使用Llama 3.1、NVIDIA NIM和LangChain构建基于知识图的智能体
GraphRAG模式目录: Graphr.ag:动态Cypher生成
名称: Text2Cypher
背景: GraphRAG模式Cypher模板和动态Cypher生成受限于实现过程中定义的查询和查询片段。
所需预处理: LLM应获取数据库架构及其领域描述。这将显著提高结果的质量。可以选择通过实际数据值示例、分布或分类值列表来增强架构,以提高从问题到查询的值翻译。
所需图模式: 领域图
描述: 用户问题由LLM翻译为Cypher查询。查询在数据库上执行,结果返回给LLM以生成答案。
用法: 该模式非常灵活。没有预定义的查询,理论上LLM可以生成任何查询。然而,该模式并不是百分百可靠的。LLM在将文本翻译为Cypher时并不完美。如果LLM无法正确翻译给定的用户查询,它将无法提供任何答案。
资源: 将Neo4j集成到LangChain生态系统,LangChain Cypher搜索:提示与技巧
GraphRAG模式目录: Graphr.ag:Text2Cypher
现有实现: LangChain:GraphCypherQAChain
如果我们比较Cypher模板、动态Cypher生成和Text2Cypher,我们可以使用以下类比(如图所示):
领域图检索器的类比。图片由DALL-E生成。
上述模式也面临同样的挑战:当从用户问题中提取实体时,实体别名需要与数据库中的现有值匹配,否则查询将无法返回任何结果。可以通过提供增强的架构或使用数据库上的全文索引搜索来缓解这个问题,如LangChain模板:Neo4j高级RAG(Neo4j Cypher FT)中所述。
Text2Cypher模式是最灵活的,但也是最不可靠的。然而,正在进行大量工作以提高其可靠性。方法包括:
语言模型的选择也在结果质量中起着重要作用,因为每个语言模型都有其独特的优缺点。我将在今年的NODES大会上详细讨论这个话题,NODES大会是一个为期24小时的免费在线活动,专注于知识图谱相关的一切。
在许多情况下,你最终会得到一个结合了词汇图和领域图的场景。在一个极端情况下,你已经拥有一个领域图,并通过添加非结构化文档进行丰富;在另一个极端情况下,你只有非结构化文档,你想从中提取实体以创建一个领域图。介于两者之间有很多场景,比如使用文本属性进行向量搜索。在所有场景中,你可以使用额外的GraphRAG检索模式来进一步提高检索结果的质量。
名称: 图增强向量搜索
又名: 图+向量,增强向量搜索
背景: 基础GraphRAG模式的最大问题是找到回答问题所需的所有相关上下文。上下文可能分布在许多未被搜索到的块中。通过检索这些块所引用的实体之间的关系,并结合向量搜索,可以提供关于这些实体的额外上下文。这些关系还可以用于通过实体网络将块彼此关联。
所需预处理: 使用LLM执行块的实体和关系提取。将提取的三元组导入图中。
所需图模式: 具有提取实体的词汇图
具有提取实体的词汇图。图片由作者提供。
描述: 使用与创建块嵌入时相同的嵌入器对用户问题进行嵌入。在块嵌入上执行向量相似性搜索,以找到_k_(由开发者/用户预先配置的数量)个最相似的块。然后从找到的块开始,执行领域图的遍历以检索更多上下文。
用法: 该模式适用于检索比仅执行向量搜索更丰富的上下文。额外的遍历检索了数据中实体的交互,揭示了比检索特定文本块更多的信息,从而为生成答案提供了更高质量的输入。自然地,设置此GraphRAG模式的预处理工作需要更多的努力和成本(费用和时间)。此外,图遍历返回的信息量显著增加了LLM处理的上下文的大小。
检索查询:
retrieval_query = ""
MATCH (node)-[:PART_OF]->(d:Document)
CALL { WITH node
MATCH (node)-[:__HAS_ENTITY__]->(e)
MATCH path=(e)-[rels:!HAS_ENTITY&!PART_OF*0..2]-(n:!Chunk&!Document)
…
RETURN …
}
RETURN …
""
资源: Going Meta——第23集:使用知识图的高级RAG模式
GraphRAG模式目录: Graphr.ag:图增强向量搜索
示例实现: Neo4j的知识图构建器
该检索器有一些变体:
名称: 全局社区摘要检索器
又名: 微软GraphRAG,全局检索器
背景: 某些可以在整个数据集上提出的问题不仅仅与某些块中存在的内容相关,而是寻求整个数据集中贯穿的总体信息。前面提到的模式不适合回答这些“全局”问题。
所需预处理: 除了提取实体及其关系外,我们还需要在领域图中形成层次化的社区。可以使用Leiden算法来实现。对于每个社区,LLM将实体和关系信息总结为社区摘要。
所需图模式: 具有提取实体和社区摘要的词汇图
具有提取实体和社区摘要的词汇图。图片由作者提供。
描述: 给定用户问题和给定的社区级别,检索社区摘要并提供给LLM。
用法: 该模式适用于具有全局性质的问题。示例包括总结整个数据库的内容或查找整个数据中的主题结构。设置此图模式的工作量相当大,因为有很多步骤需要完成:实体和关系提取、社区检测和社区总结。我们必须考虑哪些任务应由LLM执行,哪些任务可以通过其他方式处理,以保持预处理成本在可接受的范围内。
检索查询: 这种方法不使用Neo4j向量来获取相似的向量节点。它会获取给定级别的所有社区摘要。以下是一个示例查询:
community_summaries = ""
MATCH (c:__Community__)
WHERE c.level = $level
RETURN c.full_content AS output
""
资源: 《从本地到全球:一种基于GraphRAG的查询焦点摘要方法》,《使用Neo4j和LangChain实现“从本地到全球”的GraphRAG:构建图谱》,《将微软GraphRAG集成到Neo4j中》
GraphRAG模式目录: Graphr.ag:全局社区摘要检索器
示例实现: 微软GraphRAG
在使用具有提取实体、社区和社区摘要的词汇图时,有几种变体:
虽然我们已经探讨了各种GraphRAG模式,但这只是一个令人兴奋的旅程的开始。当前的列表捕捉了GraphRAG演变的早期阶段。随着我们前行,新的模式无疑会出现,带来新的见解和可能性。
每个RAG模式都针对特定类型的问题量身定制,需要独特的图模式和预处理步骤。为你的应用找到完美的GraphRAG模式并不容易——这需要对不同的检索模式进行实验,并对结果进行适当的评估。很可能单一模式无法很好地服务于每一个目的,这就是为什么几乎总是需要一种能够适应各种查询的智能体方法。这里介绍的模式都针对_一次检索_策略,即为用户问题提供上下文时只查询数据库一次。更复杂的问题可能需要_迭代_或_多阶段检索_范式,结合使用不同的模式(详见《Graph检索增强生成:检索范式调查》)。
发现理想的GraphRAG模式的旅程是一个充满试验、错误和创新的过程。让我们一起踏上这段旅程。查看开源的GraphRAG模式目录并为其做出贡献。你是否遇到其他未列出的模式?如果你有任何反馈或建议,或想分享应用,请随时提交问题。如果你想讨论GraphRAG模式,加入GraphRAG Discord频道。
保持好奇,继续实验——谁知道你接下来会发现哪些突破性的模式!