上篇(多模态 RAG 实测三)跑完 247 页真实截图、121 道题,结论是:结构类题目的失分几乎全压在”坐标式提问”上——给完全正确的可见文本,问”第 2 行第 7 列”也只有 43.5%,错答里 88% 是同一张表里数错了格子。结尾我说下篇要让转写直接产出带表头的结构化表格入库,坐标不进模型,同一批 121 题重跑一遍。
这篇是那轮的记录。结论先摆:坐标题从 13.0% 补到 52.2%,在”页面上真能数出来”的 12 道题上 12/12;剩下 11 道救不了,它们问的”第 2 列”在截图上不存在。顺带挖出一件麻烦事——上一批题里有 45 道是废题。
一、提示词只写”表格”,漏掉一半表
做法先交代:不再让模型输出 Markdown 表格文本,直接吐 JSON——{"tables":[{"headers":[...],"rows":[[...]]}]},headers 是表头行、rows 是数据行。入库后行列就是数组下标,”第 2 行第 7 列”等于 rows[1][6],数格子不再经过模型。
第一版提示词只有一句”只提取表格,忽略正文”。247 页跑完只有 38 页抽出了表,而 DOM 里视口内有 table 的页面是 116 页。承载全部 121 道题的 30 张规整表只认出 18 张(31 张里另 1 张没进题源),16 张布局型表(GitHub 文件列表、arXiv 元数据表)只认出 4 张。反过来 131 个无表页只有 5 页误报:不是乱抽,是漏抽。
第二版把口径写死:要抽的是”按行按列排布的数据”,文件列表、参数列表、键值清单都算。31 张题源表全部检出,代价立刻显现:抽出表的页面涨到 194 页,无表页误报 83/131=63.4%。
两个目标换不来。写”表格”,模型只认带表头带边框的那种;写”按行按列排布”,它连导航条都算进去。我选高召回那版,入库前用规则筛:列数至少 2、有表头、行数至少 3。
二、常规文章表格:14 张,单元格级 98.6%
两版提示词在常规文章表格上表现一样:14 张全部检出、行列数完全一致,单元格级匹配 279/283=98.6%。4 个错格全是符号级别:3~5 写成 3-5、../../../etc/passwd 少写一个 ..、”反问”写成”反间”、一处英文大小写变了。数字和单位一个没错。
难看的是 16 张布局型表(另有 1 张没进题源):v1 只检出 4 张,单元格级 0.35%;v2 全部检出,但行列完全一致的是 0 张,单元格级 18.0%。原因一句话:DOM 说有 4 列、截图里只有 1 列,比对基准本身是假的,细节见第六段。
三、入库:三层表,坐标变成下标
落库三张表:page、tbl(存表头 JSON 和行列数)、cell(table_id, row_idx, col_idx, header, value),(header, value) 上建索引。247 页落进去 384 张表、6539 个单元格。然后拿真实题目的真值跑了三个自检:
- 坐标直取:p001 第 2 行第 7 列 →
1.00,真值 1.00,过。 - 按值反查行:”版式=文档”那一行 → row_idx=0 → 该行”页数”=
5,真值 5。 - 按值反查列名:
3~5 条共 3000 上下属于”我这边典型量级”列 → 精确匹配查不到,模型写成了3-5,换 LIKE 模糊匹配才查到。
第三个没过,比前两个过了更有用:单元格级 98.6% 意味着拿值当键精确查一定会漏,查询侧得做归一化。
四、坐标题:13.0% 到 52.2%,干净表上 12/12
准确率按上篇同一份判分脚本(exact + lenient):
| 条件 | 23 道坐标题 | 其中题源表没问题的 12 道 |
|---|---|---|
| A1 可见文本上界 | 43.5% | 16.7% |
| A2 普通转写 | 13.0% | 8.3% |
| A3 结构化转写(Markdown 表格) | 26.1% | 25.0% |
| B 直接看图 | 56.5% | 33.3% |
| C 结构化入库 + 程序按下标取值 | 52.2% | 100% |
| C2 同样结构化数据,坐标题照旧交给模型答 | 17.4% | — |
第一,同样的结构化数据,坐标题照旧交给模型答只有 17.4%:光把数据换成带表头的结构,坐标题只从 13.0% 挪到 17.4%;真正拉起它的是”让程序按下标取值”。数据格式的收益和计算位置的收益,是两回事。
第二,剩下 11 道全是 GitHub 和 arXiv 的布局型表:题面问”第 2 行、第 2 列”,那张表在截图上只有一列可见,”第 2 列”是 DOM 里被 CSS 藏起来的空列,按下标取就是越界。
五、非坐标题:结构化渲染只是打平
98 道非坐标题(行内查找、列锚定、表头归属、列内取最大)用结构化键值渲染是 91.8%,题源表没问题的 64 道是 98.4%;同口径的 A2 普通转写是 96.9%(干净 95.3%)、B 直接看图 98.0%(干净 96.9%)。干净题上只高 3 个点:表格通道的收益全在坐标题那一块。
六、121 题总分,和那 45 道废题
| 链路 | 121 题总分 | 剔除废题后的 76 题 |
|---|---|---|
| A1 可见文本上界 | 86.0% | 82.9% |
| A2 普通转写 | 81.0% | 81.6% |
| A3 Markdown 转写 | 81.8% | 82.9% |
| B 直接看图 | 90.1% | 86.8% |
| C 表格通道(坐标程序取值 + 其余结构化提问) | 84.3% | 98.7% |
总分上 C 是 84.3%,不如 B(90.1%);只看题源表没问题的 76 道,C 是 98.7%,对 B 的 86.8% 差出 12 到 17 个点。
被剔掉的 45 道是我的锅。上篇出题从 DOM 表出发,只查了行列是否规整、列数是否在 3 到 8 之间,没查这一列空不空。GitHub 仓库页的文件列表就是反例:表头 ['Name','Name','Last commit message','Last commit date'],数据行 ['.claude','.claude','',''],第 3、4 列在 1200px 宽下被 CSS 藏起来,第 1、2 列是同一个值的重复。这种表生成的题目是”「Name」为「.claude」的那一行,「Name」列的值是多少”,自己查自己;上篇 col_lookup 全线 97% 到 100% 有它一份。下一轮出题加一条过滤:整列全空、表头重复的表不出题。
七、成本
| 环节 | 输入/输出 token | 费用(off-peak) |
|---|---|---|
| v1 转写 247 页 | 294,424 / 7,352 | $0.0486(单页 $0.000197) |
| v2 转写 247 页 | 308,256 / 43,710 | $0.0725(单页 $0.000293) |
| 结构化提问 121 次 | 55,410 / 401 | $0.0086(每题 $0.000071) |
| 坐标题取值 23 次 | 0 / 0 | $0 |
按 deepseek-flash 的 off-peak 价(未命中输入 0.15/1M、输出0.6/1M)算,v2 单页 0.000293,1 万页2.93;v1 更便宜是因为输出少(29.8 token/页对 177.0)。这轮两版各跑一遍全量加 121 次提问合计 $0.13,坐标题那 23 次不花钱不吃时延。
总结
坐标题的 13% 是”让模型数格子”造成的;把这一步换成数组下标,在结构还原正确的表上就是 100%,结构没还原对的表换哪条链路都救不回来。落地三条:
- 双通道:文本通道给散文,表格通道给”按行按列排布”的数据,各用各的提示词,各存各的。
- 表格一律进结构化库(headers + rows),坐标类查询由程序按下标算,模型只在”按值找行、按值找列”这类语义问题上出场。
- 出题和评测前先验数据:整列全空、表头重复、行数和截图对不上的表,先剔掉再算分。
下期预告
下篇把表格通道接到检索上。上篇检索那一节的数字很难看:cell 类查询的 Recall@5 是 0.0,col_lookup 只有 0.5641——页面级检索器不知道表在哪一行。这次让检索命中到表和行:文本通道定位候选页,再用表头加行文本做表级检索,答题只带命中的那张表。同一批题(先剔掉 45 道废题)重跑,看 Recall@5 和总分能到哪。
参考文献
- 上一篇:多模态 RAG 实测(三):247 页真实网页跑完,我推翻了自己定的切换判据:https://www.fedte.cc/p/842.html
- DeepSeek API Docs:Models & Pricing(deepseek-flash 的 off-peak 价与峰谷时段):https://api-docs.deepseek.com/quick_start/pricing
- DeepSeek API Docs:JSON Output(response_format 设 json_object 的开启条件:提示词里要出现 json 字样并给格式示例):https://api-docs.deepseek.com/guides/json_mode
- DeepSeek API Docs:Vision(传图方式与 token 折算):https://api-docs.deepseek.com/guides/vision
- MDN:HTMLTableRowElement.cells(DOM 取单元格,包含被 CSS 隐藏的列):https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableRowElement/cells
- MDN:HTMLElement.innerText(对渲染可见性敏感,隐藏单元格返回空串):https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/innerText
- ColPali 官方仓库与论文(本系列路线 B 参考,本文仍未实测):https://github.com/illuin-tech/colpali / https://arxiv.org/abs/2407.01449
转载请注明:Falost的小窝 » 多模态 RAG 实测(四):把“数格子”从模型手里拿走——结构化表格入库,坐标题从 13% 回到 52%