处理长文本提取的最佳实践:分块与RAG方法详解

232 阅读2分钟

引言

在处理长文本(如PDF文件)时,常常面临超过语言模型上下文窗口的文本。这就需要我们采取一些策略来有效地处理这些数据。本文将重点介绍如何实现两种策略:分块(Brute Force)和检索增强生成(RAG)。

主要内容

分块处理方法

分块是一种简单而有效的处理长文本的方式。可以将文档切分成多个小块,每个小块都适合语言模型的上下文窗口,然后对每个小块进行内容提取。

设置

首先,我们需要准备示例数据。在本例中,我们将从维基百科下载一篇关于汽车的文章,并将其加载为LangChain文档。

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)
# 使用HTML解析器加载
loader = BSHTMLLoader("car.html")
document = loader.load()[0]

# 清理代码
document.page_content = re.sub("\n\n+", "\n", document.page_content)

定义提取模式

我们将使用Pydantic来定义提取的信息模式。

from typing import List
from langchain_core.pydantic_v1 import BaseModel, Field

class KeyDevelopment(BaseModel):
    year: int = Field(..., description="历史发展的年份。")
    description: str = Field(..., description="描述发生了什么发展。")
    evidence: str = Field(..., description="从文章中提取的原始句子。")

class ExtractionData(BaseModel):
    key_developments: List[KeyDevelopment]

创建提取器

选择合适的LLM,并使用LangChain中的工具。

from langchain_openai import ChatOpenAI

# 使用API代理服务提高访问稳定性
llm = ChatOpenAI(model="gpt-4-0125-preview", temperature=0)

extractor = prompt | llm.with_structured_output(
    schema=ExtractionData,
    include_raw=False,
)

分块处理

from langchain_text_splitters import TokenTextSplitter

text_splitter = TokenTextSplitter(chunk_size=2000, chunk_overlap=20)
texts = text_splitter.split_text(document.page_content)

# 仅限于前三个块以便快速运行
first_few = texts[:3]
extractions = extractor.batch(
    [{"text": text} for text in first_few],
    {"max_concurrency": 5},
)

RAG方法

这种方法涉及将文本分块并仅从最相关的块中提取信息。

from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings

texts = text_splitter.split_text(document.page_content)
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("关于汽车的一些关键发展")

常见问题和解决方案

  • 重复提取: 大块重叠可能导致信息重复,需去重。
  • 信息遗漏: 信息分散在多个块中时,提取可能会失败。
  • 虚假数据: 在大文本中寻找单一事实时,可能会遇到生成错误数据。

总结和进一步学习资源

处理长文本时,选择合适的方法至关重要。本文提供的两种方法各有优劣,建议根据具体应用场景进行选择。

参考资料

  • LangChain API 文档
  • 维基百科 - 汽车

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

---END---