如何用Langchain提取PDF数据对接ChatGPT?及响应异常排查
解决Langchain与ChatGPT集成的PDF数据处理问题
核心问题定位
你遇到的问题本质是混淆了OpenAIEmbeddings的作用:它是用来生成文本向量做相似度检索的,不能直接作为文本输入ChatGPT。ChatGPT需要的是结构化的上下文文本片段,结合你的问题一起输入才能生成准确响应。
完整实现流程代码
下面是覆盖你需求的端到端代码,包含PDF提取、文本处理、向量检索与ChatGPT集成:
1. 依赖安装
pip install langchain openai unstructured pdf2image python-dotenv
2. 完整代码示例
import os from dotenv import load_dotenv from langchain.document_loaders import UnstructuredFileLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.embeddings.openai import OpenAIEmbeddings from langchain.vectorstores import Chroma from langchain.chat_models import ChatOpenAI from langchain.chains import RetrievalQA # 加载环境变量(存储OpenAI API密钥) load_dotenv() os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY") # 步骤1:提取PDF文本 loader = UnstructuredFileLoader("your_pdf_file.pdf") documents = loader.load() # 步骤2:文本分割(解决上下文窗口限制,同时保留语义连贯性) text_splitter = RecursiveCharacterTextSplitter( chunk_size=1000, # 每个文本块的字符数,可根据模型调整 chunk_overlap=200, # 块间重叠字符,避免语义断裂 length_function=len, ) split_docs = text_splitter.split_documents(documents) # 步骤3:生成向量并存储到本地向量库 embeddings = OpenAIEmbeddings(model="text-embedding-ada-002") db = Chroma.from_documents(split_docs, embeddings, persist_directory="./chroma_db") db.persist() # 步骤4:构建检索+生成链,集成ChatGPT llm = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0) # temperature=0保证输出稳定 qa_chain = RetrievalQA.from_chain_type( llm=llm, chain_type="stuff", # 适合短文本,其他可选map_reduce、refine等 retriever=db.as_retriever(search_kwargs={"k": 3}), # 检索最相关的3个文本块 return_source_documents=True # 返回引用的原文片段,方便验证 ) # 测试查询 query = "请基于PDF内容,解释XX概念?" result = qa_chain({"query": query}) # 输出结果 print("回答:", result["result"]) print("\n引用的原文片段:") for doc in result["source_documents"]: print("-", doc.page_content[:200], "...")
关键优化建议
- 文本分割参数调整:如果回答不准确,可尝试调整
chunk_size(比如800-1500)和chunk_overlap(100-300),确保关键信息不会被分割到不同块中。 - 检索策略优化:
search_kwargs={"k":3}控制返回的相关文本数量,k值过大可能导致上下文溢出,过小可能遗漏关键信息,可根据问题复杂度调整。 - Prompt自定义:如果默认的chain prompt效果不好,可自定义prompt明确要求模型基于给定上下文回答,示例:
from langchain.prompts import PromptTemplate custom_prompt = PromptTemplate( template="请严格基于以下提供的PDF上下文内容回答问题:\n{context}\n\n问题:{question}\n回答:", input_variables=["context", "question"] ) qa_chain = RetrievalQA.from_chain_type( llm=llm, chain_type="stuff", retriever=db.as_retriever(), chain_type_kwargs={"prompt": custom_prompt} ) - 结构化数据提取:如果需要提取PDF中的表格、特定字段等结构化数据,可替换
UnstructuredFileLoader为UnstructuredPDFLoader并指定mode="elements",或者结合正则表达式、LLM直接提取结构化信息:# 提取PDF中的结构化元素(如表格、标题) loader = UnstructuredPDFLoader("your_pdf_file.pdf", mode="elements") elements = loader.load() # 过滤出表格元素 tables = [e for e in elements if e.metadata["category"] == "Table"]
常见问题排查
- 如果ChatGPT回答“无法找到相关信息”:检查向量库是否正确生成,可通过
db.similarity_search("你的问题")查看返回的文本块是否包含相关内容; - 如果API调用报错:确认OpenAI API密钥有效且余额充足,同时检查网络连接;
- 如果回答偏离上下文:调整temperature为0,确保模型严格基于给定信息生成,避免幻觉。
内容的提问来源于stack exchange,提问作者Ashweeni Kulkarni
相关产品推荐
相关产品推荐

