将页面解析为结构化文本或 markdown,意味着要做出一连串的判断:
- 这块对齐的文本是表格,还是仅仅是布局?
- 跨越两行的表头是保持两行,还是被压平为一行?
- 延续到下一页的表格算一个表格还是两个?
- 流程图是被描述、转换为 Mermaid,还是被跳过?
不同的解析器会做出不同的判断。因此,两个解析器可能捕获了页面上的每一个词,却仍然交给你含义不同的输出。当智能体基于该输出采取行动时,解析器的选择就成了智能体决策的一部分,所以哪些选择是正确的就变得很重要。但对于一个正确解析的页面应该是什么样子,并没有共同的定义。
The文档解析协议(DPP)是我们提出的定义:一份文档解析的答案标准,并附上每个艰难判断背后的理由。今天我们发布工作草案 0.1。它的 140 条规则涵盖文本、表格、表单、图表、示意图等,每条规则都附带示例页面及其期望的输出。我们基于ParseBench标准答案背后的惯例制定了它。
同一张表格得出三种不同的结果
这是一个有两行表头的销售页面。年份横贯顶部,每个年份跨越各自的列,季度位于其下方。2023 年还有一个全年列。
三个解析器可能会把那张表格转换成这样的 Markdown,展示到第一行数据为止。
现在向智能体询问 2024 年第二季度全系统同店销售额。在 A 中,季度位于数据行,而包含 4.1 % 的那一列表头为空。智能体必须根据位置推断表头分组,而管道表格无法说明空白单元格是跨列的一部分还是空着。在 C 中,“Q2”匹配两列,3.8 % 和 4.1 %。B 在列标签中明确写出了年份和季度。
DPP 将 B 标记为不符合规范,尽管它能回答该问题。页面上从未印出“2024 Q2”。解析器 B 凭空造出了那个标签,而另一个解析器可能会写成“Q2 2024”或“2024-Q2”。DPP 关于多行表头的规则指出,压平“破坏了页面所印出的分组”。现在读取这些表头的代码必须考虑每个解析器的标签格式。
DPP 把每个印刷层级保留为独立的表头行,并带有精确的列跨度。它的输出是 Markdown,但 Markdown 管道表格无法表达跨度。当 Markdown 没有对应语法时,DPP 会指明应使用的 HTML 元素,因此每个表格都是 HTML<table>。以下是 DPP 对同一表格的输出,一直细化到 Ticket 行:
<table>
<tr><th></th><thcolspan="5">2023</th><thcolspan="3">2024</th></tr>
<tr>
<th><em>截至 12 月的财年,</em></th>
<th>Q1</th><th>Q2</th><th>Q3</th><th>Q4</th><th>FY</th>
<th>Q1</th><th>Q2</th><th>Q3</th>
</tr>
<tr>
<tddata-level="0"><strong>全系统同店销售额</strong></td>
<td><strong>(2.0)%</strong></td><td><strong>3.8 %</strong></td>
<td><strong>4.0 %</strong></td><td><strong>5.0 %</strong></td>
<td><strong>2.8 %</strong></td><td><strong>10.0 %</strong></td>
<td><strong>4.1 %</strong></td><td><strong>2.7 %</strong></td>
</tr>
<tr>
<tddata-level="1">Ticket</td>
<td>6.3 %</td><td>6.4 %</td><td>9.5 %</td><td>5.4 %</td>
<td>7.2 %</td><td>8.8 %</td><td>6.1 %</td><td>1.9 %</td>
</tr>
<!-- … -->
</table> 4.1 % 现在位于 2024 跨度内的 Q2 之下,因此智能体的答案来自页面印刷的结构。同一输出保留了 "(2.0)%" 和 "3.8 %" 中印刷的空格,保持加粗行仍为加粗,并使用data-level将 Ticket 标记为上方加粗行的子行。
共享的答案键
任何构建基准测试、标注数据或审查解析器输出的人,都必须写下某个页面的预期输出。上面的例子表明,这包括关于结构的决策,即使每个词和数字都正确。如今每个团队都私下做出这些决策,因此两次评估可能对同一页面接受不同的输出。我们发布 DPP,是为了让团队能够标注数据,并依据同一份写下的预期来评估解析器输出,并公开地就这些预期进行争论。
DPP 还明确说明了哪些差异是可接受的。例如,将表格行包裹在<thead>和<tbody>中,与省略这些包裹所保留的信息相同。只要文档始终使用一种形式,两种形式都符合规范。审查应接受其中任何一种。
这些决策不仅限于表格
在表单中,空字段表明某个问题被提出但未作答。丢弃它会使该字段与解析器遗漏的字段无法区分。我们将其表示为[blank]。已勾选和未勾选的复选框在输出中保留为[x]和[ ],因此某人未选择的选项也得以保留。
对于图表,我们选择数据表:每个类别一行,每个系列一列。一个包含六年和四个系列的图表有 24 个值,输出应保留每个可读取且可定位的值。印刷的数值按原样复制。若某个值仅由条形或点显示,我们对照该系列自身的坐标轴读取,并将精度限制在图表所能支持的范围内。
对于示意图,连接关系是内容的一部分。当 Mermaid 等图表语言能够保留标签、分支和箭头方向时,我们使用它。平面图需要一种同时保留其几何形状的表示方式。当没有合适的语言能够忠实呈现该图时,我们使用结构化描述,保留其可见文本和关系。
我们以渲染后的页面为准。隐藏的 PDF 文本不进入输出,可见但无法读取的文本标记为[illegible].当你请求边界框时,每个元素的位置会与 Markdown 一同记录,因此任何值都可以对照页面进行核对。
在页面上试用 DPP
DPP 已上线,地址为parseprotocol.com,每个源页面都与其预期输出并排显示。了解其功能最快的方法是在一个页面上运行它。在网站上选择 Claude 或 ChatGPT。对于 Claude,下载该 skill 并在 Customize → Skills 下上传(skill 需要代码执行)。对于 ChatGPT,将参考文件添加到对话中。然后附上页面图像并粘贴网站上的提示词。
手边没有页面?使用网站上的 Apple 示例页面。检查两个单元格中印刷的 6,485 是否在两者中都得以保留,以及 (565) 是否保留了括号。然后打开该页面的演示,其中解释了该页面上的八项解析决策。
DPP 0.1 是工作草案,我们期待你的意见。如果某条规则在你的某份文档上失效,或两条规则指向不同答案,请展示给我们。在GitHub 上提交 issue 或 pull request连同页面和你期望的输出,我们会和你一起梳理。