# 引言
在处理PDF等大文件时,您可能会遇到文本超出语言模型(LLM)上下文窗口的问题。这篇文章将介绍几种策略以有效处理这种情况,尤其是关注如何通过分块(Brute Force)和检索增强生成(RAG)方法来提取有用的信息。
# 主要内容
## 选择合适的LLM或策略
对于长文本提取,以下几种策略可供选择:
1. **更换LLM**:选择支持较大上下文窗口的LLM。
2. **分块处理**:将文档分块,并从每个块中提取内容。
3. **RAG方法**:将文档分块、索引,重点提取最相关的部分。
每种方法各有优劣,具体应用时需根据您的项目需求选择合适的策略。
## 实现分块和RAG的准备工作
首先,获取待处理的文本数据,并进行适当的清理和格式化。
```python
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)
代码示例
定义数据提取模式
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进行提取:
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4-0125-preview", temperature=0)
分块方法实现
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 texts[:3]], # 仅限于前三个块以加快执行速度
{"max_concurrency": 5},
)
# 合并结果
key_developments = []
for extraction in extractions:
key_developments.extend(extraction.key_developments)
RAG方法实现
from langchain_community.vectorstores import FAISS
from langchain_core.documents import Document
from langchain_openai import OpenAIEmbeddings
from langchain_text_splitters import CharacterTextSplitter
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("Key developments associated with cars")
for key_development in results.key_developments:
print(key_development)
常见问题和解决方案
- 信息跨块分布:信息的分布可能导致提取不完整。增加块重叠可以部分解决此问题。
- 重复提取:较大的块重叠可能导致相同信息多次提取,需要进行去重操作。
- 数据虚构:LLMs可能生成虚假数据,需要对提取结果进行额外验证。
总结和进一步学习资源
本文详细介绍了如何通过分块和RAG方法处理长文本的提取问题。更多关于LLM和自然语言处理的深入讲解,可参考以下资源:
参考资料
- LangChain 文档
- OpenAI API 文档
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!
---END---