Files
th-hotel-simple/docs/project/requirements/M011-booking-excel-pre-superagent-enrichment-v1.md

419 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# M011 Booking Excel 高亮行预处理与 SuperAgent 调用前增强 V1
| 项目 | 内容 |
| --- | --- |
| 文档状态 | 当前有效CP1 / CP2 / CP3 已实现,生产链路默认关闭 |
| 适用范围 | AgentBus 入站邮件和 Debug EML 上传邮件中的 Excel 附件,在调用 SuperAgent Open API 前做结构化预处理 |
| 当前目标 | 排除旅行名单类 Excel抽取 Booking / 附加费类 Excel 中带背景色的业务行,生成安全 JSON 并附加到发给 SuperAgent 的 payload |
| 依赖能力 | SourceMessage Inbox、Debug EML、AgentBus 自动分发、Apache POI、OSS 附件读取能力、SuperAgent Open API |
## 1. 背景
当前 AgentBus 和 Debug EML 链路都会把邮件正文、HTML、附件摘要组装成 AgentBus Outlook-like payload 后交给 SuperAgent。实际业务邮件中存在多种 Excel 附件:
- 第一种是旅行团人员名单,例如包含 `护照全名`、证件号、生日、性别等字段。这类文件主要服务 Rooming List 或旅客名单整理,不应进入 Booking 更新 / 附加费抽取逻辑。
- 第二种是春节、节假日或其他附加费用表,业务上关心其中带背景色标记的行。
- 第三种是 Wyndham / Booking Update 类多 sheet 表格,业务上同样关心最近几个月 sheet 中带背景色标记的行。
如果把整份 Excel 只作为附件 URL 交给 SuperAgent模型需要自行下载、打开、理解多 sheet 和样式,稳定性和耗时都不可控。因此本需求建议在后端调用 SuperAgent 前增加一个轻量预处理层:只提取与业务判断相关的安全结构化 JSON把它作为邮件 payload 的补充证据。
## 2. 目标
- 在 AgentBus 自动分发和 Debug EML 上传两条链路中复用同一套 Excel 附件预处理逻辑;当前两条链路均已接入,生产链路仍由配置默认关闭。
- 识别并排除旅行名单类 Excel避免把人员名单误当成 Booking 更新或附加费数据。
- 对 Booking Update / Booking Surcharge 类 Excel按最近月份筛选 sheet只抽取有业务背景色的行。
- 把抽取结果追加到发给 SuperAgent 的 AgentBus Outlook-like payload 中,字段建议为 `attachment_extractions[]`
- Debug EML 页面可以展示后端返回的安全抽取预览,用于验证解析是否符合预期。
- 不改变现有 SourceMessage Inbox 的来源事实定位不直接创建订单、任务、OPERA / OHIP 操作或客户回复。
## 3. 非目标
- 不把 Excel 高亮行直接落成订单、任务或业务状态。
- 不绕过 SuperAgent 后续 `task-results` / MCP 入站和本系统校验、人工确认流程。
- 不让前端直接调用 SuperAgent、AgentBus、OSS 或 Excel 解析服务。
- 不依赖文件名作为唯一判断依据;文件名只作为辅助信号。
- 不在普通日志、错误响应、埋点或普通业务接口中输出完整 Excel 内容、完整附件 URL、OSS 签名参数、客户敏感信息、API Key、Cookie 或 Secret。
- V1 只处理单元格背景色,不把字体颜色、批注、筛选状态或条件格式结果作为稳定业务输入;如后续需要,另开 checkpoint。
## 4. 文件类型识别规则
后端应对每个 `.xls` / `.xlsx` 附件做 sheet 级和 workbook 级识别。推荐输出稳定类型:
| 类型 | 中文说明 | V1 动作 |
| --- | --- | --- |
| `PASSENGER_ROSTER` | 旅行团人员名单 / Rooming List 来源名单 | 排除,不向 SuperAgent 提供行级抽取数据,只记录安全 warning 或 `excluded=true` |
| `BOOKING_SURCHARGE` | 春节、节假日或其他 Booking 附加费用表 | 按月份和背景色抽取行 |
| `BOOKING_UPDATE` | Booking Update / Wyndham 更新类表格 | 按月份和背景色抽取行 |
| `UNKNOWN` | 未识别 Excel | 不抽取,记录安全 warning |
### 4.1 第一种表格排除规则
推荐规则:
1. 扫描每个 sheet 前 20 行,做表头归一化,忽略大小写、前后空格、换行和中英文括号差异。
2. 如果命中以下人员名单字段中的 4 个或以上,可判定该 sheet 为 `PASSENGER_ROSTER`
```text
旅游批次
旅游日期
成团航班信息
团号
团长
姓名
护照全名
证件号
护照号
证件有效期结束
性别
生日
年龄
饮食禁忌
重大疾病
```
3. 如果同一个 sheet 同时存在明确 Booking 核心字段组合应优先标记为待确认而不是直接排除。Booking 核心字段包括:
```text
酒店 / Hotel / โรงแรม
酒店回应状况 / Hotel Status / สถานะ
备注 / Remark / หมายเหตุ
入住 / Check In / วันเช็คอิน
退房 / Check Out / วันเช็คเอาท์
房型 / Room Type
房数 / Rooms
团号 / Group Code
```
4. 如果 workbook 中全部有效 sheet 都是 `PASSENGER_ROSTER`,则整份附件排除。
5. 如果 workbook 中部分 sheet 是人员名单、部分 sheet 是 Booking 表,应只排除人员名单 sheet继续处理其他 sheet。
中文说明:第一种表格的排除重点是“字段组合”,不是文件名。后续即使文件名变化,只要字段结构是旅行名单,仍应排除。
### 4.2 第二、第三种表格识别规则
`BOOKING_SURCHARGE` 推荐同时参考:
- 表头或正文出现 `附加费``春节``新年``Surcharge``Gala Dinner``Compulsory` 等关键词。
- 存在酒店、入住 / 退房、房型、房数、费用、备注等 Booking 或费用相关字段。
- 文件名可作为辅助信号,但不能单独决定类型。
`BOOKING_UPDATE` 推荐同时参考:
- sheet 名或文件名出现 `BOOKING``UPDATE BOOKING``WYNDHAM`、月份标识等关键词。
- 存在团号、酒店、入住 / 退房、房型、房数、酒店回应状态、备注等 Booking 更新相关字段。
- 多 sheet 且 sheet 名形如 `BOOKING 01-2026``BOOKING 02-2026` 时,优先按 sheet 月份筛选。
识别置信度不足时应输出 `UNKNOWN`,不做激进抽取。
## 5. 最近月份筛选规则
第二、第三种表格通常包含多个月份 sheet但当前真实样例常见滞后到 4 月、5 月。V1 默认不应死取“当前月 + 前 2 个月”,而应使用“最近 6 个月候选窗口 + 文件内最新 3 个月”的两段式规则。
### 5.1 显式月份窗口
Debug 或后续管理配置可以显式指定月份窗口:
```text
from_month=YYYY-MM
to_month=YYYY-MM
```
规则:
- 优先从 sheet 名解析月份,例如 `BOOKING 01-2026` 解析为 `2026-01`
- sheet 名存在多个日期时,优先识别 `MM-YYYY``YYYY-MM``MMM YYYY` 这类月份粒度。
- 如果 sheet 名无法解析月份可扫描业务日期列例如入住、退房、Booking Date并以行级日期判断是否落入窗口。
- 返回结果中必须记录 `matched_sheets[]``skipped_sheets[]`,便于 Debug 页面核对“为什么某个 sheet 没被抽”。
### 5.2 默认月份选择
没有显式传入 `from_month` / `to_month` 时,默认按以下规则:
1. 取基准月份 `base_month`
2. AgentBus 链路的 `base_month` 优先来自 SourceMessage 的 `payload_received_at` 或 AgentBus 邮件 `received_at`,并按酒店本地时区转换为业务月份。
3. Debug EML 链路的 `base_month` 按本系统 Debug 上传运行创建时间计算,不再尝试按 EML 原始收件时间计算。
4. 如果来源接收时间缺失,再使用系统当前时间。
5.`base_month` 为终点,向前取 `lookback_months=6` 个自然月作为候选窗口,包含基准月。
6. 从文件实际存在且落在候选窗口内的月份中,按月份倒序选择最新 `max_selected_months=3` 个。
7. 如果候选窗口内实际存在月份少于 3 个,有几个处理几个,并返回 `MATCHED_MONTHS_LESS_THAN_LIMIT` warning。
8. 如果候选窗口内没有任何月份,返回 `NO_MATCHED_MONTH_SHEET` warning不回退到 6 个月之前的旧 sheet。
示例:
```text
邮件接收时间2026-07-19
base_month2026-07
lookback_months6
候选窗口2026-02 ~ 2026-07
文件实际月份2026-03、2026-04
最终处理月份2026-03、2026-04
```
如果文件实际月份为:
```text
2026-03、2026-04、2026-05、2026-06
```
最终处理:
```text
2026-04、2026-05、2026-06
```
中文说明:这里的“最近几个月”不要由 SuperAgent 猜应由后端配置或调试页面参数确定。生产链路建议先用默认两段式规则Debug 链路后续可允许调试人员手动覆盖。
## 6. 高亮行抽取规则
V1 只抽取单元格背景色,不抽取字体颜色。
推荐 Apache POI 判断口径:
- 只把 `FillPatternType.SOLID_FOREGROUND` 且前景色不是默认、自动、白色或主题默认色的单元格视为背景色标记。
- 忽略空白列、样式污染列和 Excel `max_col` 虚高带来的尾部空列。
- 先识别表头行和有效业务列,再只扫描业务列范围。
- 表头自身背景色不代表业务高亮,应从数据行开始判断。
- 一行只要任一业务列有有效背景色,就作为高亮业务行返回。
- 返回整行业务字段,同时返回 `highlight_cells[]`,说明哪些列触发了高亮。
建议保留颜色原始值,统一为 ARGB / RGB 字符串:
```json
{
"column": "G",
"header": "Remark",
"value": "Need confirm surcharge",
"fill_color": "FFFFFF00"
}
```
## 7. 输出 JSON 契约
后端发给 SuperAgent 的 AgentBus Outlook-like payload 建议增加:
```json
{
"attachment_extractions": [
{
"attachment_name": "WYNDHAM LIANTAI 2026 UPDATE BOOKING 12-05-2026 NO.1-3.xlsx",
"attachment_sha256": "sha256-hex",
"file_type": "BOOKING_UPDATE",
"parser_version": "booking-highlight-excel-v1",
"excluded": false,
"skipped_reason": null,
"month_filter": {
"mode": "DEFAULT_LOOKBACK_LATEST_AVAILABLE",
"base_month": "2026-07",
"lookback_months": 6,
"max_selected_months": 3,
"candidate_from_month": "2026-02",
"candidate_to_month": "2026-07",
"available_months": ["2026-03", "2026-04", "2026-05", "2026-06"],
"selected_months": ["2026-04", "2026-05", "2026-06"],
"matched_sheets": ["BOOKING 04-2026", "BOOKING 05-2026", "BOOKING 06-2026"],
"skipped_sheets": ["BOOKING 01-2026", "BOOKING 02-2026", "BOOKING 03-2026"]
},
"sheets": [
{
"sheet_name": "BOOKING 05-2026",
"header_row": 3,
"highlighted_row_count": 2,
"highlighted_rows": [
{
"row_number": 84,
"row_key": "optional-stable-row-key",
"highlight_colors": ["FFFFFF00"],
"highlight_cells": [
{
"column": "G",
"header": "Remark",
"value": "Need confirm surcharge",
"fill_color": "FFFFFF00"
}
],
"row": {
"group_code": "optional",
"hotel": "optional",
"check_in": "optional",
"check_out": "optional",
"room_type": "optional",
"rooms": "optional",
"hotel_status": "optional",
"remark": "optional"
},
"raw_row": {
"A": "raw value",
"B": "raw value"
},
"warnings": []
}
]
}
],
"warnings": []
}
]
}
```
字段说明:
| 字段 | 中文说明 |
| --- | --- |
| `attachment_name` | 附件原始文件名,只用于识别,不作为唯一业务判断依据 |
| `attachment_sha256` | 附件内容 hash用于排查和幂等不得替代 SourceMessage ID |
| `file_type` | 后端识别出的 Excel 类型 |
| `parser_version` | 解析器版本,便于后续规则升级 |
| `excluded` | 是否被排除 |
| `skipped_reason` | 排除或跳过原因,例如 `PASSENGER_ROSTER``NO_MATCHED_MONTH_SHEET``UNKNOWN_EXCEL_TYPE` |
| `month_filter` | 本次月份筛选模式、候选窗口、文件内可用月份、最终选中月份和 sheet 命中结果 |
| `highlighted_rows[]` | 高亮业务行 |
| `row` | 后端归一化后的常用业务字段;缺失时可以为空 |
| `raw_row` | 原始列值映射,仅限当前高亮行;不得包含整份表格 |
| `warnings[]` | 可展示安全警告,不包含 Secret、签名 URL 或完整敏感正文 |
中文说明:`raw_row` 是为了给 SuperAgent 和 Debug 页面提供核对依据,但范围必须限制在被高亮的数据行,不能把整张 sheet 原样塞进 payload。
## 8. 接入链路位置
### 8.1 AgentBus 自动分发
```text
AgentBus WebSocket
→ SourceMessage Inbox RECEIVED
→ 创建 platform_superagent_dispatch_run
→ worker 读取 SourceMessage payload 和附件引用
→ Excel 附件预处理
→ 把 attachment_extractions[] 追加到 AgentBus Outlook-like payload
→ 调用 SuperAgent Open API
→ 等待 SuperAgent 后续 task-results / MCP 入站
```
AgentBus 回调线程不应同步解析大 Excel也不应同步等待 SuperAgent。解析动作放在 dispatch worker 中,和外部调用一起由 dispatch run 追踪。
AgentBus payload 中的附件地址已是本系统可访问的 OSS 地址。M011 实现时可由后端通过受控 OSS / 存储适配器读取具体 Excel 附件内容,不需要前端参与,也不应把完整 OSS URL 或签名参数写入普通日志。
### 8.2 Debug EML 上传
```text
Debug EML 上传
→ 解析邮件并上传原始邮件 / 内联图片 / 附件
→ 写入 SourceMessage Inbox
→ Excel 附件预处理
→ 把 attachment_extractions[] 追加到 agentbus_like_payload
→ 调用 SuperAgent Open API
→ Debug 页面展示本系统阶段、SuperAgent trace、最终回答和安全抽取预览
```
Debug EML 可以把 `attachment_extractions[]` 作为只读调试信息返回给页面。前端不得编辑后再提交,也不得把其中的 OSS URL、客户敏感信息写入日志或埋点。Debug 链路的 Excel 内容来自本次上传 `.eml` 解析出的附件字节或上传到本系统 OSS 后的对象,不依赖外部邮箱附件临时地址。
## 9. 后端模块边界建议
建议把解析能力放在 Reservation 业务流程内,因为当前识别规则和字段归一化明显属于预订业务语义:
```text
server/src/main/java/cn/nianxx/thhotel/workflows/reservation/excelimport
├── service
│ └── impl
└── common
├── dto
├── request
├── result
└── enums
```
建议核心服务命名:
| 服务 / 类型 | 中文职责 |
| --- | --- |
| `ReservationBookingExcelAttachmentExtractionService` | 对邮件 Excel 附件做类型识别、sheet 筛选和高亮行抽取 |
| `BookingExcelAttachmentExtractionRequest` | 输入附件文件名、内容流、hash、显式月份窗口或默认月份选择参数、来源上下文 |
| `BookingExcelAttachmentExtractionResult` | 输出 `attachment_extractions[]` 中单个附件的结构 |
| `BookingExcelFileType` | `PASSENGER_ROSTER``BOOKING_SURCHARGE``BOOKING_UPDATE``UNKNOWN` |
依赖方向:
- `workflows.reservation` 可以依赖 Apache POI 做业务解析。
- Debug EML 和 AgentBus dispatch 在组装 SuperAgent payload 时调用稳定 Service / Port不能复制两套解析逻辑。
- `platform.message` 仍只负责 SourceMessage 来源事实,不反向依赖 Reservation Excel 业务字段。
- `integrations.ai.superagent` 只负责调用 SuperAgent如果需要拼装业务增强 payload应通过内部编排服务或明确的 payload enricher 调用,不把 POI 解析细节放进 Open API client。
## 10. 配置建议
| 配置 | 默认值 | 中文说明 |
| --- | --- | --- |
| `reservation.booking-excel-extraction.enabled` | `false` | 是否启用 Booking Excel 附件预处理总开关 |
| `reservation.booking-excel-extraction.lookback-months` | `6` | 未显式指定月份窗口时,先从基准月向前取最近几个自然月作为候选窗口,包含基准月 |
| `reservation.booking-excel-extraction.max-selected-months` | `3` | 在候选窗口内,从文件实际存在月份里最多选择最新几个业务月 |
| `reservation.booking-excel-extraction.max-file-size` | `10MB` | 单个 Excel 附件最大解析大小 |
| `reservation.booking-excel-extraction.max-sheets` | `24` | 单个 workbook 最大扫描 sheet 数 |
| `reservation.booking-excel-extraction.max-rows-per-sheet` | `2000` | 单个 sheet 最大扫描行数 |
| `agentbus.superagent-dispatch.include-booking-excel-extractions` | `false` | AgentBus 自动分发是否把抽取结果追加给 SuperAgent |
| `agentbus.superagent-dispatch.booking-excel-download-max-size` | `10MB` | AgentBus 自动分发读取单个 Excel 附件的最大大小,避免 worker 下载异常大文件 |
| `debug.eml-upload.include-booking-excel-extractions` | `false` | Debug EML 是否返回并传递抽取结果 |
中文说明:建议先在 Debug EML 打开,验证样例 Excel 和 SuperAgent 结果稳定后,再在测试机打开 AgentBus 自动分发增强;生产仍保持默认关闭。
## 11. 错误处理和安全边界
- Excel 解析失败不得导致 SourceMessage Inbox 入库失败。
- V1 解析失败或附件读取失败时记录安全 warning / 跳过结果,并继续调用 SuperAgent除非后续配置显式要求严格失败。
- AgentBus 附件地址按本系统可访问 OSS 地址处理;后端通过受控对象存储端口读取 Excel 内容,不依赖前端传来的临时 URL。
- 安全错误摘要只记录附件名、hash 前缀、sheet 名、行号、错误类型,不记录完整单元格敏感内容、完整附件 URL 或签名参数。
- Debug 页面展示的抽取 JSON 只面向受控 dev/test 调试入口,不进入普通业务页面。
- SuperAgent 看到的 `attachment_extractions[]` 只是证据输入;最终业务写入仍必须经过本系统入站契约校验、幂等、权限边界和人工确认。
## 12. 测试范围
后续实现时至少补充以下测试:
- 人员名单类 Excel 命中 `PASSENGER_ROSTER` 并被排除。
- Booking Surcharge 类 Excel 被识别为 `BOOKING_SURCHARGE`
- Booking Update 多 sheet Excel 被识别为 `BOOKING_UPDATE`
- sheet 名月份 `BOOKING 01-2026` 能解析为 `2026-01`
- 默认模式以来源接收时间的酒店本地月份为 `base_month`,生成最近 6 个月候选窗口。
- 候选窗口内文件实际存在月份超过 3 个时,只选择最新 3 个。
- 候选窗口内文件实际存在月份不足 3 个时,有几个处理几个,并返回 `MATCHED_MONTHS_LESS_THAN_LIMIT` warning。
- 候选窗口内没有实际存在月份时,不回退到更早 sheet并返回 `NO_MATCHED_MONTH_SHEET` warning。
- 未选中 sheet 写入 `skipped_sheets[]`
- sheet 名缺少月份时,能按入住 / 退房等业务日期列做行级兜底。
- 背景色判断忽略无填充、默认、自动、白色、表头背景色和样式污染空列。
- 有任一业务列背景色的数据行会输出到 `highlighted_rows[]`
- 输出 JSON 包含 `highlight_cells[]``highlight_colors[]``row_number` 和归一化 `row`
- 解析失败不影响 SourceMessage 入库;是否继续调用 SuperAgent 按配置执行。
- Debug EML 和 AgentBus dispatch 两条链路复用同一解析服务。
- 日志、错误响应和调试响应不泄漏 API Key、Cookie、Secret 或完整 OSS 签名 URL。
## 13. 分阶段落地建议
### CP1解析器和样例测试已实现
- 实现 Excel 类型识别、月份筛选和高亮行抽取。
- 使用当前三类样例文件补单元测试或 fixture 测试。
- 不接入 SuperAgent不改 Debug 页面。
### CP2Debug EML 预览和 payload 增强(已实现)
- Debug EML 上传后执行预处理。
- Debug 响应和 SSE 事件返回安全 `attachment_extractions[]` 预览。
- 调用 SuperAgent 时在 `agentbus_like_payload` 中包含该字段。
- 前端仍只调用本项目后端。
### CP3AgentBus 自动分发增强(已实现)
- AgentBus dispatch worker 在调用 SuperAgent 前读取 SourceMessage 已保存附件引用,并通过后端对象存储端口下载 Excel 内容。
- 复用 `ReservationBookingExcelAttachmentExtractionService` 执行同一预处理,非空结果追加到发给 SuperAgent 的 AgentBus Outlook-like payload。
- 生产链路默认配置关闭,测试机可通过 `agentbus.superagent-dispatch.include-booking-excel-extractions=true` 验证后再评估开启。
- 附件读取或解析失败时追加安全跳过结果 / warning 并继续调用 SuperAgent日志和 payload 不写完整附件 URL、签名参数、API Key、Cookie 或 Secret。
### CP4可选持久化和运营查询
如果后续需要追踪 Excel 解析历史,再单独设计持久化表,例如:
```text
workflow_reservation_booking_excel_import_batch
workflow_reservation_booking_excel_import_row
```
V1 不要求落库,避免在规则未稳定前引入长期数据模型。