spRAG框架学习小结

 spRAG是什么

  spRAG是一个针对非结构化数据的检索引擎。它特别擅长处理对密集文本的复杂查询,比如财务报告、法律文件和学术论文。有两种关键方法用于提高性能,超越了普通的RAG系统:

自动上下文(AutoContext):自动上下文的实现相当直接,首先生成文档的1-2句话摘要,将文件名添加进去,然后在嵌入之前将这些内容添加到每个文本块的前面。
相关段落提取(Relevant Segment Extraction, RSE):相关段落提取(RSE)是一个后处理步骤,它将相关文本块的集群智能地组合成长文本段落,我们称之为段落。这些段落比任何单独的文本块都能为LLM提供更好的上下文。对于简单的事实问题,答案通常包含在单个文本块中;但对于更复杂的问题,答案通常跨越更长的文本段落。RSE的目标是智能地识别提供最相关信息的文本段落,而不受固定长度文本块的限制。

spRAG使用

  spRAG的使用非常简单,安装sprag后,只需下面简单的几行代码,即可基于pdf文档内容进行问题检索。

from sprag.create_kb import create_kb_from_filefile_path = "spRAG/tests/data/levels_of_agi.pdf"
kb_id = "levels_of_agi"
kb = create_kb_from_file(kb_id, file_path)
search_queries = ["What are the levels of AGI?", "What is the highest level of AGI?"]
results = kb.query(search_queries)
for segment in results:print(segment)

    默认情况下,spRAG使用OpenAI进行嵌入,使用Claude 3 Haiku进行自动上下文处理,并使用Cohere进行重新排序。所以,如果要使用spRAG需要同时申请这三种大模型的key。如果只用OpenAI需要编写更多的代码,具体如下所示:下面的代码中通过OpenAIChatAPI来设置自动文本提取的llm使用openAI,重新排序这里,设置的NoReranker,经过下面的修改,即便只有OPENAI的key,也能正常使用spRAG了。

from sprag.llm import OpenAIChatAPI
from sprag.reranker import NoRerankerllm = OpenAIChatAPI(model='gpt-3.5-turbo')
reranker = NoReranker()kb = KnowledgeBase(kb_id="levels_of_agi", reranker=reranker, auto_context_model=llm)

spRAG实现原理

  实际spRAG的source code如下图所示,并不复杂,首先看vector_db部分,vector_db_connectors文件夹里面是直接使用第三方vectorDB工具weavite,对文档进行向量存储,添加,删除,以及查询等操作。外面的vector_db.py也定义了增加,删除文档,检索内容等方法,这个module会被vector_db_connectors中的python文件继承。

    在vector_db.py问中,封装了两种search方法,第一种是使用余玄相识度来进行内容检索,方法二是调用knn中的exhuastive_search方法来进行检索。

  以上就是向量存储方法的内容,接着看Ebedding的source code,这里没有啥复杂度,直接调用的各个LLM提供的SDK,生成向量即可。以下图为例,这里调用OpenAI提供的SDK来对输入的内容生成向量。

class OpenAIEmbedding(Embedding):def __init__(self, model: str = "text-embedding-3-small", dimension: int = 768):"""Only v3 models are supported."""super().__init__(dimension)self.model = modelself.client = OpenAI()def get_embeddings(self, text, input_type=None):response = self.client.embeddings.create(input=text, model=self.model, dimensions=int(self.dimension))embeddings = [embedding_item.embedding for embedding_item in response.data]return embeddings[0] if isinstance(text, str) else embeddingsdef to_dict(self):base_dict = super().to_dict()base_dict.update({'model': self.model})return base_dict

  接着来看看比较关键的自动上下文提取是如何实现的。下面的代码就是auto_context的source code,这段代码使用LLM生成简明扼要的文档描述,描述包含文档的标题和内容概要,并确保处理大文档时内容不会超出限制。具体代码内容,如下所示:

from sprag.llm import LLM
import tiktokenPROMPT = """
INSTRUCTIONS
What is the following document, and what is it about? Your response should be a single sentence, and it shouldn't be an excessively long sentence. DO NOT respond with anything else.You MUST include the name of the document in your response (if available), as that is a critical piece of information. Be as specific and detailed as possible in your document name. You can even include things like the author's name or the date of publication if that information is available. DO NOT just use the filename as the document name. It needs to be a descriptive and human-readable name.Your response should take the form of "This document is: X, and is about: Y". For example, if the document is a book about the history of the United States called A People's History of the United States, your response might be "This document is: A People's History of the United States, and is about the history of the United States, covering the period from 1776 to the present day." If the document is the 2023 Form 10-K for Apple Inc., your response might be "This document is: Apple Inc. FY2023 Form 10-K, and is about: the financial performance and operations of Apple Inc. during the fiscal year 2023."{auto_context_guidance}{truncation_message}DOCUMENT
filename: {document_title}{document}
""".strip()TRUNCATION_MESSAGE = """
Also note that the document text provided below is just the first ~4500 words of the document. Your response should still pertain to the entire document, not just the text provided below.
""".strip()def truncate_content(content: str, max_tokens: int):TOKEN_ENCODER = tiktoken.encoding_for_model('gpt-3.5-turbo')tokens = TOKEN_ENCODER.encode(content, disallowed_special=())truncated_tokens = tokens[:max_tokens]return TOKEN_ENCODER.decode(truncated_tokens), min(len(tokens), max_tokens)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_contextdef get_chunk_header(file_name, document_context):chunk_header = f"Document context: the following excerpt is from {file_name}. {document_context}"return chunk_header

    以上是一些比较关键的source code简要说明,接下来看看如何从调用入口开始,看看加载文件后,如何完成对文档的检索的。代码的source code封装的方法create_kb_from_file,就是使用spRAG的入口方法。可看到这个方法中,根据文件的后缀进行了不同的处理,总体而言,通过这样的处理,让spRAG可以支持多种文件格式。kb这个对象实际就是KnowlegeBase这个class的实例化。

def create_kb_from_file(kb_id: str, file_path: str, title: str = None, description: str = "", language: str = 'en', auto_context: bool = True, auto_context_guidance: str = ""):"""- kb_id is the name of the knowledge base- file_path is the absolute path to the file containing the documentsSupported file types: .docx, .md, .txt, .pdf"""if not title:title = kb_id# create a new KBkb = KnowledgeBase(kb_id, title=title, description=description, language=language, exists_ok=False)print (f'Creating KB with id {kb_id}...')file_name = os.path.basename(file_path)# add documentif file_path.endswith(('.docx', '.md', '.txt', '.pdf')):# define clean file path as just the file name here since we're not using a directoryclean_file_path = file_nameif file_path.endswith('.docx'):text = extract_text_from_docx(file_path)elif file_name.endswith('.pdf'):text = extract_text_from_pdf(file_path)elif file_path.endswith('.md') or file_path.endswith('.txt'):with open(file_path, 'r') as f:text = f.read()kb.add_document(clean_file_path, text, auto_context=auto_context, auto_context_guidance=auto_context_guidance)else:print (f"Unsupported file type: {file_name}")returnreturn kb

KnowlegeBase中包含两个重要方法

  add_document方法是将一个新文档添加到知识库中。首先验证参数的有效性,确保auto_context和chunk_header不同时设置,并检查文档ID的唯一性。如果启用了自动上下文生成,会通过LLM生成文档上下文描述并设置小块头信息。接着,它将文档文本拆分为小块,添加头信息后生成嵌入向量,然后将小块及其嵌入向量添加到数据库中,最后保存数据库以确保数据持久化。也就是前面提到的很关键的自动化上下文能力,具体的source code如下所示:

def add_document(self, doc_id: str, text: str, auto_context: bool = True, chunk_header: str = None, auto_context_guidance: str = ""):# verify that only one of auto_context and chunk_header is settry:assert auto_context != (chunk_header is not None)except:print ("Error in add_document: only one of auto_context and chunk_header can be set")# verify that the document does not already exist in the KBif doc_id in self.chunk_db.get_all_doc_ids():print (f"Document with ID {doc_id} already exists in the KB. Skipping...")return# AutoContextif auto_context:document_context = get_document_context(self.auto_context_model, text, document_title=doc_id, auto_context_guidance=auto_context_guidance)chunk_header = get_chunk_header(file_name=doc_id, document_context=document_context)elif chunk_header:passelse:chunk_header = ""chunks = self.split_into_chunks(text)print (f'Adding {len(chunks)} chunks to the database')# add chunk headers to the chunks before embedding themchunks_to_embed = []for i, chunk in enumerate(chunks):chunk_to_embed = f'[{chunk_header}]\n{chunk}'chunks_to_embed.append(chunk_to_embed)# embed the chunksif len(chunks) <= 50:# if the document is short, we can get all the embeddings at oncechunk_embeddings = self.get_embeddings(chunks_to_embed, input_type="document")else:# if the document is long, we need to get the embeddings in chunkschunk_embeddings = []for i in range(0, len(chunks), 50):chunk_embeddings += self.get_embeddings(chunks_to_embed[i:i+50], input_type="document")assert len(chunks) == len(chunk_embeddings) == len(chunks_to_embed)self.chunk_db.add_document(doc_id, {i: {'chunk_text': chunk, 'chunk_header': chunk_header} for i, chunk in enumerate(chunks)})# create metadata listmetadata = []for i, chunk in enumerate(chunks):metadata.append({'doc_id': doc_id, 'chunk_index': i, 'chunk_header': chunk_header, 'chunk_text': chunk})# add the vectors and metadata to the vector databaseself.vector_db.add_vectors(vectors=chunk_embeddings, metadata=metadata)self.save() # save the database to disk after adding a document

  再来看看search方法,search方法总体比较简单,首先就是调用常规的vector_db.search进行查询,获取到多个结果,再将问题和首次查询到的结果传递给rerank_search,进行二次查询,从而提高查询的准确率。

def search(self, query: str, top_k: int) -> list:"""Get top k most relevant chunks for a given query. This is where we interface with the vector database.- returns a list of dictionaries, where each dictionary has the following keys: `metadata` (which contains 'doc_id', 'chunk_index', 'chunk_text', and 'chunk_header') and `similarity`"""query_vector = self.get_embeddings(query, input_type="query") # embed the querysearch_results = self.vector_db.search(query_vector, top_k) # do a vector database searchsearch_results = self.reranker.rerank_search_results(query, search_results) # rerank search results using a rerankerreturn search_results

  以上就是对开源框架spRAG的学习小结。更多内容可查看官网。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/42564.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

µCOS-III 任务同步机制-任务信号量

1. 什么是任务信号量 任务信号量是一种用于任务间同步和通信的计数器&#xff0c;通常用于解决任务间的竞争条件和资源共享问题。在C/OS-III中&#xff0c;任务信号量提供了二进制信号量和计数信号量两种类型&#xff1a; 二进制信号量&#xff1a;只能取值0或1&#xff0c;适…

Debezium报错处理系列之第109篇:解决升级日志解析jar包重启集群出现的字段类型和值不匹配的错误

Debezium报错处理系列之第109篇:解决升级日志解析jar包重启集群出现的字段类型和值不匹配的错误 一、完整报错二、错误原因三、解决方法Debezium从入门到精通系列之:研究Debezium技术遇到的各种错误解决方法汇总: Debezium从入门到精通系列之:百篇系列文章汇总之研究Debezi…

传统IO和NIO文件拷贝过程

参考&#xff1a;https://blog.csdn.net/weixin_57323780/article/details/130250582

昇思25天学习打卡营第9天|ResNet50图像分类

一、Resnet残差网络模型 构建残差网络结构;Building BlockBottleneck 残差结构由两个分支构成&#xff1a;一个主分支 &#x1d439;(&#x1d465;)&#xff0c;一个shortcuts&#xff08;图中弧线表示,&#x1d465;&#xff09;。 得到残差网络结构:&#x1d439;(&#x…

SpringMVC常见的注解

一、Spring MVC Spring Web MVC是基于ServletAPI构建的原始web 框架&#xff0c;一开始就包含在Spring 框架中&#xff0c;通常被称为“Spring MVC”。 1.MVC 是什么&#xff1f; MVC(Model、View、Controller&#xff09;是软件工程中的一种软件架构设计模型。它把软件系统分…

STM32-输入捕获IC和编码器接口

本内容基于江协科技STM32视频学习之后整理而得。 文章目录 1. 输入捕获IC1.1 输入捕获IC简介1.2 频率测量1.3 输入捕获通道1.4 主从触发模式1.5 输入捕获基本结构1.6 PWMI基本结构 2. 输入捕获库函数及代码2.1 输入捕获库函数2.2 6-6 输入捕获模式测频率2.2.1 硬件连接2.2.2 硬…

2024暑假集训

Day1——枚举 Day2——测试 Day3——贪心 Day4、5——测试 ——————————————————————————————————————————— Day3T7&Day5T7:没思路 Day3T8:不知道怎么排序筛选 Day5T5:没有算法难度&#xff0c;但是不知道怎么处理2队奶牛的情…

什么牌子的头戴式蓝牙耳机好性价比高?

说起性价比高的头戴式蓝牙耳机,就不得不提倍思H1s,作为倍思最新推出的新款,在各项功能上都实现了不错的升级,二字开头的价格,配置却毫不含糊, 倍思H1s的音质表现堪称一流。它采用了40mm天然生物纤维振膜,这种振膜柔韧而有弹性,能够显著提升低音的量感。无论是深沉的低音还是清…

数据跨境法案:美国篇上

近年来随着全球数字化的加速发展&#xff0c;数据已成为国家竞争力的重要基石。在这样的背景下&#xff0c;中国软件和技术出海的场景日益丰富。本系列邀请到在跨境数据方面的研究人员针对海外的数据跨境政策进行解读。 本期将针对美国对数据跨境流动的态度和政策进行阐释。过…

非比较排序 计数排序

1.核心思路 首先要找出max 和 min&#xff0c;最大值 - 最小值 1&#xff0c;就可以计算出数据在什么范围然后创建计数数组大小&#xff0c;a[i] - min 在数组的相对位置计数 通过自然序列排序然后把计数好的值&#xff0c;按照顺序依次放回原数组即可 动图解释&#xff0c;其…

Linux—网络设置

目录 一、ifconfig——查看网络配置 1、查看网络接口信息 1.1、查看所有网络接口 1.2、查看具体的网络接口 2、修改网络配置 3、添加网络接口 4、禁用/激活网卡 二、hostname——查看主机名称 1、查看主机名称 2、临时修改主机名称 3、永久修改主机名称 4、查看本…

Java引用的4种类型:强、软、弱、虚

在Java中&#xff0c;引用的概念不仅限于强引用&#xff0c;还包括软引用、弱引用和虚引用&#xff08;也称为幻影引用&#xff09;。这些引用类型主要用于不同的内存管理策略&#xff0c;尤其是在垃圾收集过程中。以下是对这四种引用类型的详细解释&#xff1a; 1. 强引用&am…

algorithm算法库学习之——不修改序列的操作

algorithm此头文件是算法库的一部分。本篇介绍不修改序列的操作函数。 不修改序列的操作 all_ofany_ofnone_of (C11)(C11)(C11) 检查谓词是否对范围中所有、任一或无元素为 true (函数模板) for_each 应用函数到范围中的元素 (函数模板) for_each_n (C17) 应用一个函数对象到序…

一.7.(2)基本运算电路,包括比例运算电路、加减运算电路、积分运算电路、微分电路等常见电路的分析、计算及应用;(未完待续)

what id the 虚短虚断虚地? 虚短&#xff1a;运放的正相输入端和反相输入端貌似连在一起了&#xff0c;所以两端的电压相等&#xff0c;即UU- 虚断&#xff1a;输入端输入阻抗无穷大 虚地&#xff1a;运放正相输入端接地&#xff0c;导致U&#xff1d;U-&#xff1d;0。 虚…

对话大模型Prompt是否需要礼貌点?

大模型相关目录 大模型&#xff0c;包括部署微调prompt/Agent应用开发、知识库增强、数据库增强、知识图谱增强、自然语言处理、多模态等大模型应用开发内容 从0起步&#xff0c;扬帆起航。 基于Dify的QA数据集构建&#xff08;附代码&#xff09;Qwen-2-7B和GLM-4-9B&#x…

秋招突击——7/5——复习{}——新作{跳跃游戏II、划分字母区间、数组中的第K个大的元素(模板题,重要)、前K个高频元素}

文章目录 引言正文贪心——45 跳跃游戏II个人实现参考实现 划分字母区间个人实现参考实现 数组中的第K个最大元素个人实现参考做法 前K个高频元素个人实现参考实现 总结 引言 今天就开始的蛮早的&#xff0c;现在是九点多&#xff0c;刚好开始做算法&#xff0c;今天有希望能够…

【leetcode周赛记录——405】

405周赛记录 #1.leetcode100339_找出加密后的字符串2.leetcode100328_生成不含相邻零的二进制字符串3.leetcode100359_统计X和Y频数相等的子矩阵数量4.leetcode100350_最小代价构造字符串 刷了一段时间算法了&#xff0c;打打周赛看看什么水平了 #1.leetcode100339_找出加密后的…

【UML用户指南】-30-对体系结构建模-模式和框架

目录 1、机制 2、框架 3、常用建模技术 3.1、对设计模式建模 3.2、对体系结构模式建模 用模式来详述形成系统体系结构的机制和框架。通过清晰地标识模式的槽、标签、按钮和刻度盘 在UML中&#xff0c; 对设计模式&#xff08;也叫做机制&#xff09;建模&#xff0c;将它…

【web前端HTML+CSS+JS】--- CSS学习笔记02

一、CSS&#xff08;层叠样式表&#xff09;介绍 1.优势 2.定义解释 如果有多个选择器共同作用的话&#xff0c;只有优先级最高那层样式决定最终的效果 二、无语义化标签 div和span&#xff1a;只起到描述的作用&#xff0c;不带任何样式 三、标签选择器 1.标签/元素选择器…

【算法笔记自学】第 8 章 提高篇(2)——搜索专题

8.1深度优先搜索&#xff08;DFS&#xff09; #include <cstdio>const int MAXN 5; int n, m, maze[MAXN][MAXN]; bool visited[MAXN][MAXN] {false}; int counter 0;const int MAXD 4; int dx[MAXD] {0, 0, 1, -1}; int dy[MAXD] {1, -1, 0, 0};bool isValid(int …