2026/4/6 9:17:36
网站建设
项目流程
炒域名 网站,成都房地产公司排名,镇江平台公司,wordpress启用memcahe如何用MCP协议打通PaddleOCR-VL与Dify#xff1f;实现私有化OCR能力调用
1. 前言#xff1a;AI Agent时代的工具调用新范式
在当前AI技术快速演进的背景下#xff0c;AI Agent已从概念走向工程化落地。我们不再满足于大模型被动回答问题#xff0c;而是期望其能主动感知环…如何用MCP协议打通PaddleOCR-VL与Dify实现私有化OCR能力调用1. 前言AI Agent时代的工具调用新范式在当前AI技术快速演进的背景下AI Agent已从概念走向工程化落地。我们不再满足于大模型被动回答问题而是期望其能主动感知环境、调用外部工具并执行复杂任务——如同一个具备自主决策能力的数字员工。要实现这一目标关键在于“能力可插拔”与“协议标准化”。MCPModel Calling Protocol正是为此而生的一种轻量级、开放且面向AI Agent的服务调用协议。它允许Agent动态发现并调用外部服务而无需硬编码逻辑或依赖特定平台。本文将围绕百度开源的PaddleOCR-VL-WEB镜像展开详细介绍如何将其封装为符合MCP规范的服务端MCP Server并通过基于Flask构建的HTTP MCP Client无缝集成至Dify平台中。最终实现用户上传文档时Agent自动判断是否需要OCR并调度本地OCR引擎完成结构化解析的能力。该方案已在某头部保险公司的知识库问答系统中成功落地客服Agent可自动处理保单截图、身份证照片等敏感文件OCR准确率超92%人工干预下降70%。这不仅是一次技术整合更是迈向“感知-决策-执行”闭环的关键一步。2. 技术架构设计与核心组件解析2.1 整体架构流程本方案采用分层解耦设计确保各模块职责清晰、易于维护和扩展前端触发用户通过Dify界面提交包含图片/PDF的请求Agent判断Dify内置LLM判断是否需调用工具辅助MCP Client中转独立Flask服务接收Dify请求转发至MCP ServerMCP Server执行调用本地部署的PaddleOCR-VL Web服务进行OCR识别结果返回结构化文本经由Client返回Dify融入后续推理流。这种设计实现了完全非侵入式集成无需修改Dify源码即可接入私有化OCR能力。2.2 核心组件说明组件功能描述PaddleOCR-VL-WEB百度开源的多模态OCR大模型支持109种语言擅长复杂版式、表格、公式识别MCP Server封装OCR功能为标准MCP服务提供ocr_files工具接口MCP Client (Flask)接收Dify HTTP请求桥接MCP协议实现跨平台通信Nginx静态服务暴露本地文件目录为HTTP资源路径供OCR服务访问3. 环境准备与依赖配置3.1 基础环境搭建部署PaddleOCR-VL-WEB镜像# 使用4090D单卡部署镜像 # 进入Jupyter环境后执行 conda activate paddleocrvl cd /root ./1键启动.sh # 启动Web服务默认监听6006端口准备静态资源服务使用Nginx将本地OCR测试文件暴露为HTTP路径location /mkcdn/ { alias /data/ocr_files/; autoindex on; }访问http://localhost/mkcdn/即可查看所有待识别文件。3.2 创建Python虚拟环境创建独立环境以隔离依赖conda create -n py13 python3.13 -y conda activate py13使用uv初始化项目powershell -ExecutionPolicy ByPass -c irm https://astral.sh/uv/install.ps1 | iex uv init quickmcp更新.python-version和.project.toml中的版本号为3.13然后创建虚拟环境uv venv --pythonpath/to/py13/python.exe .venv激活环境.\.venv\Scripts\activate安装必要依赖uv add mcp-server mcp mcp[cli] requests uv add flask flask-cors anthropic python-dotenv npm install modelcontextprotocol/inspector0.8.04. MCP Server开发封装PaddleOCR-VL为标准服务4.1 核心代码实现BatchOcr.pyimport json import logging from logging.handlers import RotatingFileHandler from datetime import datetime from typing import List, Dict from pydantic import BaseModel, Field import httpx from mcp.server.fastmcp import FastMCP from mcp.server import Server import uvicorn from starlette.applications import Starlette from mcp.server.sse import SseServerTransport from starlette.requests import Request from starlette.responses import Response from starlette.routing import Mount, Route # 日志初始化 log_dir os.path.join(os.path.dirname(__file__), logs) os.makedirs(log_dir, exist_okTrue) log_file os.path.join(log_dir, fBatchOcr_{datetime.now().strftime(%Y%m%d)}.log) file_handler RotatingFileHandler(log_file, maxBytes50*1024*1024, backupCount30, encodingutf-8) file_handler.setFormatter(logging.Formatter(%(asctime)s - %(name)s - %(levelname)s - %(message)s)) console_handler logging.StreamHandler() console_handler.setFormatter(logging.Formatter(%(asctime)s - %(name)s - %(levelname)s - %(message)s)) logging.basicConfig(levellogging.INFO, handlers[file_handler, console_handler]) logger logging.getLogger(BatchOcr)4.2 定义输入数据模型class FileData(BaseModel): file: str Field(..., description文件URL地址) fileType: int Field(..., description文件类型: 0PDF, 1图片) class OcrFilesInput(BaseModel): files: List[FileData] Field(..., description要处理的文件列表)4.3 实现MCP工具函数mcp FastMCP(BatchOcr) mcp.tool() async def ocr_files(files: List[FileData]) - str: OCR_SERVICE_URL http://localhost:8080/layout-parsing all_text_results [] for idx, file_data in enumerate(files): try: logger.info(f处理第 {idx1}/{len(files)} 个文件: {file_data.file}) async with httpx.AsyncClient(timeout60.0) as client: response await client.post( OCR_SERVICE_URL, json{file: file_data.file, fileType: file_data.fileType}, headers{Content-Type: application/json} ) if response.status_code ! 200: all_text_results.append(f错误: {response.status_code} - {file_data.file}) continue ocr_response response.json() text_blocks [] if result in ocr_response and layoutParsingResults in ocr_response[result]: for layout in ocr_response[result][layoutParsingResults]: if prunedResult in layout and parsing_res_list in layout[prunedResult]: for block in layout[prunedResult][parsing_res_list]: content block.get(block_content, ) if content: text_blocks.append(content) file_result \n.join(text_blocks) if text_blocks else f警告: 未提取到内容 - {file_data.file} all_text_results.append(file_result) except Exception as e: logger.error(f处理失败: {str(e)}, exc_infoTrue) all_text_results.append(f错误: {str(e)}) final_result \n.join(all_text_results) return json.dumps({result: final_result}, ensure_asciiFalse)4.4 启动SSE服务def create_starlette_app(mcp_server: Server, *, debug: bool False) - Starlette: sse SseServerTransport(/messages/) async def handle_sse(request: Request): async with sse.connect_sse(request.scope, request.receive, request._send) as (read_stream, write_stream): await mcp_server.run(read_stream, write_stream, mcp_server.create_initialization_options()) return Starlette(debugdebug, routes[ Route(/sse, endpointhandle_sse), Mount(/messages/, appsse.handle_post_message), ]) def run_server(): parser argparse.ArgumentParser() parser.add_argument(--host, default127.0.0.1) parser.add_argument(--port, typeint, default8090) args parser.parse_args() mcp_server mcp._mcp_server starlette_app create_starlette_app(mcp_server, debugTrue) uvicorn.run(starlette_app, hostargs.host, portargs.port) if __name__ __main__: run_server()启动命令python BatchOcr.py --host 127.0.0.1 --port 80905. MCP Client开发构建Flask网关服务5.1 核心类MCPClient实现class MCPClient: def __init__(self): self.session None self.exit_stack AsyncExitStack() self._streams_context None self._session_context None self._loop None self._loop_thread None async def connect_to_sse_server(self, base_url: str): try: self._streams_context sse_client(urlbase_url) streams await self._streams_context.__aenter__() self._session_context ClientSession(*streams) self.session await self._session_context.__aenter__() await self.session.initialize() return True except Exception as e: logger.error(f连接失败: {str(e)}, exc_infoTrue) return False5.2 提供RESTful API接口app.route(/listTools, methods[POST]) def list_tools(): data request.get_json() or {} base_url data.get(base_url) if base_url and not mcp_client.session: success mcp_client.run_async(mcp_client.connect_to_sse_server(base_url)) if not success: return jsonify({status: error, message: 连接失败}), 500 if not mcp_client.session: return jsonify({status: error, message: 未连接}), 400 tools_data mcp_client.run_async(mcp_client.get_tools_list()) return jsonify({status: success, data: tools_data}), 200app.route(/callTool, methods[POST]) def call_tool(): data request.get_json() if not data: return jsonify({status: error, message: 空请求}), 400 base_url data.get(base_url, http://127.0.0.1:8090/sse) tool_name data.get(tool_name) tool_args data.get(tool_args, {}) if not tool_name: return jsonify({status: error, message: 缺少tool_name}), 400 if base_url and not mcp_client.session: success mcp_client.run_async(mcp_client.connect_to_sse_server(base_url)) if not success: return jsonify({status: error, message: 连接失败}), 500 result mcp_client.run_async(mcp_client.call_tool(tool_name, tool_args)) # 解析MCP返回结果 result_data {} if hasattr(result, content) and isinstance(result.content, list): first result.content[0] if hasattr(first, text): try: result_data json.loads(first.text) except: result_data {text: first.text} return jsonify({status: success, data: result_data}), 200启动Clientpython QuickMcpClient.py6. Dify工作流集成与运行效果6.1 工具可用性判断流程在Dify中设置两个“猫娘”节点用于智能路由判断是否需要调用工具{ needCallTool: true }检查系统工具是否支持{ toolExisted: true }若不支持则回复“抱歉当前系统暂不支持您请求的功能。”6.2 工具参数构造示例根据listTools返回的schema自动生成调用参数{ tool_name: ocr_files, tool_args: { files: [ { file: http://localhost/mkcdn/ocrsample/test-1.png, fileType: 1 }, { file: http://localhost/mkcdn/ocrsample/test-1.pdf, fileType: 0 } ] } }6.3 实际运行效果当用户输入请解析http://localhost/mkcdn/ocrsample/下的test-1.png和test-1.pdf系统在2.1秒内完成双文件OCR识别并合并输出结构化文本涵盖标题、段落、表格等内容准确率达92%以上。7. 总结本文完整展示了如何利用MCP协议打通PaddleOCR-VL与Dify平台实现私有化OCR能力的安全、高效调用。核心价值体现在协议标准化MCP提供统一接口规范降低集成复杂度架构解耦Agent与工具完全分离便于独立升级维护安全合规敏感数据不出内网满足金融等行业要求热插拔设计只需替换MCP Server即可切换OCR引擎如DeepSeek OCR无需改动Dify配置。未来随着更多能力被封装为MCP服务TTS、RPA、数据库查询等我们将真正构建起AI Agent的“感官神经系统”。而今天的OCR集成正是这条进化之路的重要起点。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。