baodan/docs/PPT_PDF解析与数据核对页面问题修复报告_20260730.md

755 lines
30 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.

# PPT PDF 解析与数据核对页面问题修复报告
> 日期2026-07-30
> 范围:`api/insurance/ppt/`、`api/insurance/generation/celery_tasks.py`、`frontend/src/pages/PptPage.vue`、`frontend/src/pages/components/ppt/PptDataReview.vue`
> 结论性质:源码、测试与静态界面审查结论;本次不修改业务代码
## 1. 执行结论
当前问题不是单纯的“模型不够聪明”或“页面样式不好看”,而是两条链路都存在结构性错误。
### 1.1 PDF 解析的核心问题
系统当前用“正则识别出至少 3 行利益表数据”作为整份计划书识别成功的主要分流条件。只要表格行数达到阈值,即使产品名称仍为 `unknown`、被保人年龄仍为空,也不会进入完整 LLM 结构化提取;后续 LLM 仅生成销售分析,不回填关键字段。
这直接解释了“利益表似乎有数据,但年龄和保险名称反而识别不出来”的现象。
同时还存在以下放大因素:
- 上传时已经选择的保司、产品及产品别名没有传入解析器作为先验信息;
- 文本提取采用“第一个可读结果即返回”,没有比较各解析器的字段和表格质量;
- 混合型 PDF 只按整份文档判断是否 OCR文本页正常但局部扫描页可能完全漏掉
- Docker OCR 只安装简体中文与英文,香港保险常见繁体中文未覆盖;
- 关键页筛选最多取 10 页、28,000 字符,却要求模型提取“所有页面、所有年度”,目标与输入不一致;
- 正则表格解析依赖理想化换行和列顺序,无法稳定处理多层表头、多页表格和视觉布局复杂的计划书;
- 某些数值会在解析后被代码静默改写,可能把列错位伪装成“合理结果”。
### 1.2 数据核对页面的核心问题
用户的真实任务不是“编辑一份 JSON”而是
> 用最少时间确认 AI 提取值是否与 PDF 原文一致,并安全地修正少量异常。
现有页面没有 PDF 原文、页图、高亮区域、字段来源或置信度。用户看到的是全部字段和整张可编辑表格,却看不到判断正确与否所需的证据。因此页面虽然叫“核对数据”,实际交互是“人工重新录入数据”。
此外,外层页面已经有步骤栏、上下文栏和底部操作栏,核对组件内部又增加产品栏、问题栏和第二套操作栏,形成“外层三栏套内层三栏”。错误状态还分散在四个位置,并且部分计数永远不同步。用户会持续产生三种不确定感:
1. 我现在到底应该先看哪里?
2. 我刚才改的值是否已经保存、是否已经通过?
3. 系统说的错误到底对应哪个产品、哪一页、哪一个输入框?
## 2. 调用链与根因链
```mermaid
flowchart TD
A["上传 PDF并选择险种/保司/产品"] --> B["保存 companyId / productId"]
B --> C["解析任务只传 pdf_path + plan_type"]
C --> D["首个整体可读的文本解析器直接返回"]
D --> E["正则提取产品、年龄、利益表"]
E --> F{"利益表行数 ≥ 3"}
F -->|是| G["直接采用正则结果"]
G --> H["LLM 只做销售分析,不回填名称/年龄"]
F -->|否| I["选最多 10 个关键页交给 LLM"]
I --> J["校验并可选二次纠错"]
H --> K["partial 数据进入核对页"]
J --> K
K --> L["用户看不到 PDF 证据,只能编辑全量表格"]
```
关键断点是:
- 上传阶段已有可靠先验,但解析阶段丢弃;
- 分流只看“表格行数”,不看“关键字段完整性”;
- 核对阶段只给结果,不给证据。
## 3. PDF 解析问题明细
### PARSE-P0-01解析分流条件错误
**证据**
- `ExtractionOrchestrator.REGEX_ROW_THRESHOLD = 3``api/insurance/ppt/extraction.py:391`
- 分支只判断 `regex_rows >= 3 and not used_ocr``api/insurance/ppt/extraction.py:468`
- 进入该分支后直接使用 `regex_data``api/insurance/ppt/extraction.py:470`
- LLM 输出只合并到 `sales_insights``api/insurance/ppt/extraction.py:480-491`
- `ANALYSIS_SYSTEM_PROMPT` 明确要求输出 `keyPoints/gaps/suggestedQuestions`,不输出修复后的结构化字段:`api/insurance/ppt/prompts.py:64-92`
**影响**
一份 PDF 只要利益表被识别出 3 行,即使:
- `product_name = "unknown"`
- `insured.age = null`
- 保额、缴费期、指数账户缺失;
仍会绕过完整 LLM 提取。最终只在末尾被标记为 `partial`,把解析失败的成本转移给用户人工修正。
**修复**
将分流条件改成“结构化质量门”,至少同时判断:
- 产品名称可确认;
- 被保人年龄可确认;
- 对应险种的必填保单字段完整;
- 表格字段覆盖率和年度覆盖率达标;
- 表格列关系通过基本一致性校验。
只要关键字段缺失,即使已经识别出很多利益表行,也必须进入“字段补全/冲突校验”流程,而不是销售分析流程。
### PARSE-P0-02上传阶段的产品先验被丢弃
**证据**
- 上传记录保存 `companyId``productId``api/insurance/ppt/routes.py:140-145`、`169-175`
- Celery 任务也读取了这两个字段:`api/insurance/generation/celery_tasks.py:142-147`
- 实际调用解析器时只传 `filepath``plan_type``api/insurance/generation/celery_tasks.py:167-172`
- 产品表已经维护 `display_name``aliases_json``api/insurance/models/ppt_config.py:64-65`
**影响**
用户如果已经明确选择了某个产品,解析器仍然从零猜产品名称。封面文字是图片、艺术字、缩写或 OCR 错字时,系统无法利用产品目录做标准化与纠错。
**修复**
解析器接收以下上下文:
- `company_id`
- `product_id`
- 产品标准名称;
- 产品别名、英文名、产品代码;
- 险种;
- 可选的产品小册子规则。
解析结果与用户选择冲突时,不应静默覆盖任何一方,而应产生结构化冲突问题供用户确认。
### PARSE-P1-01文本提取只判断“可读”不判断“适合提取”
**证据**
- PyMuPDF 第一个通过整体乱码检测就直接返回:`api/insurance/ppt/extraction.py:119-127`
- 后续 PyPDF2、pypdf、pdfplumber 只有前一个失败才会尝试:`api/insurance/ppt/extraction.py:135-180`
- 乱码检测只按整份文本的可见字符比例判断:`api/insurance/ppt/extraction.py:201-225`
- 文本超过 120,000 字符时从尾部直接截断:`api/insurance/ppt/extraction.py:105`、`127`
**影响**
“能读出文字”不等于“字段和表格顺序正确”。PyMuPDF 可能读出大量正常文本,但:
- 表单标签和值被拆散;
- 表格按绘制顺序而非视觉列顺序输出;
- 封面产品名是图片,没有任何文本;
- 后半部分利益表在 120,000 字符截断后消失。
由于整体文本仍然“可读”,系统不会尝试更适合表格的解析方式或局部 OCR。
**修复**
改为逐页质量评估,并为每页记录:
- 字符数;
- 可读字符比例;
- 标签命中数;
- 数字密度;
- 表格结构得分;
- 是否需要 OCR
- 使用的解析器。
不同页允许使用不同策略,不能用整份 PDF 的单一结果决定全部页面。
### PARSE-P1-02关键页筛选与“提取全部数据”的目标冲突
**证据**
- 完整 LLM 提取最多取 10 页、28,000 字符:`api/insurance/ppt/extraction.py:523-530`
- 页面评分只使用少量通用关键词和数字密度:`api/insurance/ppt/prompts.py:147-176`
- 字符预算耗尽时直接截断当前页并停止:`api/insurance/ppt/prompts.py:178-187`
- Prompt 却要求“扫描所有页面,提取所有保单年度数据”:`api/insurance/ppt/prompts.py:19-23`
**影响**
当计划书包含:
- 多页利益演示;
- 单独的客户资料页;
- 附加险页;
- 繁体字段名;
- 产品名只出现在图形化封面;
模型根本没有看到对应页面,却被要求输出完整结果。模型只能遗漏或猜测。
**修复**
先识别页面角色,再强制选入:
1. 封面/产品身份页;
2. 客户或受保人资料页;
3. 保单摘要页;
4. 所有利益演示表页;
5. 所有退保/提取表页;
6. 对应险种的专属页面。
利益表不应通过“一次大 JSON”从 100 个年度一起生成;应按页或表块解析,再在后端合并和校验。
### PARSE-P1-03正则规则只覆盖理想化标签和表格
**证据**
- 产品名称必须依赖 `产品名称:`、`Product Name:`、`Plan Name:` 等带标签格式:`api/insurance/ppt/regex_extractor.py:38-53`
- 年龄规则不覆盖繁体 `年齡`、`Issue Age`、`Age at Entry`、出生日期等常见表达:`api/insurance/ppt/regex_extractor.py:94-110`
- `Age:` 采用整份文档第一次匹配,可能误取其他人的年龄或利益表年龄;
- 表格列按换行和数字出现顺序分配,而不是按 PDF 几何坐标:`api/insurance/ppt/regex_extractor.py:266-289`、`350-397`
- 进入第一张表后,连续 5 行非数据就 `break` 整个扫描:`api/insurance/ppt/regex_extractor.py:292-347`
- 金额解析把合法的 `0` 转为 `None``api/insurance/ppt/regex_extractor.py:14-27`
- 未识别币种时默认 `USD``api/insurance/ppt/regex_extractor.py:56-76`
**影响**
- 香港繁体计划书年龄漏识别;
- 产品名以大标题或图片出现时漏识别;
- 多页表格、双层表头、保证/非保证子列容易错位;
- 合法 0 值被当成缺失;
- 未知币种被伪装成已确认的 USD。
**修复**
- 扩展繁体、英文、缩写和无冒号标签;
- 对年龄引入“受保人上下文窗口”,区分投保人、受保人、保单年度年龄;
- 支持出生日期加投保日期推算,并保留推算标记;
- 基于 PDF 词块坐标和表格边界重建列;
- 支持多页重复表头与表格续页;
- `0`、`null`、`未识别` 必须保持不同语义;
- 未知币种必须返回 `null` 并进入待确认队列。
### PARSE-P1-04OCR 对香港保险 PDF 的适配不足
**证据**
- OCR 仅在整份文本为空或整体疑似乱码后执行:`api/insurance/ppt/extraction.py:125-186`
- 最多 OCR 40 页:`api/insurance/ppt/extraction.py:228-247`
- 使用固定 `chi_sim+eng``api/insurance/ppt/extraction.py:257-265`
- Docker 只安装 `tesseract-ocr-chi-sim` 与英文包:`Dockerfile.dify-custom:9-10`
- 所有页面固定使用 `--psm 6`,假设整页为单一文本块。
**影响**
繁体中文、图形化封面、复杂多栏表单和“部分页面扫描、部分页面可选文字”的混合 PDF 都容易漏识别。
**修复**
- 安装并启用 `chi_tra+chi_sim+eng`
- 按页判断是否 OCR只 OCR 低质量页;
- 表单页、封面页、表格页使用不同版面模式;
- 加入旋转检测、去噪、二值化和 300 DPI 基线;
- OCR 结果必须保留页码、词块坐标和置信度。
### PARSE-P1-05LLM 输出约束不足
**证据**
- 最大输出固定为 8192 tokens`api/insurance/ppt/llm_client.py:21-22`
- Prompt 可能要求输出 20 至 100 个年度的多列 JSON
- `structured_output` 没有传入正式 JSON Schema只依赖 Prompt 示例:`api/insurance/ppt/extraction.py:527-530`
- 只在 JSON 无法解析时重试JSON 合法但字段遗漏时,主要依赖后置完整性检查。
**影响**
大表格容易被截断、压缩为里程碑年度,或生成合法但不完整的 JSON。模型供应商不同对同一 Prompt 的字段一致性也会不同。
**修复**
- 身份字段、保单字段、各类表格分开调用;
- 表格按页/块输出小 JSON再后端合并
- 使用正式 JSON Schema
- 结构化提取温度设为 0
- 对字段类型、必填项、枚举和数组行建立程序化校验;
- 只对缺失块重试,不重复整份文档。
### PARSE-P1-06静默“修复”可能掩盖解析错位
**证据**
储蓄险中若 `total_surrender_value < guaranteed_cash_value`,代码直接把总退保价值改成保证价值、红利和终期红利之和:`api/insurance/ppt/extraction.py:572-582`。
**影响**
如果真实原因是列错位或提取错误,系统会修改原始数字,使结果看起来符合业务常识,但不再忠实于 PDF。保险数据场景中这比显式报错风险更高。
**修复**
禁止静默覆盖来源数据。应产生:
- 原始值;
- 规则计算值;
- 差异;
- 来源页;
- `blocking_conflict` 问题。
只有用户确认后才能采用修正值。
### PARSE-P1-07缺少字段级可观测性和真实回归样本
**证据**
- `extraction_stats` 只写日志,没有保存到 extraction 结果:`api/insurance/ppt/extraction.py:459-463`、`593-602`
- 解析结果没有字段置信度、来源文本或坐标;
- 当前相关测试能通过 70 项,但主要覆盖理想化文本、少量页面筛选和流程状态;
- 没有发现真实保司 PDF 的金标回归语料。
**影响**
无法回答以下关键问题:
- 哪个解析器最常失败?
- 哪家保司、哪种模板、哪个字段准确率最低?
- 产品名是正则、产品目录、OCR 还是 LLM 得出的?
- 用户修改最多的字段是什么?
**修复**
建立脱敏金标 PDF 语料和字段级评估:
- 数字版简体、繁体、英文、双语;
- 扫描版与混合版;
- 多页利益表、多层表头、图形化封面;
- 储蓄险、重疾险、IUL
- 每次发布输出字段准确率、表格行召回率、数字单元格准确率。
## 4. 校验接口与前端契约问题
### CONTRACT-P0-01解析失败的产品可能不进入错误列表
**证据**
校验接口直接跳过 `status` 不是 `success/partial` 或没有 `data` 的 extraction`api/insurance/ppt/routes.py:581-583`。
**影响**
某个产品解析失败时,校验问题列表可能没有对应阻断项。页面的总体错误数可能为 0“确认生成”可能被错误启用后续生成接口又只要求至少存在一个有效 extraction`api/insurance/ppt/routes.py:463-469`。
**修复**
每个上传文件必须产生校验结果。解析失败必须返回带产品/文件身份的 blocking issue除非用户明确移除该文件。
### CONTRACT-P1-02问题没有产品和字段定位信息
**证据**
- 后端把所有产品的问题汇总成 `{field: code, severity, message}``api/insurance/ppt/routes.py:575-599`
- 没有 `extractionId/productIndex/pdfName/path/rowKey/sourcePage`
- 前端只能用产品名称或 `[idx]` 字符串猜测归属:`frontend/src/pages/components/ppt/PptDataReview.vue:374-384`
- 问题代码是大写枚举,前端却用小写字符串判断标签页:`frontend/src/pages/components/ppt/PptDataReview.vue:392-410`
**影响**
多产品场景下错误徽标可能全部为 0点击 `BENEFIT_ROWS_INCOMPLETE`、`ANNUAL_PREMIUM_INVALID` 等问题时,无法可靠切换到正确产品和字段,也不会聚焦具体输入框。
**修复**
统一 issue 契约:
```json
{
"id": "stable-id",
"extractionId": "pdf-or-product-id",
"pdfName": "plan.pdf",
"productIndex": 0,
"path": "insured.age",
"section": "fields",
"rowKey": null,
"sourcePage": 2,
"severity": "error",
"state": "unresolved",
"message": "被保险人年龄缺失",
"suggestedAction": "fill_or_confirm"
}
```
### CONTRACT-P1-03字段数据类型前后端不一致
**证据**
- 正则和 LLM 将缴费年期输出为 `"5年"``api/insurance/ppt/regex_extractor.py:131-150`、`api/insurance/ppt/prompts.py:14`
- 前端用 `el-input-number` 绑定该字段:`frontend/src/pages/components/ppt/PptDataReview.vue:102-104`
- 前端性别选项值是 `male/female``frontend/src/pages/components/ppt/PptDataReview.vue:93-97`
- 后端正则输出 `男/女``api/insurance/ppt/regex_extractor.py:112-128`
- `data.product_type`、`ext.planType` 同时存在并可能不一致;
- 正则结果固定写 `product_type: savings``api/insurance/ppt/regex_extractor.py:659-679`
**影响**
- 缴费年期控件可能无法正常显示字符串;
- 指标可能显示“5年年”或计算失败
- 已识别性别在下拉框中没有匹配项;
- 页面显示 IUL 标签,但“产品类型”下拉可能显示储蓄险;
- 保存后重新推断险种可能改变原始上传选择。
**修复**
建立唯一 DTO
- `premium_payment_years: number | null`
- `gender: "male" | "female" | "unknown"`
- `plan_type` 只保留一个权威字段;
- 展示层自行追加“年”“岁”等单位;
- API 入参出参都做 schema 校验和迁移兼容。
## 5. 核对页面 UX 问题明细
### UX-P1-01没有原始证据层
**证据**
- `PptDataReview` 只接收 `sessionId``frontend/src/pages/components/ppt/PptDataReview.vue:305-307`
- 页面没有 PDF 预览或来源文本;
- “来源页”被设计为可编辑数字:`frontend/src/pages/components/ppt/PptDataReview.vue:183-186`、`227-230`
- PPT 模块没有面向当前用户的源 PDF 预览接口。
**第一性原理**
核对必须同时看到“系统答案”和“原始证据”。没有证据,用户只能猜、回忆或另开窗口,认知负担和出错率都会上升。
**修复**
点击任一待确认字段时:
- 展示对应 PDF 页;
- 高亮来源区域;
- 同时显示提取值、原文、置信度、识别方式;
- 支持“接受”“修改”“标记无法确认”;
- 来源页由系统记录,不作为普通业务值自由编辑。
### UX-P1-02外层三栏套内层三栏
**证据**
- 外层步骤导航、中央内容、240px 上下文栏:`frontend/src/pages/PptPage.vue:39-132`
- 内层200px 产品栏、编辑器、240px 问题栏:`frontend/src/pages/components/ppt/PptDataReview.vue:25-275`
- 外层和内层各有一套底部操作栏:`frontend/src/pages/PptPage.vue:76-83`、`frontend/src/pages/components/ppt/PptDataReview.vue:277-291`
**影响**
固定区域在进入编辑器前已经占用大量宽度,大表格只能依赖横向滚动。状态、导航和操作同时竞争注意力,用户无法形成稳定视觉路径。
**修复**
核对步骤进入专注模式:
- 隐藏冗余外层上下文栏;
- 产品切换合并到顶部;
- 主体只保留“PDF 证据 + 当前核对任务”两栏;
- 只保留一套粘底操作栏。
### UX-P1-03校验状态重复且互相矛盾
**证据**
状态同时出现在:
1. 核对组件顶部;
2. 核对组件右栏;
3. 外层步骤导航;
4. 外层上下文栏。
父级 `stepErrors/stepWarnings` 初始化后没有接收子组件更新:`frontend/src/pages/PptPage.vue:197-198`。因此外层可能始终显示 0内层却显示真实错误。
右侧栏关闭按钮也没有真正控制 aside 的 `v-if``frontend/src/pages/PptPage.vue:87-90`。
**修复**
- 校验状态只保留一个权威 store
- 父子组件共享同一状态;
- 顶部只显示总进度;
- 详细问题只出现在问题队列;
- 修复关闭按钮条件或移除冗余栏。
### UX-P1-04问题点击不是真正的“定位”
**证据**
`jumpToIssue` 只尝试:
- 用产品名猜产品;
- 用字符串包含关系猜标签页。
它不会:
- 滚动到目标字段;
- 聚焦输入框;
- 高亮表格行或单元格;
- 打开 PDF 来源页;
- 将焦点移到下一条未解决问题。
**影响**
用户点击问题后仍需自己搜索。产品名本身缺失时,恰好无法靠产品名定位。
**修复**
使用结构化 `path + rowKey + sourcePage`,实现:
> 点击问题 → 切正确产品 → 打开正确分区 → 滚动并高亮字段 → PDF 跳页并高亮 → 修改后自动进入下一问题。
### UX-P1-05把“核对”设计成“全表编辑”
**证据**
利益表的每一个单元格始终显示 `el-input-number``frontend/src/pages/components/ppt/PptDataReview.vue:117-193`。IUL 最多同时展示十余列。
**影响**
- 数值与控件外观混在一起,扫描速度低;
- 用户不知道哪些值真的有问题;
- 20 至 100 行时出现数百个输入控件;
- 缺少键盘移动、批量粘贴、只看异常和批量确认。
**修复**
- 默认只读格式化表格;
- 只把缺失、冲突、低置信单元格高亮;
- 单击或 Enter 进入编辑;
- 支持“仅看异常”“接受当前页”“从 Excel 粘贴”;
- 支持上下一个问题和键盘导航;
- 全量表格放在二级入口,默认先完成异常队列。
### UX-P1-06保存机制给出错误安全感
**证据**
- 数据变化时所谓自动保存只提交 `{workflow_step: "review", hasEdits: true}``frontend/src/pages/components/ppt/PptDataReview.vue:322-331`
- 实际 extraction 数据只有点击“保存修改”才调用 `updateExtractions``frontend/src/pages/components/ppt/PptDataReview.vue:588-603`
- 页面离开前也只保存步骤和时间戳:`frontend/src/pages/PptPage.vue:169-176`
- 编辑后校验问题不会实时刷新,只有显式保存后重新校验。
**影响**
顶部草稿指示器可能显示“已保存”,但用户修改的真实保险数据并未保存。返回步骤、点击导航或刷新都可能丢失编辑。
**修复**
- 自动保存必须保存真实 extraction patch
- 保存状态明确区分“正在保存数据”“已保存并已校验”;
- 离开前强制 flush
- 冲突时展示字段级差异;
- 编辑后本地即时校验,防抖服务端校验;
- 提供撤销与恢复。
### UX-P1-07缺失字段反而没有输入入口
**证据**
保额字段使用 `v-if="currentExt.data.policy.sum_insured"``frontend/src/pages/components/ppt/PptDataReview.vue:105-107`。
**影响**
AI 漏识别保额时,该字段被隐藏,用户无法补录;而 CI/IUL 校验又要求保额大于 0。
**修复**
字段是否显示应由险种 schema 决定,而不是由当前值是否存在决定。缺失的必填字段必须最醒目。
### UX-P2-08状态与编辑值不同步
**证据**
- 产品列表和标题优先显示 `ext.productName`
- 输入框修改的是 `currentExt.data.product_name`
- 保存响应中的重算状态没有合并回本地 extraction。
相关代码:`frontend/src/pages/components/ppt/PptDataReview.vue:43`、`61`、`80-82`、`599-603`。
**影响**
用户修改产品名称后,标题可能仍显示旧名称;修复 partial 数据后,标签也可能继续显示“解析不完整”。
### UX-P2-09返回、删除与辅助功能问题
- 内层按钮写“返回上传”,实际只回到解析步骤:`frontend/src/pages/components/ppt/PptDataReview.vue:279`
- 外层还有一个“返回上一步”,形成重复;
- 删除表格行无确认、无撤销;
- 顶部返回和右栏关闭是可点击图标,不是语义按钮:`frontend/src/pages/PptPage.vue:6`、`90`
- 产品状态圆点主要依靠颜色表达;
- 多个独立滚动区使键盘和 200% 缩放用户难以定位。
## 6. 设计健康度
基于 Nielsen 10 项可用性原则:
| # | 原则 | 分数 | 主要问题 |
|---|---|---:|---|
| 1 | 系统状态可见 | 2/4 | 有加载和错误数,但校验陈旧、父子计数矛盾 |
| 2 | 符合现实世界 | 2/4 | 保险术语正确,但没有真实 PDF 证据 |
| 3 | 用户控制与自由 | 1/4 | 无撤销,删除立即执行,关闭按钮失效 |
| 4 | 一致性与标准 | 2/4 | 基础组件一致,状态、返回、底栏和字段类型不一致 |
| 5 | 错误预防 | 1/4 | 缺失字段隐藏来源页可误改0 与缺失混淆 |
| 6 | 识别而非记忆 | 1/4 | 必须另开 PDF 或凭记忆比对 |
| 7 | 灵活与高效 | 1/4 | 无异常队列、批量、粘贴、快捷键 |
| 8 | 美观与极简 | 1/4 | 外层三栏叠内层三栏,所有单元格长期编辑态 |
| 9 | 错误识别与恢复 | 1/4 | 问题不能定位、聚焦、高亮或提供恢复路径 |
| 10 | 帮助与文档 | 0/4 | 无置信度、字段口径、警告处理指导 |
| **总分** | | **12/40** | **Poor需要重做核对任务架构** |
认知负荷检查有 6/8 项失败,属于高负荷:
- 不能保持单一焦点;
- 视觉层级不清;
- 不能一次只处理一个决策;
- 同屏选择过多;
- 依赖工作记忆;
- 没有渐进披露。
## 7. 推荐目标交互
### 7.1 页面结构
```text
┌─────────────────────────────────────────────────────────────────┐
│ 产品/文件切换 · 已解决 4/7 · 2错误 1待确认 · 已保存并校验 │
├──────────────────────────────┬──────────────────────────────────┤
│ PDF 原文 / 页图 │ 当前待核对问题 │
│ │ 被保人年龄 │
│ 自动跳到第 2 页 │ AI 值:— │
│ 高亮“受保人年齡 38” │ 原文:受保人年齡 38 │
│ │ 置信度:低 · OCR │
│ │ [接受 38] [修改] [无法确认] │
│ │ │
│ │ 下一个问题:产品名称 │
├──────────────────────────────┴──────────────────────────────────┤
│ 撤销 · 上一个问题 保存状态 · 下一个问题/确认生成 │
└─────────────────────────────────────────────────────────────────┘
```
### 7.2 信息优先级
1. 阻断错误;
2. 字段冲突;
3. 低置信字段;
4. 缺来源字段;
5. 普通警告;
6. 已确认的正常数据;
7. 全量原始表格。
高置信且通过交叉校验的数据默认折叠,不要求用户逐项确认。
### 7.3 操作原则
- 一个页面只保留一个主要任务:清空待核对问题;
- 一个时刻只编辑一个异常;
- 所有判断依据与当前异常同屏;
- 修改后立即反馈是否解决;
- 自动保存真实数据;
- 用户可随时撤销、返回,且不会丢失工作;
- 全量编辑是高级入口,不是默认入口。
## 8. 修复顺序
### 阶段 1先修数据安全与分流
1. 以关键字段完整度替换 `regex_rows >= 3` 单一门槛;
2. 解析失败的每个文件都生成 blocking issue
3. 移除数值静默覆盖;
4.`companyId/productId/aliases` 传入解析器;
5. 统一 `plan_type/gender/premium_payment_years` DTO
6. 增加针对当前错误分支的回归测试。
### 阶段 2改造 PDF 解析
1. 逐页文本质量评估;
2. 混合页 OCR
3. 支持繁体 OCR
4. 页面角色识别与必选页策略;
5. 基于坐标的表格重建;
6. 身份、保单、表格分块结构化提取;
7. 字段级 provenance/confidence。
### 阶段 3重做校验契约
1. issue 带产品、路径、行、页码和状态;
2. 本地即时校验与服务端权威校验统一;
3. 多产品问题不再使用字符串猜归属;
4. 记录用户接受、修改和无法确认状态。
### 阶段 4重构核对页面
1. 核对步骤专注模式;
2. PDF 与当前问题双栏;
3. 待核对队列;
4. 默认只读、异常才编辑;
5. 真正的数据自动保存;
6. 撤销、批量、粘贴和键盘操作;
7. 去掉重复状态栏、上下文栏和底栏。
### 阶段 5真实数据回归与灰度
1. 建立脱敏金标 PDF 集;
2. 按保司、险种、语言、扫描类型统计准确率;
3. 记录用户修改率与问题处理耗时;
4. 新旧解析器双跑对比;
5. 达标后切换默认流程。
## 9. 验收标准
### 9.1 解析准确性
- 产品名称标准化准确率 ≥ 98%
- 被保人年龄精确准确率 ≥ 99%
- 关键保单字段准确率 ≥ 97%
- 可读数字版 PDF 的利益表行召回率 ≥ 95%
- 已识别数字单元格精确准确率 ≥ 99%
- 关键字段缺失时 100% 进入待核对,不得显示整体通过;
- 所有自动修正都可追溯,不允许静默改变 PDF 来源值。
### 9.2 核对体验
- 用户进入页面 5 秒内能看懂还有多少问题、先处理哪一个;
- 点击问题后一次操作内看到正确产品、字段和 PDF 来源页;
- 修正后 1 秒内本地状态更新,服务端校验完成后明确确认;
- 高置信数据无需逐项进入编辑;
- 正常离开、刷新、返回步骤均不丢失修改;
- 只有一套错误计数、一套主操作栏;
- 1280px 宽度下不出现“多层侧栏挤压核心编辑区”;
- 键盘可完成上一个问题、修改、接受、下一个问题和确认。
### 9.3 测试覆盖
必须新增:
- “利益表 ≥3 行但产品名/年龄缺失时仍进入字段补全”的测试;
- 繁体 `年齡`、`受保人年齡`、`Issue Age`、出生日期测试;
- 产品名无标签、别名、产品代码和 OCR 错字测试;
- 多页利益表、重复表头、多层表头测试;
- 混合型 PDF 局部 OCR 测试;
- 超过 40 页、超过 120,000 字符测试;
- 多产品 issue 精确定位测试;
- 解析失败产品阻断生成测试;
- 自动保存真实编辑数据和离开恢复测试;
- 核对页键盘、响应式和 200% 缩放测试。
## 10. 本次诊断的证据边界
- 已运行相关后端测试70 项全部通过;
- 测试通过说明现有理想化样例没有回归,不代表真实计划书准确率达标;
- 当前工作区未发现可用于复现的真实失败 PDF因此无法对具体保司模板给出字段级误差统计
- 自动界面检测器扫描 `PptDataReview.vue` 返回 0 条规则问题,但该检测器不理解“核对必须有原始证据”等业务交互问题;
- 当前浏览器运行环境不可用,未进行实页截图和交互录屏验证;
- 上述高优先级问题均可由源码调用链直接证实,真实 PDF 与实页验证主要用于量化影响,而不是决定问题是否存在。
## 11. 最终判断
修复顺序必须先保证“机器不把不完整结果当成功”,再优化 OCR 和模型,最后重做核对交互。
如果只换模型:
- 正则成功分支仍不会让模型回填名称和年龄;
- 上传产品先验仍然浪费;
- 关键页仍可能不包含所需页面;
- 用户仍然看不到来源证据。
如果只美化页面:
- 外层和内层状态仍会矛盾;
- 问题仍无法定位;
- 自动保存仍不保存真实修改;
- 用户仍然需要人工重录整张表。
因此,这次应按“解析质量门 → 来源与置信度 → 校验契约 → 核对任务架构”的顺序进行,而不是做局部样式微调。