实操|如何优雅的实现RAG与GraphRAG应用中的知识文档增量更新?

在RAG应用(包括GraphRAG)中,领域知识的导入与索引是后续增强生成的基础。一个常见的问题是,当领域知识发生更新与变化时,如何用最简洁、快速、低成本的方式更新对应的向量或知识图谱索引?让我们来探讨这个问题。

01.需求

在这里插入图片描述

一般来说企业的信息系统中都可能有较完善的知识库维护与管理应用,但是如何让变化的知识能够同步更新到RAG应用中则不一样,知识进入到RAG应用通常需要经过拆分(split)、嵌入(embedding)、向量索引(vectorindex)等步骤:

因此当更新发生时,就需要识别出输入的知识文档变化,进而将合适的策略应用到不同的知识块上,比如忽略、新增、删除或者更新。

在实际应用中有两种不同级别的增量更新策略:

一种是文档(Document)级别的简单更新策略。即在导入知识文档时识别出新增或更新的文档,然后对其进行全量解析与向量化,并做索引合并更新。

另外一种是块(Chunk)级别的更新策略。这种更加复杂但也更精细化:在一个文档发生变化的过程中,有新增的块也有发生更新的块,需要识别哪些块需要更新删除、哪些是新增的块,以及哪些块没有发生变化,应该跳过更新。

借助以上的两种策略,你可以在文档发生更新时,降低不必要的计算工作量,消除可能产生的重复块与索引,节约模型使用成本,并提高RAG应用后续检索阶段的有效性与准确性,即保持最新、有效且不重复的上下文。

02.方案

实现增量更新的解决方案通常需要借助于文档或者块的“指纹”来实现,结合必要的持久与缓存方案,在每次进行知识索引时通过“指纹”来识别出本次需要处理的文档或知识块,并执行相应的动作(如插入或者删除),跳过重复的内容,从而达到增量更新的目的。

不管是文档(Document)还是块(Chunk)级别的增量更新策略,都可以基于类似的原理来实现,我们以更细粒度的Chunk级别的增量更新为例,其原理表示如下:

在这里插入图片描述

  • 在每次处理开始时,计算每个块的hash指纹,这通常是是基于块的内容与元数据,并借助hash函数生成的唯一值

  • 为了实现增量加载更新,需要一个跟踪与保存每次处理的块信息的机制****(源文档、块信息、hash指纹、时间戳等),比如LangChain中的RecordManager组件,LlamaIndex中的DocumentStore组件

  • 每次增量更新时,通过与上一次保存的处理信息对比hash指纹,确定数据块的处理动作

  • 如果某数据块的hash指纹在上一次处理中存在,则跳过处理

  • 如果某数据块的hash指纹在上一次处理中不存在,则做新增处理

  • 对于上一次处理中存在但是本次不存在的hash指纹,则做块删除

  • **根据确定的处理动作对数据块做相应的嵌入与索引更新即可。**注意这里可能对向量数据库有一定的能力要求,以实现增量索引更新。

03.实现

在现有的两个主流底层LLM应用开发框架:LangChain与LlamaIndex中都提供了文档增量更新的实现方法。两者实现方法各有区别,但核心思想基本类似,这里做一个简单演示与研究。

【LangChain的索引API】

如果你使用了LangChain框架并需要让向量索引与输入知识文档保持同步,那么需要使用LangChain的索引API来创建知识的向量索引,而不是简单的使用from_documents方法来完成。

索引API的主要区别就在于提供了文档增量更新的能力:跳过没有变化的知识块以避免向量库中写入重复知识块、并对新增或者变化的知识块计算嵌入与写入向量库。

为了实现对文档块的跟踪,索引API的使用需要借助一个记录管理器的组件(Record Manager),以跟踪每个知识块的源文档ID、hash指纹以及时间戳等。这里直接给出参考代码:

from langchain.indexes import SQLRecordManager, index   
from langchain_openai import OpenAIEmbeddings  
from langchain_chroma import Chroma  
from langchain_text_splitters import CharacterTextSplitter  
from langchain_community.document_loaders import DirectoryLoader  
  
#嵌入模型、向量库  
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")  
vector_store = Chroma(  
    collection_name="example_collection",  
    embedding_function=embeddings,  
    persist_directory="./db_chroma"  
)  
  
#记录管理器,用来跟踪向量库中已经存储的Document(hash、时间戳、source_id)  
namespace = f"chroma/mydocs"  
record_manager = SQLRecordManager(  
    namespace, db_url="sqlite:///record_manager_cache.sql"  
)  
record_manager.create_schema()  
  
#文档加载与分割  
loader = DirectoryLoader("../data",glob='*.txt')  
docs = loader.load()  
docs = CharacterTextSplitter(separator='\n',chunk_size=30,chunk_overlap=2).split_documents(docs)  
  
#向量话并索引  
result = index(  
    docs,  
    record_manager,  
    vector_store,  
    cleanup='incremental',  
    source_id_key="source",  
)  
  
#打印处理情况  
print(result)

这里的核心区别就在于index()方法的使用。该方法除了需要输入处理的块(docs)、向量库(vector_store)、记录管理器(record_manager)、表示源文档ID的key名(source_id_key)外,还有一个**cleanup参数,该参数决定了LangChain对向量库中现有知识块的清理方式,支持三种方式。**三种方式都会根据hash值跳过重复块,并插入新知识块,但对已有块的清理方式则有区别

  • none:不会对已有块做任何清理动作

  • incremental:如果源文档知识块发生了变更(出现新的块hash指纹),则会清除知识块的旧版本

  • full:如果源文档知识块发生了变更(出现新的块hash指纹),或者做了部分块的删除(注意此时未出现新的hash指纹),都会清除知识块的旧版本

也就是说incremental与full的区别在于:如果源文档中只有部分知识块被删除(即不包含在当前正在被索引的知识块中),incremental模式不会从向量库中清除这些部分知识块,但full模式会清除。

我们用上面的代码样例来对这两种模式做详细测试,假设为如下的知识文档内容创建向量索引:

首次处理后的结果信息如下(无论incremental或full模式),由于采用了按行分割,所以添加了3个知识块:

现在我们把知识内容修改成如下,即删除了最后一行,并修改了第二行:

在这里插入图片描述

重新运行上面的代码(无论incremental或者full),处理信息如下:

在这里插入图片描述

这里跳过了第一行对应的chunk(num_skipped=1),新增了第二行对应的chunk(num_added=1),并且删除了原来的第二行与第三行对应的chunk(num_deleted=2)。可以看到,由于这里出现了知识块的修改(第二行),所以incremental与full模式效果一致。

现在让我们再直接删除第二行,输入文件变成:

此时,两种模式下的处理就会有区别:

incremental清理模式:由于删除了第二个chunk,但是并未出现新的chunk指纹,所以不会做清理动作,只会跳过第一个重复块(num_skipped=1):

full清理模式:不仅会跳过第一个重复块(num_skipped=1),还会删除掉第二个chunk(num_deleted=1):

【LlamaIndex框架的数据摄入管道】

如果你采用LlamaIndex框架,则需要借助LlamaIndex中的数据摄入管道来实现知识增量更新,并指定文档存储(docstore)以及文档存储策略(docstore_strategy),核心代码如下:

......  
pipeline = IngestionPipeline(  
    transformations=[  
        TokenTextSplitter(chunk_size=20, chunk_overlap=0,separator="\n"),  
        embedded_model  
    ],  
    vector_store=vector_store,  
    docstore=RedisDocumentStore.from_host_and_port("localhost", 6379, namespace="document_store"),  
    docstore_strategy='upserts'  
)  
  
docs = SimpleDirectoryReader(input_files=["../data/datafile1.txt"],filename_as_id=True).load_data()  
nodes = pipeline.run(documents=docs,show_progress=False)  
......

更多的信息可以参考LlamaIndex的官方文档。

04.GraphRAG的增量更新

Graph RAG是最近的一个热点,借助于知识图谱与图数据库对知识中的实体与关系进行组织与表示,同时结合向量检索、社区识别算法等实现复杂知识关系的检索与答案生成。实现Graph RAG的一种方式是借助成熟框架如Microsoft GraphRAG,但目前尚未能够实现增量更新。由于涉及到图与社区等高级数据结构,GraphRAG的知识增量更新要比普通RAG更复杂。

这里推荐一个开源的nano-GraphRAG框架,这是一个保留了Microsoft GraphRAG核心功能,但又更轻量级、更简洁的版本,且提供了一定的知识增量更新的能力。其核心思想也是借助对原始文档与知识块的hash值做分析,识别出需要添加的新知识块,并在上一次生成的Graph图基础上进行图的增量更新,插入新的实体与关系。

nano-GraphRAG也提供了社区识别与生成的功能,所以会在每次图的增量更新基础上,重新进行社区信息的生成,但社区信息的增量更新目前尚未实现,即每次都会对所有社区信息做识别与生成。

有兴趣的朋友可以在Github搜索该项目以了解细节,我们将在后续对该项目进行深入研究与测试。

如何学习大模型 AI ?

由于新岗位的生产效率,要优于被取代岗位的生产效率,所以实际上整个社会的生产效率是提升的。

但是具体到个人,只能说是:

“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。

这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

在这里插入图片描述

第一阶段(10天):初阶应用

该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。

  • 大模型 AI 能干什么?
  • 大模型是怎样获得「智能」的?
  • 用好 AI 的核心心法
  • 大模型应用业务架构
  • 大模型应用技术架构
  • 代码示例:向 GPT-3.5 灌入新知识
  • 提示工程的意义和核心思想
  • Prompt 典型构成
  • 指令调优方法论
  • 思维链和思维树
  • Prompt 攻击和防范

第二阶段(30天):高阶应用

该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。

  • 为什么要做 RAG
  • 搭建一个简单的 ChatPDF
  • 检索的基础概念
  • 什么是向量表示(Embeddings)
  • 向量数据库与向量检索
  • 基于向量检索的 RAG
  • 搭建 RAG 系统的扩展知识
  • 混合检索与 RAG-Fusion 简介
  • 向量模型本地部署

第三阶段(30天):模型训练

恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。

到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?

  • 为什么要做 RAG
  • 什么是模型
  • 什么是模型训练
  • 求解器 & 损失函数简介
  • 小实验2:手写一个简单的神经网络并训练它
  • 什么是训练/预训练/微调/轻量化微调
  • Transformer结构简介
  • 轻量化微调
  • 实验数据集的构建

第四阶段(20天):商业闭环

对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。

  • 硬件选型
  • 带你了解全球大模型
  • 使用国产大模型服务
  • 搭建 OpenAI 代理
  • 热身:基于阿里云 PAI 部署 Stable Diffusion
  • 在本地计算机运行大模型
  • 大模型的私有化部署
  • 基于 vLLM 部署大模型
  • 案例:如何优雅地在阿里云私有部署开源大模型
  • 部署一套开源 LLM 项目
  • 内容安全
  • 互联网信息服务算法备案

学习是一个过程,只要学习就会有挑战。天道酬勤,你越努力,就会成为越优秀的自己。

如果你能在15天内完成所有的任务,那你堪称天才。然而,如果你能完成 60-70% 的内容,你就已经开始具备成为一名大模型 AI 的正确特征了。

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Python_cocola/article/details/143441422