当前位置: 首页 > news >正文

《Advanced RAG》-12-增进RAG的全局理解(二)

承接上文:《Advanced RAG》-12-增进RAG的全局理解(一)

HippoRAG

HippoRAG 是一个新颖的检索框架,从人类长期记忆的海马索引理论中汲取灵感。它与 LLM、知识图谱和个性化 PageRank 算法协作。这种协作模仿了新皮质和海马体在人类记忆中的不同作用。

关键思想

图 11 说明了人脑是如何相对轻松地处理困难的知识整合任务的。

海马记忆索引理论 是著名的人类长期记忆理论,它为这种非凡的能力提供了一种可能的解释。

具体来说,基于环境、不断更新的记忆依赖于新皮质和 C 型海马体之间的相互作用。新皮层处理并存储实际的记忆表征,而海马体则维护海马索引。该索引是一组相互连接的索引,指向新皮层中的记忆单元并存储其关联。

在这里插入图片描述

在图 11 中,我们的目标是从可能描述了数千名斯坦福大学教授和阿尔茨海默病研究人员的众多段落中,找出一位参与阿尔茨海默病研究的斯坦福大学教授。

  • 传统的 RAG 对段落进行独立编码,除非段落同时提到这两个特征,否则很难识别托马斯教授。
  • 相比之下,熟悉这位教授的人却能很快记住他,这要归功于我们大脑的联想记忆能力,据说这种能力是由图 11 中蓝色所示的 C 型海马索引结构驱动的。
  • 受这一机制的启发,HippoRAG 使 LLMs 能够构建和利用类似的关联图来管理知识整合任务。

概述

受图 11 的启发,如图 12 所示,HippoRAG 的每个组成部分都与人类长期记忆的三个组成部分之一相对应。

在这里插入图片描述

HippoRAG 模拟了人类长期记忆的三个组成部分,以模仿其模式分离和完成功能。

  • 对于离线索引,LLM 将段落处理为开放式 KG 三元组。然后将其添加到人工海马体索引中,同时合成海马旁区域(PHR)检测同义词。在上述示例中,HippoRAG 提取了涉及托马斯教授的三元组,并将其纳入 KG。
  • 在线检索时,LLM 新皮质从查询中提取命名实体。然后,海马旁检索编码器将其链接到海马索引。HippoRAG 利用个性化的 PageRank 算法进行基于上下文的检索,并提取与托马斯教授相关的信息。

整体流程演示

下面是一个介绍 HippoRAG 管道的实用示例。

图 13 显示了问题、答案、辅助段落和干扰段落。

在这里插入图片描述

图 14 描述了索引编制阶段,包括 OpenIE 程序和知识图谱的相关子图谱。

在这里插入图片描述

最后,图 15 演示了检索阶段,展示了查询命名实体识别 (NER)、查询节点检索、个性化页面排名 (PPR) 算法对节点概率的影响以及顶级检索结果的计算。

在这里插入图片描述

下面,我们将结合源代码,从两个方面具体讨论 HippoRAG 如何构建长期记忆以及如何检索长期记忆。

如何建立长期记忆

建立长期记忆的过程主要包括以下三个步骤。

首先,利用 LLM,使用 OpenIE 从检索语料库的每个段落中提取一组命名实体,如图 16 所示。

在这里插入图片描述

接下来,将命名实体添加到 OpenIE 提示中,以提取最终的三元组,如图 17 所示。

在这里插入图片描述

最后,利用经过微调的现成密集编码器创建知识图谱,这也将用于检索。

如何检索

首先,使用 LLM 从用户查询中提取命名实体集,如图 18 所示。

在这里插入图片描述

然后,根据检索编码器确定的相似性,将这些命名实体链接到知识图谱中的节点。我们将这些选定的节点称为查询节点。

在海马体中,海马索引各要素之间的神经通路可使相关邻域被激活,并在上游进行回忆。

为了模仿这种高效的图搜索过程,HippoRAG 利用了个性化 PageRank(PPR)算法,这是 PageRank 的一个版本,它只通过一组用户定义的源节点在图中分配概率。相应的代码如下所示。

 def rank_docs(self, query: str, top_k=10):"""Rank documents based on the query@param query: the input phrase@param top_k: the number of documents to return@return: the ranked document ids and their scores"""......# Run Personalized PageRank (PPR) or other Graph Alg Doc Scoresif len(query_ner_list) > 0:combined_vector = np.max([top_phrase_vectors], axis=0)if self.graph_alg == 'ppr':ppr_phrase_probs = self.run_pagerank_igraph_chunk([top_phrase_vectors])[0]elif self.graph_alg == 'none':ppr_phrase_probs = combined_vectorelif self.graph_alg == 'neighbor_2':ppr_phrase_probs = self.get_neighbors(combined_vector, 2)elif self.graph_alg == 'neighbor_3':ppr_phrase_probs = self.get_neighbors(combined_vector, 3)elif self.graph_alg == 'paths':ppr_phrase_probs = self.get_neighbors(combined_vector, 3)else:assert False, f'Graph Algorithm {self.graph_alg} Not Implemented'fact_prob = self.facts_to_phrases_mat.dot(ppr_phrase_probs)ppr_doc_prob = self.docs_to_facts_mat.dot(fact_prob)ppr_doc_prob = min_max_normalize(ppr_doc_prob)else:ppr_doc_prob = np.ones(len(self.extracted_triples)) / len(self.extracted_triples)......

最后,如同海马信号在上游发送时的做法一样,HippoRAG 将输出的 PPR 节点概率与之前索引的段落进行汇总,并以此为检索排序。

spRAG

spRAG 是一种管理复杂查询的方法。它通过两种关键技术提高了标准 RAG 的性能:

  1. 自动上下文
  2. 相关片段提取 (RSE)

我们重点关注 spRAG 如何处理跨块的复杂查询。值得注意的是,目前还没有关于 spRAG 的论文,只有结合代码的分析。

AutoContext:自动注入文档级上下文

在传统的 RAG 中,文档通常被分成固定长度的块来进行嵌入。这种简单的方法往往会忽略文档级的上下文信息,导致上下文嵌入不够准确和全面。

为了解决这个问题,AutoContext 应运而生。它的主要理念是在嵌入前自动将文档级上下文信息纳入每个分块。

具体来说,**它会创建一个 1-2 句话的文档摘要,并将其与文件名一起添加到每个分块的开头。**这样,每个分块就不再是孤立的,而是包含了整个文档的上下文信息。获取文档摘要的代码如下所示。

def get_document_context(auto_context_model: LLM, text: str, document_title: str, auto_context_guidance: str = ""):# truncate the content if it's too longmax_content_tokens = 6000 # if this number changes, also update the truncation message abovetext, num_tokens = truncate_content(text, max_content_tokens)if num_tokens < max_content_tokens:truncation_message = ""else:truncation_message = TRUNCATION_MESSAGE# get document contextprompt = PROMPT.format(auto_context_guidance=auto_context_guidance, document=text, document_title=document_title, truncation_message=truncation_message)chat_messages = [{"role": "user", "content": prompt}]document_context = auto_context_model.make_llm_call(chat_messages)return document_context

相关片段提取:相关文本块的智能组合

RSE 是一个后处理步骤。其目的是智能地识别和组合能够提供最相关信息的片段,从而形成更长的片段。

具体来说,RSE 首先将检索到的内容相似或语义相关的数据块进行分组。然后,根据查询要求,它智能地选择和组合这些片段,以形成最佳片段。相应的代码如下所示。

def get_best_segments(all_relevance_values: list[list], document_splits: list[int], max_length: int, overall_max_length: int, minimum_value: float) -> list[tuple]:"""This function takes the chunk relevance values and then runs an optimization algorithm to find the best segments.- all_relevance_values: a list of lists of relevance values for each chunk of a meta-document, with each outer list representing a query- document_splits: a list of indices that represent the start of each document - best segments will not overlap with theseReturns- best_segments: a list of tuples (start, end) that represent the indices of the best segments (the end index is non-inclusive) in the meta-document"""best_segments = []total_length = 0rv_index = 0bad_rv_indices = []while total_length < overall_max_length:# cycle through the queriesif rv_index >= len(all_relevance_values):rv_index = 0# if none of the queries have any more valid segments, we're doneif len(bad_rv_indices) >= len(all_relevance_values):break        # check if we've already determined that there are no more valid segments for this query - if so, skip itif rv_index in bad_rv_indices:rv_index += 1continue# find the best remaining segment for this queryrelevance_values = all_relevance_values[rv_index] # get the relevance values for this querybest_segment = Nonebest_value = -1000for start in range(len(relevance_values)):# skip over negative value starting pointsif relevance_values[start] < 0:continuefor end in range(start+1, min(start+max_length+1, len(relevance_values)+1)):# skip over negative value ending pointsif relevance_values[end-1] < 0:continue# check if this segment overlaps with any of the best segmentsif any(start < seg_end and end > seg_start for seg_start, seg_end in best_segments):continue# check if this segment overlaps with any of the document splitsif any(start < split and end > split for split in document_splits):continue# check if this segment would push us over the overall max lengthif total_length + end - start > overall_max_length:continuesegment_value = sum(relevance_values[start:end]) # define segment value as the sum of the relevance values of its chunksif segment_value > best_value:best_value = segment_valuebest_segment = (start, end)# if we didn't find a valid segment, mark this query as doneif best_segment is None or best_value < minimum_value:bad_rv_indices.append(rv_index)rv_index += 1continue# otherwise, add the segment to the list of best segmentsbest_segments.append(best_segment)total_length += best_segment[1] - best_segment[0]rv_index += 1return best_segments

见解与思考

算法和数据结构比较

RAPTOR 通过聚类构建树状数据结构,并根据该结构执行检索。

尽管 Graph RAG 和 HippoRAG 都采用了知识图谱,但它们还是有一些不同之处:

  • 关于数据结构,Graph RAG 通过总结知识元素来整合信息。因此,每当添加新数据时,都需要重复总结过程。RAPTOR 也是如此。相反,HippoRAG 只需在其知识图谱中添加边,就能无缝集成新知识。
  • 在检索算法方面,Graph RAG 依赖于社区检测,而 HippoRAG 则利用个性化页面排名 (PPR) 算法。

与其他产品不同,spRAG 不使用高级数据结构。它只是将文档摘要和文件名添加到每个块中,然后根据相关性值进行检索。这也表明,spRAG 的索引和查询速度应该是最快的。

关于性能

如图 19 所示,HippoRAG 以 RAPTOR 为基线进行了实验,显示出一些超越 RAPTOR 的结果。

在这里插入图片描述

在 Graph RAG 论文中,不包括性能比较实验。

此外,目前还没有关于 spRAG 的论文。

关于增强型系列

这四种方法–RAPTOR、Graph RAG、HippoRAG 和 spRAG–旨在加强对整个语料库的理解。

它们各自根据整个语料库建立数据结构。

关于可定制性

在这种情况下,HippoRAG 的性能更胜一筹,因为它的所有组件都是现成的,无需额外训练,如图 20 所示。

在这里插入图片描述

因此,通过对特定组件进行微调,有很大的改进潜力。

结论

本文介绍了四种新方法,以增强传统 RAG 对文档或语料的全局理解,并辅以代码说明。其中还包括我的见解和想法。

本文为翻译,原文地址:https://medium.com/ai-advances/advanced-rag-12-enhancing-global-understanding-b13dc9a8db39

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Golang 中的 XML 魔法:encoding/xml 包的精妙运用
  • 『大模型笔记』基于LLM生成真实世界数据的合成问答数据!
  • Apache,Tomcat,Nginx有什么关系?
  • 《SQL 中计算地理坐标两点间距离的魔法》
  • 目录与文件相关的命令
  • Spring Boot全局异常
  • SQL server 同环比计算模板
  • HDU动态规划——1114.Piggy-Bank,1121.Complete the Sequence,1158.Employment Planning
  • 音视频开发继续学习
  • 【Python】线性规划模型(笔记)
  • 编译aws并访问minio
  • Spring boot 使用 jSerialComm 对串口使用发送信息并接收
  • 【香菇带你学Mysql】Linux下Mysql8使用二进制安装包安装教程【建议收藏】
  • 案例分享—国外深色UI界面设计赏析
  • 使用 C++ 实现简单的插件系统
  • Debian下无root权限使用Python访问Oracle
  • Docker 笔记(2):Dockerfile
  • docker-consul
  • ECMAScript6(0):ES6简明参考手册
  • in typeof instanceof ===这些运算符有什么作用
  • JavaScript/HTML5图表开发工具JavaScript Charts v3.19.6发布【附下载】
  • Js基础——数据类型之Null和Undefined
  • PaddlePaddle-GitHub的正确打开姿势
  • Webpack入门之遇到的那些坑,系列示例Demo
  • 大数据与云计算学习:数据分析(二)
  • 基于webpack 的 vue 多页架构
  • 前端攻城师
  • 详解移动APP与web APP的区别
  • 用 vue 组件自定义 v-model, 实现一个 Tab 组件。
  • 资深实践篇 | 基于Kubernetes 1.61的Kubernetes Scheduler 调度详解 ...
  • # 消息中间件 RocketMQ 高级功能和源码分析(七)
  • #pragma once与条件编译
  • (1)无线电失控保护(二)
  • (保姆级教程)Mysql中索引、触发器、存储过程、存储函数的概念、作用,以及如何使用索引、存储过程,代码操作演示
  • (解决办法)ASP.NET导出Excel,打开时提示“您尝试打开文件'XXX.xls'的格式与文件扩展名指定文件不一致
  • (十七)Flink 容错机制
  • (使用vite搭建vue3项目(vite + vue3 + vue router + pinia + element plus))
  • (学习日记)2024.04.04:UCOSIII第三十二节:计数信号量实验
  • (原创)可支持最大高度的NestedScrollView
  • .aanva
  • .bat批处理(九):替换带有等号=的字符串的子串
  • .bat文件调用java类的main方法
  • .net core使用EPPlus设置Excel的页眉和页脚
  • .NET MVC第五章、模型绑定获取表单数据
  • .NET/C# 推荐一个我设计的缓存类型(适合缓存反射等耗性能的操作,附用法)
  • .NET正则基础之——正则委托
  • .Net转Java自学之路—基础巩固篇十三(集合)
  • :O)修改linux硬件时间
  • @ModelAttribute 注解
  • @ModelAttribute注解使用
  • @RequestMapping-占位符映射
  • @WebService和@WebMethod注解的用法
  • [ Socket学习 ] 第一章:网络基础知识
  • [2019.2.28]BZOJ4033 [HAOI2015]树上染色
  • [240812] X-CMD 发布 v0.4.5:更新 gtb、cd、chat、hashdir 模块功能