# 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-04:OCR 对香港保险 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-05:LLM 输出约束不足 **证据** - 最大输出固定为 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 和模型,最后重做核对交互。 如果只换模型: - 正则成功分支仍不会让模型回填名称和年龄; - 上传产品先验仍然浪费; - 关键页仍可能不包含所需页面; - 用户仍然看不到来源证据。 如果只美化页面: - 外层和内层状态仍会矛盾; - 问题仍无法定位; - 自动保存仍不保存真实修改; - 用户仍然需要人工重录整张表。 因此,这次应按“解析质量门 → 来源与置信度 → 校验契约 → 核对任务架构”的顺序进行,而不是做局部样式微调。