简介
传统的 RAG 技术仍然依赖于文本匹配,无法真正理解文本背后的语义和逻辑关系,在处理复杂查询、捕捉细微差别等方面依然存在不足。想象一下,如果只是把一堆文件扔给学生,而不教给他们如何理解和分析,他们真的能找到问题的答案吗?Graph RAG 将知识图谱(KG)引入 RAG 体系,就像为 AI 构建了一张清晰的“知识地图”。知识图谱能够表达实体之间的复杂关系,例如父子关系、朋友关系、因果关系等等,从而让 AI 不仅能够“查到”信息,更能够“理解”信息之间的逻辑,给出更准确、更智能的答案。从依赖自身记忆到检索外部信息,再到利用知识图谱进行深度理解,Graph RAG 代表着 AI 问答技术的一次重大飞跃。知识图谱是对现实世界实体及其关系的结构化表示。它们由两个主要部分组成:节点和边。节点表示独立的实体,例如人物、地点、物体或概念。而边则表示节点之间的关系,表示它们如何相互关联。这种结构使 LLM 能够访问精确且与上下文相关的的数据,从而极大地提高了其生成信息丰富答案的能力。Graph RAG 的创新之处在于它将图数据库与 LLM 相结合,在生成答案之前丰富了模型的上下文。
典型 RAG 的核心是向量搜索,它接收一段文本,并从候选书面材料中返回概念上相似的文本。然而,在 RAG 上下文中,它们只有在您需要确定一些单词与另一个单词的相似程度时才有价值。但是,如果您想了解向量内部的内容,了解其周围的内容,掌握文本中表示的内容,或者了解其中任何一个如何适应更大的上下文,那么向量作为一种表示就无法做到这一点。相比之下,知识图谱是世界的声明性(或者用人工智能术语来说,是符号性)表示。因此,人类和机器都可以理解和推理知识图谱。此外,您可以查询、可视化、注释、修复和扩展知识图谱。知识图谱代表您的世界模型 - 代表您正在处理的领域的世界的一部分。Graph通过建立结点之间的连接,可以极其有效的丰富搜索结果。
- 比如query:感冒了吃什么?db:1、感冒了可能会发烧和头痛。2、对乙酰氨基酚是一种退烧和止疼药物。相似度搜索极难查询到第2个结果,而Graph方法可以将对1和2连接在一起,从而在检索到1结点的时候将相邻结点一起检索出来。
-
当你问:“这个数据集的主题是什么?”这类高级别、概括性的问题时,传统的RAG可能就会束手无策。为什么呢?那是因为这本质上是一个聚焦于查询的总结性任务(Query-Focused Summarization,QFS),而不是一个明确的检索任务。
- GraphRAG 的第一个(也是最直接、最明显的)好处是更高质量的响应。
- 治理:可解释性、安全性等
全局性问题
在 RAG 中使用知识图谱主要解决在大型文档库上问答和理解困难的问题,特别是那些普通 RAG 方法难以处理的全局性问题。普通 RAG 在回答针对整个文档库的全局性问题时表现不佳,例如问题:请告诉我所有关于 XXX 的事情,这个问题涉及到的上下文可能分布在整个大型文档库中,普通 RAG 的向量检索方法很难得到这种分散、细粒度的文档信息,向量检索经常使用 top-k 算法来获取最相近的上下文文档,这种方式很容易遗漏关联的文档块,从而导致信息检索不完整。另外是 LLM 的上下文窗口限制问题,对于全局性问题往往涉及到非常多的上下文文档,如果要全部提交给 LLM 则很容易超出 LLM 的窗口限制,而知识图谱将文档提取成实体关系后,实际上大大压缩了文档块的大小,从而让所有相关文档提交给 LLM 成为可能。
与普通 RAG 的区别
- 知识图谱 RAG 使用图结构来表示和存储信息,捕捉实体间的复杂关系,而普通 RAG 通常使用向量化的文本数据
- 知识图谱 RAG 通过图遍历和子图检索来获取相关信息,普通 RAG 主要依赖向量相似度搜索
- 知识图谱 RAG 能更好地理解实体间的关系和层次结构,提供更丰富的上下文,普通 RAG 在处理复杂关系时能力有限
大体思路
GraphRAG在整体架构与传统RAG并无更大区别,区别在于检索的知识采用图结构的方式进行构建、存储并检索。
非结构化数据入知识图谱
构建一个非结构化数据的GraphRAG应用,首要任务是把非结构化数据转换成以图结构表示的知识图谱,并存储到GraphDB如Neo4j,用来提供后续检索与生成的基础。
知识图谱 RAG 在入库过程中会将文档块进行实体和关系的提取,提取出实体和关系后再将它们保存到图数据库中。实体提取的传统方法是基于预定义的规则和词典、统计机器学习或者深度学习等技术,但进入到 LLM 时代后,实体提取更多的是使用 LLM 来进行,因为 LLM 能够更好地理解文本的语义,实现也更加简单。比如在 LlamaIndex 的 KnowledgeGraphIndex 类中的实体提取提示词是这样的:
DEFAULT_KG_TRIPLET_EXTRACT_TMPL = (
"Some text is provided below. Given the text, extract up to "
"{max_knowledge_triplets} "
"knowledge triplets in the form of (subject, predicate, object). Avoid stopwords.\n"
"---------------------\n"
"Example:"
"Text: Alice is Bob's mother."
"Triplets:\n(Alice, is mother of, Bob)\n"
"Text: Philz is a coffee shop founded in Berkeley in 1982.\n"
"Triplets:\n"
"(Philz, is, coffee shop)\n"
"(Philz, founded in, Berkeley)\n"
"(Philz, founded in, 1982)\n"
"---------------------\n"
"Text: {text}\n"
"Triplets:\n"
)
在提示词中要求 LLM 将文档块 text 提取成实体-关系-实体这样的三元组,实体一般是名词,表示文档块中的实体,关系是动词或者介词,表示实体之间的关系,并给出了几个 Few Shot,让 LLM 能更好地理解实体抽取的任务。将实体提取出来后,通常是将实体和关系保存到图数据库中,但也有一些知识图谱 RAG 的实现会将这些数据保存到文件中,然后通过其特有的算法来进行检索,比如微软的 GraphRAG。图数据库是一种专门用来存储图结构数据的数据库,它能够高效地存储和查询图数据,常见的图数据库有 Neo4j、ArangoDB 等。不同的图数据库有不同的查询语言,比如 Neo4j 的查询语言使用的是 Cypher,如果想要在 RAG 中使用 Neo4j 来存储知识图谱数据,那么掌握一些基础的 Cypher 语法是有必要的。
检索知识图谱
知识图谱 RAG 在检索过程中会将问题进行实体提取,将提取出来的实体通过图数据库进行检索,这样可以获取到名称相同的实体,以及与实体相关的实体和关系,最后将检索到的所有实体和关系提交给 LLM 进行答案生成。PS:根据query查到相关的实体entity,再根据配置的depth bfs一个范围的entity,得到一个entity/三元组列表。三元组列表作为一段文本,增强llm生成时用到的context。
可以看下 LlamaIndex 的 KGTableRetriever 类中提取问题关键字的提示词:
DEFAULT_QUERY_KEYWORD_EXTRACT_TEMPLATE_TMPL = (
"A question is provided below. Given the question, extract up to {max_keywords} "
"keywords from the text. Focus on extracting the keywords that we can use "
"to best lookup answers to the question. Avoid stopwords.\n"
"---------------------\n"
"{question}\n"
"---------------------\n"
"Provide keywords in the following comma-separated format: 'KEYWORDS: <keywords>'\n"
)
提示词要求 LLM 从问题中提取出多个关键字,并用逗号分隔,这些关键字通常是问题中的实体。将问题的实体提取出来后,再用实体名称去图数据库中进行检索, 检索的原理就是使用图数据库的查询语句对每个实体进行检索,获取对应的三元组。以 Neo4j 图数据库为例,下面是一个简单的 Cypher 查询语句:
MATCH (n {name: 'Alice'})-[r]-(m)
RETURN n, r, m
这个查询语句的意思是查找图数据库中所有与实体 Alice 相关的实体和关系,这样就可以获取到 Alice 相关的所有三元组。最后将得到的数据转换为文本,作为问题的上下文,提交给 LLM 进行答案生成。
GraphRAG
PS:GraphRAG 有点侧重于回答总结问题。 GraphRAG:复杂查询的知识图谱新框架
与 RAG 系统类似,整个 GraphRAG 管道可以分为两个核心功能组件:索引和查询。
GraphRAG 方法使用 LLM 在两个阶段构建基于图谱的文本索引:首先从源文档中推导出实体知识图谱,基于实体群体间的相关程度,创建称之为“社区”的一般主题(高层次)和更细化的主题(低层次);然后,LLM 会对社区中的每一个主题进行总结,形成一个“数据的分层摘要”。回答问题时,则使用每个社区摘要(Community summary)生成部分回应,之后将所有部分回应再次总结为最终的用户回应。这样,聊天机器人就能够更多地基于知识(即社区摘要)来回答问题,而不是依赖嵌入。
- 提取知识图谱:首先从原始文本创建“知识图谱”。知识图谱就像一个相互连接的内容实体网络,其中每个实体(或“节点”)都以有意义的方式与其他实体相连接。
- 建立社区层次结构:接下来,它将这些相互关联的内容实体组织成“社区”,将这些社区视为相关概念的集群。
- 它使用社区检测技术对整个知识图谱进行分区,并使用 LLM 进一步形成摘要。对于特定查询,它可以汇总所有相关的社区摘要以生成全局答案。
- 生成摘要:对于每个社区,GraphRAG 都会生成摘要来概括要点。这有助于理解关键内容,而不会迷失在细节中。
- 利用图谱结构:当您需要执行涉及检索和生成信息的任务时,GraphRAG 会使用这种组织良好的图谱结构。
查询引擎是 GraphRAG 库的检索模块,负责以下任务:
- 本地搜索方法通过将模型从知识图谱中提取的相关数据与原始文档的文本块相结合,生成准确的答案。这种方法特别适用于需要深入了解文档中提到的特定实体的问题,例如“洋甘菊的治疗特性是什么?”具体来说,本地搜索方法在给定用户查询和可选的对话历史记录的情况下,从知识图谱中识别出一组与用户输入语义相关的实体。这些实体作为访问知识图谱的切入点,可以进一步提取相关的细节信息,如关联实体、关系、实体协变量以及社区报告。此外,该方法还从与这些识别出的实体相关的原始文档中提取相关的文本块。接着,将这些候选数据源进行优先级排序和筛选,以适应预定义大小的单个上下文窗口,用于生成对用户查询的最终响应。
- 全局搜索方法通过以 Map-Reduce 方式搜索所有由 LLM 生成的社区报告来生成答案。这是一种资源密集型的方法,但对于需要了解整个数据集的问题,如“数据中排名前五的主题是什么?”,通常能提供较好的结果。LLM 生成的知识图谱结构揭示了整个数据集的组织方式和主题分布。这使得我们能够将私有数据集组织成预先总结的、有意义的语义集群。通过全局搜索方法,LLM 能够在响应用户查询时,利用这些集群来总结相关主题。具体而言,当接收到用户查询和(可选的)对话历史记录时,全局搜索方法使用从知识图谱社区层次结构中指定级别获取的社区报告集合作为上下文数据,以 Map-Reduce 方式生成响应。在 Map 步骤中,社区报告被分割成预定义大小的文本块。每个文本块用于生成包含要点列表的中间响应,并为每个要点附加表示其重要性的数字评分。在 Reduce 步骤中,筛选出的最重要要点被聚合,并用作生成最终响应的上下文。全局搜索的响应质量可能会受到选择的社区层次结构级别的显著影响。较低级别的层次结构及其详细报告往往能够生成更全面的响应,但由于报告量大,也可能增加生成最终响应所需的时间和 LLM 资源。
local模式的关键在于召回相关上下文,global模式关键在于map-reduce过程
local模式特别适合用于回答关于具体事实的问题,例如查询某个实体的特定信息或者探索实体间的关系等。大致流程如下:
- 根据query和对话历史,借助实体的description_embedding向量进行相似度检索从知识图谱中识别出最相关的实体
- 也有用llm 从query 中直接提取实体名称的 大模型在知识图谱问答上的核心算法详细思路及实践
- 找到这些实体更多的信息,包含:
- 关联的原始文本块。提取其文本内容
- 关联的社区。提取其社区报告
- 关联的实体。提取其实体描述信息
- 关联的关系。提取其关系描述信息
- 关联的协变量。由于默认不生成,这里忽略
- 对这些提取的信息进行排序与筛选,最终形成参考的上下文
- 借助LLM和prompt,生成最终响应
global模式查询的架构相对简单,它采用了分布式计算中的Map-Reduce架构。可以简单概括为:
- Map: 查询指定community_level的所有社区报告,使用Query、conversation_history 和 这些社区报告 调用多次LLM生成多个带有评分的中间响应
- Reduce:对中间响应进行排序后,将这些中间响应给LLM作为参考,让LLM输出最终答案
GraphRAG 太过复杂,如果想看简单版,可以参考 Nano-graphrag