从零搭建智能文档中枢:基于大语言模型的文档自动处理与问答系统

发布时间:2026/6/28 10:33:00
从零搭建智能文档中枢:基于大语言模型的文档自动处理与问答系统 引言在企业数字化转型浪潮中大量非结构化文档合同、报告、手册、邮件成为沉睡的数据资产。传统关键词搜索效率低、语义理解弱而大语言模型LLM虽然知识渊博却无法直接访问企业内部文档且存在幻觉问题。将LLM与文档检索结合的检索增强生成RAG技术成为智能文档处理的核心范式。本文将带你从零实现一个基于LLM的文档智能处理系统它能自动加载多种格式的本地文档将内容向量化存储并用自然语言提问获得精准答案。我们将使用LangChain作为编排框架Chroma作为向量数据库OpenAI提供大模型能力最终构建一个在命令行即可交互的文档问答机器人。所有代码完整可运行注释详尽可直接复现。核心概念RAG 为什么是文档智能的基石RAGRetrieval-Augmented Generation的工作流程分为三步文档索引Indexing将文档分割成合适大小的块使用嵌入模型将每个块转换为向量存入向量数据库。检索Retrieval用户提问时同样将问题向量化在向量库中搜索最相似的Top-K个文档块。生成Generation将检索到的文档块作为上下文连同问题一起送入LLM生成准确的回答。这样做的好处显而易见LLM能基于企业私有数据回答问题且答案可追溯来源大幅降低幻觉。LangChain提供了即插即用的组件能轻松串联整个流程。实战构建可运行的文档智能问答系统下面是完整的项目实现。我们将创建一个Python脚本支持pdf、docx、txt格式使用OpenAI的gpt-3.5-turbo和text-embedding-ada-002模型。运行前请确保已安装以下依赖pip install langchain langchain-openai chromadb pypdf docx2txt同时需要设置环境变量OPENAI_API_KEY。完整代码创建文件doc_qa.py代码如下import os import sys from langchain_openai import OpenAIEmbeddings, ChatOpenAI from langchain_chroma import Chroma from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.chains import RetrievalQA from langchain.document_loaders import PyPDFLoader, Docx2txtLoader, TextLoader from langchain.schema import Document # -------------------- 1. 加载多种格式文档 -------------------- def load_documents(file_path: str) - list[Document]: 根据文件扩展名选择合适的加载器返回Document对象列表。 支持pdf, docx, txt ext os.path.splitext(file_path)[1].lower() if ext .pdf: loader PyPDFLoader(file_path) elif ext .docx: loader Docx2txtLoader(file_path) elif ext .txt: loader TextLoader(file_path, encodingutf-8) else: raise ValueError(f不支持的文件格式: {ext}) return loader.load() # -------------------- 2. 文档分割 -------------------- def split_documents(documents: list[Document], chunk_size500, chunk_overlap50) - list[Document]: 使用递归字符分割器保持语义连贯性。 chunk_size: 每块最大字符数 chunk_overlap: 相邻块重叠字符数防止关键信息被截断 splitter RecursiveCharacterTextSplitter( chunk_sizechunk_size, chunk_overlapchunk_overlap, separators[\n\n, \n, 。, , , , , , ] # 中文优先 ) return splitter.split_documents(documents) # -------------------- 3. 建立向量存储 -------------------- def create_vector_store(docs: list[Document], persist_dir: str doc_vectordb): 使用OpenAI嵌入模型将文档块向量化存入Chroma本地持久化目录。 若目录已存在则直接加载避免重复计算。 embeddings OpenAIEmbeddings(modeltext-embedding-ada-002) if os.path.exists(persist_dir) and os.listdir(persist_dir): print(检测到已有向量库直接加载...) vectordb Chroma(persist_directorypersist_dir, embedding_functionembeddings) else: print(正在向量化文档并存储...) vectordb Chroma.from_documents( documentsdocs, embeddingembeddings, persist_directorypersist_dir ) return vectordb # -------------------- 4. 构建问答链 -------------------- def build_qa_chain(vectordb): 创建一个RetrievalQA链使用GPT-3.5-turbo生成答案。 检索器使用向量相似度搜索返回4个最相关文档块。 llm ChatOpenAI(modelgpt-3.5-turbo, temperature0) retriever vectordb.as_retriever(search_kwargs{k: 4}) qa_chain RetrievalQA.from_chain_type( llmllm, chain_typestuff, # 将检索到的文档直接拼接作为上下文 retrieverretriever, return_source_documentsTrue # 返回来源文档便于验证 ) return qa_chain # -------------------- 主程序 -------------------- def main(): if len(sys.argv) 2: print(用法: python doc_qa.py 文档路径) sys.exit(1) file_path sys.argv[1] if not os.path.exists(file_path): print(f文件不存在: {file_path}) sys.exit(1) # 1. 加载文档 print(f正在加载文档: {file_path}) raw_docs load_documents(file_path) print(f文档加载完毕页数/段落数: {len(raw_docs)}) # 2. 分割文档 docs split_documents(raw_docs) print(f分割为 {len(docs)} 个文本块) # 3. 建立向量库持久化到 doc_vectordb 目录 vectordb create_vector_store(docs) # 4. 构建问答链 qa build_qa_chain(vectordb) # 5. 交互式问答 print(\n文档问答系统已就绪输入问题exit 退出clr 清空历史) while True: query input(\n用户: ).strip() if query.lower() in [exit, quit]: break if query.lower() clr: vectordb.delete_collection() vectordb create_vector_store(docs) qa build_qa_chain(vectordb) print(向量库已重置) continue if not query: continue try: result qa.invoke({query: query}) answer result[result] sources result[source_documents] print(f助手: {answer}) # 显示引用的文档片段截取前80字符 if sources: print(- * 50) for i, doc in enumerate(sources): source doc.metadata.get(source, 未知来源) snippet doc.page_content.replace(\n, )[:80] print(f 来源{i1}: {source} - {snippet}...) except Exception as e: print(f出错了: {e}) if __name__ __main__: main()使用说明准备一份PDF/Word/TXT文件例如企业年报.pdf。在终端执行bash python doc_qa.py 企业年报.pdf系统会加载文档、分割、向量化并持久化到doc_vectordb目录。再次运行时直接加载无需重复计算。输入问题如“去年的总营收是多少”助手将给出基于文档的精准回答并打印引用的片段和来源页码。代码要点解析多格式加载器通过判断扩展名选用PyPDFLoader、Docx2txtLoader、TextLoader实现统一接口。中文友好分割RecursiveCharacterTextSplitter的分隔符列表中包含中文标点。优先在句末截断保持语义完整。持久化向量库Chroma支持本地磁盘存储避免每次运行都重新嵌入节省Token开销。通过检查目录是否存在来决定新建还是加载。来源追溯return_source_documentsTrue返回源头文档便于验证答案是否忠于原文。清空历史功能输入clr可删除集合并重建方便更换文档或重置。运行截图展示文字描述加载文档后向量化耗时约数秒取决于文档大小问答过程实时返回来源信息清晰可读。常见问题与注意事项1. 处理超大文档或批量文档怎么办本示例加载单个文件但load_documents可以轻松扩展为遍历文件夹将所有文档合并后统一分割索引。对于巨大文档如数百页可适当调大chunk_size如1000减少块数量同时增大k检索数量以获取更全面的上下文。若文档数量过多导致向量库过大可考虑使用Chroma的元数据过滤或更换为FAISS等索引。2. 中文文档效果不佳如何优化分割时使用中文标点优先分隔我们已配置。嵌入模型选择text-embedding-ada-002在多语言表现良好但若完全中文场景可尝试BAAI的bge-large-zh等国产模型需替换嵌入层。LLM本身的理解能力GPT-3.5对中文支持尚可复杂长文建议使用GPT-4或通义千问等。3. 成本控制API费用嵌入成本文档每1千tokens约$0.0001向量化10万字约$0.01。持久化向量库是核心省钱策略。对话成本每次问答会将问题检索到的上下文拼接发给LLM上下文越多费用越高。可通过调整k值和chunk_size平衡成本与效果。免费替代可切换为Ollama本地模型如llama2、qwen只需更换Embeddings和LLM对象LangChain社区有对应封装。4. 多轮对话支持当前实现是一问一答无历史记忆。如需多轮对话可引入ConversationalRetrievalChain并使用带记忆的聊天模型LangChain提供了ConversationBufferMemory等组件。修改时注意上下文长度控制。5. 实时更新索引当源文档改动时需重新索引。可在代码中增加文件哈希校验只在文件变化时重建向量库或利用Chroma的增量添加功能删除旧文档ID再添加新文档。6. 安全与权限本系统运行在本地但向量库和LLM调用可能涉及敏感数据上传OpenAI。企业内部部署建议使用私有化大模型例如通过FastChat部署的Vicuna和本地嵌入服务避免数据外泄。此外对用户提问也应进行适当过滤。总结本文从零搭建了一个基于大语言模型的文档智能处理系统涵盖了文档加载、智能分割、向量化存储、检索增强生成的全流程。通过LangChain的强大抽象我们用不到150行代码就实现了支持多种格式、持久化、可追溯的文档问答机器人。这个系统不仅是一个Demo更可以作为企业知识库、合同审查、档案管理等场景的原型基础。扩展方向包括支持更多文档类型HTML、Markdown、引入OCR处理扫描件、结合结构数据实现表格问答、部署为Web服务等。RAG技术的边界正在不断被拓展但核心始终是让大模型扎根于真实、可靠的数据。希望这篇实战能帮助你快速上手在业务中释放文档的价值。参考资料- LangChain官方文档https://python.langchain.com- Chroma使用指南https://docs.trychroma.com- RAG论文Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks