纲要
- 检索调优的必要性
- 原始向量检索的固有局限
- 调优的核心目标:提升召回率与答案精准度
- 上下文压缩机制
LLMChainExtractor:基于大模型提取相关片段LLMChainFilter:基于大模型进行文档级筛选DocumentCompressorPipeline:串联多个压缩器构建处理流水线
- 排序优化策略
- “Lost in the Middle”现象解析
LongContextReorder:重排文档顺序以提升关键信息捕获率
- 相似性分数过滤
similarity_search_with_score:获取带相关性分数的检索结果- 自定义打分逻辑与元数据写入
- 进阶方向:知识图谱增强 RAG(GraphRAG)
- 完整可运行示例:基于模拟模型演示压缩与排序全流程
引言
在 RAG 系统中,向量数据库返回的初步检索结果通常包含大量冗余、无关或排序不佳的内容[reference:0]。直接将未经处理的原始文档片段馈入大模型,不仅会浪费宝贵的上下文窗口资源,更可能因噪声干扰而显著降低最终回答的质量。
因此,在检索阶段之后引入调优环节——涵盖上下文压缩、智能排序与相似性分数过滤——已成为提升 RAG 应用准确性的关键路径。LangChain 提供了一套即插即用的调优组件,能够在不改动核心检索逻辑的前提下,显著优化检索结果的质量[reference:1][reference:2]。本文将结合实际代码,系统演示如何在不依赖外部 API 的情况下实现上述优化策略。
上下文压缩:从粗糙检索到精炼上下文
上下文压缩器能够有效过滤检索结果中与查询无关的内容,或直接从文档中提取最相关的句子。LangChain 提供了 LLMChainExtractor(基于大模型提取相关片段)和 LLMChainFilter(基于大模型决定是否保留整篇文档)两种压缩器,并支持通过 DocumentCompressorPipeline 将多个压缩器串联为复杂的处理流水线[reference:3][reference:4]。
环境准备
以下示例使用 FakeListChatModel 模拟大模型行为,以展示压缩效果,无需真实 API 调用。
安装依赖:
pip install langchain langchain-core langchain-community chromadb
LLMChainExtractor:提取相关片段
LLMChainExtractor 会对每一篇文档进行分析,仅提取其中与查询相关的部分,生成新的精简文档[reference:5]。
from langchain_community.embeddings.fake import FakeEmbeddings
from langchain_community.vectorstores import Chroma
from langchain_core.documents import Document
from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import (
LLMChainExtractor,
LLMChainFilter,
DocumentCompressorPipeline,
)
from langchain_community.chat_models.fake import FakeListChatModel
# 1. 构建测试向量库
docs = [
Document(page_content="LangChain 支持 OpenAI、DeepSeek 等多种模型。"),
Document(page_content="RAG 系统包含加载、切片、嵌入、检索、生成等步骤。"),
Document(page_content="模型部署需考虑延迟、成本以及云端或本地的选择。"),
Document(page_content="今日天气晴朗,适宜户外运动。"),
]
embeddings = FakeEmbeddings(size=128)
vectorstore = Chroma.from_documents(docs, embeddings, collection_name="tune")
base_retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
# 2. 使用 LLMChainExtractor 进行压缩
# 模拟大模型:返回与查询相关的精简内容
extract_llm = FakeListChatModel(responses=["模型部署需考虑延迟、成本以及云端或本地的选择。"])
extractor = LLMChainExtractor.from_llm(extract_llm)
compression_retriever = ContextualCompressionRetriever(
base_compressor=extractor,
base_retriever=base_retriever,
)
results = compression_retriever.invoke("如何部署模型?")
print("压缩后文档数:", len(results))
for doc in results:
print("内容:", doc.page_content)
ContextualCompressionRetriever 接受一个 base_compressor(即压缩器)和一个 base_retriever(即基础检索器),在检索后自动对结果进行压缩处理[reference:6][reference:7]。
LLMChainFilter:文档级快速筛选
LLMChainFilter 用于决定是否保留整篇文档,而不修改其文本内容。模拟大模型需返回 “YES” 或 “NO”[reference:8]。
filter_llm = FakeListChatModel(responses=["YES", "NO", "YES"])
compressor_filter = LLMChainFilter.from_llm(filter_llm)
filter_retriever = ContextualCompressionRetriever(
base_compressor=compressor_filter,
base_retriever=base_retriever,
)
results = filter_retriever.invoke("如何部署模型?")
print("过滤后文档数:", len(results))
DocumentCompressorPipeline:流水线组合
通过 DocumentCompressorPipeline 可以将多个压缩器串联执行,实现更复杂的处理流程[reference:9]。
pipeline = DocumentCompressorPipeline(transformers=[compressor_filter, extractor])
pipeline_retriever = ContextualCompressionRetriever(
base_compressor=pipeline,
base_retriever=base_retriever,
)
results = pipeline_retriever.invoke("如何部署模型?")
print("管道压缩后文档数:", len(results))
排序优化:应对“Lost in the Middle”现象
研究表明,大模型在处理长上下文时,更容易记住文档开头和结尾的内容,而对中间部分的信息容易忽略——这一现象被称为“Lost in the Middle”[reference:10][reference:11]。LangChain 的 LongContextReorder 通过将最相关的文档排在序列的首尾两端,将次相关文档置于中间,从而有效提升关键信息被模型捕获的概率[reference:12]。
from langchain_community.document_transformers import LongContextReorder
# 模拟一批检索结果
retrieved_docs = [
Document(page_content="北京故宫是中国明清两代的皇家宫殿。"),
Document(page_content="天气炎热,注意防暑。"),
Document(page_content="故宫博物院收藏了大量珍贵文物。"),
Document(page_content="今日油价调整。"),
Document(page_content="故宫每日限流8万人次。"),
]
reorder = LongContextReorder()
reordered_docs = reorder.transform_documents(retrieved_docs)
print("重排序后的文档顺序:")
for i, doc in enumerate(reordered_docs):
print(f"{i+1}: {doc.page_content}")
执行后可以看到,与“故宫”最相关的文档被移到了首尾位置,无关信息则被排布到中间区域,从而优化了模型对关键信息的注意力分配[reference:13]。
相似性分数过滤与自定义打分
多数向量数据库支持 similarity_search_with_score 方法,能够在返回文档的同时给出相关性分数。开发者可以利用该分数进行阈值过滤,或将分数写入文档的 metadata 中供后续环节使用。
# 使用同一向量库进行带分数的检索
results_with_score = vectorstore.similarity_search_with_score("模型部署", k=2)
for doc, score in results_with_score:
print(f"分数: {score:.4f},内容: {doc.page_content}")
# 将分数写入文档元数据
scored_docs = []
for doc, score in results_with_score:
doc.metadata["score"] = score
scored_docs.append(doc)
print("第一个文档的分数:", scored_docs[0].metadata["score"])
进阶方向:知识图谱增强 RAG(GraphRAG)
当知识库中存在大量实体及其复杂关联关系时,单纯依靠向量相似度难以有效挖掘间接关联信息。GraphRAG 在传统 RAG 架构基础上引入知识图谱,利用图结构遍历查询实体相关的其他节点(例如通过“栖息地”或“食性”找到关联物种),将图遍历结果与向量检索结果融合,从而提供更全面的上下文信息。LangChain 已提供 GraphRetriever 等组件支持该模式,尤其适用于生物分类、法律案例关联、产品配件推荐等需要多跳推理的场景。
参考文档
官方文档
- LangChain ContextualCompressionRetriever API Reference
- LangChain LLMChainExtractor API Reference
- LangChain LLMChainFilter API Reference
- LangChain LongContextReorder API Reference
- LangChain DocumentCompressorPipeline API Reference
参考链接
总结
检索调优的核心目标是将 RAG 系统从“能搜到”升级为“搜得准、答案精”。上下文压缩有效去除噪声信息,智能排序避免关键内容被模型忽略,相似性分数过滤则进一步提升了信噪比。
上述组件具有高度的灵活性,可在不改动核心检索逻辑的前提下自由组合与叠加。从简单的向量检索出发,逐步引入压缩、排序与分数过滤机制,将能够构建出高质量、高可靠性的 RAG 应用。
332



被折叠的 条评论
为什么被折叠?



