如何处理长文本提取:深入解析与实用指南

265 阅读2分钟

引言

在处理大型文件(如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))

常见问题和解决方案

  1. 信息跨多个分块:LLM可能无法提取分布在多个分块中的信息。解决方案是增加分块重叠度。

  2. 重复信息:过大的分块重叠可能导致信息被提取多次。可以通过去重过程解决。

  3. 生成虚假数据:在广大文本中使用暴力法寻找单一事实时,可能会得到虚假数据。需谨慎验证生成的数据。

总结和进一步学习资源

了解不同文本提取策略的优劣,以及如何根据具体应用场景选择合适的方法是成功的关键。对于进一步的研究和学习,建议参考以下资源:

参考资料

如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!

---END---