引言
在信息检索中,一个主要的挑战是,当你将数据输入到文档存储系统时,你往往不能确切知道系统会面临的查询。这意味着与查询最相关的信息可能被埋没在包含大量无关文本的文档中。将完整的文档通过应用程序传递给用户可能导致与大语言模型 (LLM) 的交互成本增加并影响响应质量。上下文压缩就是为了解决这个问题而设计的。其理念很简单:在返回检索到的文档之前,你可以基于给定查询对它们进行压缩,以便仅返回与查询相关的信息。“压缩”不仅是指压缩个别文档的内容,也包括对整份文档进行筛选。
本文旨在详细介绍如何在信息检索中实施上下文压缩,并提供实用的代码示例。
主要内容
基础向量存储检索器
首先,让我们初始化一个简单的向量存储检索器,并将2023年国情咨文(以块形式)存储进去。可以看到,针对一个示例性问题,我们的检索器返回了一两个相关的文档以及一些无关的文档。即使是相关的文档,其中也包含许多无关的信息。
from langchain_community.document_loaders import TextLoader
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
from langchain_text_splitters import CharacterTextSplitter
documents = TextLoader("state_of_the_union.txt").load()
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
texts = text_splitter.split_documents(documents)
retriever = FAISS.from_documents(texts, OpenAIEmbeddings()).as_retriever()
def pretty_print_docs(docs):
print(
f"\n{'-' * 100}\n".join(
[f"Document {i+1}:\n\n" + d.page_content for i, d in enumerate(docs)]
)
)
docs = retriever.invoke("What did the president say about Ketanji Brown Jackson")
pretty_print_docs(docs)
使用上下文压缩技术改进检索效果
我们可以使用上下文压缩检索器,通过 LLMChainExtractor 提取与查询相关的内容。
from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import LLMChainExtractor
from langchain_openai import OpenAI
llm = OpenAI(temperature=0) # 使用API代理服务提高访问稳定性
compressor = LLMChainExtractor.from_llm(llm)
compression_retriever = ContextualCompressionRetriever(
base_compressor=compressor, base_retriever=retriever
)
compressed_docs = compression_retriever.invoke(
"What did the president say about Ketanji Jackson Brown"
)
pretty_print_docs(compressed_docs)
更多内置压缩器:过滤器
LLMChainFilter
LLMChainFilter 是一个稍微简单但更健壮的压缩器,它使用 LLM 链决定最初检索到的哪些文档应该被过滤掉,哪些应该返回,而不操纵文档内容。
from langchain.retrievers.document_compressors import LLMChainFilter
_filter = LLMChainFilter.from_llm(llm)
compression_retriever = ContextualCompressionRetriever(
base_compressor=_filter, base_retriever=retriever
)
compressed_docs = compression_retriever.invoke(
"What did the president say about Ketanji Jackson Brown"
)
pretty_print_docs(compressed_docs)
串接压缩器和文档转换器
通过 DocumentCompressorPipeline,我们还可以很容易地按顺序组合多个压缩器。以下是创建压缩器管道的示例。
from langchain.retrievers.document_compressors import DocumentCompressorPipeline
from langchain_community.document_transformers import EmbeddingsRedundantFilter
from langchain_text_splitters import CharacterTextSplitter
splitter = CharacterTextSplitter(chunk_size=300, chunk_overlap=0, separator=". ")
redundant_filter = EmbeddingsRedundantFilter(embeddings=embeddings)
pipeline_compressor = DocumentCompressorPipeline(
transformers=[splitter, redundant_filter]
)
compression_retriever = ContextualCompressionRetriever(
base_compressor=pipeline_compressor, base_retriever=retriever
)
compressed_docs = compression_retriever.invoke(
"What did the president say about Ketanji Jackson Brown"
)
pretty_print_docs(compressed_docs)
常见问题和解决方案
- 网络访问限制:在某些地区,访问外部API可能存在网络限制,建议使用API代理服务以提高访问的稳定性。
- 匹配精度问题:确保在使用诸如
EmbeddingsFilter等工具时,合理设置相似度阈值以确保文档的准确匹配。
总结和进一步学习资源
本文探讨了如何通过上下文压缩技术提高文档检索的效率和准确性。通过应用上下文压缩,能有效减少无关信息的干扰,提升系统的响应速度。希望本文的示例能为您提供实践指导。
进一步学习资源:
参考资料
- Langchain 文档:Langchain Documentation
- OpenAI API 参考:OpenAI API
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!
---END---