如何有效处理长文本进行信息提取

如何有效处理长文本进行信息提取

在处理文本文件(如PDF)时,你可能会遇到超出语言模型上下文窗口长度的文本。为了有效处理这些文本,可以考虑以下策略:

  1. 更换语言模型:选择支持较大上下文窗口的不同语言模型。
  2. 暴力分块处理:将文档拆分为小块,并从每个块中提取内容。
  3. 检索增强生成(RAG):将文档分块、索引,并仅从看似“相关”的子块中提取内容。

请注意,这些策略各有利弊,最佳策略取决于你设计的应用程序!本指南将演示如何实现策略2和3。

设置

我们需要一些示例数据!让我们下载来自Wikipedia的关于汽车的文章,并将其加载为LangChainDocument。

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)

# 显示内容长度
print(len(document.page_content))  # 应输出:79174

定义信息提取模式

按照信息提取教程,我们将使用Pydantic定义我们希望提取的信息的模式。这里,我们将提取包含年份和描述的“重要发展”列表。

from typing import List, Optional
from langchain_core.prompts import ChatPromptTemplate
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]

# 定义自定义提示以提供说明和额外的上下文。
prompt = ChatPromptTemplate.from_messages([
    (
        "system",
        "您是一名擅长从文本中识别关键历史发展的专家。"
        "仅提取重要的历史发展。如果找不到重要信息则不提取。",
    ),
    ("human", "{text}"),
])

创建提取器

选择一个支持工具调用功能的语言模型(LLM)。你可以选择OpenAI、Google、Cohere等提供商的模型。

这里我们以OpenAI的GPT-4为例:

import os
from langchain_openai import ChatOpenAI

os.environ["OPENAI_API_KEY"] = "your-openai-api-key"  # 使用API代理服务提高访问稳定性

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

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

暴力分块处理

将文档拆分为适合LLM上下文窗口大小的块。

from langchain_text_splitters import TokenTextSplitter

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

texts = text_splitter.split_text(document.page_content)

并行地运行提取:

# 仅限前3个块以便快速重新运行代码
first_few = texts[:3]

extractions = extractor.batch(
    [{"text": text} for text in first_few],
    {"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_core.documents import Document
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可能无法提取分布在多个块中的信息。
  • 重复信息:如果块间重叠较大,相同信息可能被提取两次,需要去重。
  • 数据虚构:如果在大量文本中寻找单一事实,可能会得到虚构的数据。

总结与进一步学习资源

在处理长文本时,选择合适的方法至关重要。以上示例展示了如何通过暴力处理和RAG方法有效提取信息。可以参考以下资料以获取更多信息:

  1. LangChain Documentation
  2. OpenAI GPT Models Documentation
  3. FAISS Documentation

参考资料

  • LangChain Documentation
  • OpenAI API Docs
  • FAISS Official Website

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值