【程序员必藏】从零构建大模型文档解析系统:LangGraph+MCP实战,自动生成带图表报告

本文介绍基于LangGraph和MCP的智能文档处理系统,可自动解析多种格式文档(PDF、Word、PPT等),提取关键信息并生成结构化报告。系统采用PyMuPDF+MinerU框架进行文档解析,结合多Agent架构实现高效处理,支持私有化部署保障数据安全。全流程无需人工干预,可扩展性强,为企业文档处理提供了自动化解决方案。


大模型如何读懂任何格式文件并自动生成报告?LangGraph + MCP 实战解析

无需人工干预,上传任何文件即可生成带图表的报告,支持私有化部署。

作者:大模型知识分享员
发布时间:2025年10月11日


在信息爆炸的时代,企业每天都在产生海量的非结构化文档——市场调研报告、用户反馈、技术白皮书、会议纪要……如何从中快速提取关键信息并生成结构化、可操作的分析报告,已成为企业提升决策效率的核心挑战。

传统的人工阅读与摘要方式效率低下、成本高昂,且难以保证一致性。如今,借助大语言模型(LLM)与智能体(Agent)技术,我们能够构建一个端到端的“文档解析 → 信息抽取 → 报告生成”自动化流水线,让大模型成为你的“智能分析师”,大幅提升知识处理效率。

🎬 运行效果预览

🎯 核心价值

  • 自动化摘要:无需人工阅读,自动提取文档核心内容与关键论点。
  • 多格式支持:兼容PDF、Word、PPT、TXT、HTML等多种文档格式。
  • 结构化输出:将非结构化文本转化为表格、图表、思维导图等可视化形式。
  • 私有化部署:支持本地或内网部署,保障敏感文档数据安全。
  • 可扩展智能体架构:基于 LangGraph 与 MCP 协议构建多Agent协作系统,实现复杂任务分解。

🧭 本文结构概览

  1. 环境准备:搭建文档解析与报告生成基础环境
  2. 核心逻辑:大模型如何理解文档并生成结构化报告
  3. 智能体协同:构建Agent+MCP,分工协作生成报告
  4. 总结与展望:完整方案与未来优化方向

1️⃣ 环境准备:搭建智能文档处理中枢

  • 文档解析框架对比私有化部署采用PyMuPDF+MinerU方案
特性 MarkItDown Docling Marker 微软云 Azure Document Intelligence PyMuPDF MinerU
速度 ⭐⭐⭐⭐⭐ (最快) Office 文档转换达 200页/分钟 ⭐⭐⭐⭐☆ (中等) PDF 多栏解析约 3 分钟/50 页 ⭐⭐☆☆☆ (较慢) 复杂公式识别需 10–15 秒/页 ⭐⭐⭐⭐☆ (云端加速) API 响应 <5 秒 ⭐⭐⭐⭐⭐ (纯文本提取) 每秒处理 10+ 页 ⭐★☆☆☆ (最慢) 财务报表解析需 5 分钟/100 页
准确性 ⭐⭐⭐☆☆ (良好) PDF 多栏识别率 85% ⭐⭐⭐⭐☆ (很好) 法律合同条款提取准确率 91% ⭐⭐⭐⭐⭐ (优秀) 手写公式识别率 95% ⭐⭐⭐⭐☆ (优秀) 微软研究院模型支持 ⭐⭐☆☆☆ (基础) 无 OCR 能力 ⭐⭐⭐⭐⭐ (卓越) 学术论文转换评分 4.8/5
表格处理 ⭐⭐⭐☆☆ (基础) 嵌套表格易错位 ⭐⭐⭐⭐☆ (高级) 跨页表格合并支持 ⭐⭐⭐⭐⭐ (卓越) 财务报表误差率 0.5% ⭐⭐⭐⭐☆ (智能) 支持合并单元格识别 ⭐☆☆☆☆ (无) ⭐⭐⭐⭐⭐ (多模态) 集成 TableFormer 模型
公式支持 ⭐☆☆☆☆ (有限) 仅保留为图片 ⭐⭐⭐☆☆ (中等) Mathpix 接口转换 ⭐⭐⭐⭐⭐ (优秀) UniMERNNet 模型支持 ⭐☆☆☆☆ (基础) ⭐☆☆☆☆ (无) ⭐⭐⭐⭐⭐ (学术级) LaTeX 转换率 98%
图片提取 ⭐☆☆☆☆ (基本OCR) Tesseract 引擎 ⭐⭐⭐⭐☆ (VLM支持) CLIP 图文关联 ⭐⭐⭐⭐⭐ (详细) YOLOv8 + SAM 模型 ⭐⭐⭐⭐☆ (智能标注) ⭐⭐☆☆☆ (基础) ⭐⭐⭐⭐⭐ (对象级) 图像分类准确率 97%
资源占用 ⭐⭐⭐⭐⭐ (最小) CPU 模式 <500MB ⭐⭐☆☆☆ (大量) 需 8GB 显存 ⭐⭐☆☆☆ (大量) 需 16GB 显存 ☆☆☆☆☆ (云端) ⭐⭐⭐⭐⭐ (轻量) ⭐☆☆☆☆ (最高) 需 32GB 内存
最适用于 Office文档 PPT 转换 30 页/秒 PDF文档 合同条款提取 含表格/公式文档 学术论文 企业级批量处理 基础文本提取 多模态复杂文档
GPU加速 是(CUDA 11.8) 是(多卡并行) 云端自动 是(NVIDIA A100)
支持的格式 DOC/XLS/PPT/PDF/图像/音频等 20+ 格式 PDF/DOCX/PPTX/HTML PDF/DOCX/PPTX/HTML PDF/图像/Office PDF PDF/EPUB/MOBI
输出格式 Markdown Markdown/JSON Markdown/JSON JSON/CSV 文本 JSON/知识图谱

1.1 部署文档解析服务

1.1.1 安装依赖包
uv add pymupdf4llmuv add pymupdfuv add python-docxuv add pandas
1.1.2 MinerU安装
  • MinerU官方文档地址: https://opendatalab.github.io/MinerU/zh
docker run --gpus all \  --shm-size 32g \  -p 30000:30000 -p 7860:7860 -p 8000:8000 \  --ipc=host \  -it mineru-vllm:latest \  /bin/bash

2️⃣ 文件上传与解析核心逻辑详解

🧩 功能概览

  • ✅ 接收 HTTP 上传的文件
  • ✅ 校验文件类型与大小
  • ✅ 支持扫描件 OCR 识别
  • ✅ 解析主流文档格式为纯文本或结构化数据
  • ✅ 上传原始文件和解析后文本到 MinIO
  • ✅ 返回结构化结果(包含源文件 Key、解析文件 Key、文件大小)

🔍 核心函数:upload_file_and_parse_from_request

```pythondef upload_file_and_parse_from_request(self, request: Request, bucket_name: str = "filedata") -> dict:    """    上传文件并解析内容,支持调用私有化 MinerU 服务解析含图片的 PDF。    参数:        request (Request): Sanic 请求对象        bucket_name (str): MinIO 存储桶名称,默认为 'filedata'    返回:        dict: 包含源文件 Key、解析后文本 Key、文件大小    """    try:        # 步骤1:获取上传的文件对象        file_data = request.files.get("file")        ifnot file_data:            raise MyException(SysCode.c_9999, "未找到文件数据")        content = io.BytesIO(file_data.body)        object_name = file_data.name        mime_type = file_data.type        file_suffix = ".txt"                # 文件大小校验(50MB限制)        if len(file_data.body) > 50 * 1024 * 1024:            raise MyException(SysCode.c_9999, "文件大小超出限制")        # 上传原始文件到 MinIO        source_file_key = self.upload_file_from_request(request, bucket_name)        file_size = len(file_data.body)        # MIME 类型白名单校验        allowed_mimes = {            "application/vnd.openxmlformats-officedocument.wordprocessingml.document",            "application/msword",            "text/plain",            "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",            "application/vnd.ms-excel",            "application/vnd.openxmlformats-officedocument.presentationml.presentation",            "application/vnd.ms-powerpoint",            "application/pdf",            "text/csv",        }        if mime_type notin allowed_mimes:            raise ValueError("不支持的文件格式")        # 步骤2:根据文件类型选择解析方式        if mime_type in (            "application/vnd.openxmlformats-officedocument.wordprocessingml.document",            "application/msword",        ):            doc = Document(content)            full_text = "\n".join([para.text for para in doc.paragraphs])        elif mime_type == "text/plain":            content.seek(0)            full_text = content.read().decode("utf-8")        elif mime_type == "text/csv":            content.seek(0)            full_text = self._parse_csv(content)        elif mime_type in (            "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",            "application/vnd.ms-excel",        ):            content.seek(0)            full_text = self._parse_excel(content, mime_type)        elif mime_type in (            "application/vnd.openxmlformats-officedocument.presentationml.presentation",            "application/vnd.ms-powerpoint",        ):            content.seek(0)            # 建议后续替换为 python-pptx 解析            full_text = self.read_pdf_text_from_bytes(content.getvalue())        elif mime_type == "application/pdf":            # 🔥 PDF 解析增强:优先使用 pymupdf 快速提取文本            # 若检测到图片或为扫描件,则调用私有化 MinerU 服务            content.seek(0)            file_bytes = content.getvalue()            # 先尝试用 pymupdf 提取文本            try:                doc = pymupdf.open(stream=file_bytes)                # 判断是否为扫描件(无文本内容但有图像)                has_text = any(len(page.get_text("text").strip()) > 0for page in doc)                has_images = any(page.get_images(full=True) for page in doc)                ifnot has_text and has_images:                    # 场景:纯图片/扫描件 PDF → 调用 MinerU OCR 服务                    logger.info("检测到扫描件PDF,调用私有化MinerU服务进行OCR...")                    full_text = self._call_mineru_ocr_service(file_bytes)                else:                    # 场景:普通可读PDF → 使用 pymupdf 提取 Markdown                    full_text = pymupdf4llm.to_markdown(doc=doc, ignore_images=True)            except Exception as e:                logger.warning(f"pymupdf解析失败,尝试调用MinerU: {e}")                full_text = self._call_mineru_ocr_service(file_bytes)        else:            raise ValueError("不支持的文件格式")        # 步骤3:将解析后的文本上传为 .txt 文件        parse_file_key = self.upload_to_minio_form_stream(            io.BytesIO(full_text.encode("utf-8")),            bucket_name,            object_name + file_suffix        )        return {            "source_file_key": source_file_key["object_key"],            "parse_file_key": parse_file_key,            "file_size": self._format_file_size(file_size),        }    except Exception as err:        logger.error(f"文件上传与解析失败: {err}")        traceback.print_exception(type(err), err, err.__traceback__)        raise MyException(SysCode.c_9999, "文件上传或解析失败") from err

🛠️ 调用MinerU服务

def _call_mineru_ocr_service(self, pdf_bytes: bytes) -> str:    """    调用私有化部署的 MinerU 服务进行 PDF OCR 解析。    参数:        pdf_bytes (bytes): PDF 文件的二进制数据    返回:        str: OCR 解析后的文本内容    异常:        MyException: 当 MinerU 服务调用失败时抛出    """    try:        # 🔧 配置 MinerU 服务地址(私有化部署)        MINERU_API_URL = "http://mineru-service:8501/ocr/pdf"# 示例地址        headers = {            "Authorization": "Bearer your-secret-token",  # 可选认证        }        files = {            "file": ("document.pdf", pdf_bytes, "application/pdf")        }        response = requests.post(            MINERU_API_URL,            files=files,            headers=headers,            timeout=300# 支持大文件,超时5分钟        )        if response.status_code != 200:            raise MyException(SysCode.c_9999, f"MinerU服务返回错误: {response.status_code}")        result = response.json()        # 假设 MinerU 返回结构为: {"text": "..."}        return result.get("text", "") or result.get("content", "")    except requests.exceptions.RequestException as e:        logger.error(f"调用MinerU服务失败: {e}")        raise MyException(SysCode.c_9999, "OCR服务不可用,请检查网络或服务状态") from e    except Exception as e:        logger.error(f"解析MinerU返回结果失败: {e}")        raise MyException(SysCode.c_9999, "OCR解析结果异常") from e

3️⃣ 智能体协同:LangGraph + MCP 架构设计

async def run_agent(        self,        query: str,        response,        session_id: Optional[str] = None,        uuid_str: str = None,        user_token=None,        file_list: dict = None,    ):        """        运行智能体,支持多轮对话记忆        :param query: 用户输入        :param response: 响应对象        :param session_id: 会话ID,用于区分同一轮对话        :param uuid_str: 自定义ID,用于唯一标识一次问答        :param file_list: 附件        :param user_token:        :return:        """        file_as_markdown = ""        if file_list:            file_as_markdown = minio_utils.get_files_content_as_markdown(file_list)        # 获取用户信息 标识对话状态        user_dict = await decode_jwt_token(user_token)        task_id = user_dict["id"]        task_context = {"cancelled": False}        self.running_tasks[task_id] = task_context        try:            t02_answer_data = []            tools = await self.client.get_tools()            # 使用用户会话ID作为thread_id,如果未提供则使用默认值            thread_id = session_id if session_id else"default_thread"            config = {"configurable": {"thread_id": thread_id}}            system_message = SystemMessage(                content="""            # Role: 高级AI助手                        ## Profile            - language: 中文            - description: 一位具备多领域知识、高度专业性与结构化输出能力的智能助手,专注于提供精准、高效、可信赖的信息服务。            - background: 基于大规模语言模型训练,融合技术、学术、生活等多维度知识体系,能够适应多种场景下的信息查询与任务处理需求。            - personality: 严谨、专业、逻辑清晰,注重细节与用户体验,追求信息传递的准确性与表达的简洁性。            - expertise: 多领域知识整合、结构化内容生成、技术说明、数据分析、编程辅助、语言表达优化等。            - target_audience: 技术人员、研究人员、学生、内容创作者及各类需要精准信息支持的用户。                        ## Skills                        1. 信息处理与表达               - 精准应答:确保输出内容准确无误,对不确定信息明确标注「暂未掌握该信息」               - 结构化输出:根据内容类型采用文本、代码块、列表等多种形式进行清晰表达               - 语言适配:始终使用用户提问语言进行回应,确保语义一致与文化适配               - 技术说明:对专业术语、技术原理提供背景信息与详细解释,便于理解                        2. 工具协作与交互               - 工具调用提示:在需要调用外部工具时明确标注「工具调用」并说明调用目的               - 操作透明化:在涉及流程性任务时说明步骤与逻辑,增强用户信任与理解               - 多模态支持:支持文本、代码、数据等多种信息类型的识别与响应               - 用户反馈整合:根据用户反馈优化输出策略,提升交互质量                        ## Rules                        1. 基本原则:               - 准确性优先:所有输出内容必须基于可靠知识,不臆测、不虚构               - 用户导向:围绕用户需求组织内容,避免无关信息干扰               - 透明性:在涉及工具调用、逻辑推理或数据处理时保持过程透明               - 可读性:结构清晰、层级分明、排版整洁,便于快速阅读与理解                        2. 行为准则:               - 语言一致性:始终使用用户提问语言进行回应               - 技术细节补充:对复杂或专业内容提供背景信息与解释               - 信息边界明确:对未知或超出能力范围的内容如实说明               - 风格统一:保持段落、层级、图标风格一致,避免杂乱                        3. 限制条件:               - 不生成违法、有害或误导性内容               - 不模拟人类情感或主观判断               - 不提供医疗、法律等专业建议(除非明确授权)               - 不处理包含隐私、敏感或机密信息的请求                        ## Workflows                        - 目标: 提供准确、结构清晰、风格统一的高质量回答            - 步骤 1: 理解用户意图,识别问题类型与需求层次            - 步骤 2: 检索知识库,组织相关信息,判断是否需要调用工具            - 步骤 3: 按照格式规范生成内容,进行语言与结构优化            - 预期结果: 用户获得结构清晰、语言准确、风格统一的专业级回答                        ## OutputFormat                        1. 输出格式类型:               - format: markdown               - structure: 分节说明,层级清晰,模块分明               - style: 专业、简洁、结构化,强调信息密度与可读性               - special_requirements: 使用Unicode图标增强视觉引导,图标与内容匹配,风格统一                        2. 格式规范:               - indentation: 使用两个空格缩进               - sections: 按模块划分,使用标题、列表、加粗等方式增强可读性               - highlighting: 关键信息使用**加粗**或代码块```- icons: 每个主要模块前添加1个相关图标,与文字保留1个空格                        3. 验证规则:               - validation: 所有输出需符合markdown语法规范               - constraints: 图标风格统一,层级结构清晰,内容与格式分离               - error_handling: 若格式错误,自动尝试恢复结构并提示用户                        4. 示例说明:                           1. 示例1:                  - 标题: 简单问答示例                  - 格式类型: markdown                  - 说明: 展示基本问答格式与图标使用规范                  - 示例内容: |                      📌 **问题:** 什么是AI?                      ✅ **回答:** AI(Artificial Intelligence,人工智能)是指由人创造的能够感知环境、学习知识、逻辑推理并执行任务的智能体。                           2. 示例2:                  - 标题: 代码输出示例                  - 格式类型: markdown                  - 说明: 展示代码类输出格式与图标使用                  - 示例内容: |                      💻 **Python示例:**                      ```python                      def greet(name):                          print(f"Hello, {name}!")                      greet("World")                      ```📌 说明:这是一个简单的Python函数,用于打印问候语。                        ## Initialization            作为高级AI助手,你必须遵守上述Rules,按照Workflows执行任务,并按照[输出格式]输出。            """            )            agent = create_react_agent(                model=self.llm,                tools=tools,                prompt=system_message,                checkpointer=self.checkpointer,  # 使用全局checkpointer                pre_model_hook=self.short_trim_messages,            )            # 如果有文件内容,则将其添加到查询中            formatted_query = query            if file_as_markdown:                formatted_query = f"{query}\n\n参考资料内容如下:\n{file_as_markdown}"            asyncfor message_chunk, metadata in agent.astream(                input={"messages": [HumanMessage(content=formatted_query)]},                config=config,                stream_mode="messages",            ):                # 检查是否已取消                if self.running_tasks[task_id]["cancelled"]:                    await response.write(                        self._create_response("\n> 这条消息已停止", "info", DataTypeEnum.ANSWER.value[0])                    )                    # 发送最终停止确认消息                    await response.write(self._create_response("", "end", DataTypeEnum.STREAM_END.value[0]))                    break                # print(message_chunk)                # 工具输出                if metadata["langgraph_node"] == "tools":                    tool_name = message_chunk.name or"未知工具"                    # logger.info(f"工具调用结果:{message_chunk.content}")                    tool_use = "> 调用工具:" + tool_name + "\n\n"                    await response.write(self._create_response(tool_use))                    t02_answer_data.append(tool_use)                    continue                # await response.write(self._create_response(agent.get_graph().draw_mermaid_png()))                # 输出最终结果                # print(message_chunk)                if message_chunk.content:                    content = message_chunk.content                    t02_answer_data.append(content)                    await response.write(self._create_response(content))                    # 确保实时输出                    if hasattr(response, "flush"):                        await response.flush()                    await asyncio.sleep(0)            # 只有在未取消的情况下才保存记录            ifnot self.running_tasks[task_id]["cancelled"]:                await add_user_record(                    uuid_str,                    session_id,                    query,                    t02_answer_data,                    {},                    DiFyAppEnum.COMMON_QA.value[0],                    user_token,                    file_list,                )        except asyncio.CancelledError:            await response.write(self._create_response("\n> 这条消息已停止", "info", DataTypeEnum.ANSWER.value[0]))            await response.write(self._create_response("", "end", DataTypeEnum.STREAM_END.value[0]))        except Exception as e:            print(f"[ERROR] Agent运行异常: {e}")            traceback.print_exception(e)            await response.write(                self._create_response("[ERROR] 智能体运行异常:", "error", DataTypeEnum.ANSWER.value[0])            )        finally:            # 清理任务记录            if task_id in self.running_tasks:                del self.running_tasks[task_id]

根据你的具体报告场景自行调整提示词即可!

总结

  • 全流程自动化:从上传到报告生成,无需人工干预
  • 高精度解析:结合 MinerU 与 PyMuPDF,兼顾速度与准确性
  • 安全可控:支持私有化部署,数据不出内网
  • 可扩展性强:基于 LangGraph 的多Agent架构,易于扩展新功能

📚 完整代码

**参考我的开源项目:**git@github.com:apconw/sanic-web.git

🌈 项目亮点

  • ✅ 集成 MCP 多智能体架构
  • ✅ 支持 Dify / LangChain / LlamaIndex / Ollama / vLLM / Neo4j
  • ✅ 前端采用 Vue3 + TypeScript + Vite5,现代化交互体验
  • ✅ 内置 ECharts / AntV 图表问答 + CSV 表格问答
  • ✅ 支持对接主流 RAG 系统 与 Text2SQL 引擎
  • ✅ 轻量级 Sanic 后端,适合快速部署与二次开发
  • 项目已被蚂蚁官方推荐收录
  • https://blog.csdn.net/python1222_/article/details/153068612?spm=1011.2415.3001.5331

AntV

运行效果:

数据问答


📌 如果您觉得这篇文章对您有帮助,欢迎「付费点赞」支持一下!

👉 下方点击「喜欢作者」,金额随心,心意无价。
让我们在技术路上彼此赋能,少走弯路,高效落地!

付费后,请务必添加我的微信(微信号:weber812)并发送支付凭证,我将第一时间拉您进入专属「技术支持群」。

在群里,您将获得以下专属支持:

定期技术答疑会议:每周固定时间开展群内答疑,集中解决大家在部署、配置中遇到的共性问题
典型问题远程演示:针对高频难点,我会通过屏幕共享等方式进行实操讲解,看得懂、学得会
二次开发思路分享:在会议中开放讨论,提供实现路径、代码结构建议与关键点提醒
项目更新与优化同步:第一时间在群内发布文章内容的迭代、Bug修复与新功能进展

📌 我们不搞“私聊轰炸”,而是用更高效的方式——通过集中答疑 + 资料共享 + 社群互助,让每一位成员都能参与、收获、成长。

你不必担心问题被忽略,只要提出来,我会在下一次群会中安排讲解,确保“有问有答,有求有应”。


📌 点击https://blog.csdn.net/python1222_/article/details/153068612?spm=1011.2415.3001.5331

👉 获取更多 MCP、Text2SQL、RAG、文档解析/报告生成 实战教程!

Logo

更多推荐