# PDF 实时解析提速与精准抽取方案 ## 1. 背景 当前 PPT 生成和海报生成都依赖用户上传 PDF 计划书,再从 PDF 中抽取结构化数据。实际业务中,用户上传的 PDF 不一定是公共资料,也不一定会重复使用,同一份 PDF 缓存命中率有限。 因此,优化目标不能只依赖“同文件缓存”,而应该围绕实时解析链路做改造: - 少读:不全量读取无关页面 - 少传:不把整本 PDF 文本都交给模型 - 先准:金额、年龄、保费、利益表等字段优先用规则和表格抽取 - 补漏:模型只处理缺失字段和语义判断 - 可追溯:关键字段保留来源页和置信度 - 可降级:快速解析失败时进入精确解析或人工确认 ## 2. 总体目标 将现有链路: ```text 上传 PDF -> 全文抽取 -> 截断前 2 万字 -> LLM 完整解析 -> 等待 -> 生成 PPT/海报 ``` 改造为: ```text 上传 PDF -> 按页快速抽文本 -> 页面打分和字段覆盖分析 -> 选取关键页 -> 规则/表格优先抽取 -> LLM 补全缺失字段 -> 完整性校验 -> 缺什么补什么 -> 返回可编辑结构化数据 -> 生成 PPT/海报 ``` 预期效果: ```text 海报解析:5-15 秒返回可编辑数据 PPT 快速解析:20-60 秒返回初版结构化数据 PPT 精确解析:仅在字段缺失或用户要求时触发 ``` ## 3. 核心原则 ### 3.1 不依赖重复 PDF 缓存 PDF 每次可能不同,所以缓存只能作为辅助能力。主优化方向是让每次实时解析都更轻。 ### 3.2 不一次性相信关键页筛选 关键页筛选只是第一步,后面必须有字段完整性校验。如果缺字段,需要定向补页。 ### 3.3 不让 LLM 自由生成精确数值 年龄、保费、保额、利益演示表、现金价值、身故赔偿等字段,应优先来自规则、表格解析或原文证据。LLM 主要负责: ```text 识别字段语义 补全规则抽不到的内容 总结产品卖点 处理复杂版式 输出统一 JSON ``` ### 3.4 每个关键字段都要有来源 关键字段建议保存: ```json { "value": 100000, "source_page": 3, "confidence": 0.92, "source_type": "rule" } ``` 这样可以支持前端展示“来自第几页”,方便用户确认。 ## 4. 解析模式设计 系统提供两种解析模式。 ### 4.1 快速解析模式 默认模式,适合海报和大部分 PPT 初稿。 特点: ```text 只读取关键页 优先规则抽取 LLM 输入控制在 6000-10000 字 返回可编辑结构化草稿 ``` 适用场景: ```text 海报生成 销售快速演示 用户希望尽快看到结果 ``` ### 4.2 精确解析模式 用户主动点击,或快速解析校验不通过时触发。 特点: ```text 扩大关键页范围 补充更多候选页面 加强表格解析 必要时读取全文 模型输入允许更大 ``` 适用场景: ```text 正式 PPT 关键字段缺失 利益演示表识别失败 用户对金额准确性要求较高 ``` ## 5. 字段清单 ### 5.1 海报必填字段 ```text product_name 产品名称 company_name 保司名称 age 年龄 gender 性别 currency 币种 annual_premium 年缴保费 premium_term 缴费期 coverage_period 保障期 sum_assured 保额/保障额 key_benefits 核心利益/卖点 ``` ### 5.2 PPT 必填字段 ```text product_name 产品名称 company_name 保司名称 plan_type 计划类型 age 年龄 gender 性别 currency 币种 annual_premium 年缴保费 premium_term 缴费期 coverage_period 保障期 sum_assured 基本保额 benefit_illustration 利益演示表 death_benefit 身故保障 cash_value 现金价值/退保价值 ``` ## 6. 页面筛选策略 ### 6.1 按页抽取文本 不要一开始就拼整本文本。应先得到页面数组: ```json [ { "page": 1, "text": "第一页文本", "char_count": 1200 }, { "page": 2, "text": "第二页文本", "char_count": 900 } ] ``` ### 6.2 页面关键词打分 海报关键词: ```text 被保人、投保人、年龄、性别、保费、缴费期、保障期、保额、基本保额、身故、重疾、现金价值、退保价值、利益演示 ``` PPT 关键词: ```text 计划书、产品名称、投保摘要、保障摘要、利益演示、现金价值、保证现金价值、非保证、红利、退保价值、身故赔偿、年度保费、缴费期、保障期、内部回报率 ``` 英文关键词: ```text Insured, Policyholder, Age, Gender, Premium, Annual Premium, Sum Assured, Payment Term, Benefit Term, Cash Value, Surrender Value, Death Benefit, Policy Year, Guaranteed, Non-guaranteed, Illustration ``` ### 6.3 页面字段覆盖分析 每页不仅要打分,还要记录它可能覆盖哪些字段: ```json { "page": 5, "score": 18, "candidate_fields": [ "annual_premium", "premium_term", "sum_assured" ] } ``` ### 6.4 页面选择规则 不是固定选前 5 页,而是按字段覆盖选择: ```text 1. 必选首页、摘要页、利益演示页 2. 按得分从高到低加入候选页 3. 加到字段覆盖率达到目标值 4. 或达到最大字符数限制 ``` 建议限制: ```text 海报:最多 6000 字 PPT 快速解析:最多 10000 字 PPT 精确解析:最多 20000-30000 字 ``` ## 7. 规则抽取策略 新增规则抽取层,先从关键页文本中抽取确定性字段。 ### 7.1 基础字段规则 可优先抽取: ```text 年龄 性别 币种 年缴保费 缴费期 保障期 基本保额 产品名称 保司名称 ``` 示例规则方向: ```text 年龄:年龄 35 / Age: 35 / Insured Age 35 性别:男 / 女 / M / F / Male / Female 币种:USD / HKD / CNY / 美元 / 港元 / 人民币 年缴保费:年缴保费 / 年度保费 / Annual Premium 缴费期:缴费期 5年 / Payment Term 5 Years 保障期:终身 / 至100岁 / Whole Life / To Age 100 基本保额:基本保额 / 保额 / Sum Assured / Basic Sum Assured ``` ### 7.2 表格字段规则 利益演示表是 PPT 里最重要、也最容易出错的部分。建议单独解析,不要完全交给模型。 重点识别列: ```text 保单年度 年龄 年度保费 累计保费 保证现金价值 非保证红利 终期红利 总退保价值 身故赔偿 ``` 英文列: ```text Policy Year Age Annual Premium Total Premium Paid Guaranteed Cash Value Non-guaranteed Bonus Terminal Dividend Total Surrender Value Death Benefit ``` ## 8. LLM 补全策略 LLM 不应该收到整本 PDF,而应该收到: ```json { "mode": "poster", "rule_data": { "age": 35, "currency": "USD", "annual_premium": 100000 }, "missing_fields": [ "gender", "sum_assured", "coverage_period", "key_benefits" ], "pdf_text": "关键页文本..." } ``` Prompt 要求: ```text 请基于 PDF 关键页文本补全缺失字段。 已有 rule_data 中的字段优先保留,不要随意覆盖。 如果无法确认,字段返回 null。 金额字段必须来自原文,不得估算。 输出 JSON,不要输出 markdown。 ``` ## 9. 校验与补页闭环 ### 9.1 第一次解析后校验 解析后立即运行 validator,检查必填字段: ```text 字段是否存在 金额是否为正数 币种是否合理 利益演示表是否为空 年度表是否连续 总退保价值是否小于保证现金价值 ``` ### 9.2 缺失字段定向补页 如果缺字段,不直接失败,而是按缺失字段补页。 示例: 缺 `benefit_illustration` 时,补页关键词: ```text 利益演示、现金价值、退保价值、保证现金价值、非保证、保单年度、Policy Year ``` 缺 `sum_assured` 时,补页关键词: ```text 保额、基本保额、保障金额、Sum Assured、Basic Sum Assured ``` 缺 `annual_premium` 时,补页关键词: ```text 保费、年缴、年度保费、Annual Premium、Premium ``` ### 9.3 补页后再次解析 第二轮只把新增页面和缺失字段交给模型: ```json { "missing_fields": ["sum_assured", "benefit_illustration"], "additional_pages": [ { "page": 8, "text": "..." } ], "current_data": { "product_name": "xxx", "age": 35 } } ``` ## 10. 结果状态设计 解析结果分为四类: ```text success 字段齐全,关键字段有来源页 partial 基本可用,但存在低置信度字段 needs_review 缺关键字段,需要人工确认或精确解析 error 解析失败 ``` 建议每个结果保存解析元信息: ```json { "parse_meta": { "mode": "fast", "selected_pages": [1, 2, 5, 8], "page_count": 36, "text_chars": 5820, "rule_fields": ["age", "annual_premium", "currency"], "llm_fields": ["coverage_period", "key_benefits"], "missing_fields": [], "duration_ms": 12600 } } ``` ## 11. 后端改造范围 ### 11.1 新增 PDF 预处理模块 新增: ```text api/insurance/ppt/pdf_preprocessor.py ``` 职责: ```text 按页抽取文本 页面关键词打分 字段覆盖率分析 构建关键页文本 必要时兜底全文抽取 ``` 核心函数: ```python def extract_pages(pdf_path: str) -> list[dict]: pass def rank_key_pages(pages: list[dict], mode: str) -> list[dict]: pass def build_compact_text(key_pages: list[dict], max_chars: int) -> str: pass def extract_compact_pdf_text(pdf_path: str, mode: str) -> dict: pass ``` ### 11.2 新增规则抽取模块 新增: ```text api/insurance/ppt/rule_extractor.py ``` 职责: ```text 正则抽基础字段 解析利益演示表 生成字段来源和置信度 ``` 核心函数: ```python def extract_basic_fields(text: str) -> dict: pass def extract_benefit_rows(text: str) -> list[dict]: pass def merge_rule_and_llm_data(rule_data: dict, llm_data: dict) -> dict: pass ``` ### 11.3 改造 PPT 抽取服务 修改: ```text api/insurance/ppt/extraction.py ``` 调整点: ```text extract_for_poster 使用关键页文本 extract_plan 使用关键页文本 保留 _extract_pdf_text 作为兜底 LLM prompt 改为“补全缺失字段” 返回 parse_meta ``` ### 11.4 改造 PPT 后台任务 修改: ```text api/insurance/ppt/parse_worker.py ``` 调整点: ```text 取消 force_reparse=True 支持 fast / accurate 两种解析模式 多 PDF 有限并发,建议并发数 2 进度信息显示当前解析阶段 ``` ### 11.5 改造海报后台任务 修改: ```text api/insurance/poster/tasks.py ``` 调整点: ```text 海报解析默认 fast 模式 开启缓存作为辅助 保存解析元信息 解析结果允许 partial,但前端要求用户确认 ``` ## 12. 前端改造范围 ### 12.1 PPT 解析页面 修改: ```text frontend/src/pages/components/ppt/PptParsing.vue ``` 新增体验: ```text 显示解析模式:快速解析 / 精确解析 显示解析进度:扫描 PDF、筛选关键页、规则抽取、AI 补全、校验 如果 partial,显示“精确解析”按钮 展示字段来源页 ``` ### 12.2 PPT 数据确认页 修改: ```text frontend/src/pages/components/ppt/PptDataReview.vue ``` 新增: ```text 字段置信度展示 来源页展示 缺失字段高亮 用户可手动修正 ``` ### 12.3 海报上传页 修改: ```text frontend/src/components/poster/PosterStepUpload.vue ``` 新增: ```text 上传后快速解析 解析完成后进入字段确认 字段不完整时允许用户手动补齐 不强制等待精确解析 ``` ## 13. 接口设计建议 ### 13.1 PPT 触发解析 ```http POST /insurance/ppt/parse/{session_id} ``` 请求: ```json { "mode": "fast", "force": false } ``` 精确解析: ```json { "mode": "accurate", "force": true } ``` ### 13.2 解析状态返回 ```json { "sessionId": "xxx", "status": "parsing", "progress": 55, "message": "正在补全缺失字段", "extractions": [ { "pdfName": "plan.pdf", "planType": "savings", "status": "partial", "productName": "xxx", "yearCount": 20, "error": null, "parseMeta": { "mode": "fast", "selectedPages": [1, 2, 5, 8], "pageCount": 36, "textChars": 5820, "missingFields": ["sum_assured"] } } ] } ``` ## 14. 实施顺序 第一阶段:低风险提速 ```text 1. 取消 PPT 强制重解析 2. 海报解析开启缓存 3. 增加耗时日志 4. 增加 parse_meta ``` 第二阶段:关键页筛选 ```text 1. 新增 pdf_preprocessor.py 2. 按页抽文本 3. 页面关键词打分 4. 海报使用关键页文本 5. PPT 使用关键页文本 ``` 第三阶段:规则抽取 ```text 1. 新增 rule_extractor.py 2. 抽取基础字段 3. 抽取利益演示表 4. LLM 只补缺失字段 ``` 第四阶段:精准闭环 ```text 1. validator 检查字段完整性 2. 缺字段定向补页 3. 二次补全 4. 前端展示来源页和置信度 ``` 第五阶段:体验优化 ```text 1. 增加快速解析 / 精确解析切换 2. 增加字段确认页面 3. 支持用户手动修正后生成 4. 记录人工确认后的金标数据 ``` ## 15. 验收标准 ### 15.1 性能标准 ```text 海报快速解析:常规 PDF 15 秒内返回 PPT 快速解析:常规 PDF 60 秒内返回 同一会话重复解析:优先命中缓存 多文件解析:支持最多 2 个并发 ``` ### 15.2 准确性标准 ```text 关键金额字段必须有来源页 利益演示表不能由模型凭空生成 缺少必填字段时不能标记 success partial 状态必须允许用户确认或精确解析 ``` ### 15.3 用户体验标准 ```text 用户能看到解析进度 用户能看到哪些字段缺失 用户能看到关键字段来源页 用户能手动修正解析结果 用户能选择精确解析 ``` ## 16. 最终结论 PDF 每次都不同的情况下,不能主要依赖同文件缓存。最佳方案是建立实时解析闭环: ```text 关键页筛选 + 规则/表格优先抽取 + LLM 补漏 + 字段校验 + 缺失字段定向补页 + 来源页证据 + 人工确认 ``` 这套方案既能减少等待时间,又能保证关键数据不会因为”只抽部分页面”而漏掉。快速解析负责效率,校验和补页负责准确性,精确解析和人工确认负责兜底。 ## 17. 实施状态 > 更新于 2026-07-27 ### 已完成 ✅ | 模块 | 文件 | 说明 | |------|------|------| | 正则提取引擎 | `api/insurance/ppt/regex_extractor.py` | 纯正则提取产品信息 + 利益演示表 + 提领表,零 LLM 调用 | | 产品类型识别 | `regex_extractor._detect_product_type()` | savings / ci / iul 自动识别 | | 轻量分析 Prompt | `api/insurance/ppt/prompts.py` → `ANALYSIS_SYSTEM_PROMPT` | 正则提取后仅做关键发现分析(~300字输出) | | 关键页筛选 | `prompts.select_key_pages()` | 从全文中选取最相关的 4-5 页(~8000字符) | | Orchestrator 重构 | `api/insurance/ppt/extraction.py` | 正则优先 → 行数≥3用正则+分析 → 不足则回退 LLM | | LLM 回退 Prompt 精简 | `prompts.py` | SAVINGS/CI/IUL prompt 移除销售分析职责,仅保留数据提取 | | 任务重命名 | `parse_worker.py` + `PptParsing.vue` | “解析” → “处理/结构化” | | 缓存版本升级 | `extraction.py` | `CACHE_VERSION` 3 → 4 | | 繁体中文列名 | `regex_extractor._COLUMN_ALIASES` | AIA/CTF/FWD 风格表头全覆盖 | | 单元测试 | `tests/test_regex_extractor.py` | 58 个测试全部通过 | | 前端字段匹配 | `frontend/src/utils/ppt-parser.ts` | 模糊匹配、行标准化、回本计算、数据校验 | | 死代码清理 | `extraction.py` | 移除未使用的 `import field` | ### 未完成 | 优先级 | 任务 | 说明 | |--------|------|------| | 中 | 真实 PDF 集成测试 | 用真实计划书批量验证提取率 > 80% | | 低 | 提取率报告脚本 | 批量测试工具 |