引言
在处理大型文件(如PDF)时,常常面临文本长度超出语言模型(LLM)上下文窗口的问题。为了有效处理这些文本,开发者可以采用几种策略。本篇文章将深入探讨其中的两种策略:'暴力法'和'检索增强生成(RAG)'。我们的目标是帮助读者了解如何在文本提取任务中应对长文本,同时提供实用的代码示例和解决方案。
主要内容
改变LLM
首先,选择支持更大上下文窗口的LLM是一种解决方案。然而,这可能需要付出更多的资源或成本。
暴力法
暴力法涉及将文档分块,并从每个分块中提取内容。
from langchain_text_splitters import TokenTextSplitter
# 初始化文本分割器
text_splitter = TokenTextSplitter(chunk_size=2000, chunk_overlap=20)
# 执行分块操作
texts = text_splitter.split_text(document.page_content)
如何并行化处理
利用并行功能可以加速每个分块的提取过程,通过使用线程池来并行化工作负载。
extractions = extractor.batch(
[{"text": text} for text in first_few],
{"max_concurrency": 5}, # 限制并发数量
)
RAG方法
RAG方法则是在文本中索引分块,仅从看似“相关”的子集分块中提取内容。
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
# 使用FAISS进行文本索引
vectorstore = FAISS.from_texts(texts, embedding=OpenAIEmbeddings())
retriever = vectorstore.as_retriever(search_kwargs={"k": 1})
整合步骤
使用向量存储的检索步骤来引导提取过程。
rag_extractor = {
"text": retriever | (lambda docs: docs[0].page_content)
} | extractor
results = rag_extractor.invoke("Key developments associated with cars")
代码示例
下面是使用暴力法进行文本提取的完整代码示例:
import re
import requests
from langchain_community.document_loaders import BSHTMLLoader
# 下载和加载文档
response = requests.get("https://en.wikipedia.org/wiki/Car")
with open("car.html", "w", encoding="utf-8") as f:
f.write(response.text)
loader = BSHTMLLoader("car.html")
document = loader.load()[0]
document.page_content = re.sub("\n\n+", "\n", document.page_content)
print(len(document.page_content))
常见问题和解决方案
-
信息跨多个分块:LLM可能无法提取分布在多个分块中的信息。解决方案是增加分块重叠度。
-
重复信息:过大的分块重叠可能导致信息被提取多次。可以通过去重过程解决。
-
生成虚假数据:在广大文本中使用暴力法寻找单一事实时,可能会得到虚假数据。需谨慎验证生成的数据。
总结和进一步学习资源
了解不同文本提取策略的优劣,以及如何根据具体应用场景选择合适的方法是成功的关键。对于进一步的研究和学习,建议参考以下资源:
- LangChain Documentation # 使用API代理服务提高访问稳定性
- Pydantic Schema
- FAISS Vector Store
参考资料
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!
---END---