如何通过PDF预处理提升LLM聊天机器人的交互智能与问答精准度?
针对含相似子主题PDF的问答机器人优化方案
一、PDF预处理优化:按子主题精准分割
固定长度分割会破坏子主题的语义完整性,导致相似概念的片段混杂,优先采用基于语义/标题层级的分割策略:
基于PDF标题层级拆分:利用PyMuPDF提取文档的标题(如H1、H2层级),将同一标题下的内容作为一个完整片段,避免相似子主题的内容被拆分到不同片段中。
import fitz # PyMuPDF from langchain.schema import Document def split_pdf_by_headings(pdf_path): doc = fitz.open(pdf_path) chunks = [] current_heading = "" current_content = "" for page in doc: blocks = page.get_text("blocks") for block in blocks: text = block[4].strip() # 根据字体位置、样式判断标题(可根据实际PDF格式调整) if block[1] < 50 and "bold" in block[5].lower(): if current_heading and current_content: chunks.append(Document(page_content=current_content, metadata={"heading": current_heading})) current_heading = text current_content = "" else: current_content += text + "\n" # 添加最后一个子主题片段 if current_heading and current_content: chunks.append(Document(page_content=current_content, metadata={"heading": current_heading})) return chunks语义感知分割:使用LangChain的
RecursiveCharacterTextSplitter,通过指定段落、标题分隔符,确保拆分后的片段保留完整语义:from langchain.text_splitter import RecursiveCharacterTextSplitter text_splitter = RecursiveCharacterTextSplitter( chunk_size=1000, chunk_overlap=100, separators=["\n\n", "\n", " ", ""] ) # 传入原始文档对象执行分割 chunks = text_splitter.split_documents(raw_documents)
二、向量库与检索逻辑优化
1. 子主题元数据过滤检索
给每个片段添加子主题标签(从标题提取),检索时先基于元数据筛选相关子主题的片段,再进行语义匹配,减少相似概念的干扰:
from langchain.vectorstores import Chroma from langchain.embeddings.openai import OpenAIEmbeddings from langchain.chains import RetrievalQA # 初始化带元数据的向量库 embeddings = OpenAIEmbeddings() db = Chroma.from_documents(chunks, embeddings) # 构建指定子主题的检索器 def get_topic_retriever(target_topic): retriever = db.as_retriever( search_kwargs={"filter": {"heading": {"$contains": target_topic}}, "k": 3} ) return retriever # 调用时先分析问题对应的子主题,再使用对应检索器生成回答 qa_chain = RetrievalQA.from_chain_type( llm=OpenAI(), chain_type="stuff", retriever=get_topic_retriever("用户问题关联的子主题") )
2. 混合检索策略
结合关键词检索和语义检索:先用关键词匹配子主题标签缩小范围,再在范围内做语义检索,提升泛化问题的准确性:
from langchain.retrievers import BM25Retriever, EnsembleRetriever # BM25关键词检索器(基于标题元数据) bm25_retriever = BM25Retriever.from_documents(chunks) bm25_retriever.k = 3 # 语义检索器 semantic_retriever = db.as_retriever(k=3) # 加权融合两种检索结果 ensemble_retriever = EnsembleRetriever( retrievers=[bm25_retriever, semantic_retriever], weights=[0.4, 0.6] ) # 构建混合检索的问答链 qa_chain = RetrievalQA.from_chain_type( llm=OpenAI(), chain_type="stuff", retriever=ensemble_retriever )
三、LLM调用逻辑优化
1. 针对性提示词约束
在提示词中明确要求LLM先识别问题涉及的子主题,再从对应片段提取信息,避免混淆相似概念:
from langchain.prompts import PromptTemplate prompt_template = """处理用户提问请遵循以下规则: 1. 先明确用户问题指向的具体子主题; 2. 仅从与该子主题匹配的文档片段中提取信息; 3. 不得混淆其他相似子主题的内容,确保回答精准对应问题主题。 文档片段: {context} 用户问题:{question} 回答:""" PROMPT = PromptTemplate( template=prompt_template, input_variables=["context", "question"] ) qa_chain = RetrievalQA.from_chain_type( llm=OpenAI(), chain_type="stuff", retriever=ensemble_retriever, chain_type_kwargs={"prompt": PROMPT} )
2. 多文档汇总链
对于需要跨子主题的泛化问题,使用MapReduceDocumentsChain先分别处理各子主题内容,再汇总生成准确回答:
from langchain.chains.summarize import load_summarize_chain from langchain.chains import RetrievalQA # 构建Map-Reduce汇总链 map_reduce_chain = load_summarize_chain( llm=OpenAI(), chain_type="map_reduce", return_intermediate_steps=False ) # 用汇总链作为QA的核心逻辑 qa_chain = RetrievalQA.from_chain_type( llm=OpenAI(), chain_type="map_reduce", retriever=ensemble_retriever )
内容的提问来源于stack exchange,提问作者Pool Nolasco
相关产品推荐
相关产品推荐

