RAG流程

news2024/12/23 10:37:38

目录

    • 1. 前言
    • 2. 流程详解
      • 2.1 知识管理
        • 2.1.1 知识存储【未展开】
        • 2.1.2 知识加载
          • (1) docx
          • (2) pdf
      • 2.2 切分
        • 2.2.1 固定长度分割
        • 2.2.2 自己写的固定分块方法
      • 2.3 创建知识库的向量库
      • 2.4 检索
      • 2.5 模型部署和加载
        • (1)api生成
        • (2)Transformers加载方式
      • 2.6 内存
      • 2.7 Prompt
      • 2.8 re-ranking
      • 2.9 RAG 优化

1. 前言

构建能够推断私有数据或在模型截止日期之后引入的数据的AI应用程序时,需通过特定信息增强模型的知识,这一过程被称为检索增强生成(RAG),通过引入适当的信息并将其插入模型提示符中来实现。

RAG的基础工作流程:

离线步骤

  • 数据准备阶段:用于整理结构化、非结构化数据,并进行分类分级,这是RAG流程中的基础步骤。
  • 文档加载 -> 切分 -> 向量化 -> 存储

在线步骤

  • 问题 -> 向量化 -> 检索 -> Prompt -> LLM -> 回复

RAG的优化工作流程:

OpenAI一篇关于RAG优化方案的文章(https://www.1goto.ai/article/f0c100da-4f90-4994-8dca-93532d26fbd8):

45%: 仅采用基于向量的余弦相似性;

65%: 基础文本分块+向量化模型+初阶检索,增加文档种类切块优化手段、检索类型,性能会显著提升,技术难点:领域embedding,多模分块,索引汇聚等;

85%: 增加检索后处理,技术难点:重排,分类提示;

98%: 改进提示词工程、增加查询扩展等。

2. 流程详解

2.1 知识管理

2.1.1 知识存储【未展开】

企业内有大量业务字典,这些业务字典中出现的问题增加了解答请求的困难,同时要对数据来源进行有效的管理,隐私分类。基于此,可以将数据进行企业化元数据,统一对接企业的数据源、数据字典、用户权限,进行一体化管理。

2.1.2 知识加载
(1) docx

加载代码:

from langchain.document_loaders import UnstructuredWordDocumentLoader
documents = []
loader = UnstructuredWordDocumentLoader(file_path)
documents.extend(loader.load())
print(documents)

加载规则:
换行用“\n”分割
表格中单元格之间用“ ”分割
图片识别不了,不能加载进来
备注不能加载进来
表可以读进来,合并单元格也可以读进来
合并单元格也可读进来

打印加载结果:

由page_content和metadata组成,无页码。

[Document(page_content=‘文本内容’, metadata={‘source’: ‘/path/1.docx’})]

(2) pdf

加载代码

from langchain.document_loaders import PyPDFLoader
loader = PyPDFLoader(file_path)
documents = []
documents.extend(loader.load())
print(documents)

加载规则
换行用“\n”分割
表格中单元格之间用“ ”分割
图片识别不了,不能加载进来
表可以读进来,合并单元格不能读进来

打印加载结果:
合并单元格无法加载进来
由page_content和metadata组成,有页码:

[Document(page_content=‘当页内容 当页页眉页脚 右侧上的标题’, metadata={‘source’: ‘.pdf’, ‘page’: 0}),…,
Document(page_content=‘当页内容 当页图表内容 当页页眉页脚’, metadata={‘source’: '
.pdf’, ‘page’: 10})]

2.2 切分

非结构化数据的切分方法包括多种技术。内容感知分割不仅仅是简单的拆分,而是需要深入理解数据内容。例如,对于图片、表格和图像等类型的数据。下面举了一些方法,只详细说固定长度分割

固定长度分割:不考虑文档的结构,只按照固定数量的字符进行划分chunk,这是最简单的方式,chunk_overlap控制重叠区域的大小。这种方式不理想,很容易造成语义中断。如:
- chunk_size: 9
- chunk_overlap: 2

文本类-递归字符分割,递归字符文本分割器则是指定一系列分隔符来分割文档:
分段分隔符:英文逗号 中文逗号 换行 空格 英文句号 空两行 中文句号 英文问号 中文问号 英文感叹号 中文感叹号

标题分割,按照文本的标题进行切分,适合Word承载的文本。
NTLK 语句分割:把文本分成一个个词语或短语。
spaCy 语句分割
2.2.1 固定长度分割

2.2.1.1 基于 langchain 语法的固定长度分块

(1)分块代码

from langchain.text_splitter import RecursiveCharacterTextSplitter

text_splitter = RecursiveCharacterTextSplitter(
    chunk_size = 20,
    chunk_overlap = 5
)
splits = text_splitter.split_documents(docs)

(2)代码规则

docx:

弊端1:虽然设置了重合数,但是分割时部分块之间没有重叠,语义切断,即使重叠也会有语义切断,就不能编码出完整语义的向量,分块时块大一点可以缓解这种弊端。

弊端2:表格时语义切断影响比较严重,如下这种就会导致回答不出来,当然实际我分割块很大,设置的分割块长一点可以大大减弱这种影响,但是总会有个别的知识不能被完整的分割。
打印结果:由page_content和metadata组成,无页码。

[Document(page_content=‘文本内容’, metadata={‘source’: ‘1.docx’}), …,
Document(page_content=‘文本内容’, metadata={‘source’: ‘1.docx’})]

2.2.1.2 pdf:

弊端1:对pdf表格不友好

结果呈现:由page_content和metadata组成,有页码,每一页有很多块。

2.2.2 自己写的固定分块方法

(1)分块代码

def split_text(text, chunk_size = 100, step = 30):
    chunks = []
    for i in range(0, len(text), step):
        chunk = text[i:i + chunk_size]
        if chunk:
            chunks.append(chunk)
    return chunks

# 分块
docs = []
for document in documents:
    page_content = document.page_content
    metadata_source = document.metadata.get('source', '')
    processed_chunks = split_text(page_content)
    for chunk in processed_chunks:
        doc = Document(page_content = chunk, metadata = {'source': metadata_source})
        docs.append(doc)

(2)代码规则

docx:每块是固定的,也确定能重合。
弊端:和langchain固定语法有同样的弊端,重合值的设定得调,调不好下面这种问答就会出错:

2.3 创建知识库的向量库

# from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings

embedding = OpenAIEmbeddings()
persist_directory_chinese = '/aa/demo/'
vectordb_chinese = Chroma.from_documents(
    documents = splits,
    embedding = embedding,
    persist_directory = persist_directory_chinese  # 将persist_directory目录保存到磁盘上
)
vectordb_chinese.persist()  # 运行vectordb.persist来持久化向量数据库
# print(vectordb_chinese._collection.count())

2.4 检索

LangChain提供的检索工具:

LangChain提供了检索工具vetordb,还提供了其他检索文档的方式,例如:TF-IDF 或 SVM。
检索工具vetordb
(1)基本语义相似度
相似性搜索失败的情况-重复的块
相似性搜索失败的情况-获取所有相似的文档,不强制多样性。
(2)最大边际相关性
最大边际相关模型 (MMR,Maximal Marginal Relevance) 是实现多样性检索的常用算法。
考量查询与文档的相关度,以及文档之间的相似度。它计算每个候选文档与查询的相关度,并减去与已经选入结果集的文档的相似度。这样更不相似的文档会有更高的得分。
(3)过滤元数据
(4)LLM辅助检索

实际用检索时候最好是按照自己设计的想法自己写检索代码,不用封装好的方法。

查询理解阶段:

查询理解阶段
查询扩展(QueryExpansion):自动地向用户的原始查询中添加额外的词语或短语,这些新增的词语或短语与原始查询具有语义上的关联。
方法1:同义词和近义词替换
(1)使用同义词词典
(2)基于预训练模型:使用如BERT等预训练的中文语言模型来识别可能的同义词或近义词。
方法2:词语扩展
(1)利用知识图谱对查询中的实体进行扩展。
(2)找出与查询在语义上相关的历史查询,把历史查询中的关键词添加到原始查询中。
方法3:对于长查询,去掉冗余信息
(1)提取关键信息,去除冗余部分,优化查询的准确性。
方法4:互式查询扩展
(1)通过用户与系统的交互,收集用户对检索结果的反馈,优化查询。

问答部分有这些模式:
多种模式,如MapReduce 分批处理长文档,Refine 实现可交互问答,MapRerank 优化信息顺序
(1) 基于模板的检索式问答链
检索式问答链:提出问题,查找相关文档,将切分文档和系统提示一起传递给语言模型,并获得答案。默认是合并所有文档,一次性输入模型,弊端是若相关文档量大,难以一次将全部输入模型。
(2) 基于 MapReduce 的检索式问答链
将每个独立的文档单独发送到语言模型以获取原始答案。这些答案通过最终对语言模型的一次调用组合成最终的答案。弊端:速度慢,结果实际上更差。
(3)基于 Refine 的检索式问答链
对于每一个文档,会调用一次 LLM,最终输入语言模型的 Prompt 是一个序列,将之前的回复与新文档组合在一起,并请求得到改进后的响应。例如第一次调用,Prompt 包含问题与文档 A ,语言模型生成初始回答。第二次调用,Prompt 包含第一次回复、文档 B ,请求模型更新回答,以此类推。由于 LangChain 内部的限制,定义为 Refine 的问答链会默认返回英文作为答案。

2.5 模型部署和加载

(1)api生成

在线部署,可购买api,如购买gpt的api;本地部署大模型,可以用工具生成模型对应的api,比如可参考:https://github.com/xusenlinzy/api-for-open-llm/tree/master.

(2)Transformers加载方式

我喜欢用这种方式,简单好用,可以随着自己的设计思路随时切换模型。

2.6 内存

上面的链式(chain)没有任何状态的概念,不记得之前的问题或之前的答案,需要引入内存。
它的工作流程是:
将之前的对话与新问题合并生成一个完整的查询语句。
在向量数据库中搜索该查询的相关文档。
获取结果后,存储所有答案到对话记忆区。

2.7 Prompt

提示工程也叫「指令工程」:Prompt 就是你发给大模型的指令,比如「讲个笑话」、「用 Python 编个贪吃蛇游戏」等,他给你信息反馈。就像你在智普清言web页面聊天一样,你发出去的每一个聊天语句就是prompt。

2.8 re-ranking

RAG中的re-ranking是一个重要的步骤,用来提高检索结果的相关性。在RAG框架中,首先会检索一批与输入查询相关的文档(或知识片段),然后通过re-ranking模块对这些检索结果进行重新排序,以便更好地服务于随后的生成任务。

2.9 RAG 优化

用户反馈收集、分析在RAG模型生成过程中,哪些检索到的信息块对最终生成的内容贡献最大、RAG模型在检索过程中实际使用了多少检索到的信息块、模型评测。

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

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

相关文章

JeecgBoot入门

最近在了解低代码平台,其中关注到gitee上开源项目JeecgBoot,JeecgBoot官方也有比较完整的入门教学文档,这里我们将耕者官方教程学习,并将其记录下来。 一、项目简介 JeecgBoot 是一款基于代码生成器的低代码开发平台拥有零代码能力…

threejs开源实例-粒子地球

源码 three.js webgl - geometry - cube <script type"module">import * as THREE from "three";import { OrbitControls } from "three/addons/controls/OrbitControls.js";import { GUI } from "three/addons/libs/lil-gui.modul…

11.1 daimayuan 模拟赛总结

逆天 复盘 7:40 开题 扫了一眼四个题&#xff0c;T1 神秘构造&#xff0c;感觉和以前做过的某道题有点像啊&#xff0c;应该能做&#xff1b;T2 题意很简洁&#xff0c;感觉可做&#xff1b;T3&#xff0c;一眼感觉是什么优化 dp&#xff1b;T4&#xff0c;看上去像是拆期望…

2024年,Rust开发语言,现在怎么样了?

Rust开发语言有着一些其他语言明显的优势&#xff0c;但也充满着争议&#xff0c;难上手、学习陡峭等。 Rust 是由 Mozilla 主导开发的通用、编译型编程语言&#xff0c;2010年首次公开。 在 Stack Overflow 的年度开发者调查报告中&#xff0c;Rust 连续多年被评为“最受喜爱…

Golang | Leetcode Golang题解之第528题按权重随机选择

题目&#xff1a; 题解&#xff1a; type Solution struct {pre []int }func Constructor(w []int) Solution {for i : 1; i < len(w); i {w[i] w[i-1]}return Solution{w} }func (s *Solution) PickIndex() int {x : rand.Intn(s.pre[len(s.pre)-1]) 1return sort.Searc…

微服务day02

教学文档&#xff1a; 黑马教学文档 Docker Docker的安装 镜像和容器 命令解读 常见命令 案例 查看DockerHub&#xff0c;拉取Nginx镜像&#xff0c;创建并运行容器 搜索Nginx镜像&#xff1a;在 www.hub.docker.com 网站进行查询 拉取镜像&#xff1a; docker pull ngin…

认证鉴权框架之—sa-token

一、概述 Satoken 是一个 Java 实现的权限认证框架&#xff0c;它主要用于 Web 应用程序的权限控制。Satoken 提供了丰富的功能来简化权限管理的过程&#xff0c;使得开发者可以更加专注于业务逻辑的开发。 二、逻辑流程 1、登录认证 &#xff08;1&#xff09;、创建token …

python爬虫实现自动获取论文GB 7714引用

在写中文论文、本硕博毕业设计的时候要求非常严格的引用格式——GB 7714引用。对于普通学生来说都是在google scholar上获取&#xff0c;一个一个输入点击很麻烦&#xff0c;就想使用python完成这个自动化流程&#xff0c;实现批量的倒入论文标题&#xff0c;导出引用。 正常引…

pycharm中python控制台出现CommandNotFoundError: No command ‘conda run‘.

1、错误现象 pycharm中打开python控制台出现CommandNotFoundError: No command conda run.的错误。 2、背景 conda是4.6版本&#xff0c;在Anaconda Prompt可以正常运行虚拟环境。 3、解决方法 更新conda版本&#xff0c;基本命令&#xff0c;会自动更新到最新版本。 con…

masm汇编字符输入小写转大写演示

从键盘读取一个字符变成大写换行并输出 assume cs:codecode segmentstart:mov ah,1int 21hmov bl,alsub bl,20hmov dl,10mov ah,2int 21hmov dl,blmov ah,2int 21hmov ah,4chint 21hcode ends end start 效果演示&#xff1a;

VisualStudio远程编译调试linux_c++程序(二)

前章讲述了gdb相关&#xff0c;这章主要讲述用VisualStudio调试编译linux_c程序 1&#xff1a;环境 win10 VisualStudio 2022 Community ubuntu22.04 2:安装 1>vs安装时&#xff0c;勾选 使用c进行linux 和嵌入式开发 (这里以vs2022为例) OR VS安装好了&#xff0c; 选择工…

【002】基于SpringBoot+thymeleaf实现的蓝天幼儿园管理系统

基于SpringBootthymeleaf实现的蓝天幼儿园管理系统 文章目录 系统说明技术选型成果展示账号地址及其他说明源码获取 系统说明 基于SpringBootthymeleaf实现的蓝天幼儿园管理系统是为幼儿园提供的一套管理平台&#xff0c;可以提高幼儿园信息管理的准确性&#xff0c;系统将信息…

【AIGC】从CoT到BoT:AGI推理能力提升24%的技术变革如何驱动ChatGPT未来发展

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AIGC | ChatGPT 文章目录 &#x1f4af;前言&#x1f4af;迈向AGI的新跨越&#x1f4af;BoT与CoT的技术对比技术原理差异推理性能提升应用范围和通用性从错误中学习的能力总结 &#x1f4af;BoT的工作流程和机制初始化过程生成推…

无人机拦截捕获/直接摧毁算法详解!

一、无人机拦截捕获算法 网捕技术 原理&#xff1a;抛撒特殊设计的网具&#xff0c;捕获并固定无人机。 特点&#xff1a; 适用于小型无人机。 对无人机的损害较小&#xff0c;基本不影响其后续使用。 捕获成功率较高&#xff0c;且成本相对较低。 应用实例&#xff1a;…

解码层跑几次取决于输出词汇多少;10个单词,在解码层跑几次transformer

目录 解码层跑几次取决于输出词汇多少 10个单词,在解码层跑几次transformer 解码层跑几次取决于输出词汇多少 10个单词,在解码层跑几次transformer 取决于具体任务和输出要求 在自然语言处理任务中,Transformer 架构的解码器(Decoder)运行次数与你想要生成的输出长度有关…

算法【Java】—— 记忆化搜索

记忆化搜索 在前面我们已经学习了递归回溯等知识&#xff0c;什么是记忆化搜索&#xff0c;其实就是带着备忘录的递归&#xff0c;我们知道在递归过程中如果如果出现大量的重复的相同的子问题的时候&#xff0c;我们可能进行了多次递归&#xff0c;但是这些递归其实可以只用进…

优化EDM邮件营销,送达率与用户体验双赢

EDM邮件营销需选对平台&#xff0c;优化邮件列表&#xff0c;确保内容优质&#xff0c;进行邮件测试&#xff0c;关注用户反馈调整频率&#xff0c;以保高送达率&#xff0c;提升营销效果。 1. 了解电子邮件送达率的重要性 在开始优化邮件送达率之前&#xff0c;首先需要理解电…

Metasploit渗透测试之在云服务器中使用MSF

概述 随着云计算的发展&#xff0c;对基于云的应用程序、服务和基础设施的测试也在不断增加。在对云部署进行渗透测试时&#xff0c;最大的问题之一是共享所有权。过去&#xff0c;在进行渗透测试时&#xff0c;企业会拥有网络上的所有组件&#xff0c;我们可以对它们进行全部…

Qt桌面应用开发 第一天

目录 1.默认代码解析 1.1main.h解析 1.2myWidget.h解析 1.3FirstProject.pro解析&#xff08;FirstProject为创建的Qt项目名&#xff09; 2.命名规范与快捷键 3.按钮控件及窗口设置 3.1按钮控件QPushButton类 3.2窗口常用设计 4.Qt中的对象树 5.Qt中的坐标系 Qt是一个…

简记Vue3(三)—— ref、props、生命周期、hooks

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…