2026年7月9日 周四晚上19:30,报名腾讯会议了解“如何构建自进化的动态知识库(Brain)”(限30人)
免费POC, 零成本试错
FDE知识库

FDE知识库

学习大模型的前沿技术与行业落地应用


收藏

一文说透微软GraphRAG的理论与实践

发布日期:2024-10-15 20:14:56 浏览次数: 4850
作者:风叔云

微信搜一搜,关注“风叔云”


今年,微软开源了自主研发的Microsoft GraghRag,犹如一枚重磅炸弹,给市场带来了非常大的反响。开源后不到半年,Github上就获得了18k的star,增长迅猛。

在这篇文章中,风叔就详细拆解一下微软GraphRag的原理,并结合源代码,观察实际运行效果。


微软GraphRAG的原理

微软GraphRag的原理并不复杂,下面的一张图即可解释清楚。首先,我们仍然需要从多个原始知识文档构建知识图谱,这一部分与上篇文章介绍的GraphRAG并无太大区别;然后利用社区检测算法(比如leiden算法),把知识图谱划分成多个社区/聚簇,并利用LLM生成这些社区的自然语言摘要;在回答总结性问题时,先在社区执行查询获得中间答案,最后汇总生成全局性的答案。

可以看到,相比以往RAG结合知识图谱的方式,微软GraphRAG最大的不同就是引入了“社区”这个概念社区,即围绕某个主题的一组紧密相关的实体与关系信息,比如“三国演义”这个社区,就会关联到众多的诸侯国、主公、将领、谋士、事件等实体及其关系。

从实现流程来看,微软GraphRAG与传统RAG仍然一致,包括索引阶段和查询阶段两大环节,查询阶段相对简单,最复杂的是索引阶段。

索引阶段的主要过程如下所示:

1. 文本块拆分 将原始文档拆分成多个文本块,这个过程与经典RAG的处理过程一样。

2. 实体与关系提取: 对文本块借助LLM分析,提取实体与关系,这个过程与普通的Graph RAG也类似。

3. 生成实体与关系摘要 为提取的实体与关系生成简单的描述性信息,这是区别普通Graph RAG的一个步骤。这些描述性信息,会作为一个属性存放在实体/关系的Graph节点中。这种摘要的好处是可以借助嵌入向量更准确的对这些实体与关系进行检索,带来的负面影响是由于需要为大量的实体与关系生成描述信息,将会产生很多的LLM调用,这可能带来过长的耗时与昂贵的大模型API开销。

4. 检测与识别社区 借助社区检测算法,在Graph中识别出多个社区。

5. 生成社区摘要: 借助LLM生成每个社区的摘要信息,用来了解数据集的全局主题结构和语义,这也是微软GraphRAG的核心价值所在,也是回答全局性问题的关键。

我们再来看一下检索查询阶段,微软GraphRAG有两种查询模式,local模式和global模式。local(本地)模式通常用于针对具体事实的提问;global(全局)模式则是为了支持全局型的查询任务,即建立在高层语义理解基础之上的概要性问题。

上图是local模式,其查询的主要方法是结合相关的知识图谱结构化信息与原始文档的非结构化数据,构建用于增强生成的上下文,并借助LLM获得响应,因此非常适合回答关于特定事实的问题(比如某个实体的信息与关系等)。其主要过程如下所示:

  1. 在进行查询时,首先根据输入的查询问题与对话历史,从知识图谱中识别出最相关的实体(即在Neo4j库中标签为__Entity__的节点)。这一步主要借助实体节点的描述信息(description)的嵌入向量来实现。
  2. 从这些实体开始,提取更多的相关信息,包括关联的原始文本块、关联的社区、关联的实体和关联的关系,并对这些提取的信息进行排序与筛选,最终形成参考的上下文。
  3. 借助LLM与提示模板,输入上下文与原始问题,生成最终响应。


上图是global模式,其查询的架构相对简单,采用了分布式计算中的Map-Reduce架构,可以简单概括为:

  1. MAP过程:根据用户输入问题与对话历史,查询指定层次结构上(community_level)的所有社区报告,对这些社区报告分成多个批次生成带有评分的中间响应(RIR),评分用来表示这个观点的重要性
  2. Reduce过程:对中间响应进行排序,选择最重要的观点汇总并作为参考的上下文,最后交给LLM生成最终响应结果
  3. global查询模式的问题是响应质量可能会受到输入的社区级别参数的影响。如果层次较低,则报告较为详细,响应可能会更全面,但所需的时间和模型成本较高。所以具体需要在使用时根据实际情况作权衡考虑


微软GraphRAG实战

现在我们用一个文档来构建基于微软GraphRAG的demo应用,这里重点关注索引阶段,准备一个白话文三国演义片段的文本文件用于测试。


第一步,微软GraphRag安装和熟悉

使用pip安装graphrag库,建议在虚拟环境下进行。初始化,这里使用msgraphrag作为应用目录:

python -m graphrag.index --init --root ./msgraphrag


初始化以后会在指定的根目录下生成基本的文件与目录结构,重要的包括:

  • input目录:存放输入原始文档(txt或者csv),这里把测试的txt文件放置到该目录下
  • .env与settings.yaml配置文件:你可以在.env或者settings.yaml中修改全部配置项目,默认情况下可以只修改LLM相关的配置,注意目前只支持OpenAI或者Azure OpenAI的模型:
  • prompts目录:这里存放了自动生成的LLM提示模板文件,一共有四个,分别会在流程的不同处理阶段使用:
    • entity_extraction:用于从自然语言文本抽取实体与关系。
    • summarize_descriptions:用于生成实体与关系的描述性文本。
    • community_report:用于生成社区的摘要等报告信息。


尽管可以使用这里初始化的默认提示模板,但强烈建议通过GraphRAG提供的命令来创建自适应提示模板:GraphRAG会提取输入数据的信息,并借助大模型来分析与生成更具有针对性的提示模板。


第二步,创建索引

现在运行下面的命令来创建自适应的提示模板(更多参数请参考官方文档):

python -m graphrag.prompt_tune --language Chinese


执行成功后我们来观察两个prompts目录下新的提示模板文件内容



这里从最后输出的信息可以了解到其基本的处理过程:从拆分输入文本开始,到提取实体与关系、生成摘要信息、构建内存中的Graph结构、从Graph识别社区、创建社区报告、创建Graph中的文本块节点和文档节点等。


第三步,将索引集成到neo4j

在完成索引后,默认情况下,GraphRAG会把构建整个知识图谱所需要的数据持久化到output目录下,并以parquet格式文件的方式存放。

由于parquet文件可以很简单的通过pandas库读取成DataFrame表,所以在了解其结构后,就可以通过Cypher语句导入成Neo4j图数据库中的节点与关系。

这里使用其提供的笔记本文件在本地运行,即可成功地把上面构建的知识图谱数据全部导入到Neo4j数据库。


第四步 检索查询

我们使用上文介绍的local模式来进行检索,首先创建一个检索相关实体的向量索引。

由于需要根据用户问题从知识图谱所有节点中检索出最相关的实体(导入时设置的标签为__Entity__),这需要利用到实体节点的一个属性:description_embedding,即节点描述信息的嵌入向量。

因此我们需要在description_embedding上创建一个向量索引,并基于此索引来检索相关实体即可。使用如下Cypher语句在Neo4j创建这个索引:

CREATE VECTOR INDEX entity_index IF NOT EXISTS FOR (e:__Entity__) ON e.description_embeddingOPTIONS {indexConfig: { `vector.dimensions`: 1536, `vector.similarity_function`: 'cosine'}}


然后提取更多相关信息。在检索出的多个实体基础上,进一步检索其关联信息,包括关联的文本块、社区报告、内部关系、外部关系等,并将这些信息组装成上下文,用于后续的生成。

这里可以利用Neo4j的Vector组件的一个输入参数retrieval_query来实现这个过程。该参数作用是自定义一个Cypher代码片段,该片段会添加到到默认的Neo4j向量检索语句后一起执行,并最终要求返回text、score、metadata三个字段,以用于Langchain构建检索的返回对象。

现在我们定义一个后续处理的代码片段,在检索出的node基础上(这里就是关联的实体),进一步检索其他关联信息。

lc_retrieval_query = """
    //接收向量检索输出的node,在此基础上进一步检索    WITH collect(node) as nodes
    //查找最相关的文本块,输出text属性    WITH    collect {        UNWIND nodes as n        MATCH (n)<-[:HAS_ENTITY]->(c:__Chunk__)        WITH c, count(distinct n) as freq        RETURN c.text AS chunkText        ORDER BY freq DESC        LIMIT $topChunks    } AS text_mapping,
    //查找最相关的社区,输出summary摘要(如果没有weight,用cypher设定)    collect {        UNWIND nodes as n        MATCH (n)-[:IN_COMMUNITY]->(c:__Community__)        WITH c, c.rank as rank, c.weight AS weight        RETURN c.summary         ORDER BY rank, weight DESC        LIMIT $topCommunities    } AS report_mapping,
    //查找最相关的其他实体(nodes外部),输出描述    collect {        UNWIND nodes as n        MATCH (n)-[r:RELATED]-(m)         WHERE NOT m IN nodes        RETURN r.description AS descriptionText        ORDER BY r.rank, r.weight DESC         LIMIT $topOutsideRels    } as outsideRels,          //查找最相关的其他实体(nodes内部),输出描述    collect {         UNWIND nodes as n         MATCH (n)-[r:RELATED]-(m)          WHERE m IN nodes         RETURN r.description AS descriptionText         ORDER BY r.rank, r.weight DESC          LIMIT $topInsideRels     } as insideRels,
     //输出这些实体本身的描述     collect {         UNWIND nodes as n         RETURN n.description AS descriptionText     } as entities
//返回text,score,metadata三个字段RETURN {Chunks: text_mapping, Reports: report_mapping,        Relationships: outsideRels + insideRels,        Entities: entities} AS text, 1.0 AS score, {source:''} AS metadata """


这里的Cypher语句虽然较长,但其实并不复杂,就是对向量检索输出的node搜集后,检索更多相关信息(社区报告、其他实体、关系等),最后合并输出,注意这里必须输出text,score,metadata三个属性,这是Langchain构建输出对象的需要。

剩下的工作就很简单了,把这个片段用retrieval_query参数传入即可。

#创建neo4j向量存储对象,注意传入retrieval_query参数lc_vector = Neo4jVector.from_existing_index(    text_embedder,    url=NEO4J_URI,    username=NEO4J_USERNAME,    password=NEO4J_PASSWORD,    index_name='entity_index',    retrieval_query=lc_retrieval_query,)
#chain,并调用获得响应。此处可参考Langchain文档学习chain = RetrievalQAWithSourcesChain.from_chain_type(    llm,    chain_type="stuff",            retriever=lc_vector.as_retriever(search_kwargs={"params":{            "topChunks": topChunks,            "topCommunities": topCommunities,            "topOutsideRels": topOutsideRels,            "topInsideRels": topInsideRels,        }}))
response = chain.invoke(    {"question": "周瑜和孙权有什么关系?"},    return_only_outputs=True,)print(response['answer'])


如果运行顺利,将可以看到类似的输出:

周瑜是孙策的结拜兄弟,在孙策去世后,辅佐孙权在赤壁之战中击破曹操。


当然在实际使用中,我们还可以根据自身的需要,进一步优化检索召回策略,比如参考风叔在《RAG实战篇系列》中介绍的查询重写、查询扩展、多级索引、Rerank模型等方式。

除了local模式的查询外,global模式也可自定义实现。如果说local模式的关键在于如何召回相关上下文,global模式的关键则在于map与reduce过程的提示模板,感兴趣的朋友可参考微软GraphRAG源代码中的提示模板自行实现。

53AI,企业落地大模型首选服务商

产品:场景落地咨询+大模型应用平台+行业解决方案

承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业

联系我们

售前咨询
186 6662 7370
预约演示
185 8882 0121

微信扫码

添加专属顾问

回到顶部

加载中...

扫码咨询

扫码登录
登录即表示您同意《53AI网站服务协议》
服务协议

欢迎您使用【53AI 官方网站】(以下简称“本网站”或“我们”)。本《会员服务协议》(以下简称“本协议”)是您(以下简称“会员”或“用户”)与【深圳市博思协创网络科技有限公司】之间关于注册、登录及使用本网站会员服务所订立的法律协议。

在您注册或登录前,请务必审慎阅读、充分理解各条款内容,特别是免除或限制责任的条款、知识产权条款、争议解决条款等。此类条款将以加粗形式提示您注意。 当您通过微信公众号授权、手机验证码验证或其他方式成功登录本网站时,即视为您已完全理解并同意接受本协议的全部内容。

一、 定义

本网站:指由【深圳市博思协创网络科技有限公司】运营的,域名为【53ai.com】的网站及相关移动端页面。

会员服务:指本网站向注册会员提供的知识库文章查阅、内容检索及其他相关增值服务。

知识库内容:指本网站发布的包括但不限于文字、图表、数据、研究报告、行业分析等数字化内容资源。

二、 账号注册与登录

登录方式:本网站支持以下登录方式,您可根据实际情况选择:

微信公众号授权登录:您同意将您的微信OpenID信息授权给本网站,用于创建或关联会员账号。

手机验证码登录:您需提供真实有效的手机号码,并通过短信验证码完成身份验证与登录/注册。

账号安全:您的账号仅限您本人使用,禁止赠与、借用、租用、转让或售卖。因您保管不善导致的账号被盗、密码泄露等损失,由您自行承担。

实名认证:根据相关法律法规要求,我们可能要求您在特定功能下完成实名认证。如您拒绝提供,可能无法使用部分或全部服务。

未成年人保护:若您未满18周岁,请在法定监护人的陪同下阅读本协议,并在征得监护人同意后使用本服务。

三、 服务内容与规范

知识库查阅权限:会员登录后,有权按照其会员等级对应的权限范围,在线浏览、检索本网站知识库中的相关文章及内容。

服务变更:我们有权根据业务发展需要,调整、变更或终止部分服务内容,并将以网站公告、公众号消息等方式提前通知。

禁止行为:您在使用服务时不得实施以下行为:

利用技术手段批量爬取、下载、转存知识库内容;

将知识库内容用于商业目的或未经授权地向第三方传播;

干扰本网站正常运行或侵犯其他用户合法权益;

发布违法违规信息或从事违反公序良俗的活动。

四、 知识产权声明

权利归属:本网站知识库中的排版设计、软件代码等内容的知识产权均归【公司全称】或原权利人所有,受《中华人民共和国著作权法》等法律保护。

有限许可:本网站授予会员一项非独占、不可转让、不可转授权的普通许可,仅限于个人学习、研究之目的在线查阅知识库内容。

侵权追责:未经书面许可,任何单位或个人不得以任何形式复制、转载、摘编、镜像、汇编或以其他方式使用上述内容。一经发现,我们保留追究其法律责任的权利。

五、 个人信息保护

我们重视对您个人信息的保护。关于我们如何收集、使用、存储和保护您的个人信息,请单独阅读 《隐私政策》。

您通过微信公众号授权或手机号验证所提供的信息,我们将严格按照《个人信息保护法》的规定处理,仅用于身份识别、服务提供及安全验证等必要用途。

您可以随时通过网站设置或联系客服行使查阅、更正、删除个人信息及撤回授权同意的权利。

六、 免责声明

内容准确性:知识库内容仅供参考,不构成专业建议。我们不对其完整性、准确性、时效性作任何明示或暗示的保证,您应自行判断并承担使用风险。

不可抗力:因自然灾害、政策法规变化、网络故障、第三方平台接口异常(如微信接口维护、运营商短信通道故障)等不可抗力导致的服务中断或延迟,我们不承担违约责任。

第三方链接:本网站可能包含指向第三方网站的链接,该等网站的内容和服务不受我们控制,请您自行甄别风险。

七、 违约责任

如您违反本协议约定,我们有权视情节采取警告、限制功能、暂停服务、注销账号等措施,并保留要求赔偿损失的权利。

如因您的违约行为导致我们遭受行政处罚、第三方索赔或商誉损失,您应承担全部赔偿责任(包括但不限于罚款、赔偿金、律师费、公证费等)。

八、 法律适用与争议解决

本协议的订立、执行和解释均适用中华人民共和国大陆地区法律。

因本协议产生的或与本协议有关的任何争议,双方应友好协商解决;协商不成的,任何一方均可向【公司所在地】有管辖权的人民法院提起诉讼。

九、 其他

本协议构成双方就本服务达成的完整协议,取代此前任何口头或书面约定。

本协议任一条款被认定为无效或不可执行的,不影响其他条款的效力。

我们对本协议享有最终解释权,并在法律允许的范围内保留随时修改的权利。修改后的协议一经公布即生效,继续使用服务即视为同意修订内容。


已查阅