news 2026/6/14 11:39:06

Rerank 与上下文压缩:为什么召回 TopK 后还要重排?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Rerank 与上下文压缩:为什么召回 TopK 后还要重排?

RAG 最容易踩的坑,不是“没有召回”。

而是召回了一堆看起来相关、实际会干扰模型的资料。

所以,成熟的 RAG 链路不会把 TopK 直接塞进 Prompt。

它会先召回,再重排,再压缩。

1. 为什么召回 TopK 后还要重排?

向量召回解决的是“可能相关”。

Rerank 解决的是“到底谁更相关”。

这两个问题不一样。

Embedding 检索通常是把 query 和 document 分别变成向量,再算距离。速度很快,适合从几十万、几百万 Chunk 中先捞一批候选。

但向量距离不是最终答案。它只代表语义接近,不代表这段内容能回答问题。

所以生产级 RAG 通常会先取一个偏大的 k,比如 20、30、50,然后让 Reranker 重新打分,最后只保留 TopN。

2. Rerank 的本质:把“候选文档”重新排队

Rerank 不负责从全量知识库里找资料。

它只负责对已经召回的候选文档重新排序。

这就像招聘:第一轮海选看简历关键词,第二轮面试才判断人和岗位到底匹不匹配。

LangChain 官方的 Cross Encoder Reranker 文档也强调:Cross-Encoder 会直接给每个 query-document pair 打分,而不是分别比较两个独立向量;这种方式排序更准,但每个文档都要额外推理一次。

3. 上下文压缩是什么?不是压缩文件,是压缩噪声

Contextual Compression 翻译成“上下文压缩”。

它不是 zip 压缩。

它是根据用户问题,把召回出来的文档再处理一遍。

无关文档,直接删。

相关文档里无关段落,剪掉。

重复文档,过滤。

排序不准,重排。

最后交给模型的,不再是粗糙的 TopK,而是一组更干净、更短、更贴题的 Document。

4. BaseDocumentCompressor

先看抽象层。

LangChain 里负责“后处理检索结果”的核心抽象是 BaseDocumentCompressor。

它只关心一件事:给我一组 Document 和一个 query,我返回一组处理后的 Document。

这个处理可以是过滤,可以是重排,也可以是裁剪内容。

class BaseDocumentCompressor(BaseModel, ABC):
@abstractmethod
def compress_documents(
self,
documents: Sequence[Document],
query: str,
callbacks: Callbacks | None = None,
) -> Sequence[Document]:
"""Compress retrieved documents given the query context."""
async def acompress_documents(...):
return await run_in_executor(
None, self.compress_documents, documents, query, callbacks
)

这里有三个关键点。

第一,输入是 documents,不是原始字符串。说明它接在 Retriever 后面。

第二,输入里有 query。说明压缩不是盲目压缩,而是围绕当前问题压缩。

第三,返回还是 Sequence[Document]。说明它不会破坏 RAG 主流程,后面仍然可以继续拼 Prompt、交给 Model。

5. ContextualCompressionRetriever

BaseDocumentCompressor 只是压缩器。

真正把“基础检索器”和“压缩器”串起来的,是 ContextualCompressionRetriever。

它本质上是一个 Retriever 包装器。

你给它 base_retriever 和 base_compressor。

调用时,它先走 base_retriever 拿候选文档,再走 base_compressor 压缩候选文档。

ContextualCompressionRetriever 的源码调用链。

# 伪源码:核心逻辑可以压缩成这几行
class ContextualCompressionRetriever(BaseRetriever):
base_retriever: RetrieverLike
base_compressor: BaseDocumentCompressor
def _get_relevant_documents(self, query, run_manager):
docs = self.base_retriever.invoke(query)
if docs:
docs = self.base_compressor.compress_documents(
docs, query, callbacks=run_manager.get_child()
)
return docs

这段逻辑非常干净。

Retriever 负责召回。

Compressor 负责后处理。

ContextualCompressionRetriever 负责把两者连起来。

所以它不是一个新的向量数据库,也不是一个新的大模型。它只是给 RAG 加了一个质量关卡。

6. CrossEncoderReranker

CrossEncoderReranker 是最典型的重排器。

它的思路很直接。

把 query 和每个 Document.page_content 组成一对。

交给 CrossEncoder 打分。

按分数排序。

取前 top_n。

返回 Document 列表。

CrossEncoderReranker 的内部工作方式。

# 伪源码:CrossEncoderReranker 的核心动作
def compress_documents(self, documents, query, callbacks=None):
pairs = [(query, doc.page_content) for doc in documents]
scores = self.model.score(pairs)
docs_with_scores = sorted(
zip(documents, scores),
key=lambda x: x[1],
reverse=True,
)
return [doc for doc, score in docs_with_scores[: self.top_n]]

注意,Reranker 不会重新去库里查。

它只处理第一阶段已经召回的候选文档。

所以 k 和 top_n 要分开理解。

k 是第一阶段召回多少候选。

top_n 是重排后留下多少上下文。

k 太小,Reranker 没东西可排。

top_n 太大,Prompt 还是会被撑爆。

7. EmbeddingsFilter:更轻量的过滤器

不是所有场景都要 Cross-Encoder。

如果你只是想先过滤掉明显不相关的文档,可以用 EmbeddingsFilter。

它会把文档和 query 再做一次 embedding 相似度比较。

相似度太低,删掉。

这类方式便宜、快,但判断力不如 Cross-Encoder。

它适合做轻量过滤,不适合作为最终排序裁判。

8. DocumentCompressorPipeline:把后处理串成流水线

真实项目里,后处理往往不是一步。

可能先切得更细,再过滤,再重排,再裁剪。

这时候可以用 DocumentCompressorPipeline。

它的思想很像 Java 后端里的责任链。

每个节点只做一件事。

上一个节点输出 Document,下一个节点继续处理 Document。

# 思路示意:不是所有场景都必须这么堆
pipeline = DocumentCompressorPipeline(transformers=[
text_splitter, # 长文档再切细
embeddings_filter, # 去掉明显无关内容
reranker, # 对剩余文档重新排序
])

常见后处理方式选择。表格已转成图片,避免排版变形。

9. 生产环境怎么调参数?

参数不是越大越好。

k 越大,召回越全,但 Rerank 越慢。

top_n 越大,信息越多,但 Prompt 越贵。

score_threshold 越高,噪声越少,但可能误删关键资料。

chunk_size 越大,上下文越完整,但无关内容也越多。

chunk_overlap 越大,断句风险越低,但重复内容也越多。

真正靠谱的做法是建评测集。不要凭感觉调。

10. 企业级 RAG 必须记录哪些日志?

Rerank 一上线,问题会变得更隐蔽。

用户只看到最终答案。

但你必须知道:第一阶段召回了哪些文档,Reranker 给了多少分,哪些文档被删掉,最后哪些内容进入 Prompt。

否则答案错了,你不知道是召回错、重排错、压缩错,还是模型生成错。

企业级 RAG 的 Rerank 与 Trace 架构。

11. Java + Python 项目怎么落地?

如果你是 Java 后端项目,建议不要把 LangChain 强塞进 Java 主服务。

更稳的方式是:Java 负责业务、权限、审计、配置、任务调度;Python AI 服务负责 LangChain、Retriever、Rerank、Prompt、Model。

Java 调 Python。

Python 返回结构化结果。

所有召回文档、Rerank 分数、压缩结果、模型输入输出,都回写 MySQL / ES / 日志系统。

这样既能利用 Python AI 生态,又不会破坏 Java 主业务的稳定性。

Spring Boot
↓ REST / gRPC
Python FastAPI AI Service

base_retriever.invoke(query)

ContextualCompressionRetriever

CrossEncoderReranker / EmbeddingsFilter

Prompt + Model

结构化答案 + 引用来源 + Trace 日志

12. 总结

第一,召回是粗筛,Rerank 是精筛。

第二,上下文压缩不是少给资料,而是少给噪声。

第三,RAG 的质量上限,不只由模型决定,更由检索、重排和上下文决定。


内容来源:Rerank 与上下文压缩:为什么召回 TopK 后还要重排?:功能变化与行业影响解析_热闻岛

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/14 11:38:51

专业QQ音乐解密工具qmcdump:实现音频格式无损转换的完整指南

专业QQ音乐解密工具qmcdump:实现音频格式无损转换的完整指南 【免费下载链接】qmcdump 一个简单的QQ音乐解码(qmcflac/qmc0/qmc3 转 flac/mp3),仅为个人学习参考用。 项目地址: https://gitcode.com/gh_mirrors/qm/qmcdump …

作者头像 李华
网站建设 2026/6/14 11:37:58

明日方舟终极助手:MAA一键自动化全攻略,告别重复刷图烦恼

明日方舟终极助手:MAA一键自动化全攻略,告别重复刷图烦恼 【免费下载链接】MaaAssistantArknights 《明日方舟》小助手,全日常一键长草!| A one-click tool for the daily tasks of Arknights, supporting all clients. 项目地址…

作者头像 李华
网站建设 2026/6/14 11:36:23

除了清华北航,中科院自动化所还偏爱哪些‘宝藏’院校?一份基于3年录取数据的生源地图

解码顶尖科研院所生源密码:中科院自动化所录取偏好全景分析 当清晨的阳光洒在中关村东路95号的自动化所大楼上,一批批来自全国各地的优秀学子正通过推免通道叩开这所顶尖科研机构的大门。不同于高校统一招生,科研院所的录取往往隐藏着更多&qu…

作者头像 李华