聊聊检索增强,LangChain一把梭能行吗?

背景

ChatGPT诞生之初,大家仿佛从中看到了未来:可以拿着大语言模型(LLM)这把锤子,锤遍业务上的钉子。其中最被看好的场景,莫过于搜索,不仅是微软、谷歌、百度这样的大公司将LLM用到自己的搜索业务中,Github上也有很多知识库、文档问答相关的优秀开源项目,究其本质,是通过检索相关知识来增强LLM的回答效果

搭建一个检索增强pipeline其实很简单,“embedding模型+向量检索+LLM”这一套组合拳就足够,而且LangChain中都已经封装好了,简单写几行代码调用就能收工下班!但如果认真去分析最终回复的效果,就会发现这个pipeline只完成了工作的冰山一角,而本文,会展开聊聊冰山之下的秘密。

分片+检索+回答

首先需要对整体的流程进行概述:

  1. 文本分片。不同格式的原始数据,需要转成文本。因为文本在后续的操作中会拼接到prompt中,所以对于过长的文本,需要进行分片,控制在一定的长度之内。

  2. 文本检索。离线阶段,可以将文档片段都进行embedding,将embedding向量存储到向量数据库中;在线阶段,将用户query的embedding向量在向量数据库中进行检索,返回TopK的相关文档。

  3. LLM回答。将TopK的相关文档组织成prompt,请求LLM得到最终的回答。

这三个步骤环环相扣,每一个环节的错误都会层层传递到后续的环节。下面会分别介绍这三个环节中可能会碰到的挑战。

图来源于[3],”分片“对应图中第1、2步,”检索“对应第3、4步,”回答“对应第5步

图来源于[3],”分片“对应图中第1、2步,”检索“对应第3、4步,”回答“对应第5步

文本分片

文本数据抽取

且不论多模态数据,单单是文本数据的存储格式,常见的就有:TXT、Word、PDF、Latex、CSV、Excel、HTML、Markdown……不同格式的数据要转成纯文本,需要话费不少功夫,即使是Langchain-Loaders[1]已经提供了多种格式的文本提取接口,但对于复杂格式的文件,提取效果依然不太理想,如PDF。这时候就需要投入更多精力来进行数据清洗,否则会直接影响到最终的效果。

语义完整性

Langchain-Doc Transformers[2]中介绍了按照长度、指定符号(句号、换行符)这些简单的规则进行文本分片的方法,但用这些方法得到的分片很多情况下会有语义不完整的问题,比如:

  • 文档格式转换(如PDF无法识别段落)出问题

  • 整体语义蕴含在长文本中

  • 当文档编写者不遵守语法,胡乱断句换行

  • ……

为了保证语义的完整性,可以尝试以下方案:

  • 使用模型(比如Bert)进行分片,而不是简单的依靠规则切分。

  • 对文档进行摘要,这样可以大幅缩短文档的篇幅,保证语义的完整性。

  • 使用LLM根据文档构造多个QA pair,由于LLM可接受的prompt长度会大于文本片段的长度,通过这种方法得到QA pair能够将距离较远的信息有结构地组织到一起,控制在可接受的长度内。

文本检索

过滤无关文本片段

如果只是取检索结果的TopK拼接到后续LLM的Prompt中,那TopK中难免会有和用户问题不相关的结果,所以需要进行过滤,尽量保证给的LLM的都是相关的文本片段。

常用的过滤方式就是根据相关性分数过滤了,可以选择一个阈值,丢弃相关性低于该阈值的文档。这么做的前提,需要Embedding模型最好满足以下要求:

  • Embedding模型返回的向量最好是归一化后的,这样使用内积或欧氏距离表示相关性时,取值都在固定范围内,容易选择阈值。

  • Embedding模型最好做过**校准(Calibration)**。校准这一操作在CTR预估中很常见,主要是因为训练时一般采用pairwise,同时也主要会使用AUC、NDCG这类排序类型的评价指标,比如A>B>C,模型预测ABC的分数为[0.1, 0.2, 0.3]或[0.7, 0.8, 0.9]在评价指标上是一样的,但这样不利于选取合适的阈值来过滤无关文本,所以需要加上校准这一步骤。

多轮问答下的检索Query

假设用户前后的两个问题是:”颐和园在哪里?“、”门票多少钱?“。但如果单看第二个问题,无法知道用户想问的是哪里的门票。所以,如果只用最新的query来检索,会造成上下文依赖丢失的问题。

针对这个问题,可以尝试以下解法:

  • 增加一个模型(比如:Bert),用户判断当前的query和历史的query是否有上下文依赖关系,维护一个依赖关系链,如果有,则将依赖链上的query拼接起来用于文本检索,否则只需将最新的query用于检索即可。

  • 让LLM根据近几轮的问答生成检索query,发挥LLM的通用性。

LLM回答

Prompt

用什么样的Prompt才能让LLM输出满意的结果呢?首先来看一个常用来做检索增强的Prompt:

Use the following context as your learned knowledge, inside <context></context> XML tags.
<context>
{{context}}
</context>
When answer to user:
- If you don't know, just say that you don't know.
- If you don't know when you are not sure, ask for clarification. 
Avoid mentioning that you obtained the information from the context.
And answer according to the language of the user's question.Here is the chat histories between human and assistant, inside <histories></histories> XML tags.
<histories>
{{histories}}
</histories>human:{{question}}
ai:

以上这个Prompt,将相关文档、历史对话、用户问题都放进去了,看着是个很强的baseline。但如果你用的LLM不是强如ChatGPT,而只是6B、13B规模的开源模型,你会发现这个Prompt的效果不够稳定,经常出现Badcase。

我认为它最致命的缺点是没有采用对话的形式。之前在介绍ChatGPT的三步走方案时提到了,在第二、三步时训练数据的格式是对话的形式,所以,如果将Prompt能够保持对话的形式,效果应该能更好,下面是一个示例。关于Chatgpt是如何组织对话的,可以参考以往的这篇文章。

[{"role":"system","content":"""
Use the following context as your learned knowledge, inside <context></context> XML tags.
<context>
{{context}}
</context>
When answer to user:
- If you don't know, just say that you don't know.
- If you don't know when you are not sure, ask for clarification. 
Avoid mentioning that you obtained the information from the context.
And answer according to the language of the user's question."""},{"role":"user","content":"histories_user_1"},{"role":"assistant","content":"histories_assistant_1"},...{"role":"user","content":"question"},
]

礼貌拒答

即使有了检索增强,也不见得LLM能答上所有问题,相反,我们更希望LLM在没有把握的时候,选择有礼貌地拒答,所谓有礼貌,在很多场景中是和”人设“相关的,比如落地的场景是企业助手、电商客服等。想要实现人设和拒答的效果,主要的工作是在调优Prompt上。Prompt工程这活儿,感觉只能起到锦上添花的作用,效果想要更上一层楼还是得使用更强的LLM。

写在最后

创新到普及之间,技术到产品之间,可用到好用之间,存在着一道隐秘的GAP。篇幅有限,以上的一些经验,无法覆盖到方方面面,欢迎大家一起来讨论!

Reference

[1] Langchain-Loaders

[2] Langchain-Doc Transformers

[3] Langchain-Question Answering

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

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

相关文章

ROS2学习(一):Ubuntu 22.04 安装 ROS2(Iron Irwini)

文章目录 一、ROS2(Iron Irwini)介绍二、ROS2(Iron Irwini)安装1.设置编码2.使能代码库3.安装ROS2 Iron 三、ROS2测试四、ROS2卸载 一、ROS2(Iron Irwini)介绍 官方文档 Iron Irwini版本支持的平台如下&#xff1a; 二、ROS2(Iron Irwini)安装 1.设置编码 sudo apt update…

利用python爬取谷歌趋势某个关键词的每日搜索次数

大家好&#xff0c;我是带我去滑雪&#xff01;本期尝试利用python爬取谷歌趋势某个关键词的每日搜索次数。 目录 1、什么是谷歌趋势&#xff1f; 2、爬取谷歌趋势的搜索次数有何用&#xff1f; 3、代码如何实现&#xff1f; (1&#xff09;导入相关模块 &#xff08;2&a…

Java实现根据关键词搜索京东商品列表数据方法,当当API接口(jd.item_search)申请指南

要通过京东网的API获取商品列表数据&#xff0c;您可以使用京东开放平台提供的接口来实现。以下是一种使用Java编程语言实现的示例&#xff0c;展示如何通过京东开放平台API获取商品列表&#xff1a; 首先&#xff0c;确保您已注册成为当当开放平台的开发者&#xff0c;并创建…

Windows安装单节点Zookeeper

刚学习Dubbo&#xff0c;在Centos7中docker安装的zookeeper3.7.1。然后在启动provider时一直报错&#xff0c;用尽办法也没有解决。然后zookeeper相关的知识虽然以前学习过&#xff0c;但是已经忘记的差不多了。现在学习dubbo只能先降低版本使用了&#xff0c;之后再复习zookee…

spring cloud新版本使用loadbalancer替代Ribbon

Nacos 2021 不再集成 Ribbon&#xff0c;建议使用spring cloud loadbalancer 引入 一、简单使用 引入依赖spring cloud loadbalancer <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer<…

数据库锁简析

数据库大并发操作要考虑死锁和锁的性能问题。用T1代表一个数据库执行请求&#xff0c;T2代表另一个请求&#xff0c;也可以理解为T1为一个线程&#xff0c;T2 为另一个线程。T3,T4以此类推。下面以SQL Server为例。 锁的种类 共享锁(Shared lock) 例1&#xff1a;T1: select…

Golang数据结构和算法

Golang数据结构和算法 数据的逻辑结构和物理结构常见数据结构及其特点算法的时间复杂度和空间复杂度Golang冒泡排序Golang选择排序Golang插入排序Golang快速排序Golang归并排序Golang二分查找Golang sort包Golang链表Golang container/list标准库Golang栈stackGolang二叉搜索树…

解决css样式中last-child不生效的问题

需求 项目中需要使用v-for指令来渲染一个图片列表&#xff0c; 现状 发现&#xff0c;最后一个格子并没有跟下面绿色线对齐。 最后发现 是因为 每个格子都给了 margin-right&#xff1a;36px&#xff0c;影响到了最后一个格子 所以使用last-child 将最后一个格子的margin 属性…

ARM DIY(六)音频调试

前言 今天&#xff0c;调试一下音频 硬件焊接 硬件部分核心是 LM4871 音频功放芯片 对于 SOC 来讲很简单&#xff0c;就一个引脚 HPOUTL&#xff08;单声道&#xff09;&#xff1b;对于扬声器来讲也很简单&#xff0c;就两个引脚&#xff0c;插上就可以了。 另外一个关键点…

FastDFS+Nginx - 本地搭建文件服务器同时实现在外远程访问「端口映射」

文章目录 前言1. 本地搭建FastDFS文件系统1.1 环境安装1.2 安装libfastcommon1.3 安装FastDFS1.4 配置Tracker1.5 配置Storage1.6 测试上传下载1.7 与Nginx整合1.8 安装Nginx1.9 配置Nginx 2. 局域网测试访问FastDFS3. 安装cpolar内网穿透4. 配置公网访问地址5. 固定公网地址5.…

vue3中如何使用el-tooltip中的插槽达到换行效果

el-tooltip的content属性中的内容可以使用插槽来替换 话不多说&#xff0c;直接上代码 <el-tooltip effect"light" placement"top-start"><div slot"content" class"tips"> // 在这里运用插槽<p class"tip-tex…

数据结构--5.1图的存储结构(十字链表、邻接多重表、边集数组)

目录 一、十字链表&#xff08;Orthogonal List&#xff09; 二、邻接多重表 三、边集数组 四、深度优先遍历 一、十字链表&#xff08;Orthogonal List&#xff09; 重新定义顶点表结点结构&#xff1a; datafirstInfirstOut 重新定义边表结构结点&#xff1a; tailV…

js 将形如 ‘Aug 30 2022‘ 格式的日期转化为 ‘%Y-%m-%d‘ 的格式。

可以使用JavaScript中的Date对象和相关方法来完成此任务。具体实现如下&#xff1a; // 定义需要转换的日期字符串 const dateStr Aug 30 2022;// 将日期字符串转换为Date对象 const date new Date(dateStr);// 使用Date对象的getDate、getMonth、getFullYear方法获取年月日…

OS 死锁处理

如果P先申请mutex 则mutex从1置零&#xff0c;假设申请到的empty 0则empty变成-1阻塞态 同理C中mutex从0变为-1&#xff0c;那么如果想离开阻塞态&#xff0c;那么就需要执行V&#xff08;empty&#xff09;但是如果执行V&#xff08;empty&#xff09;就需要P&#xff08;mu…

7.react useReducer使用与常见问题

useReducer函数 1. useState的替代方案.接收一个(state, action)>newState的reducer, 并返回当前的state以及与其配套的dispatch方法2. 在某些场景下,useReducer会比useState更加适用,例如state逻辑较为复杂, 且**包含多个子值**,或者下一个state依赖于之前的state等清楚us…

后端给前端传参数忽略空属性

JsonInclude JsonInclude注解用于指定在对象序列化为JSON字符串时&#xff0c;哪些属性应该被包含进去&#xff0c;哪些属性应该被忽略掉。 JsonInclude注解有以下几个常用选项&#xff1a; JsonInclude(JsonInclude.Include.NON_NULL)&#xff1a;表示只有属性值不为null的属…

stm32之25.FLASH闪存

打开标准库 源码--- int main(void) {uint32_t d;Led_init();key_init();/* 初始化串口1波特率为115200bps&#xff0c;若发送/接收数据有乱码&#xff0c;请检查PLL */usart1_init(115200);printf("this is flash test\r\n");/* 解锁FLASH&#xff08;闪存&#xf…

GPT 系列笔记

open ai 出品, 与 google 的 bert 系列 是不同的任务, NLGeneration vs. NLUnderstanding. 二. GPT-2 hugging-face 的 transformers 库中有模型源码, 为 from transformers.models.gpt2 import GPT2Model. 成员字段 wte, Word Token Embwpe, Word Position Embh, 模型主体…

运维数据(2):全新解说运维的价值和场景

在一个项目中&#xff0c;得知客户高层一直在纠结运维的价值&#xff0c;质疑运维投入的合理性和必要性&#xff0c;要求澄清其具体价值及其与业务的关系。同时&#xff0c;当今IT界流行“场景”一词&#xff0c;不论是解决方案&#xff0c;还是具体产品都在拉关系&#xff0c;…

亚马逊云科技 re:Inforce 大会云安全合规与技术实践及 Security Jam 大赛,快来报名吧!...

‍‍ 2023年8月31日在北京 亚马逊云科技 re:Inforce 大会 首次登陆中国&#xff01; 我们期待您的莅临&#xff0c; 并与您一起迎接 AI 时代&#xff0c; 开启全面智能的安全旅程&#xff01; 在13:00-17:00的 培训与动手实验环节中 云安全合规与技术实践 及 Security Jam 大赛…