大家好,我是herosunly。985院校硕士毕业,现担任算法工程师一职,获得CSDN博客之星第一名,热衷于大模型算法的研究与应用。曾担任百度千帆AI应用挑战赛、英特尔AI创新应用大赛等比赛评委,科大讯飞AI大学堂荣誉讲师,编写微软OpenAI考试认证指导手册。曾获得多项AI顶级比赛的Top名次,其中包括阿里云天池比赛第一名,科大讯飞分类挑战赛第一名。在技术创新领域拥有多项授权发明。
本文选取两张脱敏复刻的临床嵌套表单(给药费用表、人员资质授权表,共 7 个预期嵌套子表),对 TextIn xParse、MinerU VLM、PaddleOCR-VL、GLM-OCR 四款文档解析模型进行横向评测。评测不止于识别准确率,还将各模型输出接入本地 SQLite ETL + 自动质控流程,验证解析结果能否直接写入下游关系表。结果显示:字识别准确并不等于结构可用,只有完整保留“父区块 > 子表 > 子表行“层级的输出,才能被下游直接使用。全文可为临床表单、报销明细、资质档案等复杂表格场景的解析选型提供参考。
文章目录
- 一、前言:一个被 OCR 准确率掩盖的问题
- 二、实战准备:样本构造与四模型调用配置
- 2.1 测试样本:两张脱敏复刻的临床嵌套表单
- 2.2 四款模型调用方式与参数配置
- 三、实战验证:从结构保留到下游入库
- 3.1 结构对比:文本召回之外的父子层级保留
- 3.2 下游验证:本地 SQLite ETL与自动质控
- 四、结论
一、前言:一个被 OCR 准确率掩盖的问题
做过文档类数据入库的人,大概都遇到过这么一个别扭的情况:一份表单,OCR 跑完去看,表头、金额、日期、姓名,字面上一个不差,识别得很完整。可真把它接进下游,进 ETL、跑质控、喂给检索,数据就是用不了。我最近在处理一批临床业务表单时,又遇到了同样的问题。排查到最后,症结落在一类很不起眼的结构上:表中表。临床试验的给药费用表、研究人员资质授权表,都有这个特点:大表里套着小表,父子层级本身是有意义的。“这笔标本运输费属于哪个费用区块”“这条 GCP 培训记录挂在哪个人员档案下”,层级一旦丢失,OCR 字认得再准,下游也无法确定这行数据该放在哪里。换句话说,文字识别准确,不等于结构被保留,更不等于能直接入库。
那么,到底哪些解析工具能把这层结构完整保留下来?本文选取两张脱敏复刻的临床表单,对 TextIn xParse、MinerU VLM、PaddleOCR-VL、GLM-OCR 四款模型进行横向评测。评测不仅比较识别准确度,还搭建了一套本地 SQLite ETL + 自动质控流程,直接验证各模型的输出能否被下游写入数据库,以下是完整过程与结果。
二、实战准备:样本构造与四模型调用配置
2.1 测试样本:两张脱敏复刻的临床嵌套表单
本文样本为内部脱敏复刻的临床业务表单,不是真实患者原始数据,也不是医院生产系统中的数据。但结构特征完整保留——表中表、合并单元格、父子字段、金额位数表均在其中,用于观察不同模型对嵌套结构的保留能力。下游验证仅为本地 SQLite ETL + 自动质控流程,不代表任何生产数据库或医院系统的真实接入。
第一张为给药与访视费用类业务表单,包含 3 个预期嵌套子表:
| 父字段/父区块 | 预期子表 | 下游含义 |
|---|---|---|
| 试验药物 | 给药分组及样本量安排 | 给药方案、周期、计划例数等给药明细 |
| 访视补助与标本物流费用 | 补助金额小写 | 访视补助金额位数表 |
| 访视补助与标本物流费用 | 标本运输费用 | 标本物流费用明细 |
第二张为研究人员资质与项目授权类表单,包含 4 个预期嵌套子表:
| 父字段/父区块 | 预期子表 | 下游含义 |
|---|---|---|
| 研究人员基本情况 | 教育经历 | 人员档案明细 |
| 研究人员基本情况 | GCP培训与资质情况 | 资质核验记录 |
| 项目授权与职责 | 项目经历与授权职责 | 项目授权台账 |
| 项目授权与职责 | 方案培训记录 | 授权前培训质控记录 |
两张表合计包含 7 个预期嵌套子表。后续各项对比,均围绕这 7 个子表的结构保留情况展开。
2.2 四款模型调用方式与参数配置
四款模型使用同一批样本进行测试,均调用官方API。为保证对比公平,测试前清空历史结果、重新完整运行一遍,所有输出统一保存后作为对比依据。下面列出各模型的调用方式与关键参数,便于复现;仅展示参数、运行方式与成功状态,不涉及任何密钥或账号信息。总览如下:
| 模型 | 运行方式 | 本轮参数配置摘要 | 状态 |
|---|---|---|---|
| TextIn xParse | API 调用,VLM 解析模式 | include_hierarchy=True、include_table_structure=True、title_tree=True、table_view=html、parse_mode=vlm | 成功 |
| MinerU VLM | API/VLM 方式解析 | model_version=vlm、enable_table=True | 成功 |
| PaddleOCR-VL | 异步 OCR 任务接口 | MODEL=PaddleOCR-VL-1.6、useDocOrientationClassify=False、useDocUnwarping=False、useChartRecognition=False | 成功 |
| GLM-OCR | OCR API,文本与坐标基线 | tool_type=hand_write、language_type=CHN_ENG、probability=True | 成功 |
以下分别说明四款模型本轮的运行情况。
2.2.1 TextIn xParse
xParse 通过 API 调用,采用 VLM 解析模式,并开启了表格结构相关能力。核心配置即上表中的几个参数:include_hierarchy、include_table_structure、title_tree、table_view=html、parse_mode=vlm,它们直接决定 xParse 是否输出父子层级,是本轮的观察重点。
调用成功返回后,生成两份样本对应的 Markdown 结构化结果文件,后续所有结构对比与 ETL 写入均基于这两份结果。
2.2.2 MinerU VLM
MinerU 采用批量解析任务,调用时指定model_version=vlm并开启表格识别(enable_table=True)。
任务申请、文件上传、轮询均已完成,结果解压后生成 Markdown 文件,用于后续结构对比。
2.2.3 PaddleOCR-VL
PaddleOCR-VL 通过异步 OCR 任务接口调用,模型指定为PaddleOCR-VL-1.6。本轮关闭了方向分类、文档矫正、图表识别等非核心项(useDocOrientationClassify=False、useDocUnwarping=False、useChartRecognition=False),专注版式与表格解析。
任务完成后返回结果地址,下载后导出页面级 Markdown。
2.2.4 GLM-OCR
GLM-OCR 本轮定位为 OCR 文本/坐标基线,采用hand_write工具类型、中英文识别(language_type=CHN_ENG)、返回置信度(probability=True)。
调用成功后获得行级文字、坐标与置信度,用于对照——即在仅有文本和坐标、没有表格层级时,观察下游的处理情况。
三、实战验证:从结构保留到下游入库
3.1 结构对比:文本召回之外的父子层级保留
评价指标包括:关键文本项召回、HTML 表格数量、真正嵌套的<table>数量、最大表格深度。其中“关键文本项召回”仅反映标题、父区块名、子表名等文字是否被识别出来,并不代表结构是否被保留——这一点很重要,后文可以看到两者能够明显分离。
第一张样本,TextIn xParse 返回 7 个表格,其中 3 个为嵌套表格,正好对应 3 个预期子表;MinerU VLM 和 PaddleOCR-VL 均返回 4 个表格,但嵌套表格数为 0;GLM-OCR 仅有文本和坐标层面的结果,不返回表格层级。
第二张样本,TextIn xParse 返回 5 个表格,其中 4 个为嵌套表格,对应 4 个预期子表;MinerU VLM 和 PaddleOCR-VL 均只返回 1 个表格,嵌套数仍为 0;GLM-OCR 依旧作为文本/坐标基线。
各模型在两张样本上的结构指标汇总如下:
这里有一处细节需要单独说明。第二张样本中,xParse 的精确关键词命中为 5/7,原因是两个父区块术语未被逐字命中。但这只是文本层的字面匹配口径,与结构可用是两回事——xParse 在这张表中仍完整保留了 4 个嵌套表格,后续本地 ETL 也实现了 4/4 写入(详见下游验证部分)。这恰好说明:字面召回与结构可用是两个不同的维度,下游真正依赖的是后者。值得注意的是,PaddleOCR-VL 在样本二的关键词命中为满分 7/7,高于 xParse,但其嵌套表格数为 0,文字全部识别正确,结构却没有保留下来。
3.1.1 界面直观对比
先从产品界面直观感受各工具的差异。同一张嵌套表格,解析后在各家产品界面中的呈现如下:
TextIn xParse 界面截图:
MinerU VLM 界面截图:
PaddleOCR-VL 界面截图:
单看渲染效果,几款工具的表格都相当规整,行列边界、合并单元格都适合人工阅读。但"看起来整齐"和"结构可用"是两回事——界面上的差异只是表象,真正决定下游能否入库的,是底层 HTML 里是否携带"父区块 > 子表"这层关系。下面从源码层面逐一验证。
3.1.2 源码实证
TextIn xParse
xParse 输出中可以看到父单元格内部保留子表<table>:
MinerU VLM
MinerU VLM 的输出包含表格和文本内容,但本轮结果中子表更多被展开为同层结构,下游需要额外推断父子归属:
PaddleOCR-VL
PaddleOCR-VL 也能输出普通 HTML 表格,并保留部分行列合并;但在本轮样本中,子表被表达为同一张表内的 rowspan/colspan 结构,而不是父单元格内再嵌套一个子<table>。
GLM-OCR
GLM-OCR 返回逐行文字和坐标,更适合作为 OCR 文本召回基线:
同时,还有一处容易混淆的地方:视觉规整不等于结构可用。单看渲染效果,MinerU VLM 和 PaddleOCR-VL 的表格其实相当规整,行列边界、合并单元格都适合人工阅读。但本文统计的"嵌套表格数",衡量的不是表格是否美观,而是 HTML/Markdown 中是否保留了"父区块 > 子表 > 子表行"这层关系。一个模型完全可以输出一张外观漂亮的普通大表,同时把子表全部摊平其中,此时下游若要写入子表结构,仍需自行推断该子表归属于哪个父区块。因此,对比的核心并非“谁识别的文字更多”,真正拉开差距的,是输出中是否携带“该子表属于哪个父区块”的结构信息。
3.2 下游验证:本地 SQLite ETL与自动质控
仅凭肉眼观察输出不足以说明问题,因此本轮还搭建了一套本地 SQLite ETL + 自动质控流程。该流程读取四款模型的解析结果,将可直接识别的嵌套子表写入两张目标表(nested_tables和nested_table_rows),并执行父子归属与行数完整性质控。这里是本地验证流程,不是生产数据库,也未接入任何医院系统。目的只有一个:检验解析结果是否已足够结构化,能否直接进入下游的关系表。
流程运行完成后,数据库写入统计如下:
| 表 | 记录数 |
|---|---|
model_runs | 8 |
forms | 8 |
nested_tables | 7 |
nested_table_rows | 13 |
qc_results | 35 |
其中nested_tables=7全部来自 xParse——两张样本分别写入 3 个和 4 个预期子表。其余三款模型因未直接保留可入库的父子结构,均未写入nested_tables,而是进入质控结果中的修复/重建标记。qc_results=35为 8 次模型运行产生的质控记录,覆盖父子归属、行数完整性等检查,状态分布为:通过 14 条、需修复 14 条、需重建 6 条、失败 1 条。其中失败的 1 条,来自 GLM-OCR 在第一张样本中对"给药分组及样本量安排"的父子归属检查——GLM-OCR 作为纯 OCR 文本/坐标基线,未提供可直接使用的嵌套子表,因此判为失败。这并非 xParse 的写入失败。
四款模型在 ETL 流程中的写入结果如下:
MinerU VLM 和 PaddleOCR-VL 本轮均有表格内容和关键文本,但未直接给出嵌套父子结构,因此标记为“需修复父子关系”。这并非否定其文本召回价值,而是说明若要进入同样的子表结构,仍需额外进行一遍父子关系修复。GLM-OCR 定位为 OCR 基线,需从文本和坐标重新构造表格与父子关系,因此标记为“需重建表格”。
xParse 在两张样本中写入了全部 7 个预期子表。下表给出两种口径的行数,以避免两个数字被误读为不一致:网格行数(含表头)是解析出的表格总行数,写入数据行(不含表头)是真正落入子表明细的数据行,两者的差值恰好对应每个子表的 1 行表头。
两个口径分别求和:网格行数(含表头)4+2+2+3+3+3+3=20;写入数据行(不含表头)3+1+1+2+2+2+2=13,与nested_table_rows=13一致。两个数字口径不同,但可以相互印证,每个子表恰好扣除 1 行表头。
查询本地数据库的子表记录可以看到:两张样本共写入 7 个预期子表,给药费用表 3 个、人员授权表 4 个,每个子表的实际数据行数均与预期一致,状态正常。关键在于**xParse 的输出不只是“外观像一张表”,而是能将父区块、子表名与行数校验一起落入关系表。**进一步展开到明细层,13 行子表明细也全部入库,因此 ETL 可以从父区块、子表名、行数据三个层面取用结果。
四、结论
在很多文档问答场景中,模型只要能答出某个值,就容易被认为"解析成功"。但临床表中表更关注的是—,这个值究竟属于哪里。 例如,问"标本运输费用是多少",仅回答"120 元"并不完整。下游真正需要的是带有路径的结果:
访视补助与标本物流费用 > 标本运输费用 = 120 元
再如,问"某研究人员有哪些 GCP 资质记录",仅报出培训名称也不够,系统需要知道这些记录来自:
研究人员基本情况 > GCP培训与资质情况
再如,问"已授权的项目职责是什么",该职责值必须绑定到:
项目授权与职责 > 项目经历与授权职责 > 对应项目记录
缺少父路径,答案看似有值,却无法稳定追溯到正确的业务区块。一旦进入质控、审计、RAG 溯源或自动入库环节,这层缺失就会转化为实际成本:需要额外规则判断子表边界、补全父字段、重建层级,甚至在多个相近金额、多条相似培训记录之间重新做归属判断。因此,表中表解析的目标从来不只是“把文字转出来”,而是把业务对象转成下游可以直接使用的结构化数据。回到本轮实战,结论比较清楚:表中表解析不是单纯的 OCR 准确率问题,而是结构可用性问题。四款模型的表现汇总如下:
| 模型 | 嵌套结构 | ETL 写入 | 本轮定位 |
|---|---|---|---|
| TextIn xParse | 完整保留(3+4 共 7 个子表) | 7/7 可直接入库 | 可直接入库 |
| MinerU VLM | 表格/文本有召回,未保留父子结构 | 0,需修复父子关系 | 需父子关系修复 |
| PaddleOCR-VL | 表格/文本有召回,子表被摊平 | 0,需修复父子关系 | 需父子关系修复 |
| GLM-OCR | 仅有文本/坐标,无表格层级 | 0,需重建表格 | OCR 基线 |
MinerU VLM 和 PaddleOCR-VL 本轮文本与表格内容均有召回,只是未直接保留嵌套父子结构,下游若要稳定写库,仍需先补一遍父子关系。GLM-OCR 更适合作为 OCR 文本/坐标基线,提供文字与坐标,但不返回表格层级。TextIn xParse 的价值正在于此:它输出的不是一堆 OCR 文本或一张普通二维表,而是将父子层级一并带出的结构化结果,能够直接被 LLM、Agent、RAG、ETL 等下游取用。
对于临床表单、报销明细、资质档案这类复杂表格场景,选型时的建议是:**不要只关注“识别出多少字”,更要检查结构是否保留、父子关系是否清晰、下游能否直接取用。**最直接的验证方式,是拿一张自己最棘手的嵌套表实测一遍。
如果你对复杂表格解析、文档结构化处理等方向感兴趣,可以体验 TextIn xParse,进一步了解其在真实业务场景中的解析效果:
体验链接(注册送1000页额度):https://www.textin.com/register/code/ZR28L4