如何处理长文本进行信息抽取

在处理长文本文件(如PDF)时,我们可能会遇到文本长度超过语言模型的上下文窗口的问题。为了解决这一问题,我们可以考虑以下策略:

  1. 更换LLM:选择支持更大上下文窗口的LLM。
  2. 暴力拆分:将文档分块,并从每个块中提取内容。
  3. RAG(检索增强生成):分块文档,索引这些块,然后仅从看似“相关”的子集块中提取内容。

本文将展示如何实现策略2和策略3。

技术背景介绍

在大多数实际场景中,长文本处理的挑战主要体现在如何有效分割并处理文本数据,以便在不影响准确度的情况下最大化信息提取。上下文窗口的限制促使我们寻找替代方法来解决这一问题。

核心原理解析

暴力拆分:通过将文本分块,使每个块能够适应模型的上下文窗口,从而逐块提取内容。

RAG方法:通过向量存储索引文本块,并添加检索步骤以确保处理最相关的文本块。

代码实现演示

初始化环境

首先,我们需要下载一些示例数据并加载为文档。

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))  # 输出文档长度
信息抽取的模式定义

使用Pydantic定义我们希望从文本中抽取的信息模式,包括年份、描述以及相关证据。

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

client = openai.OpenAI(
    base_url='https://yunwu.ai/v1',  # 国内稳定访问
    api_key='your-api-key'
)

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],
    {"max_concurrency": 5}  # 限制并发
)
RAG方法实现

使用FAISS向量存储来索引文档块,并执行检索增强生成(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("汽车相关的关键发展")

应用场景分析

暴力拆分适用于全文都可能含有有用信息的场景,而RAG则适用于文本内信息密度较低且关键信息分布不均的场景。

实践建议

  • 在使用暴力拆分时,要注意块间重叠可能导致重复数据的提取。
  • 在RAG方法中,选择合适的检索策略以确保对文本块的相关信息进行合理筛选。

如果遇到问题欢迎在评论区交流。

—END—

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值