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

30 KiB
Raw Blame History

PPT PDF 解析与数据核对页面问题修复报告

日期2026-07-30
范围:api/insurance/ppt/api/insurance/generation/celery_tasks.pyfrontend/src/pages/PptPage.vuefrontend/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. 调用链与根因链

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 = 3api/insurance/ppt/extraction.py:391
  • 分支只判断 regex_rows >= 3 and not used_ocrapi/insurance/ppt/extraction.py:468
  • 进入该分支后直接使用 regex_dataapi/insurance/ppt/extraction.py:470
  • LLM 输出只合并到 sales_insightsapi/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上传阶段的产品先验被丢弃

证据

  • 上传记录保存 companyIdproductIdapi/insurance/ppt/routes.py:140-145169-175
  • Celery 任务也读取了这两个字段:api/insurance/generation/celery_tasks.py:142-147
  • 实际调用解析器时只传 filepathplan_typeapi/insurance/generation/celery_tasks.py:167-172
  • 产品表已经维护 display_namealiases_jsonapi/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:105127

影响

“能读出文字”不等于“字段和表格顺序正确”。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 AgeAge at Entry、出生日期等常见表达:api/insurance/ppt/regex_extractor.py:94-110
  • Age: 采用整份文档第一次匹配,可能误取其他人的年龄或利益表年龄;
  • 表格列按换行和数字出现顺序分配,而不是按 PDF 几何坐标:api/insurance/ppt/regex_extractor.py:266-289350-397
  • 进入第一张表后,连续 5 行非数据就 break 整个扫描:api/insurance/ppt/regex_extractor.py:292-347
  • 金额解析把合法的 0 转为 Noneapi/insurance/ppt/regex_extractor.py:14-27
  • 未识别币种时默认 USDapi/insurance/ppt/regex_extractor.py:56-76

影响

  • 香港繁体计划书年龄漏识别;
  • 产品名以大标题或图片出现时漏识别;
  • 多页表格、双层表头、保证/非保证子列容易错位;
  • 合法 0 值被当成缺失;
  • 未知币种被伪装成已确认的 USD。

修复

  • 扩展繁体、英文、缩写和无冒号标签;
  • 对年龄引入“受保人上下文窗口”,区分投保人、受保人、保单年度年龄;
  • 支持出生日期加投保日期推算,并保留推算标记;
  • 基于 PDF 词块坐标和表格边界重建列;
  • 支持多页重复表头与表格续页;
  • 0null未识别 必须保持不同语义;
  • 未知币种必须返回 null 并进入待确认队列。

PARSE-P1-04OCR 对香港保险 PDF 的适配不足

证据

  • OCR 仅在整份文本为空或整体疑似乱码后执行:api/insurance/ppt/extraction.py:125-186
  • 最多 OCR 40 页:api/insurance/ppt/extraction.py:228-247
  • 使用固定 chi_sim+engapi/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 tokensapi/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-463593-602
  • 解析结果没有字段置信度、来源文本或坐标;
  • 当前相关测试能通过 70 项,但主要覆盖理想化文本、少量页面筛选和流程状态;
  • 没有发现真实保司 PDF 的金标回归语料。

影响

无法回答以下关键问题:

  • 哪个解析器最常失败?
  • 哪家保司、哪种模板、哪个字段准确率最低?
  • 产品名是正则、产品目录、OCR 还是 LLM 得出的?
  • 用户修改最多的字段是什么?

修复

建立脱敏金标 PDF 语料和字段级评估:

  • 数字版简体、繁体、英文、双语;
  • 扫描版与混合版;
  • 多页利益表、多层表头、图形化封面;
  • 储蓄险、重疾险、IUL
  • 每次发布输出字段准确率、表格行召回率、数字单元格准确率。

4. 校验接口与前端契约问题

CONTRACT-P0-01解析失败的产品可能不进入错误列表

证据

校验接口直接跳过 status 不是 success/partial 或没有 data 的 extractionapi/insurance/ppt/routes.py:581-583

影响

某个产品解析失败时,校验问题列表可能没有对应阻断项。页面的总体错误数可能为 0“确认生成”可能被错误启用后续生成接口又只要求至少存在一个有效 extractionapi/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_INCOMPLETEANNUAL_PREMIUM_INVALID 等问题时,无法可靠切换到正确产品和字段,也不会聚焦具体输入框。

修复

统一 issue 契约:

{
  "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-150api/insurance/ppt/prompts.py:14
  • 前端用 el-input-number 绑定该字段:frontend/src/pages/components/ppt/PptDataReview.vue:102-104
  • 前端性别选项值是 male/femalefrontend/src/pages/components/ppt/PptDataReview.vue:93-97
  • 后端正则输出 男/女api/insurance/ppt/regex_extractor.py:112-128
  • data.product_typeext.planType 同时存在并可能不一致;
  • 正则结果固定写 product_type: savingsapi/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 只接收 sessionIdfrontend/src/pages/components/ppt/PptDataReview.vue:305-307
  • 页面没有 PDF 预览或来源文本;
  • “来源页”被设计为可编辑数字:frontend/src/pages/components/ppt/PptDataReview.vue:183-186227-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-83frontend/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-iffrontend/src/pages/PptPage.vue:87-90

修复

  • 校验状态只保留一个权威 store
  • 父子组件共享同一状态;
  • 顶部只显示总进度;
  • 详细问题只出现在问题队列;
  • 修复关闭按钮条件或移除冗余栏。

UX-P1-04问题点击不是真正的“定位”

证据

jumpToIssue 只尝试:

  • 用产品名猜产品;
  • 用字符串包含关系猜标签页。

它不会:

  • 滚动到目标字段;
  • 聚焦输入框;
  • 高亮表格行或单元格;
  • 打开 PDF 来源页;
  • 将焦点移到下一条未解决问题。

影响

用户点击问题后仍需自己搜索。产品名本身缺失时,恰好无法靠产品名定位。

修复

使用结构化 path + rowKey + sourcePage,实现:

点击问题 → 切正确产品 → 打开正确分区 → 滚动并高亮字段 → PDF 跳页并高亮 → 修改后自动进入下一问题。

UX-P1-05把“核对”设计成“全表编辑”

证据

利益表的每一个单元格始终显示 el-input-numberfrontend/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 数据只有点击“保存修改”才调用 updateExtractionsfrontend/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:436180-82599-603

影响

用户修改产品名称后,标题可能仍显示旧名称;修复 partial 数据后,标签也可能继续显示“解析不完整”。

UX-P2-09返回、删除与辅助功能问题

  • 内层按钮写“返回上传”,实际只回到解析步骤:frontend/src/pages/components/ppt/PptDataReview.vue:279
  • 外层还有一个“返回上一步”,形成重复;
  • 删除表格行无确认、无撤销;
  • 顶部返回和右栏关闭是可点击图标,不是语义按钮:frontend/src/pages/PptPage.vue:690
  • 产品状态圆点主要依靠颜色表达;
  • 多个独立滚动区使键盘和 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 页面结构

┌─────────────────────────────────────────────────────────────────┐
│ 产品/文件切换 · 已解决 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 和模型,最后重做核对交互。

如果只换模型:

  • 正则成功分支仍不会让模型回填名称和年龄;
  • 上传产品先验仍然浪费;
  • 关键页仍可能不包含所需页面;
  • 用户仍然看不到来源证据。

如果只美化页面:

  • 外层和内层状态仍会矛盾;
  • 问题仍无法定位;
  • 自动保存仍不保存真实修改;
  • 用户仍然需要人工重录整张表。

因此,这次应按“解析质量门 → 来源与置信度 → 校验契约 → 核对任务架构”的顺序进行,而不是做局部样式微调。