夜雨聆风学习资料网

ARTICLE · 1277116

AI 说自己读完了 PDF,我先用行数和小计把结果验一遍

AI 说自己读完了 PDF,我先用行数和小计把结果验一遍

感谢朋友们点开今天的文章。

今天继续把前两天的快讯整理流程往前推一步。读 PDF 表格时,模型能返回 JSON 并不等于结果可以直接进表格,我做了一个本地验收器,先把几类看不见的错误拦下来。

一、PDF 抽取最麻烦的地方是无报错

今天看到 OpenRouter 发布的一篇 PDF 表格抽取教程,我把原文从头读了一遍。它的做法是把 PDF 作为文件发给模型,再用严格 JSON schema 约束返回的行。教程还提醒了两个容易漏掉的情况,扫描件走没有文本层的解析器时,接口可能返回空结果却不报错,长表格碰到输出上限时,结果也可能只回来一部分。

这两个结果在程序里都很像正常响应。HTTP 状态可以是成功,JSON 也能正常解析,字段甚至还在。只看“请求成功”这几个字,整理者很容易把半张表当成完整表。

我沿用前两天的思路,把人工判断前面再加一层小检查。它不评价模型聪不聪明,只检查结果是否满足继续处理的最低条件。

接口返回成功,只能说明消息回来,不能说明表格已经完整。

二、我先写一份最小验收约定

验收器目前只看三件事。

第一,finish_reason 必须是 stop。如果是 length,说明输出可能在表格中途停了。

第二,rows 必须至少有一行,空数组直接进入人工复核。

第三,如果事先知道行数或小计,就把它们也写进命令参数,结果不符时立即提示。

金额字段会做很有限的清理。1,200 会按 1200 计算,(200) 会按负数计算。它只为了核对小计,不会替你决定括号在这份财务表里是不是代表退款,也不会替你判断单位是元还是千元。

这份约定故意很小。字段名称、日期格式、币种换算和跨页表头,都应该按自己的文件另写规则。先把最容易造成误用的三类问题拦住,工具才有机会被每天使用。

验收条件要能写成几句机器规则,人才知道什么时候必须停下来。

三、准备两个本地 JSON 样本

工具使用 Node.js 18 或更高版本,没有第三方依赖,也不需要 API Key。把 pdf-table-extraction-checker.mjs 放在和样本相同的文件夹里。

通过样本只有两行,结束原因是 stop,金额相加后得到 1000。

{  ”finish_reason”: ”stop”,  ”rows”: [    { ”item”: ”软件服务”, ”amount”: ”1,200” },    { ”item”: ”退款”, ”amount”: ”(200)” }  ]}

需要复核的样本把 finish_reason 改成 length,只保留一行。这个样本模拟长表格被截断的情况,它没有伪造一整份 PDF,也没有把本地测试冒充成模型实测。

朋友们换成自己的抽取结果时,先删掉客户名称、账号和内部地址。这个工具只读本地 JSON,不会替你做脱敏,也不会把文件上传到任何服务。

先拿两份不含敏感信息的结果试跑,验收规则清楚后再接入真实文件。

四、运行命令,先看一份通过结果

在文件夹地址栏输入 powershell,运行下面的命令。

node pdf-table-extraction-checker.mjs --input 抽取结果_通过.json --expectedRows 2 --amountField amount --expectedSubtotal 1000

程序会输出一段 JSON,核心字段如下。

{  ”status”: ”PASS”,  ”rows”: 2,  ”finish_reason”: ”stop”,  ”issues”: []}

这只说明当前 JSON 通过了本地规则。它没有证明 PDF 里确实只有两行,也没有证明模型读对了每个单元格。行数和小计来自你对原文件的预先判断,验收器只是把这个判断写成可重复执行的检查。

我把结果打印到终端,没有增加输出文件。这样可以直接接到脚本、测试或提交检查里,也避开了把每次抽取结果复制到另一张表的麻烦。

通过状态表示规则暂时满足,原文件仍然是最后的参照。

五、再跑一份会被拦住的结果

运行下面的命令。

node pdf-table-extraction-checker.mjs --input 抽取结果_需要复核.json --expectedRows 2

这次输出的状态是 NEEDS_REVIEW,问题数组里会出现两项。

{  ”status”: ”NEEDS_REVIEW”,  ”rows”: 1,  ”finish_reason”: ”length”,  ”issues”: [    ”finish_reason 不是 stop”,    ”行数应为 2,实际为 1”  ]}

命令退出码也会变成 1。它可以接在批处理脚本后面,让后续流程停住。处理者需要回到原 PDF,判断是换解析路线、减少单次页数,还是提高输出限制。验收器不会替人选择模型,也不会自动重试,因为不同文件的问题原因不一样。

失败时把原因写出来,比给一个模糊的“抽取失败”更有用。

六、用测试确认规则没有写歪

测试命令如下。

node --test pdf-table-extraction-checker.test.mjs

本次结果是 5 项通过、0 项失败。测试覆盖完整结果、空数组、finish_reason 为 length、行数和小计不一致,以及千分位和括号负数。

这组测试验证的是验收器的判断方式,不是 PDF 识别准确率。我没有在当前环境调用 OpenRouter API,也没有把教程里的样本结果改写成自己的模型结果。OpenRouter 原文提到,他们在五份测试 PDF 上做了 25 次抽取,没有观察到模型凭空增加行,漏行反而是更需要防的情况。这个结论属于那篇教程的测试范围,拿到自己的文件后仍要重跑行数和小计检查。

如果以后要增加页码、币种或表头检查,先补一个失败样本,再改函数。没有失败样本的规则,很容易只在通过路径上看起来有效。

测试先把错误暴露出来,模型结果仍要回到原文件核对。

七、放进 FDE 和企业资料流程

在企业资料整理里,这个验收器可以放在模型抽取之后、写入 Excel 之前。负责资料的人先提供 PDF 和预期行数,模型返回结构化结果,脚本检查结束状态、空结果和小计,人工再抽查原文中的表头、跨页行和脚注。

遇到扫描件,先确认使用的解析器能处理图片文字。遇到很长的表格,可以按页或按章节拆开,再把每段结果合并。合并以后仍要重新检查行数和小计,不能因为每段都通过,就跳过整表核对。

这套方法适合发票明细、费用表、公开财报和内部报表的初步整理。它不适合直接决定付款、报税、授信或合规结论。涉及这些动作时,原 PDF、人工复核和权限记录都要保留。今天做的工具只负责把明显问题拦在表格落库之前。

把模型输出放进验收步骤,AI 才能进入需要留痕的资料流程。

今日一句话

觉得今天内容还可以的,朋友们可以加个免费关注。

也欢迎朋友们一键三连,转发、点赞、在看。

没有君子不养艺人,王小胖靠一个免费关注继续写。

相关学习资料