更强的RAG:向量数据库和知识图谱的结合

简介: 更强的RAG:向量数据库和知识图谱的结合

传统 RAG 的局限性

经典的 RAG 架构以向量数据库(VectorDB)为核心来检索语义相似性上下文,让大语言模型(LLM)不需要重新训练就能够获取最新的知识,其工作流如下图所示:
image-20240929145459119

这一架构目前广泛应用于各类 AI 业务场景中,例如问答机器人、智能客服、私域知识库检索等等。虽然 RAG 通过知识增强一定程度上缓解了 LLM 幻觉问题,但是依然面临准确度不高的问题,它受限于信息检索流程固有的限制(比如信息检索相关性、搜索算法效率、Embedding模型)以及大量对 LLM 能力依赖,使得在生成结果的过程中有了更多的不确定性。

下图来自 RAG 领域一篇著名的论文:《Seven Failure Points When Engineering a Retrieval Augmented Generation System》 ,它总结了在使用 RAG 架构时经常会遇到的一些问题(红框部分,原作者称之为7个失败点)。

它们包括:

内容缺失(Missing Content),用户想要的答案并不在知识库中,LLM会给出无意义的回答。
缺失排名靠前的文档(Missed Top Ranked),受限于文本切分方式、大小、嵌入模型等影响,从向量数据库中检索出来的 top-k 不一定是最精确的答案。
不在上下文中(Not in Context),和上一条类似,经过各种处理后最终取出来的上下文质量较低。
格式错误(Wrong Format),检索出来的结果没有特定格式,而 LLM 没有很好地对其识别分析。
未提取(Not Extracted),Prompt 包含大量无关信息影响了 LLM 判断,即上下文包含很多噪音。
答案不完整(Incomplete),生成的答案不够完整。
不正确的差异(Incorrect Speciticity),答案在响应中返回,但不够具体或过于具体,无法满足用户的需求。

以上问题目前都有一些优化方法来提升回答准确度,但依然离我们的预期有差距。

因此除了基于语义匹配文本块之外,业内也探索新的数据检索形式,比如在语义之上关注数据之间的关联性。这种关联性区别于关系模型中的逻辑性强依赖,而是带有一定的语义关联。比如人和手机是两个独立的实体,在向量数据库中的相似性一定非常差,但是结合实际生活场景,人和手机的关系是非常密切的,假如我搜索一个人的信息,我大可能性也关心他的周边,例如用什么型号的手机、喜欢拍照还是玩游戏等等。

基于这样的关系模型,从知识库检索出来的上下文在某些场景中可能更有效,例如“公司里面喜欢使用手机拍照的人有哪些”。
用知识图谱来呈现数据关系

为了有效地描述知识库中的抽象数据关系,引入了知识图谱的概念,它不再使用二维表格来组织数据,而是用图结构来描述关系,这里面的关系没有固定的范式约束,类似下面这种人物关系图:

上图中有最重要的三个元素:对象(人物)、属性(身份)、关系,对于存储这样的数据有专门的数据库产品来支持,即图数据库。
图数据库(GraphDB)

图数据库是属于 NoSQL 的一种,它有着较为灵活的 schema 定义,可以简单高效表达真实世界中任意的关联关系。图数据库中的主要概念有:

实体(Entity),也称之为顶点或节点,图结构中的对象
边(Edge),连接两个实体的一条路径,即实体之间的关系
属性(Property),用来具体描述实体或边的特征

以上概念可对应到前面的人物关系图。

具体到 schema 定义和数据操作层面,以流行的图数据库 NebulaGraph 为例:

创建图空间

CREATE SPACE IF NOT EXISTS test(vid_type=FIXED_STRING(256), partition_num=1, replica_factor=1);
USE test;

创建节点和边

CREATE TAG IF NOT EXISTS entity(name string);
CREATE EDGE IF NOT EXISTS relationship(relationship string);
CREATE TAG INDEX IF NOT EXISTS entity_index ON entity(name(256));

写入数据

INSERT VERTEX entity (name) VALUES "1":("神州数码");
INSERT VERTEX entity (name) VALUES "2":("云基地");
INSERT EDGE relationship (relationship) VALUES "1"->"2":("建立了");
...

图数据库的查询语法遵循 Cypher 标准:

MATCH p=(n)-[*1..2]-() RETURN p LIMIT 100;

以上语句从 NebulaGraph 中找到最多100个从某个节点出发,通过1到2条边连接的路径,并返回这些路径。

如果用可视化图结构展示的话,它是这个样子:

GraphRAG

如果借用 VectorRAG 的思想,通过图数据库来实现检索增强的话就演变出了 GraphRAG 架构,整体流程和 VectorRAG 并无差异,只是新知识的存储和检索都用知识图谱来实现,解决 VectorRAG 对抽象关系理解较弱的问题。

借助一些AI脚手架工具可以很容易地实现 GraphRAG,以下是用 LlamaIndex 和图数据库 NebulaGraph 实现的一个简易 GraphRAG 应用:

import os
from llama_index.core import KnowledgeGraphIndex, SimpleDirectoryReader
from llama_index.core import StorageContext
from llama_index.graph_stores.nebula import NebulaGraphStore
from llama_index.llms.openai import OpenAI
from pyvis.network import Network
from llama_index.core import (
Settings,
SimpleDirectoryReader,
KnowledgeGraphIndex,
)

参数准备

os.environ['OPENAI_API_KEY'] = "sk-proj-xxx"
os.environ["NEBULA_USER"] = "root"
os.environ["NEBULA_PASSWORD"] = "nebula"
os.environ["NEBULA_ADDRESS"] = "10.3.xx.xx:9669"

space_name = "heao"
edge_types, rel_prop_names = ["relationship"], ["relationship"]
tags = ["entity"]

llm = OpenAI(temperature=0, model="gpt-3.5-turbo")

Settings.llm = llm
Settings.chunk_size = 512

连接Nebula数据库实例

graph_store = NebulaGraphStore(
space_name=space_name,
edge_types=edge_types,
rel_prop_names=rel_prop_names,
tags=tags,
)
storage_context = StorageContext.from_defaults(graph_store=graph_store)

hosts=graph_store.query("SHOW HOSTS")
print(hosts)

抽取知识图谱写入数据库

documents = SimpleDirectoryReader(
"data"
).load_data()

kg_index = KnowledgeGraphIndex.from_documents(
documents,
storage_context=storage_context,
max_triplets_per_chunk=2,
space_name=space_name,
edge_types=edge_types,
rel_prop_names=rel_prop_names,
tags=tags,
max_knowledge_sequence=15,
)

信息检索生成答案

query_engine = kg_index.as_query_engine()
response = query_engine.query("神州数码云基地在哪里?")
print(response)

VectorRAG 擅长处理具有一定事实性的问题,对复杂关系理解较弱,而 GraphRAG 刚好弥补了这一点,如果把这两者进行结合,理论上能得到更优的结果。
HybridRAG — 新一代 RAG 架构

我们可以把数据在 VectorDB 和 GraphDB 各放一份,分别通过向量化检索和图检索得到与问题相关结果后,我们将这些结果连接起来,形成统一的上下文,最后将组合的上下文传给大语言模型生成响应,这就形成了 HybridRAG 架构。
image-20240929145637811

由英伟达团队Benika Hall等人在前段时间发表的论文《HybridRAG: Integrating Knowledge Graphs and Vector Retrieval Augmented Generation for Efficient Information Extraction》提出了这一设想,并使用金融服务行业中的数据集成、风险管理、预测分析等场景进行对比验证。在需要从相关文本文档中获取上下文以生成有意义且连贯的响应时 VectorRAG 表现出色,而 GraphRAG 能够从金融文件中提取的结构化信息生成更准确的且具有上下文感知的响应,但 GraphRAG 在抽象问答任务或问题中没有明确提及实体时通常表现不佳。
[box.k53.net)
[box.kulink.net)
[box.kashou99.com)
[box.lemir2.com)
[box.kyznw.com)
[box.limve.com)
该论文最后给出了 VectorRAG、GraphRAG和 HybridRAG 的测试结果:

表格中F代表忠实度,用来衡量生成的答案在多大程度上可以从提供的上下文中推断出来。AR代表答案相关性,用来评估生成的答案在多大程度上解决了原始问题。CP代表上下文精度,CR代表上下文召回率。
实现简单的 HybridRAG

以下示例用 Llama_index 作为应用框架,用 TiDB Vector 作为向量数据库,用 NebulaGraph 作为图数据库实现了简单的 HybridRAG 流程:

import os
from llama_index.core import KnowledgeGraphIndex, VectorStoreIndex,StorageContext,Settings
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.graph_stores.nebula import NebulaGraphStore
from llama_index.llms.openai import OpenAI
from llama_index.vector_stores.tidbvector import TiDBVectorStore

TIDB_CONN_STR="mysql+pymysql://xx.root:xx@gateway01.eu-central-1.prod.aws.tidbcloud.com:4000/test?ssl_ca=isrgrootx1.pem&ssl_verify_cert=true&ssl_verify_identity=true"

os.environ["OPENAI_API_KEY"] = "sk-proj-xxx"
os.environ["NEBULA_USER"] = "root"
os.environ["NEBULA_PASSWORD"] = "nebula"
os.environ["NEBULA_ADDRESS"] = "10.3.xx.xx:9669"

llm = OpenAI(temperature=0, model="gpt-3.5-turbo")

Settings.llm = llm
Settings.chunk_size = 512

class HybridRAG:
def init(self):

    # 初始化向量数据库
    tidbvec = TiDBVectorStore(
        connection_string=TIDB_CONN_STR,
        table_name="semantic_embeddings",
        distance_strategy="cosine",
        vector_dimension=1536, # The dimension is decided by the model
        drop_existing_table=False,
    )
    tidb_vec_index = VectorStoreIndex.from_vector_store(tidbvec)
    self.vector_db = tidb_vec_index

    # 初始化知识图谱
    graph_store = NebulaGraphStore(
        space_name="heao",
        edge_types=["relationship"],
        rel_prop_names=["relationship"],
        tags=["entity"],
    )
    storage_context = StorageContext.from_defaults(graph_store=graph_store)
    kg_index = KnowledgeGraphIndex.from_documents(
        [],
        storage_context=storage_context,
        max_triplets_per_chunk=2,
        max_knowledge_sequence=15,
    )
    self.kg = kg_index

    # 初始化语言模型
    self.llm = llm

    # 初始化嵌入模型
    self.embeddings = OpenAIEmbedding()

def vector_search(self, query):
    # 在向量数据库中搜索相关文本
    results = self.vector_db.as_retriever().retrieve(query)
    print(results)
    return [result.node for result in results]

def graph_search(self, query):
    # 在知识图谱中搜索相关信息
    results = self.kg.as_retriever().retrieve(query)
    print(results)
    return [result.node for result in results]

def generate_answer(self, query):
    vector_context = self.vector_search(query)
    graph_context = self.graph_search(query)
    combined_context = "\n".join(vector_context) + "\n" + graph_context

    prompt = f"Question: {query}\nContext: {combined_context}\nAnswer:"
    return self.llm.generate(prompt)

使用示例

hybrid_rag = HybridRAG()
question = "TiDB从哪个版本开始支持资源管控特性?"
answer = hybrid_rag.generate_answer(question)
print(answer)

以上实现中只是简单的拼装了从向量数据库和图数据库中的检索结果,实际应用中可引入相关reranker模型进一步做精排提高上下文精准度。不管最终使用什么样的 RAG 架构,我们要达到的目的始终是保障传递给大语言模型的上下文是更完整更有效的,从而让大语言模型给出更准确的回答。
总结

RAG 架构已经是提升大语言模型能力的有效方案,鉴于在不同的业务场景中正确率无法稳定保持,因此也衍生出了一系列变化后的 RAG 架构,如 Advanced RAG、GraphRAG、HybridRAG、RAG2.0 等等,它们之间有的是互补关系,有的是优化增强,也有另起炉灶的路线,可以看出在 LLM 应用优化上依然处于快速变化当中。

相关文章
|
23天前
|
弹性计算 人工智能 架构师
阿里云携手Altair共拓云上工业仿真新机遇
2024年9月12日,「2024 Altair 技术大会杭州站」成功召开,阿里云弹性计算产品运营与生态负责人何川,与Altair中国技术总监赵阳在会上联合发布了最新的“云上CAE一体机”。
阿里云携手Altair共拓云上工业仿真新机遇
|
16天前
|
存储 关系型数据库 分布式数据库
GraphRAG:基于PolarDB+通义千问+LangChain的知识图谱+大模型最佳实践
本文介绍了如何使用PolarDB、通义千问和LangChain搭建GraphRAG系统,结合知识图谱和向量检索提升问答质量。通过实例展示了单独使用向量检索和图检索的局限性,并通过图+向量联合搜索增强了问答准确性。PolarDB支持AGE图引擎和pgvector插件,实现图数据和向量数据的统一存储与检索,提升了RAG系统的性能和效果。
|
20天前
|
机器学习/深度学习 算法 大数据
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
2024“华为杯”数学建模竞赛,对ABCDEF每个题进行详细的分析,涵盖风电场功率优化、WLAN网络吞吐量、磁性元件损耗建模、地理环境问题、高速公路应急车道启用和X射线脉冲星建模等多领域问题,解析了问题类型、专业和技能的需要。
2575 22
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
|
18天前
|
人工智能 IDE 程序员
期盼已久!通义灵码 AI 程序员开启邀测,全流程开发仅用几分钟
在云栖大会上,阿里云云原生应用平台负责人丁宇宣布,「通义灵码」完成全面升级,并正式发布 AI 程序员。
|
3天前
|
JSON 自然语言处理 数据管理
阿里云百炼产品月刊【2024年9月】
阿里云百炼产品月刊【2024年9月】,涵盖本月产品和功能发布、活动,应用实践等内容,帮助您快速了解阿里云百炼产品的最新动态。
阿里云百炼产品月刊【2024年9月】
|
2天前
|
存储 人工智能 搜索推荐
数据治理,是时候打破刻板印象了
瓴羊智能数据建设与治理产品Datapin全面升级,可演进扩展的数据架构体系为企业数据治理预留发展空间,推出敏捷版用以解决企业数据量不大但需构建数据的场景问题,基于大模型打造的DataAgent更是为企业用好数据资产提供了便利。
162 2
|
20天前
|
机器学习/深度学习 算法 数据可视化
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码
2024年中国研究生数学建模竞赛C题聚焦磁性元件磁芯损耗建模。题目背景介绍了电能变换技术的发展与应用,强调磁性元件在功率变换器中的重要性。磁芯损耗受多种因素影响,现有模型难以精确预测。题目要求通过数据分析建立高精度磁芯损耗模型。具体任务包括励磁波形分类、修正斯坦麦茨方程、分析影响因素、构建预测模型及优化设计条件。涉及数据预处理、特征提取、机器学习及优化算法等技术。适合电气、材料、计算机等多个专业学生参与。
1575 16
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码
|
22天前
|
编解码 JSON 自然语言处理
通义千问重磅开源Qwen2.5,性能超越Llama
击败Meta,阿里Qwen2.5再登全球开源大模型王座
968 14
|
3天前
|
Linux 虚拟化 开发者
一键将CentOs的yum源更换为国内阿里yum源
一键将CentOs的yum源更换为国内阿里yum源
211 2
|
17天前
|
人工智能 开发框架 Java
重磅发布!AI 驱动的 Java 开发框架:Spring AI Alibaba
随着生成式 AI 的快速发展,基于 AI 开发框架构建 AI 应用的诉求迅速增长,涌现出了包括 LangChain、LlamaIndex 等开发框架,但大部分框架只提供了 Python 语言的实现。但这些开发框架对于国内习惯了 Spring 开发范式的 Java 开发者而言,并非十分友好和丝滑。因此,我们基于 Spring AI 发布并快速演进 Spring AI Alibaba,通过提供一种方便的 API 抽象,帮助 Java 开发者简化 AI 应用的开发。同时,提供了完整的开源配套,包括可观测、网关、消息队列、配置中心等。
732 10