心法利器
本栏目主要和大家一起讨论近期自己学习的心得和体会。具体介绍: 仓颉专项:飞机大炮我都会,利器心法我还有 。
2023年新的文章合集已经发布,获取方式看这里:又添十万字-CS的陋室2023年文章合集来袭,更有历史文章合集,欢迎下载。
往期回顾
- 心法利器[125] | 24年算法思考-RAG技术论文和实践小结
- 心法利器[126] | 24年算法思考-小模型的生存空间
- 心法利器[127] | 24年算法思考-特征工程和经典深度学习
- 心法利器[128] | 2024年算法小结-个人成长-打开思路-生日
- 心法利器[129] | deepseek-R1自测效果分析和选择建议
- 前沿重器[48-54] 合集:四万字聊搜索系统
RAG这个东西伴随大模型的发展一直是被大家所关注的方案,然而经常有人会在用了之后说效果并不好,使用RAG后废话或者幻觉更多了,搜索召回的内容并不能很好地指导大模型生成更好的效果。但从后续的讨论和分析会发现,其实并不是RAG这条技术路线的问题,而是打开方式出现了错误。今天,我从效果调优的角度,和大家讲一下RAG的一些调优的经验,方便大家更快更准地找到问题并解决问题。
- 核心思路
- 复述方法论
- RAG问题的分析思路
- 可优化的trick
- 文档处理和切片
- 搜索
- 大模型
- 后记
核心思路
复述方法论
在开始之前,仍然重述一下效果调优的核心思路。我在很多文章里其实都有零散地提到,此处我再重新梳理一下。
首先是明确整个结论的合理性,光“效果不好”四个字的结论,虽说结论简单为好,但作为调优的人,专门解决这个问题的人,是需要深入探索分析这个问题内部的细节的:
- 了解指标的具体含义,明确这个指标的合理性和科学性,说白了就是要思考这个指标是否合理。
- 明确指标计算的数据集,是否可靠、正确以及合理,例如内部的抽样规则,数量和质量是否有保证。再次强调,一两个臆想出来的case的结果不符合预期,就认为是“效果不好”,这是非常不合适的,但其实现实中类似的判断并不少见,大家一定要避免。
- 在明确这些问题后,我们才能够比较初步地把握目前整个算法方案的具体效果是什么样的。
然后是,以测试集的bad case分析为引子,逐步深入分析内部的原因,找到关键问题,这点,我在系列文章里有提到,这篇是合集:心法利器[37-40,115] | bad case治疗术:合集。此处不再赘述,唯一需要强调的是,至少在我的经验里,bad case分析是整个效果调优里非常重要的一环,他是我们真正找到问题的必经之路,尽管过程可能很枯燥,但最终的效率收益还是很高的,这套方案抛开了我们对问题的臆想,借助数据暴露的问题,能更精准地定位到问题,方便对症下药。
最后是方案的设计和事实。有了足够可靠、精准的问题分析,我们再设计方案,就更有针对性,兵来将挡水来土掩,具体有哪些可能的解决方案,可以看我下面RAG的一些调优经验。
RAG问题的分析思路
RAG和一般的算法不同,他是一个由多个模块组合而成的系统方案,离线的数据入库,在线的知识搜索和大模型结果生成,每一个模块都可能会出现问题,里面只要有一个模块出现问题,往往就会导致最终出现错误,因此,RAG问题一般的分析思路如下:
- 最终目标指标的设计与数据集的选择。
- 针对bad case,分析全流程的计算结果,确认该从case开始出错的位置,例如路由、召回、prompt构造、大模型、cot结果、反思等等,出错的次数多的,那就是问题的关键节点。
- 针对出问题的部分,再来确定这个位置出现该问题的原因。例如路由部分的错误,大部分情况就是分类模型的错误,类目边界设计是否合理,知识是否有重合,模型本身的能力是否充足,如果是用大模型做的,那prompt是否有描述清楚等,如果是召回部分,则要考虑知识切片是否合理,向量召回的话两者的语义相关性是否足够等。
- 足量分析,路径越长最好分析的数据量要越多,有些看不出问题的case,在数量的积累下会逐步有感觉,能感知到某些问题的聚集性,便能总结出某类型占所有问题的占比,占比高了就是重要问题,一旦解决便能带来可控可预知的收益。
- 针对问题提出解决方案,实施和实验。
- 回溯问题的解决情况,例如某个问题在bad case里的出现比例20%降低到10%,整体准确率是80%,那很可能整体准确率就能提升到82%左右了,带来2个点的收益,那就是明确收益了。
如此一来,一套可控、稳定的调优思路就出来了,大家可以参考这套思路,再迁移到自己的场景下实践。
可优化的trick
下面就是具体的优化方案,值得注意的是,下面的各种方法,最好都基于具体的问题定位进行针对性的选择,如果问题不出在此处,那用起来大概率是没用的。
文档处理和切片
之前我在qanything的源码解读文章里分享了各种文档处理的基本工具和原理(前沿重器[46] RAG开源项目Qanything源码阅读2-离线文件处理),然而这里是最基础的工作,但是如何切片、如何解析的细节,还没讲很多,我稍微展开讲一些可以考虑的trick。
文档处理大部分问题在切片,切片这个事并不是弄个移动窗口按着切就好了,对于不同类型的文章,尤其是不同知识密度的文章,切片粒度是不同的,在这篇文章里给出了很多切片的技巧:https://mp.weixin.qq.com/s/iqOqY3aHXEfiMELef6sNwQ,这里有非常多,我结合这篇文章和自己的经验讲一下几个重点:
- 长度上,常见的经验是专业性文章,建议用更短的分片来向量化,注意尽可能留住句子内的专业名词。综述新闻类,可以长一些,保留完整信息。
- 结合用户的输入习惯,query对长短都可能有用,可以考虑多粒度都切,然后都召回各自处理。
- small2big要做,短句做向量索引,召回后用对应位置的上下文来进大模型prompt。
- 可以额外加入一些分片的信息,例如所在章节、位置、连续信息的拼接、文章章节标题等。如果是因为切片内不包含这些信息导致无法召回,加入后应该就能召回了。
有关表格问题可能会有人来问,在一些场景可能会遇到,我自己做的会比较少,据我了解身边的经验更多是转化为xml或者markdown的格式,然后递归解析,这块因为我自己做得少所以就不赘述了。
搜索
搜索的事,顺带再把这个系列带上:前沿重器[48-54] 合集:四万字聊搜索系统,搜索的世界非常庞大,要想做好真要多学多思考,往扎心的说,别一天到晚抱着那个向量召回抱怨“效果不好”,真的要拓宽眼界。这个系列大家可以详细展开看看,我这里不赘述,我挑选一些比较重要的部分强调一下。
- 知识库的领域差异较大的话,还是非常建议通过路由/意图识别的方式来分流分别处理,避免出现领域不同这种差距很大的情况,尤其是垂直领域。有一些比较极端的场景,甚至有人直接用分类模型把高频的几个问答内容给覆盖了,不得说效果很好。
- 召回的方式可以很丰富,早期预期去调优向量,不如考虑字面召回,用BM25、关键词匹配的方式,召回率尽管低,但是准确率还是很高的,在线高频的case能快速解决,收益会非常大。
- 不对称相似度问题,除了去折磨向量模型(类似bge-m3之类的模型确实可以拷打拷打),还可以考虑挖掘一些高频问题来进行补足修正,或者借助大模型进行问答对挖掘,QQ匹配远比QA匹配容易见效。
- query改写是有用的,比较粗暴地,之前写过的这篇文章,再次拿出来:前沿重器[38] | 微软新文query2doc:用大模型做query检索拓展,收益真的很大。
- 如果内部的切片个数非常多(例如达到10w以上),可以考虑在后面增加rerank模块,对TOP内容进行重新调整,少数据量可能对这个模块的敏感度不高,但是数量多了,语义空间密集了,TOPN召回的内容区分度不够高,通过精排模块能从中优中选优。
有关向量的模块单独说,调优的方案可以考虑这些:
- bge-m3之类的后起之秀,是支持prompt的,通过提示引导模型给出不同的向量(多去看看论文以及开源代码),在其推理的开源项目里,是能找到一些prompt的,大胆使用。
- Q也好A也罢,句子太长肯定不利于匹配,长句的信息量过多,匹配起来真的容易稀释(心法利器[51] | 长短句语义相似问题探索),切片能短还是尽量短。
- 直接开源模型针对的是开放域,对于比较垂直的领域,确实是效果不是很好,此时,准备一些可供微调的数据,进一步微调是会有一定收益的,但也要把控好过拟合的风险。
- 向量召回的匹配重点有不稳定性,不知道模型认为的重点和你认为的重点是否一致,有一个比较快速的trick是,对query做关键词抽取,过滤或者降权答案内不带有特定关键词的召回结果,能提升准确率。
- 卡阈值,卡阈值,卡阈值,向量召回或者向量索引,只管给TOPN,如果文档中不存在有关内容,那就没必要放到大模型内了,应该被过滤,此时就需要卡阈值,并做好无答案时下游应该有的回应。
大模型
大模型的部分,我们其实要关心的并不是很多,在绝大多数情况,大模型能结合我们给的检索结果,就能给出合适的回答,但在一些情况,可能并不能,有一定概率是如下原因或解决方案。
- 模型自己的知识根深蒂固,不够信任我们的知识,可以加上时间、引用材料、作者之类的信息,配合CoT等方式,进行进一步的强化其忠诚度和准确度。
- 微调的收益一般不是很大,很多时候在解码方案里进行加权,或者使用回溯之类的方式可以优化,至少sft是,反而会降低对资料的信任度或削弱推理能力,至于RL,还有待验证。
- 回复的可靠性和大模型本身的能力也有很强的关系,越强的、越大的模型忠诚度还是会提升的。
- 给大模型准备好垃圾桶或者兜底方案,在所给资料中无信息时,设计好兜底方案,例如给出“参考资料中未发现符合要求的回复”,甚至做后处理验证,都是可以的,知识库终究是有限的,所以我们很难避免去做这种兜底方案。
后记
写这篇文章的核心目的是希望能给大家更多调优方面的trick建议,方便大家能有更多拿得出手的招数,也让大家能进一步理解到RAG整个生态体系下的一些常见的模块和方法,最近所谓的deep search概念出来很多人又开始焦虑,不过其实仔细研究发现,不过是新瓶装旧酒,内部很多技术仍旧类似,即使Deepseek的新模型出来,目前RAG所面临的一些问题仍旧存在,知识的更新与筛选在目前版本下,RAG仍旧是一个非常不错的路径,所以持续学习和研究仍旧是有意义的。