【手摸手学 RAG】RAG性能再突破!当知识图谱遇上LLM,打造你的终极问答机器人

举报
胡琦 发表于 2025/10/05 11:02:57 2025/10/05
【摘要】 RAG性能再突破!当知识图谱遇上LLM,打造你的终极问答机器人

大家好,我是胡琦。

在之前的教程里,我们从0到1搭建了一个基于文本检索的RAG系统。它很棒,但很快我们就会发现它的“天花板”:当面对需要多步推理、关系查询的复杂问题时,它就显得力不从心了。

比如你问它:“查询一下,和发表了关于‘图神经网络’论文的作者在同一个机构的,还有哪些作者?

传统的RAG大概率会卡住。因为它看到的是一堆孤立的文本片段,很难理解“作者”、“论文”、“机构”之间复杂的连接关系。

如何破局?答案就是——知识图谱(Knowledge Graph, KG)

今天,我们就一起探索如何将知识图谱的结构化推理能力,与LLM的强大语言能力相结合,构建一个能够深度思考、精准回答复杂问题的Graph RAG系统。

第一步:蓝图升级 —— 为什么需要知识图谱?

传统的RAG,知识库就像一本“流水账日记”,信息都平铺直叙地记录着。而知识图谱,则像一张“人物关系网”,清晰地描绘了实体(节点)之间的关系(边)。

知识图谱的优势

  • 结构化知识:能清晰表达“谁-做了-什么”、“什么-属于-哪里”这类关系。
  • 精准查询:通过图查询语言(如Cypher),可以进行多跳(Multi-hop)的复杂关系查询。
  • 可解释性强:返回的结果和路径一目了然,方便溯源。

我们的新蓝图——Graph RAG架构如下:它是一个混合系统,同时拥有向量数据库和图数据库,并增加了一个“智能路由”来决定该走哪条路。

图片来源: all-in-rag

第二步:点石成金 —— 从非结构化文本中抽取“知识”

我们的核心任务,就是从现有的海量文档中,自动地构建出这张“关系网”。这个过程就像“点石成金”,而LLM就是我们的“魔法棒”。

1. 知识建模
在抽取前,我们先要定义好想抽取哪些东西。比如,对于一篇学术论文,我们关心的可能是:论文 (Paper)作者 (Author)机构 (Institution)关键词 (Keyword) 这些节点,以及 发表了 (PUBLISHED)作者是 (AUTHOR_OF)隶属于 (AFFILIATED_WITH) 这些关系

2. LLM魔法:抽取三元组
我们可以利用LLM强大的信息抽取能力,让它读取文本,并按照我们定义的模型,输出知识三元组(头实体,关系,尾实体)。

实战代码(用LangChain实现知识抽取)

import os
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.pydantic_v1 import BaseModel, Field
from typing import List

# 确保你已设置 OPENAI_API_KEY
# os.environ["OPENAI_API_KEY"] = "sk-..."

# 1. 定义我们希望LLM输出的数据结构
class Triple(BaseModel):
    """一个知识图谱中的三元组,表示头实体、关系和尾实体"""
    head: str = Field(..., description="头实体")
    relation: str = Field(..., description="关系")
    tail: str = Field(..., description="尾实体")

class Triples(BaseModel):
    """三元组的列表"""
    triples: List[Triple]

# 2. 准备一段示例文本
text_chunk = """
在2023年的NeurIPS会议上,来自华为诺亚方舟实验室的张三发表了一篇名为《图神经网络新范式》的论文。
他的同事李四也参与了这项研究。
"""

# 3. 编写一个强大的Prompt,指导LLM进行抽取
extract_prompt = ChatPromptTemplate.from_template(
    """
    从以下文本中提取知识三元组。请识别'作者'、'论文'、'机构'、'会议'等实体,
    以及'发表了'、'参与了'、'来自'等关系。
    
    文本: ```{text}```
    """
)

# 4. 初始化一个支持结构化输出的LLM
# 注意:并非所有模型都擅长结构化输出,GPT-4/Turbo, Claude 3, Qwen-max等较新模型效果更好
llm = ChatOpenAI(model="gpt-4-turbo", temperature=0)
extraction_chain = extract_prompt | llm.with_structured_output(schema=Triples)

# 5. 执行抽取!
extracted_triples = extraction_chain.invoke({"text": text_chunk})
print(extracted_triples)

输出可能为

{
  "triples": [
    {"head": "张三", "relation": "来自", "tail": "华为诺亚方舟实验室"},
    {"head": "张三", "relation": "发表了", "tail": "《图神经网络新范式》"},
    {"head": "李四", "relation": "参与了", "tail": "《图神经网络新范式》"},
    {"head": "《图神经网络新范式》", "relation": "发表于", "tail": "NeurIPS会议"}
  ]
}

看!我们成功地将一段杂乱的文本,转换成了结构清晰的知识!

第三步:构建大脑 —— 将知识注入图数据库

抽取出三元组后,我们需要一个地方来存储和管理它们。这就是图数据库(如 Neo4j)的用武之地。

实战代码(使用LangChain连接Neo4j并写入数据)

from langchain_community.graphs import Neo4jGraph

# 1. 连接到你的Neo4j数据库 (请先通过Docker等方式启动一个Neo4j实例)
graph = Neo4jGraph(
    url="bolt://localhost:7687", 
    username="neo4j", 
    password="your_password"
)

# 2. 将我们上一步抽出的三元组写入图数据库
for triple in extracted_triples.triples:
    # 使用Cypher语句的MERGE,如果节点/关系已存在则不会重复创建
    graph.query(
        """
        MERGE (h {name: $head})
        MERGE (t {name: $tail})
        MERGE (h)-[:`{relation}`]->(t)
        """.format(relation=triple.relation),
        params={"head": triple.head, "tail": triple.tail}
    )

print("知识图谱构建完成!")

现在,打开Neo4j的浏览器界面,你就能看到一个可视化的关系网络,非常酷!

第四步:智能路由 —— 让问题找到“对”的路

现在我们的系统同时拥有了“流水账日记”(向量数据库)和“人物关系网”(图数据库)。当一个问题进来,我们该问谁呢?

答案还是LLM!我们再创建一个“路由”LLM,让它当“总调度官”。

实战代码(构建一个查询路由器)

# 1. 定义路由器的Prompt,让它做选择题
router_prompt_template = """
根据用户的提问,判断该问题更适合通过哪种方式回答:
1. 'graph': 当问题涉及多个实体及其复杂关系,需要多步推理时。例如:“谁和谁共同发表了什么论文?”
2. 'vector': 当问题是开放式的、描述性的,或是查询单个实体的具体信息时。例如:“介绍一下图神经网络。”

用户问题: `{question}`
你的选择是:
"""
router_prompt = ChatPromptTemplate.from_template(router_prompt_template)
router_chain = router_prompt | llm

# 2. 模拟用户提问并进行路由
question1 = "介绍一下华为诺亚方舟实验室。"
question2 = "张三和谁一起研究了《图神经网络新范式》这篇论文?"

route1 = router_chain.invoke({"question": question1})
route2 = router_chain.invoke({"question": question2})

print(f"问题1的路由选择: {route1.content}") # 应该会选择 'vector'
print(f"问题2的路由选择: {route2.content}") # 应该会选择 'graph'

后续流程

  • 如果路由结果是 'vector',我们就走传统RAG流程:问题 -> 向量检索 -> LLM生成。
  • 如果路由结果是 'graph',我们就需要再让LLM把自然语言问题转换成Cypher查询语句,然后执行图查询,最后将查询结果交给LLM生成答案。

后记

太棒了!我们一起完成了一次从0到1的Graph RAG系统搭建之旅。回顾一下:

  1. 理解原理:我们明白了为何需要知识图谱来处理复杂的关系查询。
  2. 知识抽取:我们学会了如何利用LLM从文本中自动抽取结构化的三元组。
  3. 图谱构建:我们将抽取的知识存入了Neo4j图数据库,构建了一个可视化的“知识大脑”。
  4. 智能路由:我们设计了一个调度官,能智能地为用户问题选择最佳的查询路径。

通过Graph RAG,我们的问答机器人不再是一个只会“背书”的简单角色,而是进化成了一个具备初步“推理”能力的智能助手。

这趟旅程充满了挑战,但也乐趣无穷。技术的边界正由我们每一个人亲手拓展。快去用你自己的数据,构建一个更聪明的RAG吧!

本文基于[datawhalechina/all-in-rag]项目整理,仅代表个人学习心得,不代表任何官方观点。小伙伴们有疑问欢迎交流讨论,一起学习一起进步!

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。