引言
在处理长文本文件时,如PDF,您可能会遇到超出语言模型上下文窗口的文本。本文旨在介绍几种策略,以帮助您在这种情况下进行信息提取。
主要内容
改变LLM
选择支持更大上下文窗口的不同LLM。
暴力分块策略
将文档划分为小块,并从每个块中提取内容。
RAG策略
划分文档、索引块,仅从“相关”块的子集提取内容。需要注意的是,各种策略有不同的权衡,最佳策略取决于您的具体应用。
以下是如何实现策略2和3的指南。
代码示例
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]
创建提取器
from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages(
[
("system", "你是识别文本中关键历史发展的专家。"),
("human", "{text}"),
]
)
from langchain_openai import ChatOpenAI
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)
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])
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("关于汽车的关键发展")
for key_development in results.key_developments:
print(key_development)
常见问题和解决方案
- 信息分块问题:如果信息跨多个块,LLM可能会提取失败。解决方案是优化分块策略。
- 重复信息:大块重叠可能导致重复信息。解决方案是去重处理。
总结和进一步学习资源
长文本处理需要根据具体应用选择合适的策略。建议进一步学习关于LLM上下文窗口和RAG方法的资料。
参考资料
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!
---END---