GPT 读 PDF 到底哪家强?5 个文档 MCP 工具深测后,我发现 OCR 只是第一步

在 Agent 工作流里,“读文档”看起来是一个很小的动作:把 PDF、Word、PPT 或图片交给工具,让模型拿到内容,然后继续总结、问答、抽取或写代码。

但真正做过文档 AI 工作流的人会发现,读文档不是 read_file() 那么简单。

一份真实文档可能是:

  • 有文本层的原生 PDF
  • 没有文本层的扫描 PDF
  • 多栏论文
  • 带复杂表格的财报
  • 带公式的技术文档
  • Word、PPT、Excel 混合资料
  • 图片截图、手写笔记或网页导出的 PDF

如果 MCP 工具只能把 PDF 里的纯文本抽出来,Agent 很快就会卡在三个地方:

  • 读不到扫描件
  • 读错多栏顺序
  • 读丢表格、公式和图片关系

所以我把“GPT / Codex Agent 里读文档”这件事拆成一个更具体的问题:

当 Agent 需要把复杂文档转成可理解、可检索、可引用、可继续推理的上下文时,哪类 MCP 工具更可靠?

本文基于公开 README、官方文档和 MCP Registry 信息,对 5 个文档类 MCP 工具做一次技术深度对比:

  • MinerU MCP
  • MarkItDown MCP
  • pdf-mcp
  • PaddleOCR MCP
  • pdf-reader-mcp

这不是单纯比较“谁能提取文字”。在 Agent 场景里,更重要的问题是:

  • 能不能处理扫描 PDF?
  • 能不能保持阅读顺序?
  • 能不能保留表格和公式?
  • 能不能输出 Markdown / JSON?
  • 能不能被 GPT / Codex 稳定调用?
  • 能不能进入 RAG、知识库和 Agent 工作流?

先给结论

如果文档主要是原生 PDF、Word、Excel、PPT,并且目标只是快速转 Markdown,MarkItDown MCP 是轻量、通用、工程成本低的选择。

如果文档主要是简单 PDF,需要快速抽文本、读元数据、抽普通表格,pdf-mcp 足够直接。

如果要处理扫描 PDF,或者想让工具自动在“文本层抽取”和“Tesseract OCR”之间切换,pdf-reader-mcp 的 read_pdf_smart 很贴近这个需求。

如果要处理图片、扫描件、表格、公式、版面结构,并且愿意管理 OCR / VLM / pipeline 依赖,PaddleOCR MCP 是开源 OCR 与文档视觉理解的强工具箱。

但如果目标是让 GPT / Codex Agent 真正“读懂复杂文档”,尤其是 PDF、扫描件、Office 文档、表格、公式、多栏论文进入 RAG、知识库和 Agent 工作流,MinerU MCP 更接近完整答案。

原因不只是 MinerU 有 OCR,而是 MinerU 把 OCR 放进了更完整的文档解析链路:

文件输入
  → OCR / VLM / 版面分析
  → 阅读顺序恢复
  → 表格、公式、图片结构化
  → Markdown / JSON / HTML / LaTeX
  → MCP / SDK / API / RAG / Agent

这也是本文的核心判断:

对 Agent 来说,最重要的不是“能不能识别文字”,而是“能不能把文档转成模型可用的结构化上下文”。MinerU MCP 的价值,正是在 OCR 之后多走了这一步。

5 个 MCP 工具分别解决什么问题

这 5 个工具都能帮助 Agent 读文档,但技术定位不同。

工具 核心定位 更适合的输入 主要输出 关键工具 / 能力
MinerU MCP 面向 LLM / RAG / Agent 的文档解析 PDF、图片、DOC、DOCX、PPT、PPTX、XLS、XLSX、HTML Markdown、JSON、图片资源等 parse_documentsget_ocr_languages、109 语言 OCR、Flash / Precision 模式
MarkItDown MCP 多格式文件转 Markdown Office、PDF、HTML、CSV、JSON、XML、图片、音频、ZIP、EPub、YouTube URL Markdown convert_to_markdown(uri);支持 file:http:https:data: URI
pdf-mcp 简单 PDF 读取 原生 PDF Text、PDF info、普通表格 extract_textget_pdf_infoextract_tables;基于 pdfplumber
PaddleOCR MCP OCR 与文档视觉理解工具箱 图片、PDF、扫描件、表格、公式、版面文档 OCR 结果、Markdown、结构元素 OCRPP-StructureV3PaddleOCR-VLPaddleOCR-VL-1.5 模式
pdf-reader-mcp PDF 文本抽取 + OCR fallback 原生 PDF、扫描 PDF、图片型 PDF Text、metadata、OCR text read_pdf_textread_pdf_ocrread_pdf_smartpdf_infoocr_status

从工具定位看,pdf-mcp 和 pdf-reader-mcp 更像 PDF reader;MarkItDown 更像 file-to-Markdown converter;PaddleOCR MCP 更像 OCR / 文档视觉模型工具箱;MinerU MCP 则更像面向大模型工作流的文档解析层。

公开资料能力评分

下面是基于官方文档、README 和 MCP 工具接口做出的静态能力评分。

评分规则:

  • 0:公开资料未体现该能力或明显不适用
  • 1:理论可绕路实现,但不是主能力
  • 3:有基础支持,适合常规场景
  • 4:能力较完整,但仍需要按文档类型实测
  • 5:官方明确支持,且是工具核心能力
工具 原生 PDF 扫描 PDF / OCR 多栏 / 版面 表格 公式 Office Agent / MCP 集成 综合判断
MinerU MCP 5 5 5 5 5 5 5 最适合复杂文档解析、RAG、Agent 工作流
MarkItDown MCP 4 2 2 3 1 5 5 最适合多格式轻量 Markdown 转换
pdf-mcp 4 0 1 3 0 0 3 最适合简单 PDF 文本、元数据和普通表格抽取
PaddleOCR MCP 4 5 5 5 5 1 4 最适合 OCR、版面、表格、公式等视觉文档 pipeline
pdf-reader-mcp 4 4 1 1 0 0 3 最适合 PDF 文本层抽取 + Tesseract OCR fallback

这张表并不是说 MinerU 在每个低层 OCR 子任务都一定替代 PaddleOCR,也不是说 MarkItDown 不值得用。更准确的结论是:

  • 简单转换:MarkItDown 很轻
  • 简单 PDF:pdf-mcp 很直接
  • 扫描 PDF fallback:pdf-reader-mcp 很务实
  • OCR / VLM 实验:PaddleOCR MCP 很强
  • 复杂文档进入 Agent / RAG:MinerU MCP 更完整

为什么不能只看“能不能读出文字”

在 GPT / Codex Agent 场景里,文档工具的输出不是给人直接看的,而是给模型继续推理的。

如果一个工具只输出纯文本,就会出现几个问题:

  • 多栏论文阅读顺序可能错乱
  • 表格被压成连续文本
  • 公式变成不可计算的字符碎片
  • 图片和图注关系丢失
  • 页眉页脚混入正文
  • Agent 难以引用来源
  • RAG 切块会切断语义

这也是为什么 OCR 不是终点。

一个更合理的文档 AI 链路应该是:

PDF / 图片 / Office 文档
        ↓
文字识别
        ↓
版面理解
        ↓
阅读顺序恢复
        ↓
表格、公式、图片结构化
        ↓
Markdown / JSON
        ↓
RAG / Agent / 知识库

MinerU 的优势,正是在 OCR 之后继续完成文档结构化。

MCP 配置与工具接口

下面整理 5 个工具的公开配置和工具接口,便于直接放进 GPT / Codex / Claude / Cursor 一类 Agent 客户端里对比。

MinerU MCP

MinerU-Ecosystem 官方提供 mineru-open-mcp,面向 Claude Desktop、Cursor、Windsurf 等 MCP 客户端。

公开资料中,MinerU MCP 的关键能力包括:

  • 解析 PDF、图片、DOC、DOCX、PPT、PPTX、XLS、XLSX、HTML 为 Markdown
  • 支持 109 种 OCR 语言
  • Flash 模式:无需 token,Markdown-only,单文件通常用于轻量解析
  • Precision 模式:需要 token,适合复杂文档、高精度解析和更丰富输出
  • 工具包括 parse_documentsget_ocr_languages,部分配置下还有 clean_logs

典型配置:

{
  "mcpServers": {
    "mineru": {
      "command": "uvx",
      "args": ["mineru-open-mcp"],
      "env": {
        "MINERU_API_TOKEN": "your_token_here"
      }
    }
  }
}

Streamable HTTP 模式也适合 Web 类 MCP 客户端:

MINERU_API_TOKEN=your_key mineru-open-mcp --transport streamable-http --port 8001
{
  "mcpServers": {
    "mineru": {
      "type": "streamableHttp",
      "url": "http://127.0.0.1:8001/mcp"
    }
  }
}

在 Agent 场景里,MinerU MCP 最适合作为“复杂文档主解析入口”:

用户上传 PDF / Office / 图片
        ↓
Agent 调用 parse_documents
        ↓
MinerU 返回 Markdown / JSON / 图片资源
        ↓
Agent 做总结、问答、抽取、RAG 入库

MarkItDown MCP

MarkItDown 是 Microsoft 开源的轻量级文件转 Markdown 工具,目标是为 LLM 和文本分析管线准备 Markdown。

公开资料显示,它支持:

  • PDF
  • PowerPoint
  • Word
  • Excel
  • 图片
  • 音频
  • HTML
  • CSV / JSON / XML
  • ZIP
  • YouTube URLs
  • EPub

MarkItDown MCP 的核心工具是:

convert_to_markdown(uri)

其中 uri 可以是:

  • file:
  • http:
  • https:
  • data:

典型 CLI 调用:

pip install "markitdown[all]"
markitdown path-to-file.pdf -o document.md

MarkItDown 的优势是轻量、多格式、Markdown 友好。它适合把 Office、网页、CSV、JSON 等文档快速变成模型可读文本。

但它的主定位不是复杂 OCR / 文档结构恢复。官方文档也强调,它是给 LLM 和文本分析使用的 Markdown 转换工具,不一定适合追求高保真的文档转换。

此外,MarkItDown 官方 README 对安全边界有明确提醒:它会以当前进程权限访问资源,所以在不可信环境里要限制输入和 URI 访问。

pdf-mcp

pdf-mcp 这类工具通常基于 pdfplumber,目标是从 PDF 中抽取文本、元数据和普通表格。

公开资料中的典型配置:

{
  "mcpServers": {
    "pdf-reader": {
      "command": "uvx",
      "args": [
        "--from",
        "git+https://github.com/gstiebler/pdf-mcp-server.git",
        "pdf-mcp-server"
      ]
    }
  }
}

常见工具包括:

  • extract_text
  • get_pdf_info
  • extract_tables

这类工具非常适合简单 PDF,尤其是:

  • 读取报告正文
  • 查看页数和元数据
  • 提取规则表格
  • 快速给 Agent 提供 PDF 文本上下文

但它的边界也很明确:

  • 主要面向有文本层的 PDF
  • 不解决扫描件 OCR
  • 不解决复杂阅读顺序
  • 不解决公式结构化
  • 不适合 Office 文档

所以 pdf-mcp 更适合放在轻量 PDF reader 层,而不是复杂 OCR / 文档解析层。

PaddleOCR MCP

PaddleOCR 官方提供 MCP Server,用于把 PaddleOCR 的文字识别、版面解析等能力接入大模型应用。

公开资料显示,PaddleOCR MCP 支持的工具 / pipeline 包括:

  • OCR:对图片和 PDF 做文本检测与识别
  • PP-StructureV3:识别文本块、标题、段落、图片、表格等版面元素,并转 Markdown
  • PaddleOCR-VL:基于 VLM 的文档元素识别与 Markdown 转换
  • PaddleOCR-VL-1.5:PaddleOCR-VL 的升级版本,官方文档称速度和精度都有提升

支持的工作模式包括:

  • local:本地 Python 库运行
  • aistudio:调用 PaddleOCR 官方服务
  • qianfan:调用百度智能云千帆平台服务
  • self_hosted:调用用户自托管服务

典型安装:

pip install -U paddleocr-mcp

典型配置:

{
  "mcpServers": {
    "paddleocr": {
      "command": "paddleocr_mcp",
      "args": [],
      "env": {
        "PADDLEOCR_MCP_PIPELINE": "PP-StructureV3",
        "PADDLEOCR_MCP_PPOCR_SOURCE": "local"
      }
    }
  }
}

直接运行:

paddleocr_mcp --pipeline PP-StructureV3 --ppocr_source local

PaddleOCR MCP 的优势是 OCR 和视觉结构解析能力强,尤其适合扫描件、图片、表格、公式、版面结构等文档视觉任务。

它的边界是工程复杂度更高:本地运行需要模型、依赖、硬件、推理性能和参数配置。对产品化 Agent 工作流来说,它更像底层 OCR / VLM pipeline,而不是完整的文档解析产品层。

pdf-reader-mcp

pdf-reader-mcp 的定位非常清晰:让 MCP 客户端读取 PDF,包括扫描和图片型 PDF。

公开 README 显示,它使用:

  • PyMuPDF 做原生文本抽取
  • Tesseract OCR 做扫描件 fallback

工具包括:

  • read_pdf_text
  • read_pdf_ocr
  • read_pdf_smart
  • pdf_info
  • ocr_status

典型配置:

{
  "mcpServers": {
    "pdf-reader": {
      "command": "pdf-reader-mcp"
    }
  }
}

read_pdf_smart 的逻辑很实用:

逐页抽取原生文本
  → 如果页面文本 >= 30 字符,使用原生文本
  → 如果页面文本 < 30 字符,渲染页面并调用 Tesseract OCR
  → 返回每页使用的方法标签和文本

这意味着它很适合混合型 PDF:有些页面有文本层,有些页面是扫描件。

但它仍然是 PDF reader + OCR fallback,不负责复杂版面、表格、公式和 Agent-ready Markdown / JSON。

可复现实测代码

下面给一份更接近真实工程的 MCP 调用骨架。它的目标不是把某一个工具绑死,而是统一比较不同 MCP Server 的工具调用结果。

运行前需要:

pip install mcp

示例代码:

import asyncio
import json
import time
from dataclasses import dataclass, asdict
from pathlib import Path

from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client


@dataclass
class Case:
    id: str
    path: str
    prompt: str
    expected_signals: list[str]


@dataclass
class ToolConfig:
    name: str
    command: str
    args: list[str]
    tool_name: str
    argument_builder: str


@dataclass
class Result:
    tool: str
    case_id: str
    success: bool
    latency_sec: float
    output_chars: int
    signal_hits: int
    markdown_score: int
    notes: str


CASES = [
    Case(
        id="native_pdf",
        path="samples/native_text_report.pdf",
        prompt="提取正文,保留标题和段落结构。",
        expected_signals=["摘要", "结论", "参考资料"],
    ),
    Case(
        id="scanned_pdf",
        path="samples/scanned_contract.pdf",
        prompt="识别扫描件正文,输出可读 Markdown。",
        expected_signals=["合同", "甲方", "乙方"],
    ),
    Case(
        id="multi_column_paper",
        path="samples/two_column_paper.pdf",
        prompt="按正确阅读顺序输出论文正文。",
        expected_signals=["Abstract", "Introduction", "Conclusion"],
    ),
    Case(
        id="table_report",
        path="samples/table_finance_report.pdf",
        prompt="保留表格行列结构。",
        expected_signals=["营收", "毛利率", "同比"],
    ),
    Case(
        id="formula_paper",
        path="samples/formula_paper.pdf",
        prompt="识别公式并保留上下文。",
        expected_signals=["equation", "LaTeX"],
    ),
]


TOOLS = [
    ToolConfig(
        name="mineru",
        command="uvx",
        args=["mineru-open-mcp"],
        tool_name="parse_documents",
        argument_builder="mineru",
    ),
    ToolConfig(
        name="markitdown",
        command="uvx",
        args=["markitdown-mcp"],
        tool_name="convert_to_markdown",
        argument_builder="uri",
    ),
    ToolConfig(
        name="pdf-mcp",
        command="uvx",
        args=["--from", "git+https://github.com/gstiebler/pdf-mcp-server.git", "pdf-mcp-server"],
        tool_name="extract_text",
        argument_builder="file_path",
    ),
    ToolConfig(
        name="paddleocr",
        command="paddleocr_mcp",
        args=[],
        tool_name="paddleocr",
        argument_builder="input_path",
    ),
    ToolConfig(
        name="pdf-reader-mcp",
        command="pdf-reader-mcp",
        args=[],
        tool_name="read_pdf_smart",
        argument_builder="path",
    ),
]


def build_arguments(config: ToolConfig, case: Case) -> dict:
    path = str(Path(case.path).resolve())

    if config.argument_builder == "mineru":
        return {
            "files": [path],
            "mode": "auto",
        }

    if config.argument_builder == "uri":
        return {
            "uri": f"file://{path}",
        }

    if config.argument_builder == "file_path":
        return {
            "file_path": path,
        }

    if config.argument_builder == "input_path":
        return {
            "input_path": path,
        }

    if config.argument_builder == "path":
        return {
            "path": path,
        }

    raise ValueError(f"Unknown argument builder: {config.argument_builder}")


def stringify_tool_result(result) -> str:
    parts = []
    for item in result.content:
        text = getattr(item, "text", None)
        if text:
            parts.append(text)
    return "\n".join(parts)


def score(text: str, case: Case) -> tuple[int, int]:
    lower = text.lower()
    hits = sum(1 for item in case.expected_signals if item.lower() in lower)

    markdown_score = 0
    if "#" in text:
        markdown_score += 1
    if "|" in text:
        markdown_score += 1
    if "```" in text or "$" in text or "\\\\" in text:
        markdown_score += 1
    if len(text) > 500:
        markdown_score += 1
    if hits >= 2:
        markdown_score += 1

    return hits, min(markdown_score, 5)


async def run_one(config: ToolConfig, case: Case) -> Result:
    params = StdioServerParameters(command=config.command, args=config.args)
    start = time.time()

    try:
        async with stdio_client(params) as (read, write):
            async with ClientSession(read, write) as session:
                await session.initialize()

                tools = await session.list_tools()
                available = [tool.name for tool in tools.tools]
                if config.tool_name not in available:
                    return Result(
                        tool=config.name,
                        case_id=case.id,
                        success=False,
                        latency_sec=round(time.time() - start, 2),
                        output_chars=0,
                        signal_hits=0,
                        markdown_score=0,
                        notes=f"Tool not found. Available: {available}",
                    )

                raw = await session.call_tool(
                    config.tool_name,
                    arguments=build_arguments(config, case),
                )
                text = stringify_tool_result(raw)
                hits, markdown_score = score(text, case)

                return Result(
                    tool=config.name,
                    case_id=case.id,
                    success=True,
                    latency_sec=round(time.time() - start, 2),
                    output_chars=len(text),
                    signal_hits=hits,
                    markdown_score=markdown_score,
                    notes="",
                )

    except Exception as exc:
        return Result(
            tool=config.name,
            case_id=case.id,
            success=False,
            latency_sec=round(time.time() - start, 2),
            output_chars=0,
            signal_hits=0,
            markdown_score=0,
            notes=str(exc),
        )


async def main():
    results = []
    for tool in TOOLS:
        for case in CASES:
            results.append(await run_one(tool, case))

    Path("results").mkdir(exist_ok=True)
    with open("results/mcp_doc_reading_benchmark.json", "w", encoding="utf-8") as f:
        json.dump([asdict(item) for item in results], f, ensure_ascii=False, indent=2)


if __name__ == "__main__":
    asyncio.run(main())

这段代码的重点不是“跑一次得到绝对真理”,而是提供统一评测口径:

  • 同一组文档
  • 同一组任务
  • 同一套工具发现和工具调用流程
  • 记录成功率、耗时、输出长度、命中信号和 Markdown 可用性

如果要进一步专业化,可以增加:

  • 阅读顺序人工评分
  • 表格结构人工评分
  • 公式可用性人工评分
  • Agent 问答正确率评分
  • 输出 Markdown 和 JSON 归档

面向 Agent 的测试任务设计

真正的评测不应该只问“工具有没有输出文本”,而应该让 GPT / Codex 基于输出完成任务。

建议设计 6 类任务。

任务 Agent 提问 评价重点
原生 PDF 总结 “总结这份报告的核心结论,并列出 3 条证据。” 标题、段落、重点信息是否保留
扫描合同抽取 “提取甲方、乙方、付款条件和违约条款。” OCR 是否读到关键条款
多栏论文阅读 “按论文结构总结 Abstract、Method、Experiment、Conclusion。” 阅读顺序是否正确
表格问答 “找出营收同比增长最高的行,并解释原因。” 表格行列是否保留
公式解释 “解释公式里的变量含义和上下文。” 公式是否可复用
Office 转知识库 “把 PPT / Word 内容转为适合知识库入库的 Markdown。” 结构是否清晰,是否可切块

对 MinerU 来说,最适合突出差异的是这三类:

  • 多栏论文
  • 表格 / 公式文档
  • 扫描 PDF + 结构化输出

因为这三类任务最能体现“读文字”和“读懂文档”的差异。

公开资料评估结论

1. 原生 PDF:pdf-mcp 和 MarkItDown 足够轻量,MinerU 更适合复杂结构

对有文本层的普通 PDF,pdf-mcp 和 MarkItDown 通常能完成基础读取。

pdf-mcp 基于 pdfplumber,适合文本、元数据和普通表格抽取。MarkItDown 则适合快速转 Markdown,并进一步进入 LLM 文本处理流程。

但如果文档里有多栏、表格、图片、脚注、跨页内容,简单文本抽取很容易把顺序打乱。此时 MinerU 的优势开始出现:它不是只抽文本,而是面向阅读顺序、结构和 Markdown / JSON 输出做解析。

2. 扫描 PDF:pdf-reader-mcp 能 fallback,PaddleOCR 和 MinerU 更适合高质量 OCR 场景

pdf-reader-mcp 的 read_pdf_smart 思路很务实:先抽文本层,文本不足再走 Tesseract OCR。它对大量混合 PDF 很有价值。

但如果扫描件包含复杂版面、表格、公式、手写内容,单纯 Tesseract OCR 只能解决一部分问题。PaddleOCR MCP 更像 OCR 专项工具箱,MinerU MCP 则更适合把 OCR 结果继续组织成大模型可用的文档结构。

3. 多栏论文:MinerU 的阅读顺序价值很明显

多栏论文是最容易暴露 PDF reader 局限的样本。

很多工具能抽出文字,但段落顺序可能变成:

左栏第一段
右栏第一段
左栏第二段
右栏第二段

这种输出对人类还能勉强看,对 RAG 和 Agent 很致命。Agent 会把不连续的上下文放在一起,导致总结和问答质量下降。

MinerU 公开资料强调按人类阅读顺序输出,并处理页眉、页脚、脚注和页码等噪音。这是它比普通 PDF reader 更适合 Agent 文档理解的关键。

4. 表格和公式:真正的差异不在 OCR,而在结构化

表格不是一堆文字,公式也不是普通字符。

对财报、论文、科研文档来说,表格和公式往往是最有价值的信息。如果工具把表格抽成一段文本,Agent 就很难回答“同比变化是多少”“哪一列最大”“公式代表什么”这类问题。

MinerU 的公开能力包括表格转 HTML、公式转 LaTeX,这让它更适合作为复杂文档进入 RAG 的前处理层。PaddleOCR MCP 也在表格、公式和 PP-StructureV3 上很强,但 MinerU 的优势在于把这些能力进一步包装到 LLM / RAG / Agent 生态中。

5. Office 文档:MarkItDown 轻量,MinerU 更关注结构与下游工作流

MarkItDown 对 Word、Excel、PowerPoint 等格式非常友好,适合快速转 Markdown。

MinerU 也支持 DOC、DOCX、PPT、PPTX、XLS、XLSX 解析,并且目标不是简单转换,而是让结果进入文档解析、RAG 和 Agent 工作流。

如果只是轻量转换,MarkItDown 很合适;如果文档要进入统一知识库、需要后续检索、问答、抽取和结构化管理,MinerU 更适合作为统一入口。

为什么这篇评测最终会引向 MinerU

读文档工具的竞争,本质上不是“谁能读出更多文字”,而是谁能把文档交给 Agent 使用。

Agent 需要的不是纯文本,而是:

  • 顺序正确的上下文
  • 可切块的 Markdown
  • 可程序读取的 JSON
  • 可复用的表格
  • 可解释的公式
  • 可追溯的图片和页面信息
  • 稳定的 API / MCP 调用入口

在这个标准下,MinerU 的优势可以总结为四点。

第一,MinerU 把 OCR 放进了文档解析链路

传统 OCR 的结果通常是文本和坐标。MinerU 的价值在于继续做版面理解、阅读顺序恢复、表格公式结构化和 Markdown / JSON 输出。

这意味着 MinerU 解决的不是“图片里有没有字”,而是“复杂文档能不能变成知识资产”。

第二,MinerU 对 Agent 更友好

MinerU-Ecosystem 提供 CLI、SDK、MCP、LangChain、LlamaIndex、RAGFlow、Dify、FastGPT 等接入方式。

对 Agent 来说,这很重要。因为 Agent 不应该依赖用户复制粘贴文档内容,而应该能通过工具调用直接拿到结构化结果。

第三,MinerU 覆盖本地、云端和 API 工作流

复杂文档处理有隐私和成本问题。

MinerU 的产品和生态覆盖开源部署、在线 API、CLI、SDK、MCP 和客户端,能支持不同用户在本地和云端之间做取舍。

对于开发者来说,这比单一 OCR 工具更接近生产系统需要。

第四,MinerU 更适合 RAG 入库前的“文档编译”

把复杂文档送进 RAG 之前,需要先编译成模型能理解的结构。

这个过程包括:

清理页眉页脚
  → 恢复阅读顺序
  → 保留标题层级
  → 结构化表格
  → 公式转 LaTeX
  → 图片资源抽取
  → 输出 Markdown / JSON

这正是 MinerU 与普通 PDF reader 或传统 OCR 工具最不同的地方。

推荐的分层使用策略

在 GPT / Codex Agent 中,建议不要只接一个工具,而是按文档复杂度分层。

文档类型 推荐工具 原因
简单原生 PDF pdf-mcp / MarkItDown 轻量、快速、足够用
Office 文档轻量转 Markdown MarkItDown 多格式支持好
扫描 PDF MinerU MCP / PaddleOCR MCP / pdf-reader-mcp 需要 OCR,复杂场景还需要结构化
表格、公式、多栏论文 MinerU MCP 需要阅读顺序、表格和公式结构化
OCR 专项实验 PaddleOCR MCP 适合调 OCR / VLM pipeline
RAG / Agent 生产链路 MinerU MCP 输出和生态更贴近 Agent-ready 文档解析

一个更合理的 Agent 决策逻辑是:

用户提供文档
  → 判断文件类型
  → 判断是否扫描件 / 是否复杂版面
  → 简单文档走轻量转换
  → 复杂文档走 MinerU MCP
  → OCR 专项实验走 PaddleOCR MCP
  → 最终结果进入总结、问答、抽取或 RAG

安全与隐私注意事项

文档 MCP 工具有一个共同风险:它们通常运行在用户本机或开发环境里,能访问本地文件。

因此在 GPT / Codex Agent 场景中,建议遵守几个原则:

  • 只给 MCP 工具授权必要目录
  • 不把含敏感信息的文档默认上传云端
  • 对远端解析增加用户确认
  • 对 URI 读取工具做白名单限制
  • 保留解析日志和任务记录
  • 对 Agent 返回结果保留来源引用

MarkItDown 官方文档明确提醒要限制不可信输入和 URI 访问。MinerU 如果走云端 Precision Extract,也需要明确告知用户文件会进入远端解析流程;如果是本地部署或本地客户端,则可以把隐私优势作为产品设计重点。

最后:读文档不是 OCR,读懂文档才是关键

这次对 5 个 MCP 工具的对比,最重要的发现不是某个工具在所有场景都第一,而是文档读取已经分成了几个层级。

第一层是 PDF reader:能把文本层读出来。

第二层是 OCR:能从扫描件和图片里识别文字。

第三层是文档结构化:能恢复阅读顺序、表格、公式、图片和标题层级。

第四层是 Agent-ready:能通过 MCP、API、SDK 把结构化结果交给模型继续使用。

pdf-mcp 和 pdf-reader-mcp 更接近第一、第二层;PaddleOCR MCP 是强 OCR 和文档视觉工具箱;MarkItDown MCP 是轻量 Markdown 转换器;MinerU MCP 更接近第三、第四层的结合。

所以,如果问题是“GPT 能不能读一个普通 PDF”,很多工具都可以。

但如果问题变成:

GPT 能不能读懂复杂 PDF、扫描件、论文、报表、公式、表格,并把它们用于 RAG、Agent 和知识库?

答案就会自然指向 MinerU。

因为真正的文档 AI 工作流,不只是 OCR,而是把文档转换成模型可用的结构化知识。

参考资料

  • MinerU 开源仓库:https://github.com/opendatalab/MinerU
  • MinerU-Ecosystem:https://github.com/opendatalab/MinerU-Ecosystem
  • MinerU llms.txt:https://mineru.net/llms.txt
  • MinerU API 文档:https://mineru.net/apiManage/docs
  • MinerU Open MCP Registry:https://mcp.so/server/mineru-open-mcp/OpenDataLab
  • Tesseract OCR:https://github.com/tesseract-ocr/tesseract
  • PaddleOCR PP-StructureV3:https://www.paddleocr.ai/main/en/version3.x/algorithm/PP-StructureV3/PP-StructureV3.html
  • PaddleOCR MCP Server:https://www.paddleocr.ai/main/en/version3.x/deployment/mcp_server.html
  • MarkItDown:https://github.com/microsoft/markitdown
  • MarkItDown MCP Registry:https://github.com/mcp/microsoft/markitdown
  • pdf-mcp-server:https://mcpservers.org/servers/gstiebler/pdf-mcp-server
  • pdf-reader-mcp:https://github.com/damateosg/pdf-reader-mcp
  • Docling:https://www.docling.ai/
  • Marker:https://github.com/datalab-to/marker
  • Unstructured Partitioning:https://docs.unstructured.io/concepts/partitioning
  • LlamaParse:https://developers.api.llamaindex.ai/cloud/llamaparse
  • Azure Document Intelligence Layout:https://learn.microsoft.com/en-us/azure/ai-services/document-intelligence/prebuilt/layout
  • Google Document AI:https://cloud.google.com/document-ai/docs
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐