Files
bid-doctor/docs/architecture/tech-validation.md
YANG JIANKUAN 3344f09563 feat(ocr): 扫描件与图片识别——OCR 进文字层、资质库上传识别、大图浏览
计划见 docs/architecture/vision-plan.md(VS1–VS13,docs/decisions.md)。

- 验证:OCR(RapidOCR + PP-OCRv6 small,CPU)和 DeepSeek Flash 看图在国动投标文件
  和 7 张证书上初测(tech-validation §7,代码 spikes/s5-ocr/)
- OCR 服务 services/ocr(镜像、Compose 服务):整页转正(含 180°)、红章附近按红色通道重读
- 扫描页和插图识别后并入文字层 v6,句子标 source=ocr;出处标「OCR」(迁移 0013);
  依据识别文字的问题降级,规则不查扫描附件;国动端到端见 check-eval §16
- 资质库上传识别:添加资质对话框最上面传证书照片,识别后填表,只预填和 OCR 文字
  对得上的字段;识别值留痕、照片挂成附件(迁移 0014,提示词 vision.cert_fields v1)
- 资质库改为查看详情(只读键值 + 附件缩略图),附件用大图浏览控件看,不开新标签页
  (设计规范 §7.23);PDF 附件按页出预览图

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 17:50:13 +08:00

87 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 技术验证结论(S1–S4 2026-11-03;S5、S6 初测 2026-11-05)
> 依据:架构文档 `architecture.md` §10。代码在 `spikes/`(一次性代码,复现步骤见 `spikes/README.md`),由样本派生的产物都在各子目录的 `out/` 里,不进 git。
> 环境:本机 Docker 29.8.2(Apple Silicon,**arm64**),Gotenberg 8.39.0;样本是 `samples/tenders/` 的 S01–S10。
> 模型:DeepSeek 官方接口,配置名 `deepseek-chat`,接口返回实际服务的模型是 `deepseek-flash`(DeepSeek-V4.1-Flash),非思考模式(思考 token 为 0)。
## 0. 结论速览
| # | 结论 | 关键数字 | 对架构的影响 |
|---|---|---|---|
| S1 | **可行,但不能直接用 Gotenberg 默认配置**:要先修正 WPS 写错的字体字符集,再换成按宋体行高调整过的开源字体 | 默认配置:页数偏差 +17%~+37%,S07 正文**全部空白**;调整后:两份有真值的文件 79/79、75/73 页,目录页码跨度误差 0%~-2.2% | §3.5 新增两步预处理和字体包 |
| S2 | **可行**:在规范化 PDF 上识别「斜体且下划线」,和 DOCX 原文件逐字对得上 | 4 份文件按字符 100% 一致;片段级召回 0.993~1.0 | 不需要 Docling 来保格式 |
| S3 | **正文可行,表格要改进**:原句高亮的几何位置全部正确;切句在表格里会把相邻单元格拼在一起 | 几何回读 50/50、300/300;文本保真:正文 97.5%,表格内 78% | 切句要识别表格单元格和页眉页脚 |
| S4 | **可行**:两道证据校验 + 第三道「依据校验」后,抽取结果可用;★ 类条款建议用规则兜底保召回 | ★ 召回 93.5%(扣除银标准噪音后约 96.6%),斜体下划线 99.8%;采纳条目 95.2% 属实;每份文件约 0.15 元(高峰价) | §3.6 新增依据校验和规则兜底 |
| S5 | **可行(初测)**:RapidOCR(PP-OCRv6 small,CPU)识别字准、坐标准、够快;整页横放能自动转正;红章压字要局部按红色通道重读 | 国动投标文件 102 页(扫描 + 图表)62 秒;合成扫描件字符差 0.1%~1.1%;坐标回画全部对上 | §3.5 OCR 阶段可以照计划做,见 §7 |
| S5 视觉 | **可行(初测)**:DeepSeek Flash 收图片,页面分类、证书 / 合同字段、图表概述都能用;字段引用 OCR 行做校验能拦住两边读错的情况,但拦不住语义错和手写 | 102 页 23 秒,约 0.47 元(每页约 0.005 元);86 个字段 70 个和 OCR 行一致,16 个不一致里 10 个是跨行 | vision-plan §2 的交叉校验要支持多行、加字段格式校验 |
| S6 | **部分**:印章有无模型判断大体对,浅色骑缝章会漏;手写签名能认出 | 102 页里判「有章」44、「看不清」6;抽查 2 页漏 1 个边缘骑缝章 | 签章位检查要加红色像素初筛;准确率要等有标注的样本 |
## 7. S5 / S6 扫描件识别初测(2026-11-05)
> 计划见 `vision-plan.md`。代码在 `spikes/s5-ocr/`(独立虚拟环境,Python 3.12),产物在 `out/`,不进 git。
> 样本:国动真实投标文件(`samples/tenders/GD/响应文件-最新.pdf`,183 页)。本次没有扫描版招标文件样本(用户:招标文件通常是文字稿),证书扫描件用户随后提供。
### 7.1 OCR(RapidOCR 3.10,PP-OCRv6 small 检测 / 识别模型,onnxruntime CPU,Apple Silicon)
- **挑页**:沿用文字层 v5 的扫描页规则,整页识别 80 页;图片占比 ≥ 0.15 的文字页只识别图片区域(跳过小于页面 5% 的小图),22 页。和文字层已有文字重叠的 OCR 行去掉。
- **速度**:200 dpi 渲染 + 识别,102 页 61 秒(约 0.6 秒 / 页,横放的报表页 1.5~3 秒)。按这个速度,300 页全扫描约 3 分钟,满足 10 分钟目标。
- **转正**:第 18、19 页的资产负债表是横放扫描,0° 识别出大量竖长框,试 90° / 270° 取「字数 × 平均置信度」最高者,判为 270°;框换算回原页坐标后画回去全部对上。
- **字准(合成扫描件)**:文字页渲染成图片,分三档退化(干净;灰度 + 倾斜 1° + 模糊 + 噪点 + JPEG 60;降采样 + 倾斜 2° + 更模糊 + JPEG 35),以文字层为真值:
| 文件 | 页 | 字数 | 字符差(不看顺序) | 按顺序的错误率 |
|---|---|---|---|---|
| 国动招标文件 | 5–24 | 12,806 | 0.31% / 0.41% / 0.32% | 1.2% / 1.4% / 1.3% |
| 国动投标文件 | 35–60 | 15,436 | 0.15% / 0.09% / 1.09% | 约 31%(表格多,阅读顺序和文字层不同,不是认错字) |
退化对字准影响很小。真实扫描件上没有真值,用视觉模型的交叉校验和人工抽查代替(§7.2)。
- **红章压字**:资产负债表「核算单位」被红章盖住,原图只认出「南京」「信息技术有限公司」两段。
- 按红色像素阈值抹掉印章:章下面的黑字也一起抹掉,更差。
- **只取红色通道当灰度图**(红章变浅、黑字不变):认出「核算单位:南京会信息技术有限公司」(错一字),肉眼可读出「南京长卿信息技术有限公司」。
- 但整页都用红色通道时,23 页有变化,有的变好(p21、p142、p162),有的变差(p16、p163)。**结论:只对红章附近的区域用红色通道重读,其余保留原图结果。**
- **图表**:技术方案里的 22 页架构图、流程图、界面截图,图里的文字全部读出(例如第 61 页系统逻辑架构图 26 行,四层的每个模块名都在)。这些文字以前不在文字层里,查标「出处没能核对」里架构图那几条(`check-eval.md` §14)就是因为这个。
### 7.2 视觉模型(DeepSeek Flash,`deepseek-chat` 不思考,`json_object`)
- **做法**:每页图片(长边 1600 像素,JPEG 85)+ 带编号的 OCR 行一起发;输出页面类型、是否续页、标题、字段(必须引用 OCR 行号)、印章 / 签名有无、图表概述。字段值归一化后在所引行里找;只有数字一致算「近似」;对不上记「不一致」。
- **速度和成本**:102 页并发 6,23 秒;输入 199,863 token、输出 9,324 token,按 §4.3 的高峰价约 0.47 元,每页约 0.005 元。
- **页面分类**:劳动合同 35、业务合同 27、系统界面截图 9、信用查询截图 8、架构图 8、财务报表 4、流程图 4、纳税证明 2、其他图表 2、营业执照 1、授权书 1、其他 1。按「不是续页」的标记数,3 份业务合同(第 104、119、123 页起)、5 份劳动合同(第 135、142、149、156、163 页起,每份 7 页)的起始页都对,和页面下方的文字说明一致;没有逐页人工核对。第 21 页「登记通知书」归到「其他」,合理。
- **字段**:86 个,70 个和所引 OCR 行一致。16 个不一致:
| 原因 | 个数 | 处理 |
|---|---|---|
| 值跨两行(住所、所属期间、合同期限、长合同名) | 10 | 允许引用多行,按拼接后的文字核对 |
| OCR 被红章或下划线切碎(「签订日期:20251」) | 4 | 红章附近用红色通道重读 |
| OCR 读错、模型读对(手写「2025」OCR 读成 2015) | 1 | 交叉校验按设计拦下,进待确认 |
| 模型读错(「长卿」读成「长顺」,还引错了行) | 1 | 交叉校验按设计拦下 |
**校验拦不住的**:
- 语义错:第 145 页「用人单位 = 甲方」「合同期限 = 1 种工时制度」,值确实在所引行里。要按字段类型加格式校验(单位名要像单位名,期限要有日期)。
- 手写:第 169 页乙方手写「2025 年 11 月 22 日」,OCR 和模型都读成「1 月」,两边一致但都错。手写区域即使两边一致也按低可信处理,不出致命级。
- 半截值:第 18 页「单位名称」取了 OCR 认出的半截「信息技术有限公司」,校验通过。被章挡住的值要标「可能不完整」。
- **印章 / 签名(S6 初测)**:判「有章」44 页、「看不清」6 页;手写签名 9 页。抽查:第 106 页右边缘的浅色骑缝章判成「无」(漏),第 131 页只露一截的骑缝章判「看不清」(合理)。签章检查只看指定签章位,骑缝章影响不大,但要加红色像素初筛补漏。没有标注,准确率没算。
- **图表概述**:架构图、流程图的概述准确(第 61 页把四层和每层的模块全部列对),适合在覆盖范围或出处卡片里作「图片说明(AI 生成,非原文)」。
### 7.3 证书识别(资质库上传识别,vision-plan 第 2 步)
> 样本:用户提供的 7 张网上公开证书图片(不进 git):人员证书 4 张(软考、职业技能等级 ×2、培训证书,其中 2 张姓名 / 编号打了马赛克)、软著 2 张(1 张低清、红章压日期)、一张照片里挂着两张软件产品证书(反光)。每张再转 90°、180°、270° 各做一份,共 28 次。标准答案由 Claude 对着图录(`spikes/s5-ocr/out/certs/gold.json`,不进 git,用户未复核)。代码 `spikes/s5-ocr/certs.py`。
- **流程**:图片按 EXIF 转正 → OCR 服务(转正、红章重读)→ 转正后的图 + 带编号的 OCR 行交给 DeepSeek Flash,按证书逐张输出类别和字段(每个字段引用 OCR 行)→ 校验。
- **转正**:90° / 270° 原来就能认;**180° 原来认不出**(逐行识别时 RapidOCR 自己翻正,字认得出,但整页图是倒的,模型把「评估机构」当成了「发证机构」、日期读错)。加了整页倒置检测:挑最多 30 个长行交给 RapidOCR 的方向分类模型,过半判 180° 就整页翻过来重识别。之后 16 种「图 × 角度」全部转对,倒置检测每页多 0.2~0.4 秒。
- **打码**:马赛克轻的地方 OCR 会「读」出字(培训证书的姓名、编号),模型照抄。两层处理:提示词要求被打码的字段不输出、写进 masked;服务端看所引 OCR 行的置信度,低于 0.9 标「识别不确定」,不自动填。透过马赛克读出的行置信度 0.69、0.88,正常行在 0.95 以上。
- **结果**(提示词改了两轮之后):200 个字段对 200,漏 0;打码字段 16 次全部没给值或标了识别不确定;一图两证两张都拆对。字段校验 192 个一致、8 个识别不确定(都是打码字段)、9 个不一致(值是对的,OCR 那行认错或值由两行拼成,会以「识别结果不一致,请核对」给用户)。
- **速度和成本**:每张 OCR 约 2 秒(含转正),模型约 1.5 秒;每张输入约 1,400 token、输出约 220 token,不到 0.005 元。
- **局限**:提示词是对着这 7 张改的(第一轮 50 个字段对 45、打码字段漏了 2 次),满分是调出来的,说明不了泛化。下一批证书不改提示词直接跑,才是正式成绩。样本里没有企业资质证书(CS、ITSS、ISO)和营业执照。
### 7.4 这份文件上能多查出什么
只是看结果做的推演,产品还没实现:
- **主体名称不一致(D14)**:营业执照(第 16 页)是「南京长卿科技有限公司」,统一社会信用代码 91320114MA27H0P5X5;利润表、资产负债表、现金流量表(第 17、18、20 页)的单位名称,以及第三份业务合同(第 123–124 页)的乙方,都是「南京长卿信息技术有限公司」;资产负债表上的纳税人识别号和营业执照一致。多半是曾用名,但投标文件里没看到更名证明,值得提示用户核对。
- **证明材料**:第二十二条要的营业执照、财务报表、纳税、信用记录都能按页面类型定位到具体页,不用再出「请人工核对」。
- **评分项**:扫描页里只有营业执照、财务报表、纳税证明、信用报告、3 份业务合同、5 份劳动合同,没有软著、人员证书、国产化证明,「软件自主研发」「团队专业能力」「国产化适配」三条可以直接说「投标文件里没有找到这类材料」,不再说「可能在扫描件里」。
- **业绩**:3 份业务合同的金额(4 万、8 万、17 万)、甲乙方、签订日期都读得出,D15 的时间窗口核对有了数据。
### 7.5 对计划的修改
见 `vision-plan.md` v0.3:多行引用、字段格式校验、红章局部重读、手写低可信、半截值标记、签章位红色初筛;招标文件里的图片按重要程度分流(用户要求)。