无查询时的分块选择:在RAG没有问题可问时使用K均值算法
在没有用户查询的情况下,RAG无法选择上下文。将K视为输出数量,用k均值对分块嵌入进行聚类,保留中心点分块及其来源。
有些大型语言模型相关的问题没有专门的名称、框架,也没有大量相关文献。这类问题的情况如下:面对海量文本,既没有用户提出的具体问题,任务就是筛选出合适的文本片段交给模型,以确保所有主题都能被覆盖,且每段文本的来源都能被追溯。
这既不属于检索增强生成,因为并没有进行任何搜索;也不属于提示词压缩或总结。学术界尚未给它明确命名,现有的工具也无法处理它。下文将阐述这一问题,说明现有技术为何存在不足,并介绍一种简单的解决方案,该方法既与学术理念相契合,又能弥补那些论文所忽略的缺陷。
当没有内容可搜索时
过去几年中使用过大语言模型进行开发的人都知道RAG循环:用户提出问题,查询会被嵌入,向量存储会返回相似的文本片段,这些片段会被加入提示词中,进而生成基于这些片段的答案。这种模式简洁高效,有大量相关文档记载,也得到了所有主流框架的支持。但它隐含了一个前提,即必定存在查询。
但实际上往往并没有查询。像LangChain和LlamaIndex这样的框架都是以查询和检索为核心的,大多数关于上下文压缩的论文也是从查询出发的。人们在寻找为大语言模型选择最佳文本片段的方法时,总是假设存在用户问题来指导选择。
以一个学习应用为例。学生上传课程资料:教科书、幻灯片、视频文字稿、手写笔记,有时甚至有数百页之多。他们不会进行任何搜索,实际上只是说“这是我的课程,帮我生成学习资料”。系统就必须据此生成结构化的输出,如测验题、抽认卡、总结和概念图。每份输出应涵盖不同的主题,并注明资料来源,而所有来源资料的总量远远超过任何上下文窗口的容量。
同时满足三项要求
现有的方法都至少无法同时满足这一用例所提出的三项约束条件之一。
- 没有查询信号。用户没有提供任何用于指导选择的信号,因此系统必须仅凭数据本身来判断哪些内容是重要的。
- 确保主题覆盖全面。这样产生的结果是一组能够全面涵盖相关内容的输出。如果遗漏了某个主题,那就属于严重失误;一份从不涉及遗传学的生物学测验毫无用处。
- 来源可追溯性。每个输出都必须指向原文中的特定部分,例如“基于生物化学教材的第3章第12至14页”。在教育领域,这一点并非可有可无,因为学生需要知道该去哪里进一步阅读。
目前还没有任何方法能够同时满足这三点要求。这就是现有的差距。
现有研究提供了什么,又存在哪些局限
为何全量发送会失败
一种简单的做法是将所有内容都放入上下文窗口中。由于现有模型的处理能力为128k到200k个标记,人们很容易认为这样就能解决问题,但实际上并非如此。“迷失在中间”的研究显示出了U形的性能曲线:模型能够很好地处理上下文的开头和结尾,却总是忽略中间的内容。即便是对长上下文进行优化的模型,当关键内容从边缘移至中间时,准确率也会下降30%以上。
因此,即使所有内容都能容纳进去,仍有大量信息会被忽略。例如测验可能只涉及第一章和最后一章,而跳过其余部分。更多的上下文并不等同于更好的上下文。
提示词压缩解决的是不同的问题
越来越多的研究通过删除输入中多余的标记,从而在内容到达模型之前就对其进行简化。
Selective Context采用小型语言模型来计算词汇单元的自信息,无论是标记、名词短语还是句子,都会剔除那些自信息较低的单元。它无需查询输入,从而满足第一个约束条件。但它仅在现有文本中进行过滤,生成的是同一文本的压缩版本,而非跨主题的代表性内容筛选结果。它无法保证内容覆盖全面,且经过处理的文本会失去与原始文本块的直接关联,因此第二个和第三个约束条件均不成立。
LLMLingua和LLMLingua-2通过迭代压缩和训练得到的标记分类器进一步发展了这一理念,压缩比可达到20倍。它们仍存在相同的根本局限:文本是为机器而压缩的,而非为人而组织。最终得到的只是模型能够解析的提示语,而非可追溯的结构化内容集合。
RECOMP训练的压缩器能够从检索到的文档中进行总结或提取信息,既支持提取式方法也支持抽象式方法。它是这一系列中最复杂的,但必须依赖查询指令来决定保留哪些内容,因此无法满足第一个约束条件。
简而言之,提示词压缩仅能减少标记数量,它不会挑选具有代表性的内容,也无法保证主题覆盖度或保留原文结构。
图排序仅能表示信息,无法对其进行组织
TextRank和LexRank会构建句子间的相似性图,再运用PageRank算法找出最核心的句子,即最能代表整篇文档的句子。这些方法无需查询输入,二十多年来一直是无监督抽取式摘要生成的标准方案。它们的已知缺陷在于冗余问题:相似的句子会获得相似的权重,因此选出的核心句子往往只是用不同词汇重复表达相同内容。例如,对一本生物学教材使用TextRank进行摘要生成时,可能会选出三句关于DNA复制的句子,却没有任何关于蛋白质合成的句子,仅仅因为复制相关内容出现的频率更高。
这会降低摘要的全面性,即便主要主题仍会体现出来;而且由于这些方法是基于句子处理的,因此只能部分满足可追溯性要求。
聚类方法最为接近理想方案
基于聚类的摘要生成方法,通过在对句子嵌入进行K-means、HDBSCAN或类似算法处理后,将相似的句子归入主题簇,并从每个簇中选取一个代表句。这种方法能有效消除冗余:每个簇仅贡献一句句子,且不同的簇对应不同的主题。
该领域近期最出色的成果是“Graphs in Clusters”方法,它将K-means与TextRank相结合。首先通过聚类实现全面覆盖,然后在每个簇内通过排序确定句子的重要性。在ArXiv和PubMed等长文档基准测试中,该方法的性能优于纯基于图的方法和纯基于聚类的方法。
它是最接近的同类技术,但在几个关键方面存在差异。它的目标是生成一份扁平的文本摘要,而此处目标是生成多个结构化的输出结果。它采用肘部法则来确定K值,而此处K值由用户需求决定。它处理的是单个句子,而此处需要按一定粒度分块以保留源文本的元数据。它的聚类结果只是隐形的中间步骤,而此处聚类结果本身就是最终输出。此外,它也不具备强制进行源文本追溯的功能。
并列对比
在三种约束条件下,会出现不同的模式。RAG能够保留来源文本,但需要查询输入且无法保证覆盖全部内容;Selective Context与LLMLingua无需查询,但会丢失来源文本的结构且无法确保覆盖全面;RECOMP需要查询输入;TextRank与LexRank则无需查询,但会产生冗余输出且可追溯性较弱;聚类总结法能够满足前两项约束,即无需查询且能保证覆盖全部内容,但其处理层面仅为句子级,因此无法重新追溯到原始来源。
目前尚不存在一种无需查询、能保证覆盖且可追溯来源文本的块选择方法。
逆向运用聚类技术
解决方案在于颠覆自然语言处理中通常的聚类使用方式。在现有研究中,K是一个超参数,研究人员会依次尝试K=5、K=10、K=50,通过绘制轮廓系数或惯性曲线来选定“最佳”值。这些聚类只是为算法服务的数学对象,用户永远无法看到它们。
在这种模式下,K变成了产品规格——学生如果要求10份测验题,K就设为10;5页总结内容对应K=5,30张闪卡则对应K=30。每个聚类都恰好对应一个输出结果,它并非中间抽象概念,而是最终交付的内容。之所以会有关于有丝分裂的测验,是因为上传内容的语义空间中存在与有丝分裂相关的文本片段聚类。
现有方法利用聚类来为机器压缩文本,而这种方法则利用聚类来为人类整理内容。
在后续处理中,这一切都发生了变化。传统上,K值是通过数学方法调整的,集群始终处于隐藏状态,聚类之后只会生成一个概要。而在这里,K值由用户需求决定,每个集群都成为用户能够获取的内容,且每个集群会触发一次大语言模型调用,从而产生一个注明来源的输出结果。
五步处理流程
1. 分块。文档可使用LlamaIndex或LangChain中的标准分块工具,或依据自定义规则进行分割。每个分块都会保留其文本、源文件、页码、位置以及其它元数据。典型的分块大小为500到1000个标记,相邻分块之间有10%到20%的重叠,这样能在保持内容完整性的同时让集群更加细致。分块还可以选择性地添加概要、关键词或实体标签,这些有助于聚类,但并非必需。
2. 嵌入处理。每个文本块都会被转换为一个密集向量。模型的选择取决于具体实现:Sentence-Transformers是一种快速且免费的基准模型,OpenAI的text-embedding-3-small在多种语言上表现优异,而Mistral Embed或Cohere Embed则是具有竞争力的选择。关键在于,语义相近的文本块无论使用何种词汇表,都会生成相近的向量。
3. K均值聚类。这是核心步骤。K均值会将嵌入空间划分为恰好K个组,K的值由用户期望的输出数量决定:
from sklearn.cluster import KMeans
n_outputs = 10 # User wants 10 quiz sheets
kmeans = KMeans(n_clusters=n_outputs, random_state=42, n_init=10)
kmeans.fit(embeddings)
有三种属性可直接满足上述三个约束条件。无需进行任何查询,因为K均值算法是根据数据块之间的相似度进行分组,而非依据其与外部信号的相关性。由于每个数据块都会恰好属于一个簇,且数据中的每个主题都能得到体现,因此能够保证主题覆盖的完整性。此外,重复信息也会被消除——表达相同内容的数据块具有相似的嵌入向量,会聚集在一起,最终只产生一个代表性结果。
4. 代表性元素的选择。 对于每个簇,选取最接近簇中心的数据块,该数据块最能体现该簇的主题:
import numpy as np
selected = []
for i in range(n_outputs):
cluster_indices = np.where(kmeans.labels_ == i)[0]
centroid = kmeans.cluster_centers_[i]
distances = np.linalg.norm(
embeddings[cluster_indices] - centroid, axis=1
)
best_local_idx = np.argmin(distances)
best_global_idx = cluster_indices[best_local_idx]
selected.append(chunks[best_global_idx]) # Full chunk with metadata
所选文本片段保留了所有原始元数据,因此不会丢失任何信息,且所有内容均可被引用。为获得更丰富的输出结果,可用每个质心最近的三个文本片段替代一个;原理依然适用。
5. 生成阶段。每个簇中选定的文本片段会连同适合该输出类型的提示词一起送入大语言模型,同时原始元数据也会一同传递,以便模型能够进行引用。簇1会生成测验1,并引用第一个PDF文件的第12至14页;簇2会生成测验2,并引用14:30处的视频文字记录。这一模式会一直重复到簇K。
未指定数量时
并非所有用户都要求十道测验题;有些人只想要“一道测验题”或“一份总结”。有三种可行的替代方法。令牌预算法是将模型的有效上下文长度除以平均块大小:对于一个16k令牌的模型和800令牌的块大小,K的值大约为20。肘部法则则是尝试多个K值,选出惯性不再显著下降的点。另一个粗略的规则是每5到10页源文本对应一个聚类。实际上,令牌预算法最为可靠,因为它直接反映了模型能够处理的信息量。
该方法能保证什么
这些是K均值算法的数学特性,而非经验观察结果。
- 覆盖性。每个数据点都会被分配到一个簇中,因此没有数据块会被遗漏。如果某个主题存在,它必定属于某个有代表数据的簇。而Top-K检索方式则可能返回与某个热门主题相关的K个数据块,却完全忽略其他主题。
- 无冗余性。相似的数据块会归为一组,每组仅保留一个代表。用不同表述表达相同内容的两个数据块会属于同一个簇,最终只会有一个被保留下来。
- 可调节的粒度。较低的K值会导致针对广泛主题的较大簇,较高的K值则会生成针对具体概念的较小簇,用户可通过请求来调整这一参数。
- 源数据保留。由于是基于数据块而非词元或句子进行处理,因此每个被选中的数据块都能保留完整的元数据链。而词元级压缩按设计无法做到这一点。
其不足之处
球形假设。 K均值聚类期望簇的形状大致为圆形,但嵌入空间并不总是如此规整。形状复杂且非凸的主题可能会被分散到多个簇中。HDBSCAN或高斯混合模型或许能有所帮助,但它们无法保证恰好形成K个簇。
仅具典型性,未必具有信息量。 距离质心最近的片段是最具典型性的。如“Clusters中的图表”方法那样在每个簇内运行TextRank,就能做出更细致的选取,这是一种很有前景的改进方式。
小型主题会被压缩。如果内容中95%是生物学内容,5%是化学内容,那么化学内容可能只形成一个聚类,而生物学内容则形成K-1个聚类。化学内容的聚类虽然存在,但其规模会被相应压缩。采用加权或分层方案可以解决这个问题。
分块质量决定一切。如果分块将某个概念一分为二,或混合了不相关的主题,那么聚类效果就会受到影响。良好的分块方式应当包含语义分割、内容重叠处理以及元数据补充,这些都是不可或缺的。
单次处理中的对比
RAG速度较快且能保留来源文本,但需要输入查询,针对同一主题可能会返回K个片段。Selective Context和LLMLingua无需查询即可快速处理,但会丢弃来源文本的结构,也无法保证覆盖全面。RECOMP功能强大,但依赖查询输入。TextRank和LexRank无需查询且速度较快,但由于存在冗余信息,覆盖范围有限,且追溯仅停留在句子层面。Clusters中的图模型无需查询且覆盖效果较好,但仅适用于句子处理,还会丢失来源文本的元数据。MapReduce总结方法同样无需查询,不过覆盖范围有限,来源链接会在总结过程中消失,且由于需要多次调用大语言模型,速度较慢。
此处介绍的K均值分块选择方法是唯一一种无需查询即可运行、天生能保证主题覆盖度、在分块层面保持完全可追溯性、处理速度在一秒以内,且既不需要微调模型也不需要向量数据库的方法。
问题的命名
让这个问题难以解决的原因并非技术难度大,而是缺乏一个合适的名称。搜索RAG会出现数千个结果;搜索提示词压缩会找到LLMLingua;搜索提取式摘要会出现TextRank、LexRank以及基于BERT的方法。但若要寻找一种无需查询、从大量语料库中挑选最佳分块以在保证来源可追溯性的同时最大化主题覆盖度的方法,几乎找不到相关资料。
一个恰当的称谓是“无查询语义压缩”。它不属于检索,因为没有查询输入;它也不属于总结,因为此阶段不会生成新文本;它更不是提示词压缩,因为不会从现有文本中删除任何标记。其实质是一种能保证覆盖范围的筛选方式:选择最少的内容片段来代表最广泛的信息范围,同时保留与原始文档的关联。
每当系统在没有明确搜索意图的情况下将大量用户提供的内容转化为结构化输出时,就会出现这类问题。例如课程内容中的学习资料、大量文档集合中的报告、数小时录音转录后的会议总结、大量代码提交中的评审摘要,以及法律分析——在这些场景中,对各个条款的全面覆盖比回答单个问题更为重要。
K均值算法是一种解决方案,可以说是最简单的。将聚类与基于图的排序、信息密度评分或轻量级大语言模型结合用于主题检测的混合方法可能会取得更好效果,而且这一领域仍有很大的发展空间。
完整的代码实现
整个筛选流程仅需不到50行代码即可实现:
from sentence_transformers import SentenceTransformer
from sklearn.cluster import KMeans
import numpy as np
def select_representative_chunks(chunks, n_outputs, model_name='all-MiniLM-L6-v2'):
"""
Select the most representative chunks from a large corpus
using K-means clustering. One cluster = one output.
Args:
chunks: list of dicts with 'text', 'source', 'page', etc.
n_outputs: number of outputs the user wants (= K)
model_name: embedding model to use
Returns:
list of selected chunks with cluster metadata
"""
# Embed
model = SentenceTransformer(model_name)
embeddings = model.encode([c['text'] for c in chunks], show_progress_bar=True)
# Cluster
kmeans = KMeans(n_clusters=n_outputs, random_state=42, n_init=10)
kmeans.fit(embeddings)
# Select representatives
selected = []
for i in range(n_outputs):
cluster_indices = np.where(kmeans.labels_ == i)[0]
centroid = kmeans.cluster_centers_[i]
distances = np.linalg.norm(embeddings[cluster_indices] - centroid, axis=1)
best_local_idx = np.argmin(distances)
best_global_idx = cluster_indices[best_local_idx]
selected.append({
'cluster': i,
'chunk': chunks[best_global_idx],
'distance_to_centroid': float(distances[best_local_idx]),
'cluster_size': len(cluster_indices),
})
return selected
在筛选阶段不需要向量数据库、检索流程、微调模型,也不需要调用大型语言模型,仅需嵌入向量、聚类以及选择质心即可。
实际应用场景
该流程是在一款学习应用中构建并测试的,该应用能够根据学生上传的讲义、教科书、视频文字记录和幻灯片等资料,生成互动学习材料,如测验、抽认卡、总结内容以及概念图。它还配备了为阅读障碍、多动症或其他认知障碍的学习者设计的工具,并融入了游戏化元素。该项目仍在持续研发中,目前提供法语版本,英文版本也在规划中。
在这种架构中,K均值层负责内容筛选。对500个文本片段进行聚类只需不到一秒,且具备良好的扩展性,无论来自结构严谨的生物学教科书还是零散的讲座录像,都能实现良好的主题覆盖。
为何刻意设计得如此简单
无需查询即可从大量文本中选出具有代表性、能实现主题覆盖且可追溯来源的文本片段,这一需求其实比文献中描述的更为普遍。任何开发用于教育、报告生成、会议分析或法律审查的大型语言模型工具的人,很可能都遇到过类似问题。
该方法的设计初衷十分简单。K均值算法已有数十年历史,句子嵌入也是标准技术。其创新之处在于框架设计:将用户的意图视为K值,将每个聚类结果视为一个输出成果,并在整个处理流程中保持文本片段与来源之间的关联不变。
仍有改进空间。主题检测方面,可将聚类技术与基于图的排序、信息密度评分或轻量级大语言模型处理方法相结合。选择聚类中心的方法也可被更精细的方式替代,比如在聚类内部进行排序、基于多样性加权进行选择,或通过小型大语言模型来确定最具信息量的片段。这些思路可供借鉴、调整与优化。