心法利器[110] | 知识文档处理和使用流程

心法利器

本栏目主要和大家一起讨论近期自己学习的心得和体会。具体介绍:仓颉专项:飞机大炮我都会,利器心法我还有。

2023年新的文章合集已经发布,获取方式看这里:又添十万字-CS的陋室2023年文章合集来袭,更有历史文章合集,欢迎下载。

往期回顾

  • 心法利器[105]  基础RAG-大模型和中控模块代码(含代码)

  • 心法利器[106]  基础RAG-调优方案

  • 心法利器[107] onnx和tensorRT的bert加速方案记录

  • 心法利器[108] | 微调与RAG的优缺点分析

  • 心法利器[109] | RAG效果评估经验

RAG强调的是通过知识检索,为大模型提供足够的知识支撑,从而缓解大模型出现幻觉的问题,但这里有一个大前提,就是“有知识”,只是从哪来,怎么处理,如何放入检索库,如何被检索、使用的,本文主要给大家讲清楚这个整体流程以及内部常见的方案。

知识的使用流程

在讲方法之前,先了解一下知识全流程的流动路线和具体的使用方法,毕竟只有知道这个数据怎么用,我们才知道什么形态适合,能更快地进行调整。

知识从原始材料到最终使用,主要会经历离线和在线两个阶段。离线阶段是指,是把原始材料存入数据库的流程,这个阶段是离线处理的,所以被称为离线阶段;在现阶段是指通过query被检索出来最终被作为prompt的一部分输入大模型的过程,这就是在线阶段。

离线阶段会经历这几个过程:

  • 基础文档解析——将各种形式的文档,转化可以容易处理模式,例如都转为文本。

  • 内容理解——从文档中提取各种重要信息,可以是关键词、实体、标签、摘要、切片等显式信息,也可以是embedding这种隐式信息。

  • 入库——存到数据库中,做成方便检索的索引,供在线的搜索使用。

在线阶段会经历这几个过程:

  • 检索出库——被搜索出来,从数据库中被取出。

  • 排序、判别、过滤——对检索出来的知识进行进一步的筛选,选出最合适的备选知识。

  • 拼接prompt——知识拼接成prompt,形成回复结果。

离线阶段——知识处理

基础文档解析

在现实应用中,我们可能会遇到各种各样不同的知识材料。从内容类型,可以有文本、音频、视频、图片,格式上,文本有word、pdf、txt甚至excel、ppt等,音频有wav、mp3,视频有mp4、rmvb等,进一步的即使是文本,有政策文档,表格、代码、富文本等多种格式,还有可能是文本的截图,输入的内容如此混乱,我们需要对各种内容进行针对性处理。

目前比较常见的,是对文本的处理,对于结构化的形式,类似json、csv、tsv格式的不需要赘述,读取方法都比较简单,更多需要关注的是pdf、word以及html。

以PDF为例,python下其实已经有大量的工具能够读取pdf了,大家可以参考这里面的内容,另外也有很多别的工具也可以自己进一步去查。

  • Python:PDF文件处理(数据处理):https://blog.csdn.net/Big_Data_Legend/article/details/129091548

  • PyPDF2: 一款操作操作PDF非常丝滑的Python库:https://zhuanlan.zhihu.com/p/674154847

  • 解密PymuPDF:Python秘籍轻松操控PDF文件!https://zhuanlan.zhihu.com/p/669887252

在对基础文档进行解析后所得到的,是更方便常规处理的各种模态内容,如常规意义的文本、音频、图片等,以便进行进一步处理和入库工作。

内容理解

内容理解本身是推搜领域的说法,但在这里,我还是想直接挪用过来,他应该是相比基础文档解析更特别的部分,需要拆解出来。他是在基础文档解析完成后进行的进一步处理,按照我的实践经验,常见的会有如下工作(可能还会结合实际情况加减):

  • 向量化,即embedding,通过多种方式,例如多个不同结构的模型、多种不同的特征或训练方法得到的模型,可以得到多种不同类型的向量。

  • 特定字段或特征的提取,例如对文档进行分类得到类目标签,对实体进行提取得到实体标签。

  • 对长文本进行摘要或者切片,然后再进行向量化(这里可以看到,各个工作是可以自由组合的)。

  • 内容的重新结构化,把很多特征,从列表形式或者表格形式转化为更适合进行检索的json形式,对应到库里的字段,以便后续存入各种检索库里。

可见,内容理解的所要做的以及用到的技术是完全不同的,这一步其实可能有大量的NLU工作,通过提取更多不同维度的信息,以便后续更好地检索,这里的工作远不是文档切片和向量化两件事,不是向量化存入库,在线一查就好了的,为了让内容更好地被查出来,从离线的内容理解开始,就要做好各种准备。

此处以文档切片为例简单说一下里面所涉及的技术和关注点。文档切片是针对文档而言的,由于匹配对空间信息的要求较高(太长容易出现内容稀释),且后续大模型使用这些信息时对长度有要求(现阶段看,前者问题更大),因此对长文档而言,切片是最简单便捷的方案。常见的方案基本可以在“langchain.text_splitter”中找到,例如RecursiveCharacterTextSplitter可以递归尝试不同字符来切割文本,CharacterTextSplitter可以按照字符来切割文本等,通用地,这些方案可以直接拿来使用,但为了最终效果,这种生硬的方式可能不能达到理想水平,大家需要根据实际情况自己写或者是继承下来对某些小部分进行小幅度调整。

另外,在之前我给出的开源项目中,也有比较简单的内容理解模块的代码,是以向量化为例的(心法利器[104] | 基础RAG-向量检索模块(含代码))。我再把这块相关的代码片段放出来

vec_model = VectorizeModel(VEC_MODEL_PATH, DEVICE)
index_dim = len(VectorizeModel(VEC_MODEL_PATH, DEVICE).predict_vec("你好啊")[0])
source_index_data = []
with open(SOURCE_INDEX_DATA_PATH, encoding="utf8") as f:
    for line in f:
        ll = json.loads(line.strip())
        if len(ll["title"]) >= 2:
            source_index_data.append([ll["title"], ll])
        if len(ll["desc"]) >= 2:
            source_index_data.append([ll["desc"], ll])
        # if len(source_index_data) > 2000:
        #     break
logger.info("load data done: {}".format(len(source_index_data)))

# 推理向量
vectorize_result = []
for q in tqdm(source_index_data):
    vec = vec_model.predict_vec(q[0]).cpu().numpy()
    tmp_result = copy.deepcopy(q)
    tmp_result.append(vec)
    vectorize_result.append(copy.deepcopy(tmp_result))

此处就是把处理好的数据从本地打开,然后进行向量推理的过程,看起来是比较简单的,但实际应用中,背后可能还有很多工作要做:

  • 向量模型的调优,就是这个模型VectorizeModel

  • 原始数据的处理,这里可以看到,目前的数据是已经被结构化的,是json结构,但实际上并不一定是,还需要进一步的抽取挖掘。

在实际情况,这块的工作的坑可以很深,还是得耐着性子去做,配合后续RAG效果的bad case反馈,逐步迭代完善优化。

入库

在对各种文档进行了内容理解后,一般我们能够得到待入库的数据物料,然后,我们就批量地灌入到检索库中去。在之前我给出的开源项目中,就已经给了这个模块的脚本demo(心法利器[104] | 基础RAG-向量检索模块(含代码)),我直接放出来。

vec_searcher = VecSearcher()
vec_searcher.build(index_dim, VEC_INDEX_DATA)

# 开始存入
for idx in tqdm(range(len(vectorize_result))):
    vec_searcher.insert(vectorize_result[idx][2], vectorize_result[idx][:2])

# 保存
vec_searcher.save()

这里只是demo,数据量有大有小,使用的工具各异,接口也可能不同,大家需要根据实际情况整,可能的情况有这些:

  • 数据字段类型不同,可能是关键词、数字啥的,那要考虑用关键字索引、数字索引之类的。

  • 检索库的选择,单机的分布式的之类的。

  • 向量索引里面可能也有一些参数需要依赖,例如hnsw索引中要权衡内存占用和召回率的关系。

在线阶段——知识检索

在现阶段大家应该会比较了解了,其实就是知识的检索和使用。

检索出库

检索出库是指,给定query去库里面检索和他最接近的doc,最简单能想到的,依旧是向量,就是根据接口查就行,这里就不赘述了。这里可以给大家打开多个思路:

  • 召回链路是可以多路的,具体选哪个交给下一步就行。可以是不同模型的向量,可以是不同特征、训练方法构造的向量;可以是字面的召回或者有关特征的召回,例如“适合1岁以下宝宝的奶粉”,类似这种问题交给向量、字面其实都不合适,肯定是数字索引,一定要注意因地制宜。

  • 检索要记得截断,简单的思路就是TOPN,即只取前N个,但有些时候,可能知识库里就没有合适的,即使TOPN,前面几个也并不能很好地回答问题,此时更多情况是宁可不召也比召错强,没答案的话后续弄兜底方案就行。

排序、判别、过滤

这些操作其实都是原来老的推荐、搜索领域一脉相承了,对召回回来的内容做进一步的筛选,主要思路就是排序、判别和过滤。

排序是指,对给定的知识进行重新的排序,召回的多路在融合后,谁在前面谁在后面,往往需要一个统一的标准进行融合,且排序层因为面对的数据较少,所以逐个和query进行相似度计算,也不会很难,此时可以大胆的使用准确度、灵活性更高的交互式深度学习模型、基于特征的机器学习模型或者是规则打分。这里也可以看到,排序是可以使用交互式深度学习模型、基于特征的机器学习模型或者是规则打分的,可以结合目前已有的数据、具体效果需求、召回链路情况来进行综合判断。

判别是指直接评价特定的一个召回的doc和query的关系,本质也是一个分类,只有两者的关系足够紧密,召回结果才能被用于后续的大模型推理中,类似的思路在CRAG论文里面可以用到,之前我有对这篇论文做详细的讨论(前沿重器[43] | 谷歌中科院新文:CRAG-可矫正的检索增强生成),在这篇论文里,用的是大模型来判别,这是一个好方法,但不绝对,很多时候其实小模型也能达到不错的效果,需要根据实际情况进行选择。

过滤是对一定不对的内容进行过滤,常规的阈值和TOPN过滤是比较直接的,但有些情况可能会有一些变化,可能还要添加别的标准,例如某些字段的限定,像人物百科下要对人进行限制(这些在向量召回中,可能会不好约束,得召回回来后再进行约束),这个根据具体业务需求来做就行,得有一个意识存在这个方案。

拼接prompt

拼接prompt是一个大家应该都知道的活了,简单的就是这个模式:

RAG_PROMPT = """请根据用户提问和参考资料进行回复。

用户提问:{}

参考材料:
{}"""

复杂的可以考虑多个方面给出更多具体信息,可以参考这些:

  • 描述场景和角色,让大模型对场景有一定的认识,配合场景的回复能更精准。

  • 字数、长度限制,避免无限制写。

  • 进一步约束不匹配情况,对不匹配的给出拒绝回复。

补充——实际情况选择

今天的文章我在很多地方都提到了根据实际情况选择,这里有两个重点,其一是必要的知识储备,其二是对实际情况的把握。

必要的知识储备要求的是我们得有足够的“招数”以免对不同的实际情况,以前面基础文件解析为例,我们需要面对的可能是各种各样的文档,都需要做解析,pdf、excel等等,我们只有对类似的文档类型有了解才能够去处理。我们要提前有一定的知识储备才能够做。扎心的,遇到问题多想想,手里是不是只有大模型这一招,别的就不会了。

实际情况的把握来自对业务、数据的理解,对目前面对的问题的了解。我们要经常看数据,带着思考解决方案的目标去看,此时我们手里有很多方案,但是具体要用哪个,是要根据问题来确定的,例如大部分知识问答是很适合用faq的,但是一些结构化的知识,可能用query理解+字面检索的方式可能更加适合,此时早期全链路的设计就有天壤之别,很多成熟的算法工程师甚至可能会花好几天甚至一周的时间来看数据和分析方案,原因就在此,磨刀不误砍柴工,觉得看数据无趣,直接想当然地要动手干可能要吃亏了。

后记

本文是计划是解释文档知识处理的主要方法,但是提纲写下来就改为知识的整体使用流程了,文档处理的方案已经能从多个平台上找到很多大佬的讲解,然而挺多讲解都缺少一个全局视野,只讲了具体的方法,虽然很完整,但是没讲好怎么选择,所以我想着要把全局和大家说明白,这样更有利于方案选择和理解,只有有关的细节技术,大家可以结合我列举的技术,在网上都能找到类似的方案,此处我也就略写了。

84379bd85bfb1d50644fe34fe4119e33.png

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++的缺省参数,函数重载,引用

目录 1、缺省参数(不能在函数声明和定义中同时出现,若声明和定义是分开的,则缺省参数放在声明里面) 1.1、缺省参数的概念 1.2、全缺省 1.3、半缺省 2、函数重载 2.1、特殊情况 2.2、特殊情况 2.3、为什么C支持函数重载而C语…

四、C语言中的数组:二维数组

四、C语言中的数组:二维数组 本章的学习内容如下: 四、C语言中的数组:数组的创建与初始化 四、C语言中的数组:数组的输入与元素个数 C语言—第6次作业—十道代码题掌握一维数组 四、C语言中的数组:二维数组 我们可以…

学习SpringBoot笔记--知识点(2)

目录 数据访问 基础特性 自定义banner Profiles Profiles组件 Profiles配置文件 外部化配置 单元测试 数据访问 整合SSM场景 SpringBoot 整合 Spring&#xff0c;SpringMVC&#xff0c;MyBatis 进行数据访问场景开发 需要的依赖&#xff1a; <!-- web启动…

遇到了问题,Firepower 2140配置带外IP时报错 commit-buffer failed

onsite we have a cisco firepower 2140 device which run ASA as we try to modify the 2140 OOB mgmt ip by CLI, we got an error why ? 经过查询发现&#xff0c;需要进入ASA里面打上以下这条命令&#xff0c;并重启ASA 1 修改模式并重启 ciscoasa# configure termina…

注册、配置中心-微服务小白入门(2)

Nacos 已经下载安装并且使用了&#xff0c;那么看如何使用&#xff1a; Nacos 注册及配置&#xff0c;以下是一个服务启动后注册到nacos&#xff0c;同时&#xff0c;把该服务的相关配置&#xff0c;写到nacos之中 1、nacos设置 命名空间中&#xff0c;添加对应的服务命名空间…

agent利用知识来做规划:《KnowAgent: Knowledge-Augmented Planning for LLM-Based Agents》笔记

文章目录 简介KnowAgent思路准备知识Action Knowledge的定义Planning Path Generation with Action KnowledgePlanning Path Refinement via Knowledgeable Self-LearningKnowAgent的实验结果 总结参考资料 简介 《KnowAgent: Knowledge-Augmented Planning for LLM-Based Age…

CharacterController.Move called on inactive controller

【问题背景】 Unity3D中开发物体的移动&#xff0c;实现代码如下&#xff1a; public class TargetController : MonoBehaviour {private CharacterController character;private float speedRate 4f;private void Start(){character GetComponent<CharacterController&…

第十二届蓝桥杯JavaB组省赛真题 - 时间显示

解题思路&#xff1a; 数量级较大&#xff0c;需要使用long类型 import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scan new Scanner(System.in);long num scan.nextLong();long allseconds num / 1000;long seconds allse…

ROS机器人入门第四课:话题通信

文章目录 ROS机器人入门第四课&#xff1a;话题通信一、话题通信概述&#xff08;一&#xff09;概念&#xff08;二&#xff09;作用 二、话题通信基本操作需求:分析:流程:&#xff08;一&#xff09;发布方解释一些关键的ROS函数和概念&#xff1a; &#xff08;二&#xff0…

如何使用WordPress插件保护网站的安全

前段时间我们的网站受到了黑客的攻击&#xff0c;网站丢失了一些重要的数据&#xff0c;为了防止这种情况的再次发生&#xff0c;我们准备将网站全部迁移到高防服务器&#xff0c;经过一番对比后&#xff0c;我们选择了Hostease提供的高防服务器。它可以有效地抵御各种类型的网…

网络七层模型:理解网络通信的架构(〇)

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

开箱即用的中后台管理模版,建议收藏!

公众号&#xff1a;程序员白特&#xff0c;欢迎一起交流学习~ 原文作者&#xff1a;前端充电宝 大家好&#xff0c;我是白特。 今天来推荐几款开箱即用的中后台管理模版&#xff01; Vue Element Admin vue-element-admin 是一个后台前端解决方案&#xff0c;它基于 vue 和 …

WMS仓储管理系统如何优化供应链管理

随着信息技术的快速发展和市场竞争的加剧&#xff0c;优化供应链管理已成为企业提升竞争力的关键。WMS仓储管理系统作为供应链管理的核心工具&#xff0c;其在优化供应链过程中的作用日益凸显。本文将深入探讨WMS仓储管理系统如何优化供应链管理。 首先&#xff0c;WMS仓储管理…

pdfjs 实现给定pdf数据切片高亮并且跳转

pdfjs 实现给定pdf数据切片高亮并且跳转 pdfjs 类的改写基本展示需求的实现高亮功能的实现查询功能分析切片数据处理 pdfjs 类的改写 需求&#xff1a; pdf文件被解析成多个分段&#xff0c;每个分段需要能够展示&#xff0c;并且通过点击分段实现源pdf内容的高亮以及跳转需求…

Oracle数据库入门第三课(函数)

前面二白讲了一些简单的查询语句&#xff0c;仅仅知道查询语句的语法是不够的&#xff0c;要想实现更多的需求&#xff0c;更重要的是函数的使用&#xff0c;这节课我们简单说一下一些函数的使用。 一、函数的分类 什么叫做函数? 函数就是用来实现某种功能的,提前声明好的代…

微博修改密码后无法通过微博开放接口发送微博

生产环境&#xff0c;因密码修改导致授权失效致接口发送微博失效&#xff01;内部网站编辑完博文后无法发送微博。在修改密码时&#xff0c;有提示授权应用失效&#xff0c;操作人员不清晰情况&#xff0c;直接忽视。 微博应用开放接口----》微博转发博文接口文档 无示例 遗憾…

淘宝API接口推荐:淘宝app商品详情数据接口

淘宝的商品详情API接口是一种技术工具&#xff0c;它允许开发者通过编程的方式获取淘宝平台上商品的详情页面的数据。这些数据对于电商智能决策至关重要&#xff0c;因为它们可以提供关于消费者偏好、商品质量和市场趋势的宝贵信息。 淘宝天猫API列表 item_get 获得商品详情i…

多线程死锁,java内存模型,wait、notify方法

死锁出现的第一种情况 可重入 同一个线程针对同一个锁连续继续加锁多次的行为。如果发生了死锁情况&#xff0c;那就是发生了不可重入&#xff0c;反之不会发生死锁&#xff0c;就是可重入的。 当进行多次加锁会发生什么情况 在这个方法中实现了在外面对方法的加锁&#xff08;…

操作系统的理解|冯·若依曼体系结构|进程的状态

操作系统的理解 冯诺伊曼体系结构为什么必须通过内存然后到cpu存储金字塔冯诺伊曼结构的改进在哪&#xff1f;我们可不可以全部用寄存器来做存储器在硬件数据流动角度学以致用&#xff1a;解释程序运行为什么要加载到内存程序没被运行之前存在哪里&#xff1f; 操作系统概念广义…

快速熟悉ElasticSearch的基本概念

1.全文检索 全文检索是通过文本内容进行全面搜索的技术。通过全文检索可以快速地在大量文本数据中查找包含特定关键词或者短语的文档&#xff0c;并且返回相关的搜索结果。 检索和查询的区别 检索没有搜索条件边界&#xff0c;检索的结果取决于相关性&#xff0c;相关性计算…