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

FDE知识库

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


收藏

【下】深入Microsoft GraphRAG之查询阶段:基于Neo4j自定义实现检索与生成

发布日期:2024-08-22 08:44:23 浏览次数: 3710
作者:AI大模型应用实践

微信搜一搜,关注“AI大模型应用实践”

在上篇中,我们基于一段约2万字的描述“漫威世界”的文本使用Microsoft GraphRAG框架与工具完成了索引阶段。由于默认输出为本地目录中parquet格式存储的文件(理解成可以通过Pandas读写的数据库文件),我们借助Python代码与Cypher语言将它们导入Neo4j图数据库,从而能够更直观的分析与使用已经构建的知识图谱

现在让我们一起探索Microsoft GraphRAG的查询(Query)阶段:

  • 官方查询工具与API

  • 深入Microsoft GraphRAG查询原理

  • 基于Neo4j实现自定义GraphRAG查询


官方查询工具与API

如何在已经构建的Microsoft GraphRAG知识图谱上完成查询呢?首先简单来看官方提供的两种主要用法。

【借助命令行工具】

Microsoft GraphRAG提供了CLI工具用于在已经构建的知识图谱上进行查询,你可以在配置好基本的环境变量(或者配置文件)后,直接使用命令进行查询调用。这里了解几个重要的查询参数:

  • community_level:社区的层级。这是使用leiden算法识别社区时生成的一个级别(level)数值,值越高意味着社区越小,默认是2。可以使用如下命令在导入的Neo4j库中分析不同级别的社区数量:

MATCH (c:__Community__)
RETURN c.level AS level, COUNT(*) AS count
ORDER BY level
  • response_type:一个描述响应类型和格式的自然语言文本。这是对响应结果格式的要求,比如默认的“Multiple Paragraphs”,表示用多段落的方式输出响应;你也可以修改成“Single Sentence“等。

  • method : 可以是localglobal这是Microsoft GraphRAG支持的两种核心查询模式,local(本地)模式通常用于针对具体事实的提问;global(全局)模式则是为了支持QFS型的查询任务,即建立在高层语义理解基础之上的概要性问题。

这是一个local模式的查询例子:

python -m graphrag.query 
--root ./msgraphrag
--method local
--community_level 2
'X教授的名字是怎么来的?他和天启之间有怎样的联系'

这是一个global模式的查询例子:

python -m graphrag.query
--root ./msgraphrag
--method global
--community_level 2
'请概括介绍文章中复仇者联盟的相关信息'

【借助API使用】

除了使用命令行工具做测试,还可以使用官方API进行开发,当然过程会较繁琐,但好处是可以借助代码与其他应用作灵活集成。官方已经在源代码的“examples_notebooks"目录下提供了详细的local/global_search.ipynb文件,你可以参考其中的讲解,拷贝相关代码后作简单修改即可使用,此处不再做详细介绍。

深入Microsoft GraphRAG查询原理

现在让我们来深入了解Microsoft GraphRAG在查询阶段的内部过程与原理,这需要结合官方文档介绍与源代码查看来完成。这些原理将指导我们在后面基于Neo4j实现自己的查询过程。

【local模式查询】

Microsoft GraphRAG的local模式查询的基本过程如下:

图片来自官方文档

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

1. 在进行查询时,首先根据输入的查询问题与对话历史,从知识图谱中识别出最相关的实体(即在Neo4j库中标签为__Entity__的节点)。这一步主要借助实体节点的描述信息(description)的嵌入向量来实现。

2. 从这些实体开始,提取更多的相关信息。包括:

  • 关联的原始文本块。提取其文本内容

  • 关联的社区。提取其社区报告

  • 关联的实体。提取其实体描述信息

  • 关联的关系。提取其关系描述信息

  • 关联的协变量。由于默认不生成,这里忽略


并对这些提取的信息进行排序与筛选,最终形成参考的上下文。

3. 借助LLM与提示模板,输入上下文与原始问题,生成最终响应。

【global模式查询】

Microsoft GraphRAG的global模式查询的基本过程如下:

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

1. MAP过程:根据用户输入问题与对话历史,查询指定层次结构上(community_level)的所有社区报告,对这些社区报告分成多个批次生成带有评分的中间响应(RIR),评分用来表示这个观点的重要性

2. Reduce过程: 对中间响应进行排序,选择最重要的观点汇总并作为参考的上下文,最后交给LLM生成最终响应结果

global查询模式的问题是响应质量可能会受到输入的社区级别参数的影响。如果层次较低,则报告较为详细,响应可能会更全面,但所需的时间和模型成本较高。所以具体需要在使用时根据实际情况作权衡考虑。

基于Neo4j实现自定义GraphRAG查询

了解内部原理后,可以在已经导入到Neo4j的知识图谱基础上自定义实现自己的检索与响应过程。这里我们参考上面的查询过程原理,在Neo4j中的知识图谱基础上自定义实现一个local模式的查询过程大致过程如下(基于LangChain):

  1. 创建一个检索相关实体的向量索引

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

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

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

如何验证这个索引是否有用呢?可以创建一个简单的向量组件来测试这个索引(名字为entity_index)

......
os.environ["AZURE_OPENAI_API_KEY"] = '自行准备'
os.environ["AZURE_OPENAI_ENDPOINT"] = '自行准备'

#模型准备,后续也会用到
text_embedder = AzureOpenAIEmbeddings(
    azure_deployment='text-embedding-3-small',
    openai_api_version='2024-05-01-preview',
)

llm = AzureChatOpenAI(
    deployment_name='gpt-4o-mini',
    openai_api_version='2024-05-01-preview',
)

#以下为测试代码,实际不需要:使用Langchain的Neo4jVector组件,从已经创建的neo4j中的向量索引进行检索测试
entity_vector = Neo4jVector.from_existing_index(
    text_embedder,
    url=NEO4J_URI,  
    username=NEO4J_USERNAME,
    password=NEO4J_PASSWORD,
    index_name='entity_index',
    text_node_property='description',  #这个不可少,用来指定节点的text属性字段
)

result = entity_vector.similarity_search("复仇者联盟",top_k=5)
print(result[0].page_content)

结果输出如下,证明这个索引是有效的:

2. 提取更多相关信息。在检索出的多个实体基础上,进一步检索其关联信息,包括关联的文本块、社区报告、内部关系(即检索出来的节点之间)、外部关系等,并将这些信息组装成上下文,用于后续的生成。这里可以利用Neo4jVector组件的一个输入参数retrieval_query来实现这个过程。

该参数作用是:允许你自定义一个Cypher代码片段,该片段会添加到到默认的Neo4j向量检索语句后一起执行,并最终要求返回text,score,metadata三个字段,以用于Langchain构建检索的返回对象。

如果你查看LangChain代码,可以看到最终执行的Cypher语句默认是这样构造的:

read_query = (

  "CALL db.index.vector.queryNodes($index, $k, $embedding) "

  "YIELD node, score "

) + retrieval_query

这里可以看到,在默认的向量检索节点代码后,添加了retrieval_query片段。因此你可以利用这个参数,来接收向量检索输出的node和score,做后续处理。

现在我们定义一个后续处理的代码片段,在检索出的node基础上(这里就是关联的实体),进一步检索其他关联信息。然后把这个片段用retrieval_query参数传入即可。这个Cypher片段如下:

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构建输出对象的需要。

剩下的工作就很简单了,只需要将上面的测试向量检索的代码稍做修改即可:去掉text_node_property参数,增加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'])

如果一切正常,你将可以看到类似的输出:

大功告成!

如果你习惯使用LlamaIndex框架,也可以采用类似方法实现。当然在实际使用中,你还可以根据自身的需要,进一步优化这里的检索召回策略。甚至可以结合查询重写、其他索引(如普通向量索引)策略、Rerank模型等实现更复杂的RAG范式,以获得最佳效果,这很好地扩充了Microsft GraphRAG的应用场景。

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


END








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

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

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

联系我们

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

微信扫码

添加专属顾问

回到顶部

加载中...

扫码咨询

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

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

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

一、 定义

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

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

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

二、 账号注册与登录

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

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

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

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

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

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

三、 服务内容与规范

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

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

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

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

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

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

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

四、 知识产权声明

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

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

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

五、 个人信息保护

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

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

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

六、 免责声明

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

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

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

七、 违约责任

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

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

八、 法律适用与争议解决

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

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

九、 其他

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

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

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


已查阅