news 2026/9/8 12:36:52

PDF转Markdown工具选型:开源方案对比与私有化部署实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PDF转Markdown工具选型:开源方案对比与私有化部署实践

1. 项目背景:为什么公司非做 PDF 转 Markdown 不可

故事得从去年年底说起。当时我们部门要启动一个企业内部知识库项目,目标很直接——把过去几年积累的几千份技术文档、产品手册、会议纪要和设备说明书统一整理成结构化文本,喂给后续的大模型检索链路。第一批调研刚做完,所有人就意识到一个绕不开的瓶颈:这些资料百分之八十是 PDF,而 PDF 是一个为“打印”而非“阅读”设计的格式。

听起来很简单对吧,PDF 转 Markdown,复制粘贴不就行了?真去做了才明白,这个需求背后藏着一大堆细节。PDF 内部根本没有“段落”“表格”“标题”这样的语义结构,它只有一个个字符的绘制坐标、字体信息和绘制指令。转换工具要做的其实是从这些“画出来的文字”里反推出逻辑结构:哪一段是标题、哪几行组成表格、图片和正文怎么分离、公式怎么还原成 LaTeX、双栏论文怎么保持阅读顺序。任何一个环节处理不好,产出的 Markdown 就是一堆看得见却没法用的“字符垃圾”。

而我们最终的目标场景,决定了转换质量的下限。知识库里的文档要被切成小块送进向量库做检索增强生成,还要在前端以 Markdown 格式呈现给业务人员阅读。如果标题层级混乱,切块就会切到一半;如果表格丢失,检索问答就答不对;如果公式变成乱码,工程师直接没法用。所以这不只是选一个“能用”的工具,而是要选一个“能满足企业级质量线”的方案。

我估计不少朋友也遇到过类似的处境:想把手头的 PDF 批量转成 Markdown 做二次处理,但市面上工具五花八门,用了 A 觉得表格不行,换了 B 发现公式乱码,再换 C 又折腾半天部署不上。这篇文章就把我这几个月踩过的坑、对比过的方案、最后沉淀下来的选型逻辑完整复盘一遍,给正在做同样事情的你一个可直接参考的决策框架。

先说结论:开源工具 MinerU、marker、docling,规则派选手 pandoc、pdfplumber、PyMuPDF,商业闭源 API,以及多模态大模型识别,这四类路线各有各的适用区间,不存在一个万能工具能同时满足“中文友好、公式完美、表格规整、速度快、可私有化”五个要求。企业落地的正确姿势,是做一个按文档类型分流的静态路由,不同来源的 PDF 走不同的解析管线。

2. 四类方案横向测评:开源三件套、规则派、闭源 API 与多模态模型

在开始填充细节之前,我先把这四类路线的整体情况摊开。这是我们在选型阶段做的一张粗筛表,后面所有的实测结论都建立在它的基础上。

2.1 第一梯队:版面识别型开源三件套

版面识别型工具的核心思路,是先用目标检测模型找到页面上的标题区、正文区、表格区、图注区,再用 OCR 或文本提取模块逐区块解析,最后按阅读顺序组装成 Markdown。这一类的代表是 MinerU、marker 和 docling。

MinerU是上海 AI 实验室开源的项目,GPU 推理模式下对中文文档的支持在开源方案里可以说是第一梯队。它能输出带位置坐标的中间结果,公式识别用的是自研的 TeX 识别模型,表格走专门的表格结构模型。我用一份 30 页的中文产品手册测过,输出的 Markdown 里标题层级基本正确,表格结构和图片位置都保持了合理顺序,公式能还原成 LaTeX 格式。缺点也在测试里暴露得很充分:依赖重、显存占用高,CPU 模式下单页耗时能到 3 秒以上,批量跑 500 页文档必须有 GPU 兜底。

marker是另一款高人气工具,底层基于深度学习模型做版面分析和阅读顺序恢复。它在英文论文、英文技术书上的效果相当不错,中文表现则明显逊色一些。对纯文本型 PDF,marker 的速度比 MinerU 快不少,我在同一台 GPU 机器上跑 20 页英文文档,marker 大约 12 秒,MinerU 大约 40 秒。但速度换来的代价是细节损失:复杂表格的单元格合并经常出错,行内公式偶尔会被吞掉。如果你的语料以英文技术文档为主,marker 效率很好;中文语料占大头的话,我更推荐 MinerU。

docling是 IBM 开源的项目,特点是对“文档结构”的理解比较完整,能输出 JSON 结构的文档树,而不只是 Markdown 字符串。这个特性对后续做知识库切块非常有价值——你可以直接从 JSON 树里按标题层级切分。它内置的表格识别模型支持复杂表头,英文场景表现不错,中文场景受限于训练数据,公式识别能力也一般。docling 还有一个让人头疼的点:依赖库非常多,部署环境稍微一复杂就缺包。

2.2 规则派:pdfplumber、PyMuPDF 与 pandoc 的能力边界

在深度学习方案流行之前,PDF 转 Markdown 基本都是规则派的地盘。pdfplumber 擅长按坐标提取文本块和表格线,PyMuPDF 在速度和中文编码支持上表现稳定,pandoc 则更适合把已经有结构信息的 docx、html、epub 转成 Markdown。

这三件套的真实价值,在于处理“无脑型 PDF”——也就是那些由 Word 或 LaTeX 直接导出的、带文本层且版面规整的电子版文档。对这种输入用正则在文本层里找标题、按坐标聚合成段落、识别表格线结构,效果通常比深度学习模型更稳定也更可控。我处理过一批内部系统导出的报表 PDF,纯文本加简单表格,pdfplumber 加二十行 Python 代码就能把表格还原得整整齐齐,跑一份文档只要一两秒。

但规则派的边界非常明显。遇到双栏学术论文、无文本层的扫描件、复杂嵌套表格,或者有图像遮挡的版面,它就彻底抓瞎了。pandoc 对 PDF 的直接支持更是依赖外部引擎,实际就是把 PDF 当作文本先抽出来再转换,并没有版面理解能力。所以我的定位是:规则派不是替代方案,而是预处理和后处理阶段的好帮手。比如用 PyMuPDF 判断页面是不是纯扫描件、抽取图片、清理页眉页脚,这些脏活累活交给它最合适。

2.3 闭源 API 与多模态模型:把问题外包给云端

闭源方案里,一类是专门的 PDF 解析 API,比如 Mathpix 这类早年从数学公式识别起家的服务,到现在已经发展成完整的文档转换接口;另一类则是通用多模态大模型,直接把 PDF 页面渲染成图片塞给模型,让它输出 Markdown。

多模态大模型的优势是理解力天花板最高。GPT-4 级别的模型看完一整页图后,能正确推断段落层次、理解表格语义、把页眉页脚识别为干扰信息——这在真实业务里太重要了。我实测过一份版面极其混乱的说明书,开源工具全军覆没,多模态模型硬是给出了基本可读的 Markdown。但它的劣势同样致命:成本高、速度慢、数据出境问题。企业文档里常有内部价格、客户名单、未公开产品信息,这些内容送进云端 API 之前必须经过严格合规评估。我自己在项目里定了条红线:内部敏感文档一律不允许走公网 API,只能走私有化部署的开源模型。

至于 Mathpix 这类专业转换 API,英文数学论文场景的识别质量非常高,公式和表格都处理得很干净。中文支持相对弱一些,定价也不便宜,比较适合小批量高价值文档,不适合几千份文档规模化批量跑。

2.4 我做的选型粗筛表

综合第一轮调研,我按企业关心的维度做了张对比表。这里仅代表我自己的测试环境和样本集,不同数据集的结论可能有差异,但框架可以参考。

维度MinerUmarkerdocling规则派组合云端 API/多模态
中文版面识别中等中等因服务而异
公式转 LaTeX中等中等不支持
复杂表格还原较好一般较好简单表格才可用
扫描件支持内置 OCR需接 OCR需配合 OCR不支持自带
部署门槛高,需 GPU零部署
单份 20 页耗时40-60 秒12-20 秒20-40 秒1-3 秒5-20 秒
是否可私有化
中间结果可编程性好,有坐标一般好,有 JSON 树

这张表做出来之后,选型方向基本就清晰了:私有化部署为主,内部按文档类型分流,主力解析走 MinerU,规整文档走规则派,疑难杂症单独评估。下一章我会用六个高危场景,把每个工具的“真面目”逐一揭开。

3. 六个最考验工具的高危场景实测

选型阶段最忌讳的就是拿一份“标准文档”测一遍就下结论。真实的企业文档库,什么牛鬼蛇神都有。我们项目组专门攒了一批“刁钻样本”,覆盖了六类最容易翻车的场景,逐一跑所有候选方案。

3.1 数学公式:最容易翻车的格式高地

数学公式是 PDF 转 Markdown 的试金石。PDF 里的公式本质上是无数个字符和曲线指令,没有语义,转换工具要做的是把它重新识别成结构化的 LaTeX 或 MathML。

我用一份包含 50 个行内公式和 20 个行间公式的数学文档做了测试。MinerU 的表现最稳,行间公式识别率在 90% 以上,行内公式会有少量把 $x_i$ 误识别成 $x i$ 的情况,但整体可读。marker 对行间公式不错,行内公式丢失率比较高。docling 对公式支持一般,复杂的积分、求和符号容易变成一串乱码。

最值得注意的坑是字体子集问题。有些 PDF 为了压缩体积,会把字体裁剪成只包含文档用到的字符子集,转换工具遇到未嵌入的字符映射时,公式里会直接出现“缺字”方块。这种问题靠解析器本身解决不了,必须上 OCR 或者多模态模型兜底。我们在生产流程里加了一条规则:凡是输出 Markdown 里出现大量缺字符号的片段,自动标记为“公式专项人工复核”。

3.2 表格:从“能看”到“能用”的距离

表格是另一个重灾区。Markdown 表格本质上是简单的行列矩阵,但真实世界的表格有合并单元格、跨页表头、嵌套内容、多行文本。开源工具解析表格时,经常出现“行列错位”“内容丢失”“多行文本被压成一行”这三类问题。

我测过一份设备参数表,里面有个单元格包含了 5 行说明文字,marker 直接把 5 行内容拼成一行,后面的列全部串位。MinerU 相对好一些,但也偶尔丢失合并单元格信息。docling 的表格结构模型对复杂表头识别不错,但遇到跨页表格时表头列会错乱——表头被当成数据行输出,下游检索时列名就全错了。

真实项目的处理方案是以“能用”为标准,不要追求“完美还原”。我的经验是:转换出的 Markdown 表格只用于预览和简单问答;凡是需要精确制表分析的文档,解析阶段直接把表格转成 HTML 结构,再存成独立模块,下游按 HTML 解析,而不是硬转 Markdown。Markdown 表格本身表达能力有限,硬转只会损失信息。

3.3 代码与程序输出片段

技术文档里的代码块,是另一个容易被低估的高频场景。问题在于,PDF 保存代码时通常会丢失等宽字体信息,缩进和空格虽然在文本层里存在,但解析器经常把它们合并或移除,导致 Python 代码的缩进结构被破坏。

更麻烦的是,有的代码片段在 PDF 里是以“高亮背景 + 边框”的形式呈现的,比如 LaTeX 导出的程序列表。规则派方案直接抽文本会把代码页眉里的文件名、行号混进代码里;版面识别工具在“代码区域”的检测上也没有专门优化。我们实测 MinerU 对这类场景的识别效果一般,代码中的注释行偶尔被识别成正文段落。

应对手段是后处理:在解析管线的末尾加一个“代码块修复器”,用启发式规则识别以常见编程关键字开头、包含等号和括号的段落,自动把它们重组成代码块,并保留缩进。这个修复器是我强烈建议要做的一层,它能把最终可读性从 60 分拉到 90 分。

3.4 双栏学术论文与复杂版面

双栏论文的阅读顺序问题,是所有版面识别工具共同的痛点。人类阅读时先读左栏从上到下,再读右栏从上到下,但 PDF 的字符绘制顺序往往不是这样——同一行的左栏文字和右栏文字在文本流里是交替出现的。

MinerU 对中文双栏的处理还行,大多数情况下能按正确顺序输出。marker 在英文双栏论文上的表现也不错,毕竟训练数据充足。docling 偶尔会出现左右两栏文本穿插的情况,可能与模型先检测文本块再排序的策略有关。真正让人头大的是三栏及以上版面,比如某些企业年报、产品彩页,四栏、五栏排版都有,几乎所有工具都会乱序。

这里我建议做一个“列数检测器”:解析前用 PyMuPDF 统计页面文字的 x 坐标分布,如果在同一高度上有多个明显的列聚集,就把页面切成列区间,逐列单独提取文本,最后按列拼接。这个预处理能将双栏场景的阅读顺序准确率提升到 95% 以上。

3.5 扫描件与图片型 PDF

扫描件是另一个完全不同的赛道。整页 PDF 就是一张图片,没有文本层,必须走 OCR。理论上,带 OCR 能力的版面识别工具都能处理扫描件,但实际效果差异很大。

MinerU 内置的 OCR 对中文印刷体识别率很高,但扫描件分辨率一旦低于 150dpi,识别率断崖式下降。所以我们的扫描规范明确要求入库前至少 300dpi 扫描。marker 需要单独接入 OCR 引擎,多了一个环节也多了一层出错风险——OCR 输出和版面模型之间的坐标对齐是难点,经常出现文本框漂移。docling 对扫描件的支持更弱,需要专门配置 OCR 服务。

还有一类“伪扫描件”,其实是设计软件生成的图片型 PDF,页面背景是图片,上面叠了少量文字。这种文档骗过了很多只检查“页面是否有文本层”的工具。我建议在流程里加一步预检:用 PyMuPDF 提取每页文本量,如果某页文字量几乎为零,就判定为扫描页,单独走 OCR 管线,而不是排队等待版面模型处理——否则只是白白浪费算力。

3.6 页眉页脚与“幽灵文本”

最后一类是页眉页脚干扰。企业文档的页眉页脚简直是重灾区:公司名称、文档编号、页码、版本号、内部密级标识,密密麻麻。解析器如果不做处理,这些文字会被当作正文揉进段落里,污染后续的检索环节。

更隐蔽的问题是“幽灵文本”。某些 PDF 在页面上有不可见的文字层,比如为方便检索而叠加的隐藏文本、水印文字,或者编辑工具留下的元数据残留。这些文字肉眼看不见,但解析器提取文本层时会原样提取,造成输出里出现大量重复、无关的片段。

处理方案分两步:第一步,在最前面用 PyMuPDF 把页面文字按坐标分层,过滤掉页面顶部和底部边距内的文字;第二步,针对“幽灵文本”,建立一个基于字体和透明度的过滤规则——透明度为零或字体异常的文字直接丢弃。这套规则在应对正规厂商导出的文档时效果很好,能清理掉九成以上的页眉页脚污染。

4. 企业落地时真正决定成败的工程细节

选型只是开始,真正让项目从“Demo 跑通”变成“生产可用”的,是下面这些工程细节。我在这个阶段踩的坑,比选型阶段多出一倍。

4.1 并发与批处理时的显存和内存管理

开源版面模型几乎都是 PyTorch 生态,推理时要常驻 GPU 显存。一开始我们按最朴素的思路:每个任务起一个进程,跑完关掉。结果并发数一旦到 4,GPU 直接 OOM。

后来改成模型常驻 + 任务队列模式:启动时加载一次模型,之后多个文档复用同一个进程,通过队列调度。MinerU 单卡能同时跑的并发数大概在 2 到 3 个任务之间,再高需要拆分任务为“按页并发”,因为长文档内部页与页之间没有依赖关系。CPU 模式只建议用于低峰期的补救,速度实在没法看,20 页文档要跑 10 分钟以上,生产环境基本不可用。

批处理还有一个容易被忽略的点:文档大小需要提前探测。一个 500 页的超大 PDF 和 50 个 10 页的小文档,在调度策略上应该区别对待。超大 PDF 必须按页拆包,分批送入模型,避免单任务长时间占用 GPU;小文档则可以优先批量处理,提高整体吞吐。

4.2 与知识库和检索流程的衔接

转换工具只是链路中的一环。Markdown 产出的质量,最终要接受下游检索的检验。我们在实践中发现三个衔接要点:

第一,切块策略不能只按字数,要结合 Markdown 的标题层级。用 docling 的 JSON 树可以精确找到各级标题的位置,按标题切块能保证每个块是一个语义完整的小节,检索命中后的上下文更连贯。

第二,表格和代码块需要特殊标记。向量检索对表格的处理天然偏弱,检索时把整个 Markdown 表格塞进 embedding 模型,效果远不如转成“表头 + 行记录”的逐条文本。我们的做法是解析后额外输出一个“结构化视图”,把表格转成 dict 列表,让下游单独建索引。

第三,不要直接把 Markdown 原始文本送进大模型生成答案。Markdown 里的 # , * , | 这些符号会干扰模型输出格式。我们在提示词层面做了约束,先让模型把检索到的 Markdown 转换为纯文本摘要再回答,实测回答稳定性提升明显。

4.3 私有化部署与数据合规边界

企业知识库的内容通常涉及商业机密,数据出境是绝对不能碰的红线。我们的默认策略是:所有解析流程跑在内网 GPU 服务器上,模型权重从内网镜像源拉取,转换过程不产生任何外部网络请求。

这里有个小坑:MinerU 和 marker 的模型权重默认从 Hugging Face 下载,而在部分网络环境下这个下载路径不可用或极慢。部署时要提前把模型权重下载好,放到本地目录,再通过环境变量指定模型路径。docling 的依赖解析同样要从内网 PyPI 源走,否则装到一半必然卡住。

云端 API 不是完全不能用,但要有边界。我们对非敏感文档做了一个白名单机制,只有经过审批的样例可以走外部服务做对照测试。这个机制既保住了合规底线,也给疑难场景保留了后路。

4.4 监控、失败重试与质量验收

生产环境跑起来之后,最怕的不是解析质量偶尔波动,而是“不知道它坏了”。建立监控体系的成本不高,收益极大。

我给每个解析任务都打点这几项指标:任务耗时、GPU 显存峰值、输出 Markdown 字节数、失败原因分类、重试次数。输出字节数是早期很有效的质量代理指标——一份 20 页文档正常输出大约 10KB Markdown,如果某次输出只有 1KB,大概率是解析过程中某一步挂了。

失败的 PDF 也要分类处理。加密文档走解密流程;损坏文档直接返回“无法处理”;超大文档拆分重试;识别率低于阈值的文档进人工复核队列。这套机制上线后,我们的自动处理覆盖率从 70% 提升到 90% 以上,剩下的疑难样本交给人工兜底,项目才算真正达到了可交付的状态。

5. 最终选型结论与排错经验分享

到这里,文章的核心内容基本都覆盖了。最后一章把我们的最终选型结论,以及几个可复用的排错经验集中记录下来。

5.1 不存在的“万能工具”:按文档类型分流的静态路由

我们的最终架构长这样:入口先做文档预检,用 PyMuPDF 快速判断页面数、文本层、扫描率、加密状态。预检结果决定走哪条管线:

  • 规整电子版 PDF:pdfplumber + 自研清洗脚本,速度最快,成本最低
  • 常规业务文档:MinerU 推理,输出 Markdown + 坐标 JSON
  • 扫描件/图片型 PDF:先 OCR 再加版面识别,OCR 分辨率必须达标
  • 疑难复杂版面:多模态大模型兜底,但走内部私有化部署的模型实例

这个路由不是一次定死的,而是根据数据分布动态调整的。我们每两周做一次采样评估,看各条管线的通过率变化。数据集中新增了某种类型的文档时,就把它抽出样本,重新验证该走哪条路线。

5.2 几个值得记录的故障现象与根因

挑三个有代表性的案例讲讲。

第一个是“重复文本幽灵”。某个 PDF 转换后正文里反复出现同一句设备描述,排查后发现,这个 PDF 是用在线编辑器生成的,文件里叠加了一层不可见的旧文本层,肉眼看不到但能被提取。修复方案就是前面提到的按透明度过滤。

第二个是“数字表格错位”。一份财务报表转换后,第二列和第三列的数字全串了。根因是表格线的检测误判——表头下方有一条横贯整页的分隔线,模型把它当成表格线,导致列数识别错误。修复方案是生成时对表格区域做一次列数众数统计,出现单页列数异常时触发重新解析。

第三个是“长篇文档内存爆炸”。一个 700 页的技术手册在转换到 400 多页时进程崩溃,反复重试都在同一位置崩溃。后台看日志确认是单页图表高分辨率导致 CPU 内存溢出,而 GPU 版本不受影响。最终方案是给 CPU 兜底模式设置了每页图片最大边长限制,超限自动压缩。

5.3 我的建议:先用 1 到 2 周做采样集评测

如果你现在正准备做类似的项目,我最想给你的建议是:开工之前,先花一到两周的时间建立采样集做评测,不要急着上线。

从库里随机抽取 50 份有代表性的 PDF,让团队成员手工标注每一份的预期转换结果,包括文档类型、版面特征、重点难点。然后让候选工具逐份跑,用统一标准打分:A 表示直接可用,B 表示小修可用,C 表示重转还是不行。按文档类型统计各工具的 A 级率,再结合部署成本、速率、合规要求做决策。

这套做法的价值在于,它逼着你在选型前想清楚“我的文档到底长什么样”。很多项目失败,不是因为工具不好,而是因为需求方自己都不清楚数据集的真实构成。采样集评测做完,你脑子里会有一张非常清楚的“文档类型—工具能力”映射表,后面所有决策都会顺畅得多。

说到我自己踩完这些坑之后的体会,有一点特别想强调:不要迷信任何单一工具的官方样例。官方 Demo 永远是挑最好看的文档展示,企业真实文档库里的排版复杂度远超它们的演示集。一定要用自己业务里的真实数据做测试,而且要测足够多的样本,否则上线后第一周就会被各种意外版面搞得焦头烂额。这个项目做完之后,我们内部还沉淀了一份“企业 PDF 版面易错点清单”,现在已经成了团队培训的必备材料,每次新人接手转换任务都要先过一遍。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 12:36:31

AI Agent行业分析师设计:隔离宏大叙事与入场理由的关键机制

在一个由 9 个 AI Agent 组成的研究团队里,行业分析师是最容易被误会的角色。它看起来只需要读资料、写行业综述,实际搭建之后才会发现,这个角色的价值不在于描述一个行业有多大,而在于回答一个更克制的问题:这个行业的…

作者头像 李华
网站建设 2026/9/8 12:35:57

下载工具怎么选?六款神器组合拳,从直链到磁力全覆盖

经常有人私信问我:有没有一款下载工具能通吃所有资源?说实话,每次看到这种问题我都想先反问一句——你说的"所有资源"到底是指什么?直接链接的文件、种子、磁力、还是网页里的流媒体视频?我这些年把各种下载…

作者头像 李华
网站建设 2026/9/8 12:35:51

8款热门AI写作辅助软件横向实测,本硕博撰稿避坑全指南

前言:AI 写论文乱象频发,实测 8 款工具理清适配边界 每到毕业季,本科生、硕博生都会集中寻找 AI 论文辅助工具,市面各类写作软件层出不穷。但普遍存在几类硬伤:虚假参考文献、无法匹配本校格式、不支持公式代码生成、A…

作者头像 李华
网站建设 2026/9/8 12:34:08

1-Wire单总线协议深度解析:从物理层到时序与ROM搜索

做嵌入式这么多年,凡是搞过温度采集、电池管理或者传感器网络的人,基本都绕不开Dallas Semiconductor(现在归了Maxim)推出的1-Wire单总线协议。特别是一提到DS18B20,几乎成了单总线代名词。这东西的厉害之处在于&#…

作者头像 李华
网站建设 2026/9/8 12:32:41

磁力链接聚合搜索:基于DHT网络的多源去重排序实践

简介:这是一份磁力链接聚合搜索的前端工程源码包,面向需要搭建聚合检索工具或学习前端项目结构的开发者。在传统多源检索场景中,信息分散、结果重叠,这套源码围绕关键词提交、结果聚合展示和配置管理核心流程,提供了完…

作者头像 李华
网站建设 2026/9/8 12:32:37

STM32F429移植STemWin+FreeRTOS:用GUI Builder实现LED图形控制

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华