写点什么

懒懒笔记 | 课代表带你梳理【RAG 课程 19:基于知识图谱的 RAG】

  • 2025-07-07
    北京
  • 本文字数:7086 字

    阅读完需:约 23 分钟

大家好呀!这里是你们的课代表懒懒~不知不觉,我们已经来到课程的最后一节,为我们的坚持和努力点赞!


通过之前的学习,我们已经学会了如何使用 RAG 增强大模型的能力。有细心的小伙伴发现,传统的 RAG 在召回上存在碎片化的局限。为了解决传统 RAG 存在的问题,知识图谱 RAG 应运而生,本节课就让懒懒带大家回顾如何搭建知识图谱 RAG 吧!


知识图谱 RAG,超越朴素 RAG!


朴素 RAG:😔

  • 检索返回的内容孤立、缺乏结构关联。

  • 回答在需要跨文档、跨段落推理的场景中,召回片段之间缺乏逻辑和语义连贯性。

  • 无法识别文档间的主题关系,信息冗余与漏召。


知识图谱 RAG:😊

  • 实体-关系-属性的三元组形式显式建模语义关联,使系统能够清晰刻画知识之间的语义路径。

  • 在图谱上进行结构感知的检索或路径遍历,更有针对性地召回与用户问题语义相关、逻辑连贯的信息。

  • 跨文档实体的对齐与融合,增强主题聚合与复杂推理能力。


知识图谱:让机器理解世界的“知识网络”

一切从图说起:


(图(Graph)结构)


图是一种由一组节点(或称为顶点)和节点之间的边组成的数据结构,例如上图可以表示地铁路线图,每个顶点表示一个站点,每个边表示站点之间的连通性。


知识图谱(Knowledge Graph, KG)是一种用 “图” 结构表示知识的方式,通常由三元组组成,其中每个三元组包含一个实体、关系以及与该实体相关的另一个实体,结构形式为 (实体 1)—[关系]→(实体 2)。


(知识图谱示例(图源网络))


知识图谱有三个重要组成部分,即实体,关系和属性,每个部分的解释如下:


  • 实体(Entity):知识图谱的基本构成单位,代表现实世界中的物品、概念、事件等。例如图 2 中的每个人物、城市、课程都是实体。

  • 关系(Relationship):描述实体间联系的方式,通常用边来表示。比如图 2 中男士与 Bonn 的关系是“lives in”,表示这位男士生活在 Bonn City。

  • 属性(Attribute):实体或关系的附加信息。例如图 2 中 Bonn City 有“Type”,“Population”和“Area”三个属性。


从文档中构建知识图谱


拆解流程::


RAG 系统的“智能外挂”:知识图谱如何赋能 RAG?

构建知识图谱


要构建基于知识图谱的 RAG 系统,就像是在搭建一座“知识摩天楼”。现成的结构化数据(比如数据库、RDF、Neo4j)就像预制好的砖块,拆开就能直接用,省时又省力。而非结构化数据(比如那些长篇大论的文字)嘛,就像一堆散落的乐高零件,需要你仔细翻找,才能拼出点有用的东西,比如人名、地名、日期,以及它们之间的“小八卦”(比如“谁创办了什么”“谁住在哪儿”)。


怎么处理这些“碎片”呢?😮


可以采用传统的信息抽取方法,主要分两步:

  • NER(命名实体识别):像一位“考古专家”,负责从文本中挖掘出关键的实体,例如人物、组织、地点等;

  • 关系抽取:这位专家则专注于搞清楚实体之间的“人际关系”,比如“张三是某公司的创始人”。


当然,还有另一种更“现代”的做法——直接派出大型语言模型(LLM)这个“全能大工匠”。它能在一句话中同时识别实体、提取关系,甚至顺带润色输出,效率极高。


所以,搭建知识图谱就是这么一件“从零件到艺术品”的事情,有了这些工具,轻松又有趣!

(利用大模型构建知识图谱流程)


处理文本构建知识图谱就像拆书搭积木,步骤如下:


  1. 文本分块:先把长文本切成小块,方便操作,这步和普通 RAG 的“切片”手法一样。

  2. 提取图元素:用 LLM 发“指令”从每块文本里找出关键积木:

  • 第一步:找实体(例如名字、类型、描述),就像从一堆零件里挑出有用的砖块。

  • 第二步:找关系(谁和谁有啥联系,比如“合作”“位于”),把砖块之间的连接线画出来。

3.合并实体和关系:最后,把不同文本块中重复的积木合并,拼成一个完整、连贯的知识图谱!


简单来说,就是“切片-找积木-拼完整”,过程清晰又高效!😮


使用知识图谱召回

其流程如图所示:

基于知识图谱的 RAG 系统回答过程有这样几个步骤:


  • 检索阶段,根据用户输入问题从知识图谱中召回相关的实体、关系以及原文内容。

  • 增强阶段,将召回的结构化结果整合为额外的上下文信息,与用户输入一起提供给大模型,以增强其理解和推理能力。

  • 生成阶段,系统通过大模型生成答案,该过程与朴素 RAG 系统一致。


两大知识图谱 RAG 系统供你挑选

GraphRAG


GraphRAG 通过构建知识图谱和分层社区结构,将局部信息聚合为全局理解。


其核心优势在于:

  • 利用 LLM 从文档中提取实体、关系和事实声明构建知识图谱,通过图结构索引捕捉语义关联。

  • 通过分层社区检测,使用图社区算法将图谱划分为紧密关联的社区,递归生成从局部到全局的摘要。

  • 采用 Map-Reduce 式回答生成方法,借助社区摘要的并行处理与聚合,生成全面且多样的全局回答。


GraphRAG 工作流程

1.将文档拆分为文本块,并使用 LLM 提取其中的实体、关系及事实声明

2.基于提取结果构建知识图谱,将实体和关系转化为图节点和边,对重复实例进行聚合并生成节点描述,同时根据关系出现频率设定边的权重。

3.利用 Leiden 算法对图谱进行递归划分,形成嵌套的社区结构,每个社区代表一个语义主题,构建从局部到全局的层级结构。

社区新概念!

微软 GraphRAG 在知识图谱的基础上增加了一个社区(Community)的概念。


社区是 GraphRAG 中的高级结构,表示一组相关实体的集合。每个社区包含以下字段:


ID:社区的唯一标识符。Level:社区的层级(如 0、1、2 等)。Entity IDs:社区中包含的实体 ID 列表。Relation IDs:社区中包含的关系 ID 列表。Text Block IDs:社区中包含的文本块 ID 列表。Description:社区的描述信息。Summary:社区的摘要信息。
复制代码


GraphRAG 在是构建 Knowledge Graph 后,增加了一个社区摘要(Community Summaries)的生成环节。这一策略使得系统在检索时只关注与查询高度相关的社区,而不是检索整个图。社区摘要对数据全局结构和语义的高度概括, 即使没有问题, 用户也可以通过浏览不同层次的社区摘要来理解语料库!😮


社区摘要生成由两步组成:

  1. 社区检测:使用图分析算法,获得具有高度连接性的实体簇

  2. 摘要提取:使用 LLM 根据社区中的实体和关系,提取各类型总结。


(微软 Graph RAG 的社区聚类效果图)


Light RAG


LightRAG 的知识图谱是比较基础的分片+实体/关系


LightRAG 就像一位“轻装上阵”的知识图谱专家,甩掉了复杂的社区聚类,直接构建知识图谱,支持增量更新——新数据只需补充节点和关系,无需重建全图,方便又高效!


它的检索方式也很聪明,采用了双层检索策略

  1. 低层级检索:专注细节,锁定具体实体的信息,比如“某人是谁”“某地在哪”。

  2. 高层级检索:关注全局,处理宏观主题和趋势,比如“某领域的发展方向”。


这种设计让 LightRAG 能快速适应动态数据场景,同时保证检索既全面又精准,堪称高效实用的“知识捕手”!



(LightRAG 整体结构(图源 LightRAG 论文))


LightRAG 通过以下步骤实现知识图谱的构建与检索:

  1. 实体和关系抽取:从文档中提取实体和关系(如实体名称、类型、描述等),完成后进行去重操作,然后进行图索引,构建知识图谱。

  • 节点属性:包括实体名称、类型、描述、来源文档 ID。

  • 关系属性:包括起点实体、终点实体、关键词、描述、来源文档 ID。

2.关键词提取

  • 具体关键词:关注精确信息(如实体名称、属性),用于底层级检索。

  • 抽象关键词:关注宏观主题或领域信息,用于高层级检索。

3.双层级检索

  • 低层级检索:针对具体关键词,查找特定实体及其属性,提供详细信息。示例关键词:如“beekeeper”“hive”,获取具体实体的属性和关系。

  • 高层级检索:针对抽象关键词,分析宏观主题、趋势或多个实体间的关系。示例关键词:如“agriculture”“production”,提供全局性见解。

4.动态更新:当有新数据加入时,仅需更新新增的节点和边,无需重建整个知识图谱,降低计算成本。


通过这种设计,LightRAG 能够高效处理具体细节和宏观主题问题,为用户提供精准且深度的答案。


LightRAG VS GraphRAG

对于 Legal Dataset,共 94 篇文章,约 5000K Token(约 5 个水浒传大小)。GraphRAG 生成了 1399 个 communities,平均每个社区报告生成需要 5000Token, 其中 610 个 level-2 communities, 平均每个 level-2 的社区占用 1000Token。下表对比了创建知识图谱和一次检索所消耗的 LLM Token。C_Max 为 API 单次请求最多 Token 限制,T_extract 代表提取实体和关系消耗 Token 数,C_extract 则表示提取产生的 API 调用次数。



实战演练:知识图谱 RAG 对复杂 query 的提升


我们基于 LightRAG 进行实战,来看看需要的配置吧!


Dataset:

  • 水浒传_utf8.txt (约 912K Tokens)

切分及召回

  • NaiveRAG Chunk 1200 Token; top_k: 10

  • LightRAG Chunk 1200 Token ; relation/entity top_k: 60


使用 LightRAG 构建知识图谱

Step 0: 环境准备

🔨vLLM

pip install vllm
复制代码

🔨LightRAG

pip install lightrag-hku
复制代码

🔨infinity

pip install infinity-emb
复制代码

🔨LazyLLM

pip3 install lazyllmlazyllm install full
复制代码


  • Git clone https://github.com/HKUDS/LightRAG 并安装 lightrag pip install "lightrag-hku[api]"

  • 下载语料 水浒传.txt 转为 utf8,并重命名放入比如"novel/shuihu.txt"

    主动创建保存知识图谱的目录


Step1️⃣: 使用 VLLM/Ollama 等工具部署 openai 兼容格式的 LLM 服务。

⚠️注:由于文章较长,尝试过多个平台的在线模型,即使换不同的语料,依然会有触发“内容安全限制”的情况。所以只能选择本地部署的 LLM。


下载模型(Qwen 2.5-32B-Instruct),推荐从 ModelScope 下载:

python -m vllm.entrypoints.openai.api_server --model /mnt/lustre/share_data/lazyllm/models/Qwen2.5-32B-Instruct/ --served-model-name qwen2 --max_model_len 16144 --host 0.0.0.0 --port 12345
复制代码


Step2️⃣: 部署 embedding 服务或使用已有平台的 openai 兼容格式的 embedding 在线服务。


下载模型(bge-large-zh-v1.5),推荐从 ModelScope 下载:


infinity_emb v2 --model-id "/mnt/lustre/share_data/lazyllm/models/bge-large-zh-v1.5" --port 19001 --served-model-name bge-large
复制代码


Step3️⃣:参照 examples/lightrag_openai_compatible_demo.py 修改 LLM 服务和 embedding 服务的配置  配置 llm_model_func 和 embedding_func 的三个参数:model, base_url, api_key。


✅设置处理的文件名和保存知识图谱的文件夹路径

  • WORKING_DIR 为 知识图谱保存的文件夹路径

  • PATH_TO_TXT 为 待解析的小说 <水浒传>,注意检查是否为 utf8 格式

✅修改 llm_model 的配置

  • base_url 改为 http://{ip}:{port}/v1

  • model_name 改为 vLLM 中配置的 qwen2

✅修改 openai_embed 的配置

  • base_url 改为 http://{ip}:{port}

  • model_name 改为 infinity 中配置的 bge-large


Step4️⃣: 调整 examples/lightrag_openai_compatible_demo.py 中的 main 函数  设置知识图谱的存储目录 WORKING_DIR 和文本文件的路径 PATH_TO_TXT。

async def main():    WORKING_DIR = "****"    PATH_TO_TXT = "shuihu.txt"    try:        embedding_dimension = await get_embedding_dim()        print(f"Detected embedding dimension: {embedding_dimension}")
rag = LightRAG( working_dir=WORKING_DIR, llm_model_func=llm_model_func, embedding_func=EmbeddingFunc( embedding_dim=embedding_dimension, max_token_size=8192, func=embedding_func, ), ) with open(PATH_TO_TXT, "r", encoding="utf-8") as f: await rag.ainsert(f.read()) except Exception as e: print(f"An error occurred: {e}")
复制代码


Step5️⃣: 运行 Demo,并检查 WORKING_DIR 中是否有 graph_chunk_entity_relation.graphml 生成,其大小约为 5M 左右表示成功。

LazyLLM 融合 LightRAG


整体流程图:

Step 1: 参考 LightRAG 构建知识图谱中的方式部署本地 LLM 和 embedding 服务。

Step 2: 设置 LightRAG 知识图谱的存储目录 working_dir 和文本文件的路径 txt_path ,并配置 LazyLLM 知识库目录 dataset_path。


import osimport asyncioimport lazyllmfrom lazyllm import pipeline, parallel, bind, Retrieverfrom lightrag import LightRAG, QueryParamfrom lightrag.kg.shared_storage import initialize_pipeline_statusfrom lightrag.utils import setup_logger, EmbeddingFuncfrom lightrag.llm.openai import openai_complete, openai_embed
class LightRAGRetriever: def __init__(self, working_dir, txt_path, mode="hybrid"): self.working_dir = working_dir self.txt_path = txt_path self.mode = mode self.api_key = "empty" self.rag = None self.loop = asyncio.new_event_loop() setup_logger("lightrag", level="INFO")
if not os.path.exists(working_dir): os.makedirs(working_dir)
self.loop.run_until_complete(self.initialize_rag()) async def initialize_rag(self): self.rag = LightRAG( working_dir=self.working_dir, embedding_func=EmbeddingFunc( embedding_dim=1024, max_token_size=8192, func=lambda texts: openai_embed( texts=texts, model="bge-large", base_url="http://0.0.0.0:19001", api_key=self.api_key, ) ), llm_model_func=openai_complete, llm_model_name="qwen2", llm_model_kwargs={"base_url": "http://0.0.0.0:12345/v1", "api_key": self.api_key}, ) await self.rag.initialize_storages() await initialize_pipeline_status()
with open(self.txt_path, "r", encoding="utf-8") as f: content = f.read() await self.rag.ainsert(content) def __call__(self, query): return self.loop.run_until_complete( self.rag.aquery( query, param=QueryParam(mode=self.mode, top_k=3, only_need_context=True) ) ) def close(self): if self.rag: try: self.loop.run_until_complete(self.rag.finalize_storages()) except Exception as e: print(f"关闭LightRAG时出错: {e}") finally: self.loop.close() self.rag = None
def main(): kg_retriever = None try: documents = lazyllm.Document(dataset_path="****") prompt = ('请你参考所给的信息给出问题的答案。')
print("正在初始化知识图谱检索器...") kg_retriever = LightRAGRetriever( working_dir="****", txt_path="****" ) print("知识图谱检索器初始化完成!")
bm25_retriever = lazyllm.Retriever( doc=documents, group_name="CoarseChunk", similarity="bm25_chinese", topk=3 ) def bm25_pipeline(query): nodes = bm25_retriever(query) return "".join([node.get_content() for node in nodes])
def context_combiner(*args): bm25_result = args[0] kg_result = args[1] return ( f"知识图谱召回结果:\n{kg_result}" f"BM25召回结果:\n{bm25_result}\n\n" )
with lazyllm.pipeline() as ppl: with parallel() as ppl.multi_retrieval: ppl.multi_retrieval.bm25 = bm25_pipeline ppl.multi_retrieval.kg = kg_retriever ppl.context_combiner = context_combiner ppl.formatter = (lambda nodes, query: dict(context_str=nodes, query=query)) | bind(query=ppl.input) ppl.llm = ( lazyllm.OnlineChatModule().prompt( lazyllm.ChatPrompter( instruction=prompt, extra_keys=['context_str'] ) ) )
lazyllm.WebModule(ppl, port=23466).start().wait() except Exception as e: print(f"\n处理过程中发生错误: {e}") import traceback traceback.print_exc()
if __name__ == "__main__": main()
复制代码

Step 3: 运行 Demo,则会启动 Web 端服务,即可向 LLM 提出问题啦。


通过这次的深入学习与实战,我们不仅了解了如何让知识图谱 RAG“抽取实体、建图索引、逻辑推理”,更真正掌握了:一个能从碎片化信息中构建语义关联、支持复杂推理的 RAG 系统,不再只是简单的检索工具,而是具备全局视角与结构化思考能力的智能助手!


从分块抽取让系统“识别知识点”,到构建知识图谱为 RAG 搭建“语义网络”,再到高低层级检索实现从细节到全局的全面回答,我们一步步,把 RAG 从文本问答助手,进化成了语义理解+知识聚合的超级推理专家。


这不仅是功能的叠加,更是一次认知能力的全面升级!知识图谱 RAG 不再仅仅“回忆知识”,它开始学会“理解语义”、“关联信息”、“生成深度洞察”。


更多技术交流,欢迎移步“LazyLLM”gzh~


发布于: 刚刚阅读数: 4
用户头像

用AI大模型,找商汤大装置。 2023-04-04 加入

还未添加个人简介

评论

发布
暂无评论
懒懒笔记 | 课代表带你梳理【RAG课程 19:基于知识图谱的RAG】_AI_商汤万象开发者_InfoQ写作社区