AI知识库

53AI知识库

学习大模型的前沿技术与行业应用场景


LLM-RAG-QA: 训练一个过滤模型
发布日期:2024-04-07 21:06:37 浏览次数: 1888


在<LLM+RAG框架下:如何过滤掉不相关的检索信息>中介绍一种构建过滤模型对检索的内容进行筛选的方法<Learning to Filter Context for Retrieval-Augmented Generation>。本次是对该方法进行下实践,下面展开说下。

1、构建检索数据集

使用PKUMOD-CCKS(QA)数据集,利用bing搜索引擎,采集了4000条query召回的文档集合数据;

PKUMOD-CCKS数据样例


数据采集的样例,其中abstract和text字段用于检索用

2、构建过滤模型训练数据集

在论文中提出三种方法来构建过滤模型(M_ctx)的监督数据,分别为StrInc,CXMI,Lexical。本次采用的是Lexical方法,因为发现用StrInc方法命中的数据条数太少,CXMI需要用大模型来预测判断,过于麻烦。此外,在实验中,发现直接用答案o进行分词检索,比原文使用e=q+o放在一起进行分词检索效果好,可能这跟本次选择的数据集有关系(PKUMOD-CCKS中答案都比较简洁,大多数类似实体词,导致答案与query在词层面很多没有关联,增加query反而加大了噪声引入)。

主要步骤包括:

1)对采集的text,abstract字段进行清洗;

2)对text+abstract内容进行切片,切片(seg)最大长度为128;

3)利用jieba对answer进行关键词抽取,判断answer关键词在seg占比,作为排序分数;

4)对每个seg按分数降序排序,取第一条seg为要筛选出的检索数据,其他作为检索内容;

此外, 片段seg长度小于32不考虑, 对于第一条seg的分数低于0.6数据不考虑,组成的检索内容最大长度不超过1212。

处理主要代码如下:

def extract_keywords(a):
"""利用jieba进行关键词识别,并过滤掉标点符号"""
keywords = set()
pun_list=['。',',','.',',','?','!','《','》','<','>','_','-','“','”','"','\t','\n','(',')']
for w in jieba.cut(a,HMM=True):
if w in pun_list:
continue
keywords.add(w)
return list(keywords)

def judge_p1(seg,keywords):
"""判断答案中的关键词在检索片段出现的比例,作为排序分数"""
score = 0
for kw in keywords:
if kw in seg:
score +=1
return score / len(keywords)


max_seq = 128 #检索片段的最大长度
maxlen = 1212 #所有检索片段的最大长度
data = []
with open(r'E:\mygithub\LLM-RAG-QA\data\pkumod-ccks_query_list_crawl2.json','r', encoding='utf-8') as f:
for line in f.readlines():
line = json.loads(line)
q = line['query']
a = line['answer']
keywords = extract_keywords(a)
seg_list = {}
for item in line['crawl']:
abstract =item['abstract']
text = item['text']
abstract = clean_abstract(abstract)
text = clean_text(text)
content = abstract + '\n' + text
for seg in text_segmentate(content,max_seq,seps='\n'):
if len(seg)>32:
seg = re.sub('\n','',seg)
seg = seg.strip('。|,|;')
score = judge_p1(seg,keywords)
seg_list[seg] = score
if len(seg_list)<=1:
continue

seg_list = sorted(seg_list.items(),key=lambda x:x[1],reverse=True)
if seg_list[0][1]<0.6:
continue

r_list = [s[0] for s in seg_list]
r_list = truncation_text(r_list,maxlen)
random.shuffle(r_list)
tmp = {}
tmp['query'] = q
tmp['answer'] = a
tmp['select_segment'] = seg_list[0][0]
tmp['recall_segment'] = r_list
data.append(tmp)

片段排序样例如下:

3、过滤模型训练

按照上述方法构建2031条数据,按10%比例切分成一个训练集和测试集,用于过滤模型 M_ctx训练;此外,另外论文也提及在检索出内容下,同上训练下生成模型M_gen。这样对应两个指令任务,其数据格式如下:

过滤模型的指令数据

生成模型的指令数据

两个指令在baichuan2-7b-chat模型上采用lora方式进行微调3轮,在测试集上结果如下:

任务1:M_ctx准确率为35%;

任务2:M_gen测评结果为:{'rouge-1': 68.05, 'rouge-2': 57.08, 'rouge-l': 64.43, 'bleu-4': 47.83}

baichuan2测评结果为:{'rouge-1': 65.75, 'rouge-2': 53.88, 'rouge-l': 62.24, 'bleu-4': 44.09}

测评预测样例

4、结论与分析

1)过滤模型M_ctx在测试集上表现并不好,预测准确率35%;其中原因有可能有:1)在检索排序中支撑答案的片段并不唯一,可能存在多个片段都能回答query,而这版只选择分数最高的片段作为结果,是有点偏颇,可以尝试用多标签预测的方式;2)我们人为选择的最佳片段与LLM选择的片段标准不一致,即存在对齐的偏好差距。

2)在LLM+RAG方式下,对比纯LLM,提升的效果虽有2个点左右,但并不明显,因为很多学术paper上提升的效果都是近10%的,这说明本次实验还是做的不够完美;

3)实验中显示,既然召回到正确的片段,有时大模型还是回答错,说明其对利用检索的内容不够好,其原因可能是将检索内容放在prompt这种形式固有的缺陷。


5、实践样例

query:有什么和"凿壁偷光"意思相近的词语?

#LLM response:"凿壁偷光"形容勤奋好学,意思相近的词语有:
1. 破窗而读
2. 破窗而读
3. 破窗而读
4. 穿墙透壁
5. 穿墙透壁


#LLM+RAG+关键词召回
--------------bg_text--------
[ záo bì tōu guāng ] 形容勤学苦读。也作“穿壁引光”。
这是一个相似词在线查询工具,为用户提供相似词查询服务,返回的结果包含了近义词、反义词和同义词。
该工具常用于写作辅助(关 键词联想)和论文降重(同义词替换)。本网站收录了最新版的新华字典,
以及通过全网数据挖掘出海量的中文词条,并对数据进行持续更新,保证查询的效果与时俱进。什么 是相似词?
1. 近义词指意思相近,但不完全相同的词,比如:“开心”和“高兴”、“谦虚”和“谦逊”、“满意”和“欣慰”。
--------------bg_text--------
response:凿壁偷光


#LLM+RAG+Mctx
--------------bg_text--------
,在墙上凿开一个小孔;偷借邻家的灯光读书。形容在艰苦的条件下仍坚持刻苦学习。出自:晋 葛洪《西京杂记》第二卷:
“匡衡字稚 圭,勤学而无烛,邻舍有烛而不逮,衡乃穿壁引其光,以书映光而读之。”近义词有:囊虫映雪、穿壁引光、废寝忘食,
反义词有:不学无术,凿壁偷光是中性成语,连动式成语;可作谓语、定语、状语;含褒义。。
--------------bg_text--------
Response:"囊萤映雪"



#Answer <悬梁刺股> <囊萤映雪>


可以看出来:

1)直接用LLM回答,出现重复生成问题;

2)对比LLM+RAG+关键词与LLM+RAG+M_cxt,后者召回的片段质量更高些;

3)且大模型还具有修正功能:将召回的“囊虫映雪”输出为“囊萤映雪”;

4)但是,召回的片段包含了3个答案(囊虫映雪、穿壁引光、废寝忘食),而模型就输出就一个,难道大模型还是没有真正理解召回内容和query之间的含义,这点还需要进一步分析。




53AI,企业落地应用大模型首选服务商

产品:大模型应用平台+智能体定制开发+落地咨询服务

承诺:先做场景POC验证,看到效果再签署服务协议。零风险落地应用大模型,已交付160+中大型企业

联系我们

售前咨询
186 6662 7370
预约演示
185 8882 0121

微信扫码

与创始人交个朋友

回到顶部

 
扫码咨询