baodan/docs/PDF实时解析提速与精准抽取方案.md

773 lines
16 KiB
Markdown
Raw Normal View History

2026-07-28 16:45:14 +08:00
# 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% |
| 低 | 提取率报告脚本 | 批量测试工具 |