当前位置: 首页 > article >正文

变相提高大模型上下文长度-RAG文档压缩-2.带早停机制的map-refine

我试过用map-refine方法来精炼上下文,由于它是线性的,运行时间随着文档数量线性增长。所以可以考虑通过判断上下文是否可以满足QA来提前结束过程。

import os
import json
from langchain_core.documents import Document

data = []
file_path = './data/data_>=10.json'
with open(file_path) as f:
    for line in f:
        a_record = json.loads(line)
        data.append(a_record)

print(len(data))

data_indice = 1
a_query = data[data_indice]['query']
a_docs = data[data_indice]['pos']
a_docs = [Document(item) for item in a_docs]
50

Map-Refine 附加早停机制

Map 阶段

import asyncio
from pydantic import BaseModel, Field
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import PydanticOutputParser
from langchain_core.prompts import PromptTemplate, ChatPromptTemplate
from langchain.output_parsers import OutputFixingParser


# ===== map =====

class MapSummary(BaseModel):
    reasoning: str = Field(description="关于问题和本内容之间关联性的思考")
    summary: str = Field(description="对文本中与问题相关片段的提取,直接输出为str")

map_parser = PydanticOutputParser(pydantic_object=MapSummary)

map_prompt = ChatPromptTemplate.from_messages(
    [
        # role, message
        ("system", "你是一名专业的内容提取和总结专家。"),
        ("human", (
					"请清晰简明地总结以下文本以回答问题。\n\n"  
					"在总结时,请注意以下几点:\n" 
                    "- 你的任务是总结问题相关的文本,而不是回答问题。" 
					"- 包含关键事件、重要事实和核心信息。\n"  
					"- 省略不必要的细节。\n\n"  
					"按以下格式要求输出:\n{format_instructions}\n\n"
					"[问题-开始]:\n{query}\n[问题-结束]\n\n"
					"[需要总结的文本-开始]:\n{context}\n[需要总结的文本-结束]\n" 
				)
         ),
    ]
)

map_prompt = map_prompt.partial(format_instructions=map_parser.get_format_instructions())

llm = ChatOpenAI(
	base_url='http://localhost:5551/v1',
	api_key='EMPTY',
	model_name='Qwen2.5-7B-Instruct',
	temperature=0.5,
)

map_chain = map_prompt | llm | map_parser
tasks = [
	map_chain.ainvoke(
		{
            "query":a_query,
        	"context":doc.page_content,
		}
	)
	for doc in a_docs
]

map_results = await asyncio.gather(*tasks)
map_results
[MapSummary(reasoning='文本主要介绍了90版本阿修罗武器的排行,提到了四把武器的特点和排名依据。', summary='荒古排名第一,理由是其技能攻击力和魔能提升效果;妖刀村正排名第二,因其无视和额外黄字属性;暗影蔽日排名第三,虽然所有攻击力亮眼但需注意堆属性的搭配;圣剑排名第四,适合当前版本的天域套装备。'),
 MapSummary(reasoning='文本主要讨论了90版本阿修罗的武器排行,提到了支点、别云和天丛云这三把武器的相关信息。', summary='支点、别云和天丛云是90版本阿修罗的优秀武器,支点适合光强修罗,别云有高黄字但存在黄字冲突问题,天丛云则有27白字且适合一觉cd换装。'),
 MapSummary(reasoning='文本主要描述了90版本阿修罗武器的排行情况,但并未直接提及名刀32和90版本的具体排行情况,因此需要进一步筛选相关信息。', summary='名刀32和七支刀在描述中被提及,但具体排名信息未给出。'),
 MapSummary(reasoning='文本主要讨论了90版本阿修罗武器的排行,提到了三把武器的特点和优势,与问题相关性较强,可以直接提取关键信息作为总结。', summary='90版本阿修罗武器排行:1.荒古太(未升级和升级后的技能攻击力及获取方式);2.妖刀村正(90版本新武器,无视和额外黄字优势);3.暗影蔽日(所有攻击力高,搭配需注意)。'),
 MapSummary(reasoning='文本主要讨论了90版本阿修罗的主流武器测试排名,特别是针对吞噬魔和破锁血马蹄卡的测试结果。', summary='90版本阿修罗主流武器测试排名:吞噬魔-支点>开魔能荒古>妖刀传奇;破锁血马蹄卡-妖刀不适合作为破锁血武器。'),
 MapSummary(reasoning='文本主要讨论了90版本阿修罗武器在20人本的表现,提到了妖刀、开魔能荒古、圣剑等武器的排名情况,以及影响排名的因素。', summary='20人本妖刀>开魔能荒古>圣剑=支点=避日,圣剑攻击力受自身属强影响,荒古属性攻击选最高值。'),
 MapSummary(reasoning='文本内容与90版本阿修罗武器排行无关,为避免误导,应排除。', summary=''),
 MapSummary(reasoning='文本主要讨论了90版本DNF游戏中阿修罗武器的排行,特别是前10名的排名情况,与问题相关度高。', summary='90版本DNF修罗武器排行榜:10.无影剑,荒古太刀排名第一。'),
 MapSummary(reasoning='文本主要介绍了90版本阿修罗武器的排行及特点,与问题相关性较强,但未直接提到排行结果。', summary='文本介绍了90版本阿修罗武器的排行及特点,如七支刀、名刀、天丛云等,但未直接给出具体排行结果。'),
 MapSummary(reasoning='文本主要介绍了90版本阿修罗武器的排行,提到了别云、支点和圣剑这三种武器的特点和适用情况。问题询问90版本阿修罗武器排行,因此这些信息与问题直接相关。', summary='别云武器适合搭配50黄字装备,支点适合幽魂套和光强修罗,圣剑100属强适合全属强套装,但释放速度慢影响手感。'),
 MapSummary(reasoning='文本主要讨论了90版本阿修罗武器的排行,提到了暗影蔽日和妖刀村正的优缺点。', summary='90版本阿修罗武器排行,暗影蔽日和妖刀村正表现突出,分别适用于幽魂流光和未升级的荒古。')]

Refine 阶段

一开始的早停只有两个选项:内容不完整(继续)和内容完整(早停)。但有问题,例如枚举类问题,你可以拿部分文档来回答问题,也可以那更多文档来提高QA效果,所以增加第三选项,可以继续完善。这个选项和内容不完整没有什么根本的不同,都是某种意义上的内容不完整。

class RefineSummary(BaseModel):
    query_context_reasoning: str = Field(description="关于问题、先前内容总结、新内容之间联系的思考")
    refined_summary: str = Field(description="整合局部内容总结的全局总结")
    summary_sufficiency_reasoning: str = Field(description="关于当前总结是否足够回答问题(是否提供了所有必要的细节)的思考,此外也需要判断是否可以再扩充新文本以获得更好的回答效果")
    summary_sufficiency_score: int = Field(description="用100分制表示利用当前总结回答问题的效果预期分数")
    next_action: str = Field(description="决定下一个动作,从以下选项中选一个:内容不完整, 内容完整, 内容可继续完善")

refine_parser = PydanticOutputParser(pydantic_object=RefineSummary)

refine_prompt = ChatPromptTemplate.from_messages(
    [
        # role, message
        ("system", "你是一名专业的摘要专家。你的任务是生成一个最终的内容总结。"),
        ("human", (
                    "我提供你一份当前的总结,和一份新文本,你需要结合两者,精炼出一份新的总结,以作为参考材料回答问题。\n\n"
					"在总结时,请注意以下几点:\n" 
                    "- 你的任务是总结问题相关的文本,而不是回答问题。" 
					"- 包含关键事件、重要事实和核心信息。\n"  
					"- 省略不必要的细节。\n"  
					"- 去除重复冗余内容,使语言更加简洁和凝练。\n\n"
					"按以下格式要求输出:\n{format_instructions}\n\n"
					"[问题-开始]:\n{query}\n[问题-结束]\n\n"
                    "[当前内容总结-开始]:\n{previous_summary}\n[当前内容总结-结束]\n\n"
					"[新文本-开始]:\n{current_summary}\n[新文本-结束]\n"  
				)
         ),
    ]
)

refine_prompt = refine_prompt.partial(format_instructions=refine_parser.get_format_instructions())

llm = ChatOpenAI(
	base_url='http://localhost:5551/v1',
	api_key='EMPTY',
	model_name='Qwen2.5-7B-Instruct',
	temperature=0.2,
)

refine_chain = refine_prompt | llm | refine_parser
refine_prompt.pretty_print()
================================[1m System Message [0m================================

你是一名专业的摘要专家。你的任务是生成一个最终的内容总结。

================================[1m Human Message [0m=================================

我提供你一份当前的总结,和一份新文本,你需要结合两者,精炼出一份新的总结,以作为参考材料回答问题。

在总结时,请注意以下几点:
- 你的任务是总结问题相关的文本,而不是回答问题。- 包含关键事件、重要事实和核心信息。
- 省略不必要的细节。
- 去除重复冗余内容,使语言更加简洁和凝练。

按以下格式要求输出:
[33;1m[1;3m{format_instructions}[0m

[问题-开始]:
[33;1m[1;3m{query}[0m
[问题-结束]

[当前内容总结-开始]:
[33;1m[1;3m{previous_summary}[0m
[当前内容总结-结束]

[新文本-开始]:
[33;1m[1;3m{current_summary}[0m
[新文本-结束]
refine_result_saves = []

for indice, item in enumerate(map_results):
		
	if indice == 0:
		previous_summary = item.summary
	else:
		refine_result = refine_chain.invoke(
			{
				"query":a_query,
				"previous_summary":previous_summary,
				"current_summary":item.summary,
			}
		)
		refine_result_saves.append(refine_result)
		previous_summary = refine_result.refined_summary
		print(refine_result)
	print('='*20)
	
====================
query_context_reasoning='新文本提供了90版本阿修罗的另外三种优秀武器,分别是支点、别云和天丛云,补充了当前总结中未提及的武器信息。' refined_summary='90版本阿修罗的优秀武器包括荒古(排名第一)、妖刀村正(排名第二)、暗影蔽日(排名第三)、圣剑(排名第四)、支点、别云和天丛云。其中,支点适合光强修罗,别云有高黄字但存在黄字冲突问题,天丛云则有27白字且适合一觉cd换装。' summary_sufficiency_reasoning='当前总结已经涵盖了90版本阿修罗的大部分优秀武器,但新文本提供了更多细节,特别是支点、别云和天丛云的具体适用情况,这些信息对于回答问题是有帮助的。' summary_sufficiency_score=85 next_action='内容可继续完善'
====================
query_context_reasoning='新文本补充了90版本阿修罗的优秀武器中未提及的名刀32和七支刀,但未给出具体排名。当前总结中已经包含了其他排名较高的武器,因此需要更新总结以包含新文本中的信息。' refined_summary='90版本阿修罗的优秀武器包括荒古(排名第一)、妖刀村正(排名第二)、暗影蔽日(排名第三)、圣剑(排名第四)、支点、别云、天丛云、名刀32和七支刀。其中,支点适合光强修罗,别云有高黄字但存在黄字冲突问题,天丛云则有27白字且适合一觉cd换装。' summary_sufficiency_reasoning='当前总结已经包含了大部分排名较高的90版本阿修罗武器,但未提及名刀32和七支刀的具体排名。新文本提供了这两款武器的信息,因此需要更新总结。' summary_sufficiency_score=85 next_action='内容可继续完善'
====================
query_context_reasoning='新文本提供了荒古太的具体信息和妖刀村正的详细描述,补充了当前总结中未提及的内容。' refined_summary='90版本阿修罗的优秀武器排名为:1. 荒古太(未升级和升级后的技能攻击力及获取方式);2. 妖刀村正(90版本新武器,无视和额外黄字优势);3. 暗影蔽日(所有攻击力高,搭配需注意)。支点适合光强修罗,别云有高黄字但存在黄字冲突问题,天丛云则有27白字且适合一觉cd换装。' summary_sufficiency_reasoning='当前总结已经涵盖了90版本阿修罗的主要武器排行,但新文本提供了更详细的武器信息,特别是荒古太和妖刀村正的具体描述,可以进一步丰富总结内容。' summary_sufficiency_score=85 next_action='内容可继续完善'
====================
query_context_reasoning='新文本提供了90版本阿修罗武器的主流测试排名,补充了当前总结中未提及的武器排名信息。' refined_summary='90版本阿修罗的优秀武器排名为:1. 吞噬魔-支点;2. 开魔能荒古;3. 妖刀村正;4. 暗影蔽日;5. 天丛云。支点适合光强修罗,别云有高黄字但存在黄字冲突问题,妖刀村正适合破锁血武器。' summary_sufficiency_reasoning='当前总结包含了90版本阿修罗的主要武器排名和部分武器的详细信息,但未提及妖刀村正适合破锁血武器的信息,需要补充。' summary_sufficiency_score=85 next_action='内容可继续完善'
====================
query_context_reasoning='新文本提供了20人本环境下妖刀村正的排名和属性攻击规则,需要结合当前内容总结进行整合。' refined_summary='90版本阿修罗的优秀武器排名为:1. 吞噬魔-支点;2. 开魔能荒古;3. 妖刀村正;4. 暗影蔽日;5. 天丛云。支点适合光强修罗,别云有高黄字但存在黄字冲突问题,妖刀村正适合破锁血武器。20人本环境下,妖刀村正>开魔能荒古>圣剑=支点=避日,圣剑攻击力受自身属强影响,荒古属性攻击选最高值。' summary_sufficiency_reasoning='当前总结已经涵盖了90版本阿修罗的优秀武器排名和适用情况,但未完全包含20人本环境下的具体排名和属性规则,需要进一步完善。' summary_sufficiency_score=85 next_action='内容可继续完善'
====================
query_context_reasoning='新文本为空,无需补充。当前总结已经涵盖了90版本阿修罗武器的排名和适用情况。' refined_summary='90版本阿修罗的优秀武器排名为:1. 吞噬魔-支点;2. 开魔能荒古;3. 妖刀村正;4. 暗影蔽日;5. 天丛云。支点适合光强修罗,妖刀村正适合破锁血武器。20人本环境下,妖刀村正>开魔能荒古>圣剑=支点=避日,圣剑攻击力受自身属强影响,荒古属性攻击选最高值。' summary_sufficiency_reasoning='当前总结已经涵盖了90版本阿修罗武器的排名和适用情况,信息较为全面。' summary_sufficiency_score=95 next_action='内容完整'
====================
query_context_reasoning='新文本提供了90版本DNF修罗武器排行榜的最新信息,但与当前内容总结中的具体排名和详细分析有所差异,需要结合两者进行整合。' refined_summary='90版本阿修罗的优秀武器排名为:1. 吞噬魔-支点;2. 开魔能荒古;3. 无影剑;4. 妖刀村正;5. 暗影蔽日;6. 天丛云。支点适合光强修罗,妖刀村正适合破锁血武器。20人本环境下,妖刀村正>开魔能荒古>圣剑=支点=避日,圣剑攻击力受自身属强影响,荒古属性攻击选最高值。' summary_sufficiency_reasoning='当前总结提供了详细的武器排名和适用情况,但未提及无影剑的具体排名,需要补充。' summary_sufficiency_score=85 next_action='内容可继续完善'
====================
query_context_reasoning='新文本补充了90版本阿修罗武器排行的相关信息,但未直接给出具体排行结果。当前内容总结已经包含了详细的排行结果,因此需要结合新文本进一步完善。' refined_summary='90版本阿修罗的优秀武器排名为:1. 吞噬魔-支点;2. 开魔能荒古;3. 无影剑;4. 妖刀村正;5. 暗影蔽日;6. 天丛云。支点适合光强修罗,妖刀村正适合破锁血武器。20人本环境下,妖刀村正>开魔能荒古>圣剑=支点=避日,圣剑攻击力受自身属强影响,荒古属性攻击选最高值。' summary_sufficiency_reasoning='当前总结已经包含了详细的排行结果和武器特点,但新文本提供了更多武器的信息,可以进一步完善总结。' summary_sufficiency_score=85 next_action='内容可继续完善'
====================
query_context_reasoning='新文本提供了关于别云武器和支点的额外信息,补充了当前内容总结中未提及的装备搭配和属性影响。' refined_summary='90版本阿修罗的优秀武器排名为:1. 吞噬魔-支点;2. 开魔能荒古;3. 无影剑;4. 妖刀村正;5. 暗影蔽日;6. 天丛云。支点适合光强修罗,妖刀村正适合破锁血武器。20人本环境下,妖刀村正>开魔能荒古>圣剑=支点=避日,圣剑攻击力受自身属强影响,荒古属性攻击选最高值。别云武器适合搭配50黄字装备,支点适合幽魂套和光强修罗,圣剑100属强适合全属强套装,但释放速度慢影响手感。' summary_sufficiency_reasoning='当前总结已经涵盖了主要的武器排名和属性,但补充了关于别云武器和支点的额外信息,使得总结更加全面。' summary_sufficiency_score=95 next_action='内容完整'
====================
query_context_reasoning='新文本补充了90版本阿修罗武器排行中的两个重要武器,暗影蔽日和妖刀村正,并指出了它们的适用流派。' refined_summary='90版本阿修罗的优秀武器排名为:1. 吞噬魔-支点;2. 开魔能荒古;3. 无影剑;4. 妖刀村正;5. 暗影蔽日;6. 天丛云。支点适合光强修罗,妖刀村正适合破锁血武器。20人本环境下,妖刀村正>开魔能荒古>圣剑=支点=避日。暗影蔽日适用于幽魂流光。' summary_sufficiency_reasoning='当前总结涵盖了90版本阿修罗的主要武器排名及其适用性,但未提及所有武器的详细对比,可以进一步完善。' summary_sufficiency_score=85 next_action='内容可继续完善'
====================
score_threshold = 95
refine_result_saves = []

for indice, item in enumerate(map_results):
		
	if indice == 0:
		previous_summary = item.summary
	else:
		refine_result = refine_chain.invoke(
			{
				"query":a_query,
				"previous_summary":previous_summary,
				"current_summary":item.summary,
			}
		)
		refine_result_saves.append(refine_result)
		previous_summary = refine_result.refined_summary
		
		# 根据分数早停
		if refine_result.summary_sufficiency_score > score_threshold:
			break
		# 根据大模型的判断早停
		if refine_result.next_action == '内容完整':
			break

		print(refine_result)
	print('='*20)
	

http://www.kler.cn/a/547252.html

相关文章:

  • CAS单点登录(第7版)9.属性
  • CAS比较并交换
  • 《Python全栈开发:构建高并发物联网数据中台实战》
  • 使用 playwright 自定义 js 下载的路径和文件名
  • 智能编程助手功能革新与价值重塑之:GitHub Copilot
  • Word正文中每两个字符之间插入一个英文半角空格
  • Myplater项目
  • 【Linux】详谈 进程控制
  • Python 爬虫中的异常处理
  • 探索Hugging Face:开源AI社区的核心工具与应用实践
  • NVIDIA 开发者社区第十一届Sky Hackathon训练营实验手册---AWS Sagemaker AI部分
  • 【无线感知会议系列-22 】Vivisecting Mobility Management in 5G Cellular Networks
  • 使用Java爬虫获取1688商品评论:实战案例指南
  • 基于STM32的智能家居安防系统
  • 蓝桥杯备考:贪心算法之纪念品分组
  • 网络安全初级实战笔记(一):owasp zap 暴力破解
  • 深入理解Linux网络随笔(一):内核是如何接收网络包的(下篇)
  • 25动科畜牧研究生复试面试问题汇总 动科畜牧专业知识问题很全! 动科畜牧复试全流程攻略 动科畜牧考研复试真题汇总
  • 【愚公系列】《Python网络爬虫从入门到精通》009-使用match()进行匹配
  • 一键高清修复、智能剪辑,媒体处理还能多智能?