变相提高大模型上下文长度-RAG文档压缩-3.优化map-reduce(reranker过滤+社区聚类)

news2025/2/20 22:45:28

我遇到的业务问题实际上是RAG需要处理很多同一对象的日常报告,不像常识类问题,它的相关Document更多而且更分散,日常报告代表数据库里有很多它的内容,而且对象可能只在段落中的几句话提及到。top-k数量受限于大模型长度,目前是top-10/15,明显一个月的情况都没法正常枚举,而且上下文中也有很多无关内容,既会干扰大模型又会占着token,所以必需对上下文进行过滤,到这一步后再压缩下文本。

流程图

我的方法主要灵感来自于map-reduce总结方法,主要由于它可以并行处理的优点,利用小模型做简单任务。

  • Inner-chunk 过滤

    • 将块拆分为更小的单元,通过语义分块,
    • 使用重排序器过滤掉不相关的部分,
    • 将剩余的句子合并为较小的块或片段。
  • Outer-chunk 重合成

    • 对片段执行社区检测,并将同一聚类中的片段在块长度限制内合并成新的块。社区检测的主要目的是将语义上相近或重复的内容保持在同一块中,以便我们能够很好地合并它们或去除冗余。
    • 合成上下文内容,确保保留相关和有用的信息,以便为后续的 QA 阶段提供合理的内容,同时防止丢失潜在有价值的上下文。
import os
import json
from langchain_core.documents import Document

data = []
file_path = './data/data_100.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 = 0
a_query = data[data_indice]['query']
a_docs = data[data_indice]['pos']
a_docs = [Document(item) for item in a_docs]
100
import asyncio
import nest_asyncio

# 应用 nest_asyncio 以支持 Jupyter 笔记本中的异步操作
nest_asyncio.apply()

Inner-chunk 过滤

原始代码

from meta_chunking import meta_chunking

_, sentences_doc = meta_chunking(a_docs[0].page_content, 'PPL Chunking', 'zh', 0.5, 256)
print(*sentences_doc, sep='\n====\n')
。据路透社6月17日报道,在华盛顿对中国在太平洋地区不断扩大的影响力感到担忧之际,路透社记者17日看到的一份声明显示,美国和马绍尔群岛同意努力在今年就美国对后者的经济援助达成协议。报道称,美国《自由联系协定》谈判特使尹汝尚本周前往马绍尔群岛,与这个具有战略意义的太平洋岛国的相关部门举行会谈。根据一份联合声明,双方希望在9月前签署一项谅解备忘录,“目的是在秋末或初冬之前完成《自由联系协定》谈判”。声明称,双方阐明了在2023年《自由联系协定》到期后美国继续向马绍尔群岛提供经济援助的重要性。
====
报道还说,长期以来,华盛顿与马绍尔群岛、帕劳和密克罗尼西亚联邦保持着特殊关系,这使得美军能够进入太平洋地区的广阔战略区域。但这三个太平洋岛国抱怨说,美方的援助没有跟上。尹汝尚还负责与密克罗尼西亚联邦和帕劳就延长《自由联系协定》进行谈判。
====
报道说,中国加强了与太平洋岛国的经济、军事和警务联系,并在商业和旅游方面向马绍尔群岛、帕劳和密克罗尼西亚联邦示好。前不久,中国与所罗门群岛签署安全协议,凸显了北京在该地区日益增强的影响力。此举引发了澳大利亚、新西兰和美国的关切。战略与国际问题研究中心的专家哈里森·普雷拉表示:“该地区国家更感兴趣的可能是轮流吸引中国和西方的投资,而不是作出加入北京阵营的承诺。”声明还说,尹汝尚和马绍尔群岛外长基特兰·卡布阿还讨论了美国在马绍尔群岛进行核试验的遗留问题。
====
在尹汝尚今年3月上任之前,这个问题一直是双方关系的症结所在。报道写道,1946年至1958年期间,美国在马绍尔群岛进行了67次核试验——其中包括1954年在比基尼环礁进行的“喝彩城堡”氢弹试验。这些核试验对健康和环境造成的影响迄今仍然令岛国居民感到困扰。另据路透社6月17日报道,在所罗门群岛与中国的安全协议引发地区关切之际,澳大利亚外长黄英贤周五造访所罗门群岛一个骚乱频发的社区,以强调澳大利亚警方的能力。黄英贤表示,在访问期间,她与所罗门群岛总理索加瓦雷举行了“建设性”会谈。
====
报道称,黄英贤的访问强调了澳大利亚对所罗门群岛的教育和医疗援助,以及在当地去年发生骚乱后澳大利亚警方为恢复稳定作出的努力。黄英贤对媒体称,索加瓦雷重申了他的公开保证,即根据与中方的协议,所罗门群岛不会有军事基地,也不会有持续的外国驻军。黄英贤周五说:“澳大利亚仍然认为,应该由太平洋大家庭来负责我们的安全问题。”黄英贤访问了所罗门群岛首都霍尼亚拉以东的伯恩斯克里克定居点,那里的房屋在去年11月的骚乱中被烧毁。澳大利亚、斐济和新西兰的警察以及当地年轻人参与了重建工作,在那里修建了一个诊所。
from langchain_community.cross_encoders import HuggingFaceCrossEncoder

# Initialize the model
reranker = HuggingFaceCrossEncoder(
	model_name="../../DataCollection/officials/bge-reranker-v2-m3",
	model_kwargs = {'device': 'cuda:6'}
	)

reranker.score([('今天是星期几?', '今天是星期二。')])
array([0.8927492], dtype=float32)
fragment_maxlen = 256
reranker_score_threshold = 0.1

_, doc_fragments = meta_chunking(a_docs[0].page_content, 'PPL Chunking', 'zh', 0.5, fragment_maxlen)

fragment_scores = reranker.score([(a_query, frag) for frag in doc_fragments])

filtered_fragments = [
	frag
	for frag, score in zip(doc_fragments, fragment_scores)
	if score > reranker_score_threshold
]

new_chunk = Document(''.join(filtered_fragments), metadata=a_docs[0].metadata)

print(f'过滤前文本长度: {len(a_docs[0].page_content)}')
print(f'过滤后文本长度: {len(new_chunk.page_content)}')
过滤前文本长度: 1077
过滤后文本长度: 485

至于为什么要组合回去:保持文档逻辑结构
原始文档被分割成多个chunk,每个chunk是根据文档内的逻辑顺序切分的。每个chunk内部的内容具有较强的上下文相关性,通常是围绕某个主题或段落展开。因此,组合回去可以最大限度地保留文档内部的逻辑顺序和连贯性。

封装为 Runnable

import asyncio
from typing import List, Dict
from langchain.schema import Document
from langchain.schema.runnable import Runnable
from langchain_community.cross_encoders import HuggingFaceCrossEncoder

class Fragment_Filter(Runnable):
	def __init__(self, reranker, fragment_maxlen=256, reranker_score_threshold=0.1):
		"""
		继承 Runnable,实现文档切片与筛选逻辑。

		:param model: 评分模型
		:param fragment_maxlen: 片段最大长度
		:param reranker_score_threshold: 重新排序得分阈值
		"""
		self.model = reranker
		self.fragment_maxlen = fragment_maxlen
		self.reranker_score_threshold = reranker_score_threshold

	async def process_document(self, a_query: str, a_doc: Document) -> Document:
		"""
		异步处理单个文档的 fragment,并根据得分筛选。

		:param a_query: 查询字符串
		:param a_doc: Document 对象
		:return: 处理后的 Document 对象
		"""
		# 文档切片
		_, doc_fragments = meta_chunking(
			a_doc.page_content, 'PPL Chunking', 'zh', 0.5, self.fragment_maxlen
		)

		# 计算 fragment 的得分
		fragment_scores = self.model.score([(a_query, frag) for frag in doc_fragments])

		# 过滤符合条件的 fragments
		filtered_fragments = [
			frag for frag, score in zip(doc_fragments, fragment_scores)
			if score > self.reranker_score_threshold
		]

		# 返回新的 Document
		return Document(''.join(filtered_fragments), metadata=a_doc.metadata)

	def invoke(self, inputs: Dict[str, any]) -> List[Document]:
		"""
		同步调用,并通过 asyncio.run() 调用异步任务。

		:param inputs: 包含 `query` 和 `documents` 的字典
		:return: 过滤后的 List[Document]
		"""
		a_query = inputs["query"]
		documents = inputs["documents"]

		# 使用 asyncio.run 执行异步的并行任务
		return asyncio.run(self.ainvoke(a_query, documents))

	async def ainvoke(self, a_query: str, documents: List[Document]) -> List[Document]:
		"""
		异步处理多个文档的 fragment,并根据得分筛选。

		:param a_query: 查询字符串
		:param documents: 要处理的文档列表
		:return: 过滤后的 List[Document]
		"""
		# 使用 asyncio.gather 并行处理每个文档
		tasks = [self.process_document(a_query, a_doc) for a_doc in documents]
		return await asyncio.gather(*tasks)


fragment_filter = Fragment_Filter(reranker=reranker)
# 示例用法
result_doc = fragment_filter.invoke({"query": a_query, "documents": a_docs})
print(f'过滤前文本长度: {sum([len(item.page_content) for item in a_docs])}')
print(f'过滤后文本长度: {sum([len(item.page_content) for item in result_doc])}')

Outer-chunk 重组织

原始代码

在做 query-focused summarization 时,出现了一个问题,summarization 始终会造成信息损失,在二次总结时最明显。

例如问题是泰坦尼克号是如何沉没的,原始的总结只会返回泰坦尼克号沉没的信息,但有其他信息虽然与问题不直接相关,但确实可以作为上下文来优化问答效果,例如泰坦尼克号的背景、远航的原因和宣传、航线路线、沉没的后续救援行动、对行业的影响等等。这些辅助信息都因为不直接下相关被去除。

我认为应该是任务定义错误,summarization一定是减少信息,因为他的定义本身就是总结。所以现在改为"上下文重新组织",强调必须保留辅助性的细节。

当然这估计只能缓解,所以我后期会再与query改写相结合,不管是改写为多轮query,还是单独改写为更丰富的query。

from langchain_openai import ChatOpenAI
from langchain_core.prompts import PromptTemplate, ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

reorganzie_prompt = PromptTemplate(
	template=(
		"Given the following set of document fragments and the query, filter out irrelevant content and reorganize the remaining fragments into a single, cohesive chunk.\n\n"  
		"The goal is to synthesize contextual content that will support a detailed and nuanced QA response, ensuring diverse perspectives are preserved while reducing redundancy. "
		"Retain important background information and supplementary details, even if they are less directly relevant to the query. "
		"Present the reorganized content in {language} language. \n"
        "[query-START]:\n{query}\n[query-END]\n"
        "[fragments-START]:\n{fragments}\n[fragments-END]\n"
	),
	partial_variables={
		"language":"Chinese" # "English" or "Chinese"
	}    
)

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

output_parser = StrOutputParser()

reorganzie_chain = reorganzie_prompt | llm | output_parser
query = a_query
fragments = a_docs[0].page_content
result = reorganzie_chain.invoke(
    {
        "query":query,
        "fragments":fragments
    }
)

print(query, fragments, result, sep='\n========\n')
澳大利亚新任外长黄英贤近日访问了哪个国家,他的目的是什么?
========
 。据路透社6月17日报道,在华盛顿对中国在太平洋地区不断扩大的影响力感到担忧之际,路透社记者17日看到的一份声明显示,美国和马绍尔群岛同意努力在今年就美国对后者的经济援助达成协议。报道称,美国《自由联系协定》谈判特使尹汝尚本周前往马绍尔群岛,与这个具有战略意义的太平洋岛国的相关部门举行会谈。根据一份联合声明,双方希望在9月前签署一项谅解备忘录,“目的是在秋末或初冬之前完成《自由联系协定》谈判”。声明称,双方阐明了在2023年《自由联系协定》到期后美国继续向马绍尔群岛提供经济援助的重要性。报道还说,长期以来,华盛顿与马绍尔群岛、帕劳和密克罗尼西亚联邦保持着特殊关系,这使得美军能够进入太平洋地区的广阔战略区域。但这三个太平洋岛国抱怨说,美方的援助没有跟上。尹汝尚还负责与密克罗尼西亚联邦和帕劳就延长《自由联系协定》进行谈判。报道说,中国加强了与太平洋岛国的经济、军事和警务联系,并在商业和旅游方面向马绍尔群岛、帕劳和密克罗尼西亚联邦示好。前不久,中国与所罗门群岛签署安全协议,凸显了北京在该地区日益增强的影响力。此举引发了澳大利亚、新西兰和美国的关切。战略与国际问题研究中心的专家哈里森·普雷拉表示:“该地区国家更感兴趣的可能是轮流吸引中国和西方的投资,而不是作出加入北京阵营的承诺。”声明还说,尹汝尚和马绍尔群岛外长基特兰·卡布阿还讨论了美国在马绍尔群岛进行核试验的遗留问题。在尹汝尚今年3月上任之前,这个问题一直是双方关系的症结所在。报道写道,1946年至1958年期间,美国在马绍尔群岛进行了67次核试验——其中包括1954年在比基尼环礁进行的“喝彩城堡”氢弹试验。这些核试验对健康和环境造成的影响迄今仍然令岛国居民感到困扰。另据路透社6月17日报道,在所罗门群岛与中国的安全协议引发地区关切之际,澳大利亚外长黄英贤周五造访所罗门群岛一个骚乱频发的社区,以强调澳大利亚警方的能力。黄英贤表示,在访问期间,她与所罗门群岛总理索加瓦雷举行了“建设性”会谈。报道称,黄英贤的访问强调了澳大利亚对所罗门群岛的教育和医疗援助,以及在当地去年发生骚乱后澳大利亚警方为恢复稳定作出的努力。黄英贤对媒体称,索加瓦雷重申了他的公开保证,即根据与中方的协议,所罗门群岛不会有军事基地,也不会有持续的外国驻军。黄英贤周五说:“澳大利亚仍然认为,应该由太平洋大家庭来负责我们的安全问题。”黄英贤访问了所罗门群岛首都霍尼亚拉以东的伯恩斯克里克定居点,那里的房屋在去年11月的骚乱中被烧毁。澳大利亚、斐济和新西兰的警察以及当地年轻人参与了重建工作,在那里修建了一个诊所。
========
澳大利亚新任外长黄英贤近日访问了所罗门群岛。据报道,黄英贤在访问期间与所罗门群岛总理索加瓦雷进行了“建设性”的会谈。黄英贤强调了澳大利亚对所罗门群岛的教育和医疗援助,以及在去年发生骚乱后澳大利亚警方为恢复稳定所作出的努力。黄英贤表示,索加瓦雷重申了他不会在所罗门群岛设立军事基地或持续驻扎外国军队的公开保证。黄英贤还访问了所罗门群岛首都霍尼亚拉以东的伯恩斯克里克定居点,该定居点在去年11月的骚乱中遭受了严重破坏。澳大利亚、斐济和新西兰的警察以及当地年轻人参与了重建工作,其中包括修建了一个诊所。黄英贤的访问正值中国与所罗门群岛签署安全协议,引发澳大利亚、新西兰和美国的关切之际。

封装

import asyncio
import numpy as np
from typing import List, Dict
from langchain_openai import ChatOpenAI
from langchain.schema.runnable import Runnable
from langchain_core.prompts import PromptTemplate
from langchain_core.output_parsers import StrOutputParser

from sklearn.cluster import AgglomerativeClustering
from sklearn.metrics.pairwise import cosine_similarity


class Content_Reorganizer(Runnable):
	
	def __init__(self, llm, embedding_model, threshold:float=0.5, chunk_size:int=512):

		self.llm = llm
		self.embedding_model = embedding_model
		self.threshold = threshold
		self.chunk_size = chunk_size

		self.reorganzie_prompt = PromptTemplate(
			template=(
				"Given the following set of document fragments and the query, filter out irrelevant content and reorganize the remaining fragments into a single, cohesive chunk.\n\n"  
				"The goal is to synthesize contextual content that will support a detailed and nuanced QA response, ensuring diverse perspectives are preserved while reducing redundancy. "
				"Retain important background information and supplementary details, even if they are less directly relevant to the query. "
				"Present the reorganized content in {language} language. \n"
				"[query-START]:\n{query}\n[query-END]\n"
				"[fragments-START]:\n{fragments}\n[fragments-END]\n"
			),
			partial_variables={
				"language":"Chinese" # "English" or "Chinese"
			}    
		)

		output_parser = StrOutputParser()

		self.reorganzie_chain = self.reorganzie_prompt | llm | output_parser

	
	def compute_similarity_matrix(self, texts):
		embeddings = self.embedding_model.embed_documents(texts)
		embeddings = np.array(embeddings)
		similarity_matrix = cosine_similarity(embeddings)
		return similarity_matrix
	
	def hierarchical_community_detection(self, texts):
		
		# 计算相似度矩阵
		similarity_matrix = self.compute_similarity_matrix(texts)
		distance_matrix = 1 - similarity_matrix
		
		# 以相似度为阈值来控制聚类
		clustering = AgglomerativeClustering(
			metric='precomputed',
			linkage='average',
			distance_threshold=self.threshold,
			n_clusters=None
		)
		
		# 聚类结果
		labels = clustering.fit_predict(distance_matrix)
		
		# 输出每个社区的文本
		communities = {}
		for idx, label in enumerate(labels):
			if label not in communities:
				communities[label] = []
			communities[label].append(texts[idx])

		return communities
	
	def combine_texts_into_chunks(self, communities):

		chunks = []
	
		for community, texts_in_community in communities.items():
			current_chunk = []
			current_chunk_size = 0
			
			for text in texts_in_community:
				text_size = len(text.split())  # 计算文本大小(按单词数)
				
				# 如果当前文本大小超过chunk_size,则直接单独放入一个块
				if text_size > self.chunk_size:
					if current_chunk:  # 当前块不为空,则保存并开始新块
						chunks.append(" ".join(current_chunk))
						current_chunk = []
						current_chunk_size = 0
					chunks.append(text)  # 该文本单独作为一个块
				else:
					# 当前块 + 文本的大小是否超过chunk_size
					if current_chunk_size + text_size <= self.chunk_size:
						current_chunk.append(text)
						current_chunk_size += text_size
					else:
						# 当前块满了,保存并开始新块
						chunks.append(" ".join(current_chunk))
						current_chunk = [text]
						current_chunk_size = text_size
			
			# 如果还有剩余的文本块,添加到chunks中
			if current_chunk:
				chunks.append(" ".join(current_chunk))
		
		return chunks
	
	def invoke(self, inputs: Dict[str, any]):

		return asyncio.run(self.ainvoke(inputs))


	async def ainvoke(self, inputs: Dict[str, any]):
		
		query = inputs["query"]
		documents = inputs["documents"]

		texts = [doc.page_content for doc in documents]
		communities = self.hierarchical_community_detection(texts)
		chunks = self.combine_texts_into_chunks(communities)

		tasks = [self.process_document(query, content) for content in chunks]
		return await asyncio.gather(*tasks)

reorganizer = Content_Reorganizer()
import asyncio
import numpy as np
from typing import List, Dict
from langchain_openai import ChatOpenAI
from langchain_openai import OpenAIEmbeddings
from langchain.schema.runnable import Runnable
from langchain_core.prompts import PromptTemplate
from langchain_core.output_parsers import StrOutputParser

from sklearn.cluster import AgglomerativeClustering
from sklearn.metrics.pairwise import cosine_similarity

class Content_Reorganizer(Runnable):
    
    def __init__(self, llm, embedding_model, threshold: float = 0.5, chunk_size: int = 512):
        """
        初始化 ContentReorganizer 类,接受大模型、嵌入模型、阈值和块大小等参数。
        
        :param llm: 用于生成重组内容的语言模型
        :param embedding_model: 用于生成文本嵌入的模型
        :param threshold: 社区检测时相似度的阈值
        :param chunk_size: 生成的每个块的最大大小(以单词为单位)
        """
        self.llm = llm
        self.embedding_model = embedding_model
        self.threshold = threshold
        self.chunk_size = chunk_size

        # 用于内容重组的提示模板
        self.reorganzie_prompt = PromptTemplate(
            template=(
                "Given the following set of document fragments and the query, filter out irrelevant content and reorganize the remaining fragments into a single, cohesive chunk.\n\n"  
                "The goal is to synthesize contextual content that will support a detailed and nuanced QA response, ensuring diverse perspectives are preserved while reducing redundancy. "
                "Retain important background information and supplementary details, even if they are less directly relevant to the query. "
                "Present the reorganized content in {language} language. \n"
                "[query-START]:\n{query}\n[query-END]\n"
                "[fragments-START]:\n{fragments}\n[fragments-END]\n"
            ),
            partial_variables={
                "language": "Chinese"  # "English" 或 "Chinese"
            }
        )

        # 输出解析器,将最终生成的文本从模型输出中提取出来
        output_parser = StrOutputParser()
        self.reorganzie_chain = self.reorganzie_prompt | llm | output_parser

    def compute_similarity_matrix(self, texts: List[str]) -> np.ndarray:
        """
        计算文本之间的相似度矩阵。

        :param texts: 输入的文本列表
        :return: 文本之间的相似度矩阵
        """
        # 获取文本的嵌入表示
        embeddings = self.embedding_model.embed_documents(texts)
        embeddings = np.array(embeddings)
        
        # 计算余弦相似度矩阵
        similarity_matrix = cosine_similarity(embeddings)
        return similarity_matrix
    
    def hierarchical_community_detection(self, texts: List[str]) -> Dict[int, List[str]]:
        """
        基于文本的相似度矩阵进行层次社区检测。

        :param texts: 输入的文本列表
        :return: 返回每个社区的文本列表
        """
        # 计算相似度矩阵并转换为距离矩阵
        similarity_matrix = self.compute_similarity_matrix(texts)
        distance_matrix = 1 - similarity_matrix
        
        # 层次聚类
        clustering = AgglomerativeClustering(
            metric='precomputed',  # 使用预计算的距离矩阵
            linkage='average',     # 使用平均链接法
            distance_threshold=self.threshold,
            n_clusters=None
        )
        
        # 获取聚类结果
        labels = clustering.fit_predict(distance_matrix)
        
        # 输出每个社区的文本
        communities = {}
        for idx, label in enumerate(labels):
            if label not in communities:
                communities[label] = []
            communities[label].append(texts[idx])

        return communities
    
    def combine_texts_into_chunks(self, communities: Dict[int, List[str]]) -> List[str]:
        """
        将社区内的文本重新组合成大小不超过 `chunk_size` 的块。

        :param communities: 每个社区及其对应文本的字典
        :return: 组合后的文本块列表
        """
        chunks = []
        
        # 遍历每个社区的文本
        for community, texts_in_community in communities.items():
            current_chunk = []
            current_chunk_size = 0
            
            for text in texts_in_community:
                text_size = len(text.split())  # 计算文本的大小(按单词数)
                
                # 如果当前文本超过 chunk_size,直接单独作为一个块
                if text_size > self.chunk_size:
                    if current_chunk:  # 当前块不为空,将其保存
                        chunks.append(" ".join(current_chunk))
                        current_chunk = []
                        current_chunk_size = 0
                    chunks.append(text)  # 单个文本单独作为一个块
                else:
                    # 判断当前块 + 文本是否超过 chunk_size
                    if current_chunk_size + text_size <= self.chunk_size:
                        current_chunk.append(text)
                        current_chunk_size += text_size
                    else:
                        # 当前块满了,保存并开始新的块
                        chunks.append(" ".join(current_chunk))
                        current_chunk = [text]
                        current_chunk_size = text_size
            
            # 如果最后还有剩余的文本块,添加到 chunks 中
            if current_chunk:
                chunks.append(" ".join(current_chunk))
        
        return chunks
    
    async def process_document(self, query: str, fragment: str) -> str:
        """
        使用 LLM 进行文档内容的重组。

        :param query: 输入查询
        :param fragment: 文本片段
        :return: 生成的重组文本
        """
        # 组织提示并调用 LLM 进行内容重组
        result = await self.reorganzie_chain.ainvoke({"query": query, "fragments": fragment})
        return result
    
    async def ainvoke(self, inputs: Dict[str, any]) -> List[str]:
        """
        异步方法,执行内容重组过程。

        :param inputs: 输入参数,包括查询和文档列表
        :return: 返回重组后的文本列表
        """
        query = inputs["query"]
        documents = inputs["documents"]
        
        # 获取文档的文本内容
        texts = [doc.page_content for doc in documents]
        
        # 进行社区检测
        communities = self.hierarchical_community_detection(texts)
        
        # 将社区内部文本重新组合成块
        chunks = self.combine_texts_into_chunks(communities)
        
        # 并行处理每个块,调用 LLM 进行重组
        tasks = [self.process_document(query, content) for content in chunks]
        return await asyncio.gather(*tasks)
    
    def invoke(self, inputs: Dict[str, any]) -> List[str]:
        """
        同步方法,调用异步的 `ainvoke` 方法。

        :param inputs: 输入参数,包括查询和文档列表
        :return: 返回重组后的文本列表
        """
        return asyncio.run(self.ainvoke(inputs))


openai_embedding = OpenAIEmbeddings(
	model="bge-m3",
	base_url='http://localhost:9997/v1',
	api_key='Empty',
	# dimensions=1024,
)
llm = ChatOpenAI(
	base_url='http://localhost:5551/v1',
	api_key='EMPTY',
	model_name='Qwen2.5-14B-Instruct',
	temperature=0.2,
)

reorganizer = Content_Reorganizer(llm, openai_embedding)
results = reorganizer.invoke(
    {
        "query":a_query,
        "documents":result_doc
    }
)
print(*results, sep='\n====\n')
澳大利亚新任外长黄英贤近日访问了所罗门群岛。据报道,黄英贤在6月17日访问了所罗门群岛一个骚乱频发的社区,以强调澳大利亚警方的能力。她与所罗门群岛总理索加瓦雷进行了“建设性”的会谈,并表示澳大利亚仍然认为,应该由太平洋大家庭来负责安全问题。黄英贤的访问强调了澳大利亚对所罗门群岛的教育和医疗援助,以及在去年发生骚乱后澳大利亚警方为恢复稳定所作的努力。此外,索加瓦雷重申了所罗门群岛不会根据与中国的安全协议设立军事基地或持续的外国驻军的公开保证。黄英贤还访问了所罗门群岛首都霍尼亚拉以东的伯恩斯克里克定居点,该定居点在去年11月的骚乱中遭受了破坏。澳大利亚、斐济和新西兰的警察以及当地年轻人参与了重建工作,修建了一个诊所。
====
澳大利亚新任外长黄英贤近日访问了萨摩亚和汤加这两个太平洋岛国。她表示,澳大利亚将加强与太平洋国家的安全合作,并强调与太平洋岛国之间的联系。黄英贤上任后尤其重视加强澳大利亚与太平洋岛国之间的关系,她认为澳大利亚需要表明自己是该地区国家可靠和值得信赖的伙伴,并且“决心弥补”在气候行动方面“失去的十年”。此外,黄英贤还于12月20日至21日对中国进行了访问,这是四年多来澳大利亚外长首次访华,标志着中澳关系迈出重要一步。黄英贤表示,她将在同王毅的会晤中推动贸易限制措施的取消,并称两国关系中有许多棘手问题,需要时间根据双方各自利益去解决。黄英贤此次访问也引起了媒体的广泛关注,被认为是中澳关系正在慢慢解冻的信号。

在这里插入图片描述

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

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

相关文章

电解电容的参数指标

容量 这个值通常是室温25℃&#xff0c;在一定频率和幅度的交流信号下测得的容量。容量会随着温度、直流电压、交流电压值的变化而改变。 额定电压 施加在电容上的最大直流电压&#xff0c;通常要求降额使用。 例如额定电压是4V&#xff0c;降额到70%使用&#xff0c;最高施…

计时器任务实现(保存视频和图像)

下面是一个简单的计时器任务实现&#xff0c;可持续地每秒保存一幅图像&#xff0c;也可持续地每60秒保存一个视频&#xff0c;图像和视频均以当前时间命名&#xff1a; TimerTask类的实现如下&#xff1a; class TimerTask { public:TimerTask(const std::string& path):…

Django 美化使用ModelForm的输入框

在初次使用ModelForm时&#xff0c;我的html文件代码如下&#xff0c;主要内容是显示一个卡片式表单&#xff0c;通过循环遍历 form 对象动态生成表单字段 {% extends layout.html %}{% block content %} <div class"container"><div class"c1"&g…

应用层优秀的共享民宿物联网框架该怎么选?

有一说一&#xff0c;应用层优秀的物联网框架通常能帮助提升用户体验、提高运营效率、节能减排等等优势&#xff0c;很多老板也很注重这个层面的设计和打磨&#xff0c;那么对于选择应用层优秀的共享民宿物联网框架时&#xff0c;大家可以从哪几个关键因素进行考量呢&#xff1…

【kafka系列】生产者

目录 发送流程 1. 流程逻辑分析 阶段一&#xff1a;主线程处理 阶段二&#xff1a;Sender 线程异步发送 核心设计思想 2. 流程 关键点总结 重要参数 一、核心必填参数 二、可靠性相关参数 三、性能优化参数 四、高级配置 五、安全性配置&#xff08;可选&#xff0…

Unity 获取独立显卡数量

获取独立显卡数量 导入插件包打开Demo 运行看控制台日志 public class GetGraphicCountDemo : MonoBehaviour{public int count;// Start is called before the first frame updatevoid Start(){count this.GetIndependentGraphicsDeviceCount();}}

Deepseek R1模型本地化部署+API接口调用详细教程:释放AI生产力

文章目录 前言一、deepseek R1模型与chatGPT o1系列模型对比二、本地部署步骤1.安装ollama2部署DeepSeek R1模型删除已存在模型&#xff0c;以7b模型为例 三、DeepSeek API接口调用Cline配置 前言 随着最近人工智能 DeepSeek 的爆火&#xff0c;越来越多的技术大佬们开始关注如…

Mac ARM 架构的命令行(终端)中,删除整行的快捷键是:Ctrl + U

在 Mac ARM 架构的命令行&#xff08;终端&#xff09;中&#xff0c;删除整行的快捷键是&#xff1a; Ctrl U这个快捷键会删除光标所在位置到行首之间的所有内容。如果你想删除光标后面的所有内容&#xff0c;可以使用&#xff1a; Ctrl K这两个快捷键可以帮助你快速清除当…

用pytorch实现一个简单的图片预测类别

前言&#xff1a; 在阅读本文之前&#xff0c;你需要了解Python&#xff0c;Pytorch&#xff0c;神经网络的一些基础知识&#xff0c;比如什么是数据集&#xff0c;什么是张量&#xff0c;什么是神经网络&#xff0c;如何简单使用tensorboard,DataLoader。 本次模型训练使用的是…

深度学习框架探秘|TensorFlow:AI 世界的万能钥匙

在人工智能&#xff08;AI&#xff09;蓬勃发展的时代&#xff0c;各种强大的工具和框架如雨后春笋般涌现&#xff0c;而 TensorFlow 无疑是其中最耀眼的明星之一。它不仅被广泛应用于学术界的前沿研究&#xff0c;更是工业界实现 AI 落地的关键技术。今天&#xff0c;就让我们…

Linux 服务器部署deepseek

把手教你在linux服务器部署deepseek&#xff0c;打造专属自己的数据库知识库 正文开始 第一步&#xff1a;安装Ollama 打开官方网址&#xff1a;https://ollama.com/download/linux 下载Ollama linux版本 复制命令到linux操作系统执行 [rootpostgresql ~]# curl -fsSL http…

DeepSeek、Kimi、文心一言、通义千问:AI 大语言模型的对比分析

在人工智能领域&#xff0c;DeepSeek、Kimi、文心一言和通义千问作为国内领先的 AI 大语言模型&#xff0c;各自展现出了独特的特点和优势。本文将从技术基础、应用场景、用户体验和价格与性价比等方面对这四个模型进行对比分析&#xff0c;帮助您更好地了解它们的特点和优势。…

CSDN、markdown环境下如何插入各种图(流程图,时序图,甘特图)

流程图 横向流程图 mermaid graph LRA[方形] --> B{条件a}B -->|满足| C(圆角)B -->|不满足| D(圆角)C --> E[输出结果1]D --> E效果图&#xff1a; 竖向流程图 mermaid graph TDC{条件a} --> |a1| A[方形]C --> |a2| F[竖向流程图]A --> B(圆角)B …

unity学习40:导入模型的 Animations文件夹内容,动画属性和修改动画文件

目录 1 Animations文件夹内容 2 每个模型文件的4个标签 3 model 4 rig 动画类型 5 Animation 5.1 新增动画和修改动画 5.2 限制动画某个轴的变化&#xff0c;烘焙 6 material 材料 1 Animations文件夹内容 下面有很多文件夹每个文件夹都是不同的动作模型每个文件夹下…

web第三次作业

弹窗案例 1.首页代码 <!DOCTYPE html><html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>综合案例</title><st…

GMSL 实例1:当 MAX96717 遇上 MAX96724,打通 Camera 视频数据传输

新年伊始&#xff0c;继 Deepseek 在 AI 圈掀起风波之后。比亚迪在2月10日发布会上重磅官宣&#xff1a;全系车型将搭载自研的高阶智驾系统“天神之眼”&#xff0c;覆盖从10万元级入门车型到高端豪华车型的所有范围。此举如一颗重磅炸弹投向当前一卷再卷的新能源汽车赛道&…

DeepSeek 助力 Vue 开发:打造丝滑的侧边栏(Sidebar)

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 Deep…

基于opencv的 24色卡IQA评测算法源码-可完全替代Imatest

1.概要 利用24色卡可以很快的分析到曝光误差&#xff0c;白平衡误差&#xff0c;噪声&#xff0c;色差&#xff0c;饱和度&#xff0c;gamma值。IQA或tuning工程一般用Imatest来手动计算&#xff0c;不便于产测部署&#xff0c;现利用opencv实现了imatest的全部功能&#xff0c…

数据结构与算法之排序算法-(计数,桶,基数排序)

排序算法是数据结构与算法中最基本的算法之一&#xff0c;其作用就是将一些可以比较大小的数据进行有规律的排序&#xff0c;而想要实现这种排序就拥有很多种方法~ &#x1f4da; 非线性时间比较类&#xff1a; 那么我将通过几篇文章&#xff0c;将排序算法中各种算法细化的&a…

MATLAB图像处理:图像特征概念及提取方法HOG、SIFT

图像特征是计算机视觉中用于描述图像内容的关键信息&#xff0c;其提取质量直接影响后续的目标检测、分类和匹配等任务性能。本文将系统解析 全局与局部特征的核心概念&#xff0c;深入讲解 HOG&#xff08;方向梯度直方图&#xff09;与SIFT&#xff08;尺度不变特征变换&…