# PPT 与海报生成全链路详细修复计划书 > 编制日期:2026-08-02 > 依据文档:`docs/PPT与海报生成全链路深度审计报告_20260802.md` > 适用范围:计划书 PDF 解析、人工复核、PlanData、海报生成、PPT 生成、场景与模板、异步任务、质量门禁、测试、监控与数据留存 > 文档性质:实施主计划。既有 PPT、海报和 PDF 专项计划继续作为局部设计参考;若与本计划冲突,以“统一事实快照、字段证据链、失败关闭、版本可追溯”四项原则为准。 > 2026-08-02 实施说明:计划中的代码基础、治理接口和失败关闭门禁已推进至 Phase 6;实际里程碑仍须以 30 份获批金标准、真实模板试跑、业务公式签字和灰度观察结果验收。详见 `docs/PPT与海报Phase4至6补充实施记录_20260802.md`。 ## 1. 结论与实施决策 本次整改不能按“海报修一套、PPT 再修一套”的方式推进。审计报告中的 55 项问题共享四个根因:事实来源分裂、字段语义失真、配置运行时失效、任务与输出不可复现。因此,修复主线确定为: 1. 先止损:阻止空数据、未知值、错误币种、错误字段兜底和不兼容模板继续进入成品; 2. 再建事实层:PDF 先形成保留页码、坐标、表格和 OCR 信息的 Document IR; 3. 再建唯一快照:人工确认后生成不可变 PlanData Snapshot,海报与 PPT 只能消费该快照; 4. 再重构配置:场景负责业务规则,模板负责视觉槽位,生成策略负责兼容、缺失和阻断; 5. 最后封闭交付:任务冻结全部输入,输出数值与快照逐项对账,P0 不一致时失败关闭。 不得把“有字段”“能打开 PPTX”“测试通过”当作准确性验收。上线以真实脱敏 PDF 金标准集、字段证据完整率和输出数值一致率为准。 ## 2. 目标、边界与工作假设 ### 2.1 核心目标 - 同一份 PDF 只产生一套经过确认的事实数据; - 每个进入海报或 PPT 的关键金额都能定位到 PDF 页码和区域,或有明确的人工录入理由; - `missing`、`conflict`、`derived` 与真实数值 `0` 在全链路中严格区分; - 后台发布的场景、模板和生成策略实际控制生成结果,并可回放; - 异步任务提交后不再受会话、模板和配置后续修改影响; - 成品中的文本、表格和图表数值与提交时快照 100% 对账; - 客户 PDF、解析中间产物、确认快照和成品都有明确留存、鉴权和清理闭环。 ### 2.2 本计划不做的事项 - 不优先扩充大模型提示词、模板风格或新海报版式; - 不把大模型作为密集金额表逐格抄录的唯一方案; - 不把现有不可信旧解析结果批量标记为 `confirmed`; - 不在首期实现跨币种收益排名或实时汇率换算; - 不改 BaoDan/Dify 基座中除现有路由注册约定之外的代码; - 不顺带重构与 PPT、海报、文档解析无关的模块。 ### 2.3 工作假设 - 当前仓库迁移已到 `migrate_035`,本计划从 `migrate_036` 起分批增加可回滚的增量迁移; - 第一批正式金标准不少于 30 份脱敏计划书,至少覆盖 3 家保险公司、3 类险种及原生/扫描/混合 PDF; - 业务字段由保险业务人员确认口径,技术团队不自行推断“退保价值等于身故保障”等规则; - 旧接口需要在灰度期兼容,但所有新生成任务必须可识别所使用的数据契约版本; - 文档审计中的发生比例仍需真实样本测量,因此工期使用区间,不承诺单点日期。 ## 3. 当前代码基线与修复约束 以下事实已结合当前代码核验,作为实施起点: | 领域 | 当前代码事实 | 修复约束 | |---|---|---| | 海报解析 | `poster/tasks.py` 优先执行 `extract_for_poster`,只有映射结果失败才回退完整解析 | 过渡期先收紧完整性门,最终删除独立事实解析,只保留 PlanData projection | | 海报确认 | `poster/service.py::confirm_case_upload` 直接保存 `confirmedData`,未校验解析状态、必填、冲突、证据和文件哈希 | 前端校验只能改善体验,最终门禁必须在后端 | | 海报复核 | `PosterSourcePanel.vue` 仅编辑基础字段和 10/20/30 年值,未挂载 PDF 预览和完整利益表 | 先复用已有 `PdfPagePreview.vue`,不另造第二套 PDF 查看器 | | 数值语义 | `normalizer.py` 多处把缺失/非法值转为 `0`,仍存在字段互相兜底和保费乘年期推导 | 先引入兼容型 nullable 语义,再切换到 FieldValue;不可一次修改全部渲染器后才测试 | | 场景 | 前后端均存在硬编码检测,运行时重新推断场景 | 场景解析只保留服务端单一入口,返回 `matchTrace` | | 模板 | `scenarioSlides` 优先于后台 `slidesConfig`;模板上传可直接置 `clone_ready=True` | 先明确临时优先级,再建立 pageSpec-slot 契约和发布门禁 | | 任务快照 | 已有 `input_snapshot_json` 和 `input_revision`,但 Worker 仍读取当前 session/template | 扩展现有任务模型和创建流程,不另建平行任务系统 | | 留存 | 清理逻辑覆盖部分海报成品和 PPT 历史,但未覆盖源 PDF、case、Document IR、快照和证据 | 新数据必须在同一版本同时接入鉴权与清理 | ## 4. 目标链路与责任边界 ```text PDF 上传 -> Document Ingest(哈希、鉴权、页数、文件类型) -> Document IR(页面、bbox、文本块、表格、OCR 候选) -> Extraction Candidates(正则、profile、表格解析、LLM 语义候选) -> Reconciliation(字段语义、业务规则、冲突与场景归属) -> Review(PDF / 字段 / 表格双向定位) -> Confirmed PlanData Snapshot(不可变、版本化、可追溯) -> Poster Projection / PPT DeckContract -> ScenarioDefinition + GenerationPolicy + TemplateDefinition -> Frozen Generation Input -> Render -> 数值对账 + 视觉检查 -> 成品或失败报告 ``` 模块职责必须保持清晰: | 模块 | 唯一职责 | 禁止行为 | |---|---|---| | `api/insurance/document/` | 保存 PDF 的版面事实和解析过程 | 直接决定保险字段最终值 | | `api/insurance/plan_data/` | 候选合并、业务校验、人工确认、快照、投影 | 为了适配某个海报模板修改事实 | | `api/insurance/ppt/` | 将 PlanData 转为 DeckContract 并渲染 PPT | 重新解析 PDF 或静默补造金额 | | `api/insurance/poster/` | 将 PlanData 投影为海报内容并渲染 | 维护独立计划书事实或覆盖里程碑值 | | `api/insurance/generation/` | 解析场景、冻结输入、调度、对账、追溯 | 在 Worker 中读取可变业务状态 | | 管理后台 | 编辑、验证、发布场景和模板版本 | 修改已发布版本的内容 | ## 5. 数据模型与迁移计划 ### 5.1 `migrate_036`:Document IR 与文档访问 新增表: - `insurance_documents` - `id`、`user_id`、`sha256`、`storage_key`、`original_name`、`mime_type`、`file_size`、`page_count`; - `document_type`、`pdf_kind`(native/scanned/mixed)、`status`; - `parser_version`、`ocr_version`、`profile_code`、`profile_version`; - `quality_json`、`processing_log_json`、`expires_at`、时间字段; - 唯一约束建议为 `(user_id, sha256)`,不得跨用户复用授权。 - `insurance_document_pages` - `document_id`、`page_number`、`width`、`height`; - `native_text_quality`、`ocr_quality`、`page_class`; - `text_blocks_json`、`ocr_blocks_json`、`images_json`; - 唯一约束 `(document_id, page_number)`。 - `insurance_document_tables` - `document_id`、`table_id`、`scenario_type`、`headers_json`、`rows_json`; - `source_pages_json`、`continuation_of`、`bbox_json`、`conflicts_json`。 取舍说明:文本块和表格首期以 JSON 按页/表存储,避免把每个 PDF 单元格展开成海量数据库记录;需要检索的字段证据单独结构化存储。 ### 5.2 `migrate_037`:PlanData、证据与确认快照 新增表: - `insurance_plan_snapshots` - `id`、`document_id`、`schema_version`、`snapshot_version`、`previous_snapshot_id`; - `status`(draft/review_required/confirmed/superseded/invalid); - `plan_data_json`、`validation_results_json`; - `snapshot_hash`、`document_sha256`、`confirmed_by`、`confirmed_at`、`created_at`、`expires_at`; - 唯一约束 `(document_id, snapshot_version)` 和 `snapshot_hash` 索引。 - `insurance_field_evidence` - `snapshot_id`、`field_path`、`document_id`、`page_number`、`bbox_json`; - `table_id`、`row_id`、`column_id`、`raw_text`、`text_hash`; - `extractor`、`extractor_version`、`confidence`、`evidence_status`。 - `insurance_plan_overrides` - `snapshot_id`、`field_path`、`old_value_json`、`new_value_json`; - `reason`、`operator_id`、`created_at`。 核心约束: - `confirmed` 快照内容不可原地更新;修改必须派生新版本; - `snapshot_hash` 对规范化 JSON 计算,字段排序、数字精度和空值表达必须固定; - `confirmed` 前关键字段的 `conflict` 数量必须为 0; - 每个导出关键金额必须存在证据,或存在人工覆盖记录和原因。 ### 5.3 `migrate_038`:场景、策略与模板版本 保留现有 `insurance_ppt_scenarios` 和 `insurance_ppt_templates` 作为稳定标识与当前指针,新增版本表: - `insurance_ppt_scenario_versions` - `scenario_code`、`version`、`lifecycle`(draft/validated/published/retired); - `selector_json`、`page_specs_json`、`metric_specs_json`、`comparison_years_json`; - `compatibility_rules_json`、`fallback_scenario`、`definition_hash`; - `published_by`、`published_at`。 - `insurance_generation_policy_versions` - `code`、`version`、`lifecycle`; - `calculation_policy_json`、`missing_value_policy_json`、`conclusion_policy_json`、`policy_hash`。 - `insurance_ppt_template_versions` - `template_id`、`version`、`lifecycle`; - `asset_id`、`asset_sha256`、`page_slots_json`、`theme_json`、`capacity_rules_json`; - `supported_scenario_versions_json`、`validation_report_json`、`definition_hash`。 已发布版本禁止更新,只能创建新版本。旧的 `slides_config_json` 在兼容期只读映射为 draft version,不自动视为 validated/published。 ### 5.4 `migrate_039`:任务冻结与输出审计 扩展 `insurance_generation_tasks`: - `snapshot_id`、`snapshot_hash`、`scenario_version_id`、`scenario_hash`; - `policy_version_id`、`policy_hash`、`template_version_id`、`template_hash`、`asset_sha256`; - `renderer_version`、`submit_revision`、`output_reconciliation_json`、`visual_check_json`; - `heartbeat_at`、`attempt_no`、`result_state`(current/stale/failed) 。 扩展 PPT/海报历史记录,保存实际使用的快照、场景、策略、模板和渲染器版本。不得只保存请求中的 `template_id`。 ### 5.5 `migrate_040`:留存策略与清理审计 - 为 Document、Page、Table、Snapshot、Evidence、Override、PPT/海报成品增加 `expires_at` 或可推导的留存策略; - 新增不含敏感正文的清理审计记录; - 清理逻辑按依赖顺序删除对象文件和数据库数据; - 清理任务支持 dry-run、批量上限、失败重试和孤儿文件检查。 所有迁移必须满足:可重复执行、启动失败即停止、先加后切、旧字段灰度期可读、不在迁移中执行耗时 PDF 重解析。 ## 6. 分阶段实施计划 ## Phase 0:止损、基线与开关(P0,4~6 人日) ### 目标 在统一事实层完成前,先阻止已知错误继续进入海报和 PPT,并建立可以量化修复效果的基线。 ### 任务包 #### P0-A:海报确认与生成后端门禁 关联问题:P0-05、P0-06、P0-07、P1-08、P1-16、P2-01。 修改: - 为 `confirm_case_upload` 增加服务端 schema; - 只允许 `parse_status in ('parsed', 'partial')` 进入确认,`partial` 必须补齐必填并解决冲突; - 验证 `file_hash`、解析快照哈希和当前 case 一致; - 按险种校验年龄、性别、币种、保费、缴费期、保额和关键利益字段; - 检查所选产品与 PDF 提取产品;不一致时必须提交 `overrideReason` 并写审计记录; - 空对象、非法数字、未解决冲突、无证据关键金额一律返回 4xx 业务错误; - 生成接口再次执行同一门禁,不能信任 `confirmed_data is not None`; - `parsed` 只表示“可复核”,只有 `confirmed` 快照可用于生成。 主要文件: - `api/insurance/poster/service.py` - `api/insurance/poster/routes.py` - `api/insurance/poster/tasks.py` - `api/insurance/models/poster_case_upload.py` - 新增 `api/insurance/plan_data/validators.py` 的兼容入口 验收: - `{}`、错误状态、缺必填、未解决冲突均无法确认; - 绕过前端直接请求同样被阻断; - 已确认数据修改后必须重新确认; - 错产品不会被后台选择静默覆盖。 #### P0-B:修正未知值、错误兜底和币种 关联问题:P0-11、P0-12、P0-13、P1-12、P1-13、P1-14、P1-15。 修改: - 新增 nullable 数值转换函数,明确区分 `None`、非法、`0`; - 停止以 `deathBenefit` 写入 `totalSurrenderValue`; - 停止 `sumAssured -> deathBenefit`、现金价值字段互相兜底; - 停止把 `annualPremium * payYears` 当合同总保费;需要展示时标记 `derived_estimate`,默认不参与对账、排名和结论; - 海报字段取值从 Python `or` 改为显式 `is not None`; - 显式里程碑与利益表同年值不一致时产生冲突,不覆盖; - 渲染器统一使用 `currency` 和 `currency_symbol`,删除所有硬编码 `US$`; - 兼容期渲染器对未知值显示 `—` 或“待确认”,不得显示 `0`。 主要文件: - `api/insurance/ppt/normalizer.py` - `api/insurance/ppt/comparison.py` - `api/insurance/ppt/validator.py` - `api/insurance/ppt/scripts/fast_pptx_renderer.py` - `api/insurance/poster/tasks.py` - `api/insurance/poster/content_builder.py` 验收: - 真实 0 保留为 0;缺失和非法值均不变成 0; - 退保价值与身故保障不再互相替代; - HKD、CNY、SGD、USD 样本的所有页面币种一致; - 缺失金额不会进入排名、IRR 或“更优”结论。 #### P0-C:模板适用性、排序与后台诚实提示 关联问题:P0-08、P0-09、P1-18、P1-20、P2-03。 修改: - 前后端多产品模板适用条件统一为“所有输入产品均满足”; - 自动模板查询增加稳定排序:精确场景、产品覆盖、优先级、版本、ID;同优先级多个匹配时阻断; - 在场景系统完成前,后台明确标注现有 `slidesConfig` 仅影响视觉页框/元数据,不能承诺控制业务页面; - 记录临时 `scenario_override_trace`,把硬编码检测、用户选择、模板标签和最终场景全部写入任务日志; - 生成页文案与真实能力一致,暂不展示不存在的“手动选择场景”。 验收: - 任一产品不适用时模板不可选且后端拒绝; - 同一输入重复自动选模板结果稳定; - 管理员能看到当前配置是否只作为视觉配置使用。 #### P0-D:金标准与回归基线 关联问题:P0-17、P2-08。 修改: - 建立脱敏样本登记表、标注规范和双人复核流程; - 首批 10 份用于开发探针,Phase 2 前扩充到不少于 30 份; - 标注标量、完整利益表、场景、页码、bbox、币种、单位和允许的空值; - 将当前解析结果、耗时、人工修改率和 PPT/海报输出保存为基线,不把当前值当正确值; - 新增批量评测命令,输出 JSON 和 Markdown 差异报告。 建议文件: - `tests/fixtures/plan_goldens/manifest.json` - `tests/fixtures/plan_goldens/labels/*.json` - `tests/plan_data_golden_test.py` - `scripts/tools/evaluate_plan_goldens.py` Phase 0 出口门禁:所有止损测试通过;10 份样本可批量运行;确认和生成接口无法绕过门禁;不开启新架构开关时现有已确认记录仍可查看。 ## Phase 1:Document IR 与字段证据基础(P0,7~10 人日) ### 目标 解决“字符可读但页、表、行、列归属错误”的根因,保留后续对账所需的几何和来源信息。 ### 任务包 #### P1-A:统一文档摄取 关联问题:P0-02、P1-01、P1-02、P1-03、P1-11。 - 新建 `api/insurance/document/ingest.py`,统一计算 SHA-256、文件类型、页数、存储键和权限; - 新建 `pdf_classifier.py` 判断 native/scanned/mixed,不再只依赖全文乱码率; - 按页保存文本块、读取顺序、bbox 和质量,不再使用 120000 字符全局硬截断; - OCR 由“最多 40 页”改为按页质量和任务预算调度,超过预算时明确 partial/blocked; - 缓存键包含文档哈希、parser/OCR/profile/规则/model/prompt 版本; - 文档读取失败、加密、超限和低质量返回结构化错误。 #### P1-B:表格恢复与跨页关系 关联问题:P0-03、P0-04、P1-04、P1-05。 - 新建 `layout.py`、`tables.py`;保留线条、坐标聚类、表头层级、合并单元格和单位; - 续页识别使用表格边界、列坐标、表头指纹和页间连续性,不只依赖关键词; - 行主键改为 `(table_id, scenario_type, policy_year, row_variant)`,禁止只按 `policy_year` 去重; - `source_page` 由解析器根据真实块坐标产生,不接受模型孤立给出的页码作为唯一证据; - 同一值存在多个候选时全部保留并标为 conflict。 #### P1-C:EvidenceRef 服务 关联问题:P1-10、P1-27。 - 新建 `evidence.py` 提供字段到 PDF 区域、表格单元格到字段的双向索引; - 原文保存必要的最小片段和 hash,避免在日志中复制全文; - 提供受鉴权的页面预览接口和证据定位接口; - 证据状态包含 `auto/confirmed/rejected/superseded`。 建议 API: - `GET /api/insurance/documents/{id}` - `GET /api/insurance/documents/{id}/pages/{page}` - `GET /api/insurance/documents/{id}/pages/{page}/preview` - `GET /api/insurance/plan-snapshots/{id}/evidence?fieldPath=...` Phase 1 出口门禁:每个关键金额具有真实页码和 bbox;同年份多场景不合并;跨页表在金标准中的行召回达到阶段阈值;服务端路径不出现在 API 响应。 ## Phase 2:候选合并、人工复核与金标准达标(P0,8~12 人日) ### 目标 让“正确性”取代“完整度”成为确认依据,并让用户真正具备核对能力。 ### 任务包 #### P2-A:Extraction Candidate 与 Reconciliation 关联问题:P1-06、P1-07、P1-08、P1-09、P1-10、P1-14、P1-15。 - 正则、profile 表格提取、OCR、LLM 语义识别均输出候选,不直接覆盖最终值; - 候选包含 `raw_value`、`normalized_value`、`unit`、`currency`、`status`、`evidence[]`; - 文件名和所选产品只写入 `context_hint`;与 PDF 证据不一致时生成 conflict; - 正则不再因为“有标签”自动压过 LLM/表格结果;由证据质量、profile 和业务校验统一评分; - LLM 仅负责页面/表头语义、同义词和段落摘要,密集金额优先由表格解析产生; - completeness 与 correctness 分开计算,存在关键冲突时最高只能 `review_required`。 #### P2-B:业务校验规则 关联问题:P0-02、P0-11、P0-12、P1-13、P1-26。 最少实现: - 币种/单位一致; - 保单年度与受保人年龄关系; - 保证、非保证、总额公式(只在产品规则明确时启用); - 场景、提取前后和红利实现率隔离; - 身故利益、退保价值、账户价值不可互代; - 比较输入的年龄、性别、吸烟、保费、缴费期、保额、币种、附加险和提取方案兼容性; - 口径不可比时允许并列展示,但禁止生成排名和“更优”结论。 #### P2-C:复核工作台 关联问题:P0-07、P1-27、P1-29。 - 把 `PdfPagePreview.vue` 抽成 PPT/海报共享证据预览组件; - 宽屏使用 PDF、字段、完整利益表三栏;窄屏使用标签页,不隐藏关键校验状态; - 点击字段定位 PDF 页和 bbox;点击 PDF 区域反向高亮候选字段; - 完整利益表按 `scenario_type` 分组,支持逐行编辑、冲突比较和证据查看; - 人工修改必须填写原因;`modificationLog` 通过后端持久化为 override,不再只存前端内存; - 所有阻断项集中展示,确认按钮展示具体不可用原因。 Phase 2 出口门禁:30 份双人标注样本完成;关键标量精确率不低于 99.5%;金额单元格精确率和目标行召回率不低于 99.0%;同年多场景污染为 0;所有导出候选金额证据覆盖率 100%。未达门槛不得进入默认解析路径。 ## Phase 3:统一 PlanData Snapshot 与海报/PPT 投影(P0,6~9 人日) ### 目标 消除海报和 PPT 两套计划书事实,使任何修改、生成和历史记录都指向唯一快照。 ### 任务包 #### P3-A:PlanData Schema 和不可变快照 关联问题:P0-01、P0-14、P0-15、P1-28、P1-29。 - 定义版本化 PlanData JSON Schema; - 身份、保单、受保人、分场景利益、提领、附加险、假设、校验结果分区; - 所有字段使用 FieldValue 或等价结构; - 通过 `document_id/snapshot_id` 更新,不再按 `pdfName` 匹配; - 确认、修改、撤销确认都创建新版本并保留 previous link; - 快照 hash 使用规范化 JSON,写入历史和生成任务。 #### P3-B:海报 Projection 关联问题:P0-01、P0-05、P1-12、P1-14、P1-15。 - 删除海报独立紧凑解析在新链路中的事实职责; - `extract_for_poster` 仅在兼容开关下保留,标记 deprecated; - 新建 `plan_data/projections.py::to_poster_projection`,里程碑值只从已确认完整表投影; - 文案事实、产品手册规则和计划书事实分开传递,禁止互相覆盖; - 海报渲染后抽取文本并与 projection 对账。 #### P3-C:PPT DeckContract Projection - Normalizer 改为纯 PlanData -> DeckContract 转换,不做业务猜测; - DeckContract 保留字段状态、币种、单位和 evidence id; - 图表只接收可比较且已确认的 series; - 不允许渲染器自行推导缺失值。 #### P3-D:旧数据策略 - 旧记录只读展示; - 需要重新生成时提示“需使用当前解析器重新解析并确认”; - 不自动把旧 `confirmed_data` 转为可信快照; - 可将旧数据导入 draft candidate,但状态必须是 `review_required`。 Phase 3 出口门禁:同一 snapshot 的海报和 PPT 基础字段、币种、10/20/30 年值一致率 100%;任何修改生成新版本;成品可追溯到唯一 snapshot hash。 ## Phase 4:PPT 场景、策略与模板可执行化(P0/P1,8~12 人日) ### 目标 让后台配置真实、确定地控制 PPT 的业务页面、比较规则和视觉承载。 ### 任务包 #### P4-A:ScenarioDefinition 与服务端解析器 关联问题:P0-08、P0-09、P0-10、P1-19、P1-25、P2-02、P2-03。 - 实现场景 selector:文件数量、险种/产品/公司组合和客户条件; - 实现 pageSpecs、metricSpecs、comparisonYears、fallback; - 前端删除硬编码场景检测,只展示服务端 `/resolve-scenario` 结果; - 用户明确选择已发布场景时优先;不兼容则阻断,不静默改为硬编码场景; - 多个同优先级命中或无匹配时阻断并返回 `matchTrace`; - 后台补齐编辑、复制版本、校验、发布、停用和规则试跑。 #### P4-B:GenerationPolicy 关联问题:P1-26。 - 明确兼容性、计算、缺失、排名、结论、阻断和降级策略; - 不同口径只能并列展示时,在 pageSpec 中使用 `nonComparableReason`; - IRR、倍数和排名所用公式、输入字段和精度必须版本化; - 不允许策略写回或修改 PlanData。 #### P4-C:TemplateDefinition 与发布门禁 关联问题:P1-22、P1-23、P1-24、P2-04、P2-08。 - 每种 page_type 定义语义槽位、容量、溢出规则和样本; - 上传 PPT 后校验必需 page_type、slot、唯一映射、字体、图表和页容量; - 取消页面匹配失败时静默取第一张未使用页面; - `clone_ready` 改为校验结果,不得仅因文件能打开就设为 true; - 不再无差别清除模板文本/图表/表格;只替换已声明的业务 slot; - 风格选项要么提供真实独立主题,要么合并重复选项,避免后台虚假差异。 #### P4-D:唯一合并规则 运行时顺序固定为: 1. 解析并冻结 ScenarioDefinition; 2. 使用 pageSpecs 形成业务页面清单; 3. 验证 GenerationPolicy; 4. 将 page_type 映射到 TemplateDefinition slot; 5. 无槽位或容量超限则阻断; 6. 生成 DeckContract; 7. 渲染器严格按合并结果执行。 不得再以 `scenarioSlides or slidesConfig` 这种隐式优先级决定业务逻辑。 Phase 4 出口门禁:修改场景比较年份和 pageSpecs 后样本输出按新版本变化;修改模板映射后页面顺序变化;不兼容输入可解释地阻断;同输入同版本结构确定;发布配置应用测试 100% 通过。 ## Phase 5:冻结任务输入、输出对账与任务可靠性(P0,6~9 人日) ### 目标 保证提交时预览、Worker 实际输入和最终成品一致,并让错误成品无法显示为成功。 ### 任务包 #### P5-A:完整输入冻结 关联问题:P0-14、P0-15、P1-20、P1-21。 任务创建时冻结: - PlanData 内容、ID、版本、hash; - 源 PDF hash; - ScenarioDefinition 内容、版本、hash; - GenerationPolicy 内容、版本、hash; - TemplateDefinition 内容、版本、hash 和源资产 hash; - renderer version; - 用户选择、人工覆盖记录、brand policy; - 提交时 `draft_revision`。 Worker 只读 `input_snapshot_json` 或不可变版本记录,不查询当前 `session.extractions_json`、当前模板配置或当前场景。完成时使用 `submit_revision`:若会话已变化,则标记 `stale`,不得把 `generated_revision` 写成当前草稿版本。 #### P5-B:PPTX 数值对账 关联问题:P0-16。 - 生成后解析 PPTX XML; - 校验所有可见金额文本、表格单元格和图表 series; - 对账键至少包含 `field_path/page_type/series/category/currency/value`; - 区分格式化差异与数值差异; - P0 数值缺失、多余、币种错误或冲突直接失败; - 失败任务保留诊断报告,不提供成功下载入口。 #### P5-C:海报数值对账 - 对 render document 和最终 DOM/导出文本做字段清单对账; - AI 背景不得包含业务文字; - 导出尺寸、裁切、文本溢出和空模块纳入门禁。 #### P5-D:任务心跳、幂等与重试 关联问题:P2-05、P2-06。 - Worker 定期更新 `heartbeat_at`;超时判断使用心跳而非创建时间; - 幂等键包含 artifact type、snapshot hash、scenario/template/renderer hash; - 重试复用同一冻结输入,禁止重试时重新解析或重新选模板; - 旧 `parse_worker.py` 明确标记 deprecated,确认无引用后单独删除,不与主修复混改。 Phase 5 出口门禁:排队期间修改会话或后台配置不改变已提交任务;PPT/海报所有输出金额对账 100%;任何 P0 对账失败都不会产生可下载成功成品;任务可按冻结输入重放。 ## Phase 6:监控、隐私、灰度与正式切换(P1/P2,5~7 人日) ### 目标 让准确率、异常和数据生命周期持续可管理,并安全替换旧链路。 ### 任务包 #### P6-A:质量看板与结构化日志 关联问题:P2-07。 解析指标: - 文档 hash、PDF 类型、页数、profile 和版本; - 原生/OCR 页数、耗时、字段候选数、冲突数; - 表格数、跨页表数、未识别列数; - 自动通过、人工修改、阻断数量和按字段修改率。 生成指标: - snapshot/scenario/policy/template/renderer 版本与 hash; - `matchTrace`、页面类型、降级、对账和视觉检查; - 队列时间、执行时间、心跳、重试和最终状态。 指标需可按保险公司、产品、版式、PDF 类型和解析版本聚合。 #### P6-B:隐私、访问与清理 关联问题:P1-17、P1-30。 - `PosterCaseUpload.to_dict()` 不再返回服务器绝对路径; - PDF 仅通过鉴权预览/下载接口访问; - 日志禁止写原始全文、完整客户身份和大段解析内容; - 为源 PDF、IR、候选、快照、证据、海报、PPT 和日志分别配置留存期; - 到期清理同时覆盖数据库和对象文件,并留下脱敏审计; - 金标准集仅使用获批脱敏样本。 #### P6-C:双轨灰度与切换 - 功能开关建议:`DOCUMENT_IR_V1`、`PLAN_SNAPSHOT_V1`、`SCENARIO_ENGINE_V2`、`OUTPUT_RECONCILIATION_V1`; - 先影子解析,不影响用户输出;比较新旧字段并记录差异; - 达到金标准门槛后按保司/profile 灰度到 10% -> 30% -> 100%; - 新链路稳定后关闭紧凑解析和旧场景检测的默认入口; - 旧链路仅作为短期只读回放,不允许产生新成品。 Phase 6 出口门禁:指标、报警、权限和清理任务可验证;100% 流量切换后连续观察期无 P0 对账错误;旧写路径关闭;应急回滚可在不丢失新快照的情况下执行。 ## 7. API 改造清单 ### 7.1 文档与证据 | 方法 | 路径 | 用途 | 关键约束 | |---|---|---|---| | POST | `/api/insurance/documents` | 统一上传并创建 Document | 返回 documentId,不返回绝对路径 | | GET | `/api/insurance/documents/{id}` | 文档状态和质量 | 仅所有者/授权角色可见 | | GET | `/api/insurance/documents/{id}/pages/{page}/preview` | PDF 页预览 | 鉴权、限时、可审计 | | GET | `/api/insurance/documents/{id}/tables` | 表格和跨页关系 | 支持 scenario/page 过滤 | | POST | `/api/insurance/documents/{id}/extract` | 创建解析任务 | 接收 profile hint,不允许覆盖文档事实 | ### 7.2 PlanData 与复核 | 方法 | 路径 | 用途 | 关键约束 | |---|---|---|---| | GET | `/api/insurance/plan-snapshots/{id}` | 获取快照与校验结果 | 返回 schemaVersion、hash、status | | GET | `/api/insurance/plan-snapshots/{id}/evidence` | 查询字段证据 | fieldPath 必填或分页 | | PATCH | `/api/insurance/plan-snapshots/{id}/draft` | 编辑草稿 | 乐观锁 + overrideReason | | POST | `/api/insurance/plan-snapshots/{id}/validate` | 执行业务校验 | 不改变 confirmed 版本 | | POST | `/api/insurance/plan-snapshots/{id}/confirm` | 生成确认版本 | 冲突为零、关键证据齐全 | | GET | `/api/insurance/plan-snapshots/{id}/poster-projection` | 海报只读投影 | 不允许调用端覆盖事实 | | GET | `/api/insurance/plan-snapshots/{id}/deck-contract` | PPT 只读投影 | 返回可比较性和缺失状态 | ### 7.3 场景与模板 | 方法 | 路径 | 用途 | |---|---|---| | POST | `/api/insurance/ppt/scenarios/resolve` | 基于 snapshot 列表返回唯一场景和 matchTrace | | POST | `/api/insurance/admin/ppt/scenarios/{code}/versions` | 创建 draft 版本 | | POST | `/api/insurance/admin/ppt/scenario-versions/{id}/validate` | 使用样本试跑 | | POST | `/api/insurance/admin/ppt/scenario-versions/{id}/publish` | 发布不可变版本 | | POST | `/api/insurance/admin/ppt/template-versions/{id}/validate` | 校验 page_type、slot、容量和样本渲染 | | POST | `/api/insurance/admin/ppt/template-versions/{id}/publish` | 发布模板版本 | ### 7.4 生成 现有 PPT/海报生成入口保留,但请求改为携带 `snapshotId`、可选的已发布 `scenarioVersionId` 和 `templateVersionId`。响应和任务详情新增: - `submitRevision`、`snapshotHash`; - `scenarioVersion`、`policyVersion`、`templateVersion`、`rendererVersion`; - `matchTrace`、`reconciliationStatus`、`visualCheckStatus`; - `resultState=current|stale|failed`。 错误码至少区分:数据未确认、证据不足、存在冲突、场景多匹配、场景不匹配、模板槽位缺失、输入不兼容、输出对账失败、视觉门禁失败。 ## 8. 前端实施计划 ### 8.1 复核工作台 - PPT 与海报共用一个证据复核核心组件,业务外壳可分别保留; - 显示字段状态:自动提取、人工确认、冲突、缺失、推导; - 未知值显示 `—`,不预填 0; - 金额编辑同步选择币种/单位,避免只改数字; - 完整利益表按场景标签分组; - 提交确认前展示阻断项数量、警告项数量和人工覆盖数量; - 后端返回错误使用字段路径定位到具体控件。 ### 8.2 PPT 生成页 - 删除本地场景计算,调用服务端 resolver; - 展示最终场景、版本、命中规则和不可比较原因; - 模板列表只显示服务端返回的兼容模板; - 管理员/用户明确选择场景时,显示“已选择”而不是被后台替换; - 历史成品展示数据、场景、模板版本以及 current/stale 状态。 ### 8.3 管理后台 - 场景:选择规则、比较条件、指标、年份、页面、缺失/结论策略; - 模板:page_type、semantic slot、容量、溢出规则、预览和校验报告; - 发布前必须选样本集试跑; - 已发布版本只读;编辑操作自动创建新 draft; - 明确展示“验证失败不可发布”的原因。 ### 8.4 可访问性和响应式 - 键盘可完成字段跳转、冲突选择、表格编辑和确认; - 状态不能只依赖颜色; - PDF bbox 高亮有文本说明; - 小屏不强行三栏,使用固定操作栏和标签切换; - 长表使用虚拟滚动或分页,但不得只加载里程碑行。 ## 9. 测试与质量门禁 ### 9.1 测试分层 | 层级 | 重点 | 必须覆盖 | |---|---|---| | 单元测试 | 数值语义、候选合并、业务规则、hash | 0/None/非法值、场景隔离、币种/单位、公式 | | Schema 测试 | Document IR、FieldValue、PlanData、配置版本 | 向后兼容、未知字段、版本拒绝 | | API 测试 | 上传、确认、覆盖、发布、生成 | 越权、绕过前端、乐观锁、错误码 | | 金标准测试 | 真实 PDF 精确值和证据 | 标量、每个表格单元格、页码、bbox、场景 | | 集成测试 | PDF -> confirmed snapshot -> 海报/PPT | 同快照一致、任务冻结、重放 | | 输出对账 | PPTX XML、海报 DOM/导出文本 | 文本、表格、图表 series、币种 | | 视觉回归 | 页面图片差异和布局探针 | 溢出、遮挡、裁切、空图、字体 | | 稳定性 | 队列、重试、并发、清理 | 心跳、幂等、旧版本、孤儿文件 | ### 9.2 金标准样本矩阵 - 原生文本、全扫描、混合 PDF; - 单栏、多栏、横向页; - 有线框/无线框表、合并表头; - 单页表、跨页表、续页无表头; - 中文、英文、中英混合; - 储蓄、重疾、IUL; - 同一年多场景、提取前后、不同演示利率; - 正确文件名、错误文件名、无意义文件名; - 加密、损坏、超长、OCR 模糊/倾斜/低对比度。 ### 9.3 强制验收指标 | 指标 | 门槛 | 阻断级别 | |---|---:|---| | 关键标量精确率 | >= 99.5% | 未达不得默认开启新解析 | | 金额表格单元格精确率 | >= 99.0% | 未达不得默认开启新解析 | | 目标利益行召回率 | >= 99.0% | 未达不得默认开启新解析 | | 导出金额正确证据覆盖率 | 100% | 单次任务失败 | | 同年份不同场景污染 | 0 | 发布阻断 | | 未解决冲突自动确认 | 0 | 确认阻断 | | 未知值静默变 0 | 0 | 测试/发布阻断 | | 海报与 PPT 同快照一致率 | 100% | 发布阻断 | | PPT 与 DeckContract 数值一致率 | 100% | 单次任务失败 | | 已发布场景/模板应用测试 | 100% | 配置发布阻断 | | 生成物版本追溯率 | 100% | 发布阻断 | ### 9.4 建议回归命令 ```bash pytest -q tests/ppt_poster_optimization_test.py \ tests/ppt_template_asset_test.py \ tests/ppt_task_lifecycle_test.py \ tests/ppt_parse_route_test.py \ tests/poster_render_document_test.py \ tests/poster_render_validation_test.py \ tests/user_product_material_test.py pytest -q tests/plan_data_*_test.py tests/document_ir_*_test.py tests/output_reconciliation_*_test.py cd frontend npm run lint npm run build ``` 部署环境另行执行 LibreOffice/Office/WPS 打开验证和页面渲染对比;本地缺少 `python-pptx` 时不得把相应跳过项当作通过。 ## 10. 发布、灰度与回滚 ### 10.1 发布顺序 1. 上线 Phase 0 门禁和兼容代码; 2. 上线 `migrate_036~037` 与只写不读的 Document/Snapshot 基础设施; 3. 开启影子解析,旧链路继续服务,收集差异; 4. 达到金标准门槛后按 profile 小流量读取新快照; 5. 上线版本化场景/模板,但先只发布内置样本验证通过的版本; 6. 上线任务冻结和输出对账,先 warning 模式观察,再切 failure 模式; 7. 关闭旧紧凑解析、旧场景检测和旧任务可变读取; 8. 观察稳定后清理 deprecated 写路径。 ### 10.2 回滚原则 - 数据迁移只增表/增列,业务回滚不删除新数据; - 功能开关按 profile 或租户回退,不回写旧确认状态; - 已生成的新快照和审计记录保留,可在修复后重放; - 对账 failure 模式可临时回退到“阻断下载、允许内部预览”,不得回退为对外成功交付; - 已发布配置不修改,通过切换当前版本指针回滚; - 任何回滚都记录操作者、原因、版本和影响范围。 ### 10.3 灰度停止条件 - 任一错误金额进入成品; - 同一快照海报/PPT 值不一致; - 新解析人工修改率显著高于基线; - 场景多匹配、模板错配或任务输入漂移; - 鉴权绕过、绝对路径泄露或清理误删; - P95 解析/生成时延超过约定容量且无法通过限流缓解。 ## 11. 工作量、人员与里程碑 ### 11.1 粗略工作量 | 阶段 | 预计人日 | 主要角色 | |---|---:|---| | Phase 0 止损与基线 | 4~6 | 后端、前端、QA、业务 SME | | Phase 1 Document IR | 7~10 | 后端/PDF、QA | | Phase 2 合并与复核 | 8~12 | 后端/PDF、前端、QA、业务 SME | | Phase 3 统一快照与投影 | 6~9 | 后端、前端、QA | | Phase 4 场景与模板 | 8~12 | 后端、前端、PPT、QA | | Phase 5 冻结与输出门禁 | 6~9 | 后端、PPT/前端、QA | | Phase 6 运营与切换 | 5~7 | 后端、运维、安全、QA | | 合计 | 44~65 人日 | 不含业务样本收集等待时间 | 建议配置:2 名后端(其中 1 名熟悉 PDF/PPTX)、1 名前端、1 名 QA、1 名兼职保险业务 SME、1 名兼职运维/安全。该配置下预计 7~10 个自然周;如果仅 1 名开发串行推进,应按阶段门禁排期,不压缩金标准标注和灰度观察。 ### 11.2 里程碑 - M1:Phase 0 完成,已知高危错误停止扩散; - M2:Document IR 和证据定位可用,30 份金标准建立; - M3:海报/PPT 统一消费 confirmed snapshot; - M4:后台场景和模板版本真实控制生成; - M5:任务可重放,输出对账失败关闭; - M6:全量切换、留存闭环、旧写路径关闭。 每个里程碑必须单独评审,不以“代码已合并”代替完成。 ## 12. 风险、依赖与需要确认的业务决策 | 风险/决策 | 影响 | 处理方式 | |---|---|---| | 缺少获批真实 PDF | 无法量化准确率 | Phase 0 即启动脱敏和双人标注;样本不到位不发布新解析 | | 不同保司版式差异大 | 通用解析准确率波动 | profile + 通用回退;按 profile 灰度 | | bbox/表格 IR 数据量大 | 存储和查询成本 | 按页 JSON、压缩、分层留存、避免逐字符入库 | | OCR 成本与时延 | 队列拥塞 | 按页质量调度、预算和并发限制、心跳 | | 业务公式口径不明确 | 校验误报或错误推导 | 所有公式进入版本化 GenerationPolicy,由 SME 签字 | | 模板缺少语义槽位 | 无法自动适配旧资产 | 旧模板作为 draft,逐个补 slot 并样本验证 | | 旧记录无法可靠迁移 | 历史再生成受限 | 旧记录只读;再生成前重新解析确认 | | 失败关闭降低短期成功率 | 用户感知任务变“更容易失败” | 明确错误原因,提供修复入口;不以错误成品换成功率 | | 多版本系统增加管理成本 | 管理员操作复杂 | 只提供 draft/validate/publish 三步,不引入无需求的审批流 | 开发前需业务明确: 1. 各险种关键必填字段及合理范围; 2. 哪些公式可用于校验,哪些仅可作为提示; 3. 同类比较与跨类并列展示的兼容条件; 4. 非保证利益的情景命名、演示利率和提取前后口径; 5. 源 PDF、快照、成品和日志的留存天数; 6. 金标准样本的授权、脱敏和双人复核负责人。 ## 13. 问题覆盖矩阵 | 审计编号 | 计划任务 | 解决方式 | 验收位置 | |---|---|---|---| | P0-01 | P3-B/P3-C | 海报/PPT 共用 confirmed snapshot | Phase 3 | | P0-02 | P1-A/P1-B/P2-B | 版面 IR、表格和业务校验 | Phase 2 | | P0-03 | P1-B | 复合行键保留场景 | Phase 1 | | P0-04 | P1-B | 跨页表连续性识别 | Phase 1 | | P0-05 | P0-A/P3-B | 收紧回退并删除独立事实解析 | Phase 3 | | P0-06 | P0-A | 后端确认 schema 和冲突门禁 | Phase 0 | | P0-07 | P2-C | PDF、字段、完整表并排复核 | Phase 2 | | P0-08 | P0-C/P4-D | 临时诚实提示 + 唯一合并规则 | Phase 4 | | P0-09 | P0-C/P4-A | 服务端场景解析与 matchTrace | Phase 4 | | P0-10 | P4-A/P4-B | 可执行场景和生成策略 | Phase 4 | | P0-11 | P0-B/P2-B | nullable/FieldValue 语义 | Phase 2 | | P0-12 | P0-B | 删除错误字段兜底 | Phase 0 | | P0-13 | P0-B | 统一币种格式化 | Phase 0 | | P0-14 | P3-A/P5-A | 快照与完整任务冻结 | Phase 5 | | P0-15 | P5-A | 使用 submit_revision 标记结果 | Phase 5 | | P0-16 | P5-B/P5-C | 输出数值对账失败关闭 | Phase 5 | | P0-17 | P0-D/P2 | 真实 PDF 金标准 | Phase 2 | | P1-01 | P1-A | 按页处理,取消全文硬截断 | Phase 1 | | P1-02 | P1-A | OCR 按页质量和预算调度 | Phase 1 | | P1-03 | P1-A | 版面质量触发 OCR | Phase 1 | | P1-04 | P1-B/P2-A | 强 schema + 表格优先 | Phase 2 | | P1-05 | P1-C | 真实 bbox 证据 | Phase 1 | | P1-06 | P2-A | 候选合并,不静默覆盖 | Phase 2 | | P1-07 | P2-A | 文件名仅作为 context hint | Phase 2 | | P1-08 | P0-A/P2-A | 产品选择只参与冲突检测 | Phase 2 | | P1-09 | P2-A/P2-B | correctness 与 completeness 分离 | Phase 2 | | P1-10 | P1-C | 字段级 EvidenceRef | Phase 1 | | P1-11 | P1-A | 完整版本化缓存键 | Phase 1 | | P1-12 | P0-B | 显式 None 判断 | Phase 0 | | P1-13 | P0-B/P2-B | 禁止推导值冒充合同值 | Phase 2 | | P1-14 | P0-B/P3-B | 字段语义统一 | Phase 3 | | P1-15 | P0-B/P2-A | 冲突替代覆盖 | Phase 2 | | P1-16 | P0-A | PDF 产品一致性门禁 | Phase 0 | | P1-17 | P6-B | 鉴权接口替代绝对路径 | Phase 6 | | P1-18 | P0-C | 全产品满足模板条件 | Phase 0 | | P1-19 | P4-A | 删除前端硬编码场景 | Phase 4 | | P1-20 | P0-C/P5-A | 稳定排序并冻结实际模板 | Phase 5 | | P1-21 | P5-A | 保存实际模板版本 | Phase 5 | | P1-22 | P4-C | 仅替换语义槽位 | Phase 4 | | P1-23 | P4-C | 页面无法匹配即阻断 | Phase 4 | | P1-24 | P4-C | validate/publish 门禁 | Phase 4 | | P1-25 | P4-A | comparisonYears 可配置 | Phase 4 | | P1-26 | P2-B/P4-B | 完整兼容策略 | Phase 4 | | P1-27 | P1-C/P2-C | PDF 双向定位 | Phase 2 | | P1-28 | P3-A | document/snapshot ID 更新 | Phase 3 | | P1-29 | P2-C/P3-A | 后端持久化 override | Phase 3 | | P1-30 | P6-B | 全链路留存和清理 | Phase 6 | | P2-01 | P0-A | parsed 与 confirmed 状态分离 | Phase 0 | | P2-02 | P4-A | 完整场景版本编辑 | Phase 4 | | P2-03 | P0-C/P4-A | 前端能力与文案一致 | Phase 4 | | P2-04 | P4-C | 真实主题或合并重复风格 | Phase 4 | | P2-05 | P5-D | 旧 Worker 退役 | Phase 5 | | P2-06 | P5-D | 心跳超时 | Phase 5 | | P2-07 | P6-A | 解析质量看板 | Phase 6 | | P2-08 | P0-D/P4-C/P5 | 视觉回归和输出门禁 | Phase 5 | ## 14. Definition of Done 只有同时满足以下条件,本次全链路修复才算完成: - 55 项审计问题均有关闭证据或经批准的延期记录; - 30 份以上真实脱敏样本金标准通过,关键指标达到第 9.3 节门槛; - 海报和 PPT 不再独立解析同一计划书事实; - 所有新生成任务只接受 confirmed snapshot; - 未知、冲突和推导值不会静默作为真实 0 或合同值输出; - 后台场景、策略和模板均经过版本化发布与样本验证; - Worker 不读取提交后的可变会话、场景和模板状态; - PPT/海报成品数值对账 100%,P0 差异失败关闭; - API 不暴露服务器绝对路径,源文件访问有鉴权; - 源 PDF、IR、快照、证据、成品和日志留存清理经过 dry-run 与实删验证; - 前端 lint/build、后端单元/集成/金标准/输出对账/视觉回归全部通过; - 灰度、回滚、监控和运维手册已完成并演练; - 相关 API、数据字典、测试用例和用户操作文档同步更新。 ## 15. 建议立即启动的首个迭代 首个迭代只做以下内容,避免同时开太多架构分支: 1. 完成 P0-A:海报后端确认/生成门禁及绕过前端测试; 2. 完成 P0-B:`None/0`、错误字段兜底、币种的止损修复; 3. 完成 P0-C:模板全量适用条件、稳定排序和后台提示; 4. 建立 10 份开发金标准、标注规范和批量评测脚本; 5. 评审并冻结 Document IR、FieldValue、PlanData Snapshot 三份 schema,再开始 `migrate_036~037`。 首个迭代结束时必须提供:变更清单、测试证据、10 份样本基线、未解决冲突清单、下阶段 schema 评审记录。没有这些产出,不进入 Document IR 开发。 ## 16. 与既有文档的关系 - `PDF计划书解析后续演进详细计划_20260802.md`:作为 parser profile、金标准和未知保司接入的详细参考;本计划补充统一快照及海报/PPT 消费边界。 - `海报生成工作台完整重构修复计划.md`:作为海报画布、资产、导出和工作台交互参考;事实模型统一改用本计划 PlanData Snapshot。 - `保险智能客服系统_PPT与海报优化修复计划书_20260731.md`:作为已完成/历史专项修复记录;新发现的配置覆盖和可复现性问题以本计划为准。 - `PPT与海报编辑体验及解析问题专项优化修复计划书_20260731.md`:继续作为局部 UI 与编辑体验参考;确认门禁、证据和版本规则以本计划为准。 - `PPT多文件上传比对功能_详细修复计划书.md`:继续作为上传和多文件交互参考;比较兼容性和场景解析迁移到 ScenarioDefinition/GenerationPolicy。 本计划不删除或覆盖既有文档,通过统一的阶段门禁和问题覆盖矩阵把它们纳入同一实施路线。