来自工业界的知识库 RAG 服务(七),RagFlow 知识图谱实践与优化方案探索

背景介绍

在2024年,我曾撰写过 RagFlow 源码全流程深度解析,对 RagFlow 的完整 RAG 流程进行了深入剖析。自那时起,RagFlow 经历了多轮迭代演进,不仅增强了 Agent 能力,更是在知识图谱支持方面取得了显著进展。

最近,RagFlow 公众号发布了 RAGFlow 0.16.0 特性总览,详细介绍了 RagFlow 对知识图谱机制的优化。本文将对 RagFlow 的知识图谱实现流程与机制进行深入分析,帮助读者更好地理解其实现细节,从而更有效地利用 RagFlow 的相关功能。

RagFlow 产品页面

首先,让我们了解当前产品页面的配置选项,以便更好地理解实现细节。

截至2025年4月,RagFlow 的 Web 页面中,知识图谱配置页面提供以下维度的配置:

请添加图片描述

  • 实体类型:知识图谱的核心在于实体与关系的提取,选择具有实际业务价值的实体类型至关重要,这直接影响知识图谱的准确性;
  • 方法:支持 Light 和 General 两种模式。Light 模式采用 LightRAG 的实体抽取 prompt,而 General 模式则采用微软 GraphRAG 的 prompt,后者更全面但消耗更多 token;
  • 实体归一化:用于合并相同实体,提升知识图谱的准确性。该功能自 RagFlow 0.9 版本引入,在 RagFlow 0.16 中支持手动关闭,因为实体重复判断基于大模型,会消耗大量 token;
  • 社区报告生成:基于 GraphRAG 引入的功能,通过生成社区实体和关系的摘要来提升社区召回准确性。社区摘要的生成同样依赖大模型,会消耗大量 token,在 RagFlow 0.16 中支持可选关闭;

从产品设计可以看出,RagFlow 在 GraphRAG 的基础上进行了多项优化,特别是在减少大模型 token 消耗方面做了重要权衡。下面将详细介绍具体的实现方案。

GraphRAG 方案

RagFlow 的知识图谱实现基于 GraphRAG 方案,并在此基础上进行了优化。要理解 RagFlow 的实现,首先需要了解 GraphRAG 的基本原理,详细内容可参考微软的论文 From Local to Global: A GraphRAG Approach to Query-Focused Summarization。该方案的核心流程如下图所示:

请添加图片描述

左侧部分是从原始文档到知识图谱的构建流程,右侧是基于知识图谱的社区构建与摘要生成。核心环节包括:

  • 实体和关系抽取(Text Chunks -> Entities and Relations):此环节是从原始的文档中提取实体和关系,目前是利用大模型直接抽取完成的,上面提到的 Light 和 General 的区别影响的就是这部分抽取的 prompt;
  • 知识图谱构建(Entities and Relations -> Knowledge Graph):此环节是直接将实际和关系构建为知识图谱,属于标准操作;
  • 社区构建(Knowledge Graph -> Graph Communities):此环节是使用社区检测算法将图划分为强连接节点的社区,GraphRAG 使用的是 Leiden 社区检测算法;
  • 社区摘要生成(Graph Communities -> Community Summaries):此环节是基于社区的实体和关系生成对应的摘要,这样才能更精准地召回对应的社区,上面提到的社区报告生成的可选开关就是关闭这部分摘要的生成;

RagFlow 知识图谱构建实现方案

RagFlow 在 GraphRAG 方案的基础上进行了优化和扩展,下面详细介绍具体实现细节。

构建整体流程

RagFlow 的知识图谱构建完整流程在 graphrag/general/index.pyrun_graphrag() 方法中实现,包含以下环节:

  1. 基于文档分片构建知识图谱,包括实体和关系的抽取,以及知识图谱的生成;
  2. 知识图谱合并,将新生成的知识图谱与原有知识图谱进行合并;
  3. 知识图谱的实体合并,减少实体重复,提升准确性;
  4. 基于知识图谱构建社区,包括社区构建与摘要生成;

实现代码如下:

async def run_graphrag(
    row: dict,
    language,
    with_resolution: bool,
    with_community: bool,
    chat_model,
    embedding_model,
    callback,
):
    # 获取文档分片

    tenant_id, kb_id, doc_id = row["tenant_id"], str(row["kb_id"]), row["doc_id"]
    chunks = []
    for d in settings.retrievaler.chunk_list(
        doc_id, tenant_id, [kb_id], fields=["content_with_weight", "doc_id"]
    ):
        chunks.append(d["content_with_weight"])

    # 构建知识图谱

    subgraph = await generate_subgraph(
        LightKGExt
        if row["parser_config"]["graphrag"]["method"] != "general"
        else GeneralKGExt,
        tenant_id,
        kb_id,
        doc_id,
        chunks,
        language,
        row["parser_config"]["graphrag"]["entity_types"],
        chat_model,
        embedding_model,
        callback,
    )
    if not subgraph:
        return

    # 合并知识图谱

    subgraph_nodes = set(subgraph.nodes())
    new_graph = await merge_subgraph(
        tenant_id,
        kb_id,
        doc_id,
        subgraph,
        embedding_model,
        callback,
    )
    assert new_graph is not None

    if not with_resolution or not with_community:
        return

    # 可关闭的实体合并机制

    if with_resolution:
        await resolve_entities(
            new_graph,
            subgraph_nodes,
            tenant_id,
            kb_id,
            doc_id,
            chat_model,
            embedding_model,
            callback,
        )

    # 可关闭的社区发现机制

    if with_community:
        await extract_community(
            new_graph,
            tenant_id,
            kb_id,
            doc_id,
            chat_model,
            embedding_model,
            callback,
        )
    return
实体与关系抽取

知识图谱构建的基础是实体与关系的抽取。在 GraphRAG 方案中,通过精心设计的 prompt 和 Few-Shot 机制,利用大模型完成实体和关系的抽取。

这部分对应的实现在 graphrag/general/graph_extractor.py 中的 _process_single_content() 方法中完成,GraphRAG 为实体与关系提取设计了一个精巧的 prompt, 并通过 Few Shot 的机制进行了必要的优化,从 Few Shot 可以大致了解提取的实体与关系的格式:

请添加图片描述

根据上面看到的 example,大模型的结果是文本对应的实体和关系,并使用分隔符进行连接,之后在 _entities_and_relations() 方法中使用基于分隔符进行切分,即可得到对应的实体和关系。

知识图谱生成与合并

实体和关系抽取完成后,RagFlow 基于 networkx 生成知识图谱,并与知识库中原有知识图谱进行合并。

知识图谱生成通过调用 networkx 的 add_node()add_edge() 方法实现,具体实现可参考 graphrag/general/index.py 中的 generate_subgraph() 方法。

知识图谱合并在 graph_merge() 中完成,处理逻辑如下:

  • 节点存在时,将新节点的描述信息叠加至原有节点;
  • 关系存在时,将新关系的描述信息、权重和关键词叠加至原有关系;
知识图谱的实体合并

实体合并是知识图谱构建的重要环节,重复实体会降低检索准确性。RagFlow 在 graphrag/entity_resolution.py 中实现实体合并,采用两步策略:

  1. 初步相似度判断:使用编辑距离等工程手段筛选相似实体,基于 editdistance 实现;
  2. 大模型相似度判断:确定最终的实体合并结果;

初步相似度判断主要用于减少候选实体对的数量。虽然基于大模型的相似度判断准确性更高,但会带来较大的计算开销,这也是 RagFlow 提供手动关闭选项的主要原因。

社区构建

RagFlow 的社区构建基于 Leiden 算法实现,该算法通过模块度优化生成高质量的社区划分。具体实现原理可参考论文 From Local to Global: A GraphRAG Approach to Query-Focused Summarization。实现位于 graphrag/general/leiden.py

社区构建基于 graspologichierarchical_leiden 实现:

def _compute_leiden_communities(
        graph: nx.Graph | nx.DiGraph,
        max_cluster_size: int,
        use_lcc: bool,
        seed=0xDEADBEEF,
) -> dict[int, dict[str, int]]:

    results: dict[int, dict[str, int]] = {}
    if is_empty(graph):
        return results
    if use_lcc:
        graph = stable_largest_connected_component(graph)

    # 多层级社区划分

    community_mapping = hierarchical_leiden(
        graph, max_cluster_size=max_cluster_size, random_seed=seed
    )
    for partition in community_mapping:
        results[partition.level] = results.get(partition.level, {})
        results[partition.level][partition.node] = partition.cluster

    return results
社区摘要生成

社区摘要生成基于社区中实体和关系的描述信息,完全依赖大模型实现。通过精心设计的 prompt,生成能够代表社区核心内容的文本,提升检索和召回准确性。

相关 prompt 在 graphrag/general/community_report_prompt.py 中定义,核心内容如下:

请添加图片描述

输入为实体和关系数据,大模型生成社区摘要和关键见解,提升社区召回的准确性。

知识图谱检索

知识图谱构建完成后,RagFlow 利用知识图谱增强 RAG 检索。以 /dify/retrieval 接口为例,检索实现如下:

ranks = settings.retrievaler.retrieval(
    question,
    embd_mdl,
    kb.tenant_id,
    [kb_id],
    page=1,
    page_size=top,
    similarity_threshold=similarity_threshold,
    vector_similarity_weight=0.3,
    top=top,
    rank_feature=label_question(question, [kb])
)

# 可选开启知识图谱检索

if use_kg:
    ck = settings.kg_retrievaler.retrieval(question,
                                            [tenant_id],
                                            [kb_id],
                                            embd_mdl,
                                            LLMBundle(kb.tenant_id, LLMType.CHAT))
    # 知识图谱检索的内容插入常规检索的最前面,知识图谱检索优先展示

    if ck["content_with_weight"]:
        ranks["chunks"].insert(0, ck)

检索流程在 graphrag/search.py 中实现,具体步骤如下:

  1. 查询重写:调用 query_rewrite 方法,使用大模型提取问题中的实体类型关键词和实体;
  2. 实体与关系检索:通过关键词和实体类型检索相关实体,通过原始问题检索相关关系;
  3. 路径分析:从关键词检索到的实体出发,获取 N 跳邻居,实现相似度衰减;
  4. 结果融合与评分:融合关键词检索、实体类型检索和关系检索结果,确定最终得分;
  5. 结果排序与截断:按相似度和 PageRank 乘积排序,截取前 N 个结果;
  6. 社区检索:调用 _community_retrival_() 方法检索相关社区报告;
  7. 结果组合:将实体、关系和社区报告组合为最终结果;

总结

本文详细介绍了 RagFlow 知识图谱的构建与检索流程。整体实现基于 GraphRAG 方案,并在此基础上进行了多项优化。RagFlow 提供了灵活的配置选项,如社区摘要和实体合并的可选关闭,使用户能够在效果与性能之间进行权衡。这些优化使得 RagFlow 的知识图谱功能更加实用和高效。

### RAGFlow知识图谱介绍使用 #### 背景概述 RAGFlow 是 InfiniFlow 开源的一个端到端解决方案,专注于实现检索增强生成(Retrieval-Augmented Generation, RAG)。该工具不仅能够帮助开发者构建高效的知识库查询系统,还支持通过自然语言处理技术来提升数据检索的质量和效率[^1]。 #### 架构特点 作为一款先进的知识图谱应用,RAGFlow 继承并扩展了传统知识图谱的核心概念——即由节点(Node) 和边(Relationship)构成的有向带标签图结构。这种设计允许利用计算机科学领域内广泛研究过的图论理论、算法以及具体实现方法来进行优化改进[^2]。 #### 功能亮点 - **强大的语义理解能力**: 结合最新的预训练模型和技术手段,使得机器可以更好地解析人类语言表达的信息需求; - **高效的多模态融合机制**: 支持文本、图像等多种形式的数据输入,并能自动建立它们之间的关联关系; - **灵活可定制的工作流管理**: 用户可以根据实际应用场景调整各个组件的功能配置,满足不同业务逻辑的要求; #### 使用案例展示 假设有一个在线教育平台想要为其用户提供个性化的学习路径规划服务,则可以通过部署RAGFlow 来完成如下操作: ```python from ragflow import RagEngine engine = RagEngine() query = "我想学Python编程" results = engine.search(query) for result in results: print(f"推荐课程:{result['title']}") ``` 此段代码展示了如何创建一个简单的搜索引擎实例,它接收用户的查询请求后返回一系列匹配度较高的结果列表。这些结果可能来自于预先定义好的知识点集合或者是实时抓取自互联网上的公开资源链接等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

易迟

高质量内容创作不易,支持下

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值