【AI大模型】告别新手级RAG!一文掌握专业级后检索优化之「压缩」,提升效率与准确性!
文章探讨了在RAG系统中,虽然大模型上下文窗口增大,但将所有检索文档直接传给模型并非最优解。这会导致效率降低、成本增加和性能下降。文章介绍了后检索压缩技术,包括LangChain框架的上下文压缩检索器、EmbeddingsFilter和多阶段管道压缩,以及LLMLingua提示词压缩方法。通过这些技术,可在保证核心信息不丢失的前提下,提升系统响应速度,降低运营成本,实现效率、成本和性能的平衡。
前言
现在随着大语言模型的快速发展,支持的上下文窗口也越来越大。这时我在想,是不是可以构建RAG系统中,我们把所有检索到的文档都传给生成模型,让它有足够的背景信息,这样生成的答案是不是更全面、更准确呢?
然而,实际情况并不是这样。更长的上下文不仅会影响响应速度,还会面临“大海捞针”的困境,关键的信息被淹没在大量无关的文档信息中,这样生成质量也并不理想。
这时候就引出另外一个后检索优化技术——压缩(compression)。
为什么需要压缩?
压缩技术主要解决下面这几个问题:
- • 效率:有效的压缩,可以使上下文信息更加简洁明了,从而使模型能够更高效地处理这些信息。
- • 节省成本:更多的上下文代表更多的token数量,随之而来的就是更贵的API调用费用,压缩上下文可以明显降低这些成本。
- • 性能提升:更长的上下文也会增加大模型的处理压力,压缩上下文则可以提升模型的性能。
常见压缩策略
1. 使用LangChain
进行上下文压缩
在LangChain
框架中可以使用封装的 Contextual Compression Retriever
(上下文压缩检索器) 来实现。
它包括下面两个组件来实现:
- • Base Retriever(基础检索器)
- • Document Compressor(文档压缩器)
基本流程是:上下文压缩检索器将查询传递给基础检索器,获取初始文档并将它再传递给文档压缩器。文档压缩器获取文档列表后,对内容进行筛选或缩短,只保留最相关的信息。此外,它还根据与查询的相关性对文档重新排序。代码实现流程如下:
创建基础检索器
# 导入相关的库
import os
from dotenv import load_dotenv
from typing import List
# 加载环境变量
load_dotenv()
# LangChain 核心组件
from langchain.text_splitter import CharacterTextSplitter
from langchain_community.vectorstores import FAISS
from langchain.schema import Document
def pretty_print_docs(docs: List[Document], title: str = "检索结果"):
...省略格式化打印代码...
# 医疗健康领域的示例文档内容
document_contents = [...省略测试文档...]
# 1. 创建文档对象列表
documents = []
for i, content in enumerate(document_contents):
doc = Document(
page_content=content.strip(),
metadata={ "类型": "医疗健康"}
)
documents.append(doc)
# 2. 初始化嵌入模型
print("\n🔧 第二步:初始化中文嵌入模型")
# 使用 BGE 中文嵌入模型
embedding_model = HuggingFaceEmbeddings(
model_name="BAAI/bge-small-zh-v1.5",
model_kwargs={"device": "cpu"},
encode_kwargs={"normalize_embeddings": True},
)
print("✅ 成功加载 BGE 中文嵌入模型")
# 3. 创建基础向量检索器
print("\n🗂️ 第三步:创建基础向量检索器")
# 文本分割
text_splitter = CharacterTextSplitter(
chunk_size=500, # 每个文本块的最大字符数
chunk_overlap=50, # 相邻文本块之间的重叠字符数,确保上下文连续性
separator="\n" # 分割符号
)
texts = text_splitter.split_documents(documents)
print(f"📝 文档已切分为 {len(texts)} 个文本块")
# 创建向量存储
print("🔍 正在创建向量存储...")
vectorstore = FAISS.from_documents(texts, embedding_model)
base_retriever = vectorstore.as_retriever(search_kwargs={"k": 4})
# 4. 基础检索演示
print("\n🔍 第四步:基础检索演示")
# 测试查询
test_query = "糖尿病的主要症状和治疗方法有哪些?"
print(f"查询问题: {test_query}")
# 执行基础检索
original_docs = base_retriever.get_relevant_documents(test_query)
pretty_print_docs(original_docs, "基础检索结果")
================================================================================
📚 基础检索结果 (共 4 个文档)
================================================================================
📄 文档 1:
--------------------------------------------------
糖尿病是一组以高血糖为特征的代谢性疾病,分为1型糖尿病和2型糖尿病。1型糖尿病通常在儿童或青少年时期发病,
是由于胰岛β细胞破坏导致胰岛素绝对缺乏。2型糖尿病多见于成年人,是由于胰岛素抵抗和相对胰岛素缺乏引起。
糖尿病的并发症包括糖尿病肾病、糖尿病视网膜病变、糖尿病神经病变和大血管病变等。
治疗方法包括生活方式干预、药物治疗和胰岛素治疗,血糖控制目标通常为空腹血糖4.4-7.0mmol/L。
📄 文档 2:
--------------------------------------------------
心血管疾病是全球范围内导致死亡的主要原因之一,包括冠心病、高血压、心力衰竭等多种疾病。
冠心病是由于冠状动脉血管发生动脉粥样硬化病变而引起血管腔狭窄或阻塞,造成心肌缺血、缺氧或坏死而导致的心脏病。
主要危险因素包括高胆固醇、高血压、吸烟、糖尿病、肥胖和缺乏运动。预防措施包括健康饮食、
规律运动、戒烟限酒、控制体重和定期体检。早期发现和及时治疗对于预防心血管事件具有重要意义。
📄 文档 3:
--------------------------------------------------
神经系统疾病包括阿尔茨海默病、帕金森病、脑卒中、癫痫等多种疾病。阿尔茨海默病是一种神经系统退行性疾病,
主要表现为进行性记忆障碍、认知功能障碍、人格改变及语言障碍等。帕金森病是一种慢性神经系统退行性疾病,
主要表现为静止性震颤、肌强直、运动迟缓和姿势步态异常。脑卒中是由于脑血管循环障碍导致的急性脑血管疾病,
分为缺血性脑卒中和出血性脑卒中。癫痫是大脑神经元突发性异常放电导致的短暂性大脑功能障碍的慢性疾病。
神经系统疾病的治疗需要多学科协作,包括药物治疗、康复治疗和心理支持等。
📄 文档 4:
--------------------------------------------------
消化系统疾病包括胃炎、消化性溃疡、肝炎、胆囊炎、胰腺炎等多种疾病。胃炎是胃黏膜的炎症,分为急性胃炎和慢性胃炎,
主要病因包括幽门螺杆菌感染、药物、酒精等。消化性溃疡是指发生在胃和十二指肠的慢性溃疡,主要与幽门螺杆菌感染和
非甾体抗炎药使用有关。病毒性肝炎是由多种肝炎病毒引起的以肝脏炎症和坏死为主要病变的传染性疾病。
胆囊炎是胆囊壁的炎症性疾病,多与胆囊结石有关。预防消化系统疾病的措施包括合理饮食、戒烟限酒、
避免滥用药物和及时治疗幽门螺杆菌感染。
================================================================================

使用 LLMChainExtractor
进行上下文压缩
from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import LLMChainExtractor
from langchain_deepseek import ChatDeepSeek
# LLM链式压缩演示
# 创建 LLM 和压缩器
print("🔧 正在初始化 DeepSeek LLM...")
llm = ChatDeepSeek(
model="deepseek-chat",
temperature=0,
api_key=os.getenv("DEEPSEEK_API_KEY"),
)
compressor = LLMChainExtractor.from_llm(llm)
# 创建压缩检索器
compression_retriever = ContextualCompressionRetriever(
base_compressor=compressor,
base_retriever=base_retriever
)
# 获取压缩结果
llm_compressed_docs = compression_retriever.get_relevant_documents(test_query)
pretty_print_docs(llm_compressed_docs, "LLM链式压缩结果")
================================================================================
📚 LLM链式压缩结果 (共 1 个文档)
================================================================================
📄 文档 1:
--------------------------------------------------
糖尿病是一组以高血糖为特征的代谢性疾病,分为1型糖尿病和2型糖尿病。1型糖尿病通常在儿童或青少年时期发病,
是由于胰岛β细胞破坏导致胰岛素绝对缺乏。2型糖尿病多见于成年人,是由于胰岛素抵抗和相对胰岛素缺乏引起。
治疗方法包括生活方式干预、药物治疗和胰岛素治疗,血糖控制目标通常为空腹血糖4.4-7.0mmol/L。
结果对比
📊 LLM链式压缩 压缩效果分析
----------------------------------------
原始上下文长度: 912 字符
压缩后长度: 165 字符
压缩比: 5.53x
节省空间: 81.9%
使用 EmbeddingsFilter
进行上下文压缩
LLMChainExtractor
对每个检索到的文档进行额外的 LLM 调用又慢而且还更成本更高。EmbeddingsFilter
提供了一种更经济、更快速的方案,它通过嵌入文档和查询,并仅返回那些与查询具有足够相似嵌入 EmbeddingsFilter
文档。
from langchain.retrievers.document_compressors import EmbeddingsFilter
# 嵌入过滤压缩演示
# 创建嵌入过滤器
print("🔧 正在创建嵌入过滤器...")
embeddings_filter = EmbeddingsFilter(
embeddings=embedding_model,
similarity_threshold=0.7 # 相似度阈值:保留相似度大于0.7的内容
)
# 创建压缩检索器
compression_retriever = ContextualCompressionRetriever(
base_compressor=embeddings_filter,
base_retriever=base_retriever
)
# 获取压缩结果
embedding_compressed_docs = compression_retriever.get_relevant_documents(test_query)
pretty_print_docs(embedding_compressed_docs, "嵌入过滤压缩结果")
================================================================================
📚 嵌入过滤压缩结果 (共 1 个文档)
================================================================================
📄 文档 1:
--------------------------------------------------
糖尿病是一组以高血糖为特征的代谢性疾病,分为1型糖尿病和2型糖尿病。1型糖尿病通常在儿童或青少年时期发病,
是由于胰岛β细胞破坏导致胰岛素绝对缺乏。2型糖尿病多见于成年人,是由于胰岛素抵抗和相对胰岛素缺乏引起。
糖尿病的并发症包括糖尿病肾病、糖尿病视网膜病变、糖尿病神经病变和大血管病变等。
治疗方法包括生活方式干预、药物治疗和胰岛素治疗,血糖控制目标通常为空腹血糖4.4-7.0mmol/L。
结果对比
📊 嵌入过滤压缩 压缩效果分析
----------------------------------------
原始上下文长度: 912 字符
压缩后长度: 209 字符
压缩比: 4.36x
节省空间: 77.1%
将压缩器和文档转换器串联在一起
使用 DocumentCompressorPipeline
,我们还可以轻松地按顺序组合多个压缩器。除了压缩器之外,我们还可以在管道中添加 BaseDocumentTransformers
,它们不执行任何上下文压缩,而只是对一组文档执行一些转换。例如, TextSplitter
可以用作文档转换器,将文档拆分成更小的部分,而 EmbeddingsRedundantFilter
可以根据文档之间的嵌入相似性来过滤掉冗余文档。
from langchain.retrievers.document_compressors import DocumentCompressorPipeline
from langchain_community.document_transformers import EmbeddingsRedundantFilter
# 多阶段管道压缩演示
# 1. 文本分割器:将长文档进一步细分
splitter = CharacterTextSplitter(
chunk_size=200, # 更小的分块大小
chunk_overlap=0, # 无重叠
separator="。" # 按句号分割
)
# 2. 冗余过滤器:移除相似的重复内容
redundant_filter = EmbeddingsRedundantFilter(embeddings=embedding_model)
# 3. 相关性过滤器:保留与查询高度相关的内容
relevant_filter = EmbeddingsFilter(
embeddings=embedding_model,
similarity_threshold=0.7
)
# 创建压缩管道
pipeline_compressor = DocumentCompressorPipeline(
transformers=[splitter, redundant_filter, relevant_filter]
)
# 创建压缩检索器
compression_retriever = ContextualCompressionRetriever(
base_compressor=pipeline_compressor,
base_retriever=base_retriever
)
# 获取压缩结果
print("🔍 正在执行多阶段管道压缩...")
print(" 📝 阶段1: 文本分割 (200字符)")
print(" 🔄 阶段2: 冗余过滤 (移除重复内容)")
print(" 🎯 阶段3: 相关性过滤 (相似度>0.7)")
pipeline_compressed_docs = compression_retriever.get_relevant_documents(test_query)
pretty_print_docs(pipeline_compressed_docs, "多阶段管道压缩结果")
================================================================================
📚 多阶段管道压缩结果 (共 2 个文档)
================================================================================
📄 文档 1:
--------------------------------------------------
糖尿病是一组以高血糖为特征的代谢性疾病,分为1型糖尿病和2型糖尿病。1型糖尿病通常在儿童或青少年时期发病,
是由于胰岛β细胞破坏导致胰岛素绝对缺乏。2型糖尿病多见于成年人,是由于胰岛素抵抗和相对胰岛素缺乏引起。
糖尿病的并发症包括糖尿病肾病、糖尿病视网膜病变、糖尿病神经病变和大血管病变等
📄 文档 2:
--------------------------------------------------
治疗方法包括生活方式干预、药物治疗和胰岛素治疗,血糖控制目标通常为空腹血糖4.4-7.0mmol/L
================================================================================
结果对比
📊 多阶段管道压缩 压缩效果分析
----------------------------------------
原始上下文长度: 912 字符
压缩后长度: 204 字符
压缩比: 4.47x
节省空间: 77.6%
2. 使用LLMLingua
压缩提示词
LLMLingua
是由清华大学和微软的研究人员开发的框架,目的是为了提高上下文压缩的效率。其核心思想是:在将长文本发送给昂贵的大模型之前,先用一个轻量级的小模型进行“预处理”,智能地移除其中的冗余信息。 这就像制作一份“内容摘要”交给大模型,既能让它理解问题,又能大幅降低计算负担。
实验表明,LLMLingua
可以在性能损失极小的前提下,实现最高 20倍 的提示词压缩率,显著提升推理效率。
LLMLingua实现过程
随后又推出了最新版本LLMLingua-2
引入了一种与任务无关的方法,比以前的方法更快、更高效。核心亮点如下:
- • 与任务无关:它采用了一种通用的压缩方法,无需针对特定场景(如对话、翻译)进行额外训练,开箱即用。
- • 双向理解:内置一个轻量级的双向Transformer编码器,能同时从上下文两个方向捕捉关键信息,压缩得更准。
- • 更低延迟:整个压缩过程计算效率高,能有效缩短用户等待时间。
LLMLingua、LongLLMingua、LLMLingua-2
初始化压缩器
from llmlingua import PromptCompressor
# 使用 LLMLingua2 模型进行提示压缩
llm_lingua = PromptCompressor(
model_name="microsoft/llmlingua-2-bert-base-multilingual-cased-meetingbank",
use_llmlingua2=True,
device_map="cpu" # 明确指定使用CPU
)
加载数据
# 构建一个详细的医疗咨询场景
medical_context = """
患者基本信息:
姓名:张某,性别:男,年龄:45岁,职业:软件工程师
主诉:近3个月来反复出现胸闷、心悸,伴有头晕、乏力
病史:
现病史:患者3个月前开始出现间歇性胸闷、心悸,多在工作压力大或熬夜后出现,每次持续5-10分钟,休息后可缓解。近1个月症状加重,伴有头晕、乏力、失眠。无胸痛、气促、水肿。
既往史:5年前诊断为高血压,不规律服用降压药物。父亲有冠心病史,母亲有糖尿病史。
个人史:吸烟史20年,每日1包,偶尔饮酒。工作压力大,经常熬夜,缺乏运动。
...省略...
"""
# 测试问题
question = "根据以上病例,患者最可能的诊断是什么?"
初始化LLM
from langchain_deepseek import ChatDeepSeek
import os
from dotenv import load_dotenv
# 加载环境变量
load_dotenv()
# 初始化 DeepSeek LLM
llm = ChatDeepSeek(
model="deepseek-chat",
temperature=0.1, # 较低的温度以保证结果一致性
api_key=os.getenv("DEEPSEEK_API_KEY"),
)
使用 LLMLingua
压缩
compressed_result = llm_lingua.compress_prompt(
medical_context,
rate=0.6, # 压缩率
force_tokens=["!", "。", "?", "\n", ":", ",", ";", "(", ")", "、"], # 更全面的中文标点符号
drop_consecutive=True, # 删除连续重复的标记
use_sentence_level_filter=True, # 启用句子级过滤,保持句子完整性
use_token_level_filter=True, # 启用标记级过滤
use_context_level_filter=True, # 启用上下文级过滤
)
compressed_context = compressed_result["compressed_prompt"]
compressed_full_prompt = f"{compressed_context}\n\n问题:{question}\n回答:"
print(f"压缩后完整提示词:{compressed_full_prompt}")
测试LLM响应
response = llm.invoke(compressed_full_prompt)
response_content = response.content
print(f"响应内容: {response_content}")
不同压缩比例结果对比
==================================================
🔍 测试压缩提示的LLM响应...
==============================
🤖 压缩提示测试 (保留80%)
------------------------------
提示长度: 1957 字符
响应时间: 25.18 秒
响应长度: 806 字符
响应内容: 根据提供的病例信息,患者最可能的诊断是**冠心病:不稳定型心绞痛**,并伴有高血压病2级(中危)、血脂异常和焦虑状态。
**诊断依据如下:**
1. **冠心病:不稳定型心绞痛**
- **症状**:患者主诉反复胸闷、心悸3个月,近期加重,伴头晕、乏力。症状在工作压力大、熬夜时出现,持续5-10分钟可自行缓解,符合心绞痛特征(胸闷为常见心绞痛等效症状)。
- **危险因素**:男性、45岁、高血压病史5年、吸烟史20年(每天1包)、高脂血症(总胆固醇和LDL-C升高)、家族史(父亲有冠心病和糖尿病)。
- **辅助检查**:心电图显示窦性心律伴ST-T改变(提...
📊 质量评估:
🎯 医疗术语保留率: 108.3%
📋 结构完整性: 80.0%
⭐ 综合质量评分: 94.2%
==============================
🤖 压缩提示测试 (保留60%)
------------------------------
提示长度: 1449 字符
响应时间: 18.47 秒
响应长度: 634 字符
响应内容: 根据提供的病例信息,患者最可能的诊断是:
**1. 冠心病:不稳定型心绞痛**
- 支持点:患者有典型的心绞痛症状(间歇性胸闷、心悸,持续5-10分钟后可缓解),近期加重,心电图显示心肌缺血(ST-T改变),同时存在多个冠心病危险因素(高血压、吸烟史、血脂异常、缺乏运动)。
**2. 高血压病2级(中危组)**
- 支持点:血压测量为150/95 mmHg(符合2级高血压标准),并有靶器官损害表现(心电图心肌缺血改变)。
**3. 血脂异常**
- 支持点:总胆固醇6.2 mmol/L(升高)、低密度脂蛋白4.1 mmol/L(升高)、甘油三酯2.8 mmol/L(升高...
📊 质量评估:
🎯 医疗术语保留率: 100.0%
📋 结构完整性: 40.0%
⭐ 综合质量评分: 70.0%
总结
总而言之,面对大语言模型日益增长的上下文窗口,简单粗暴地“投喂”所有检索到的文档并非最优解。它不仅会导致响应延迟和成本飙升,还可能因信息过载而降低生成质量。因此,后检索压缩技术成为RAG中至关重要的一环。
无论是利用LangChain
框架中灵活多样的上下文压缩检索器(如基于LLM的抽取、基于嵌入的过滤),还是采用更为专注和高效的LLMLingua
这类专业提示词压缩工具,其核心目标都是一致的:在送入大模型前,对信息进行“降噪”和“精炼”。通过这些方法,我们可以在保证核心信息不丢失的前提下,有效提升系统的响应速度、降低运营成本,最终在效率、成本和性能之间找到最佳的平衡点。
最后
为什么要学AI大模型
当下,⼈⼯智能市场迎来了爆发期,并逐渐进⼊以⼈⼯通⽤智能(AGI)为主导的新时代。企业纷纷官宣“ AI+ ”战略,为新兴技术⼈才创造丰富的就业机会,⼈才缺⼝将达 400 万!
DeepSeek问世以来,生成式AI和大模型技术爆发式增长,让很多岗位重新成了炙手可热的新星,岗位薪资远超很多后端岗位,在程序员中稳居前列。
与此同时AI与各行各业深度融合,飞速发展,成为炙手可热的新风口,企业非常需要了解AI、懂AI、会用AI的员工,纷纷开出高薪招聘AI大模型相关岗位。
最近很多程序员朋友都已经学习或者准备学习 AI 大模型,后台也经常会有小伙伴咨询学习路线和学习资料,我特别拜托北京清华大学学士和美国加州理工学院博士学位的鲁为民老师给大家这里给大家准备了一份涵盖了AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频 全系列的学习资料,这些学习资料不仅深入浅出,而且非常实用,让大家系统而高效地掌握AI大模型的各个知识点。
这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费
】

AI大模型系统学习路线
在面对AI大模型开发领域的复杂与深入,精准学习显得尤为重要。一份系统的技术路线图,不仅能够帮助开发者清晰地了解从入门到精通所需掌握的知识点,还能提供一条高效、有序的学习路径。
但知道是一回事,做又是另一回事,初学者最常遇到的问题主要是理论知识缺乏、资源和工具的限制、模型理解和调试的复杂性,在这基础上,找到高质量的学习资源,不浪费时间、不走弯路,又是重中之重。
AI大模型入门到实战的视频教程+项目包
看视频学习是一种高效、直观、灵活且富有吸引力的学习方式,可以更直观地展示过程,能有效提升学习兴趣和理解力,是现在获取知识的重要途径
光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。
海量AI大模型必读的经典书籍(PDF)
阅读AI大模型经典书籍可以帮助读者提高技术水平,开拓视野,掌握核心技术,提高解决问题的能力,同时也可以借鉴他人的经验。对于想要深入学习AI大模型开发的读者来说,阅读经典书籍是非常有必要的。
600+AI大模型报告(实时更新)
这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。
AI大模型面试真题+答案解析
我们学习AI大模型必然是想找到高薪的工作,下面这些面试题都是总结当前最新、最热、最高频的面试题,并且每道题都有详细的答案,面试前刷完这套面试题资料,小小offer,不在话下
这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费
】

更多推荐
所有评论(0)