21 KiB
M011 Booking Excel 高亮行预处理与 SuperAgent 调用前增强 V1
| 项目 | 内容 |
|---|---|
| 文档状态 | 当前有效;CP1 / CP2 / CP3 已实现,测试机 AgentBus 增强已开启,生产链路默认关闭;CP4 暂不推进 |
| 适用范围 | 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 附件预处理逻辑;当前两条链路均已接入,测试机 AgentBus 增强已开启,生产链路仍由配置默认关闭。
- 识别并排除旅行名单类 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 第一种表格排除规则
推荐规则:
- 扫描每个 sheet 前 20 行,做表头归一化,忽略大小写、前后空格、换行和中英文括号差异。
- 如果命中以下人员名单字段中的 4 个或以上,可判定该 sheet 为
PASSENGER_ROSTER:
旅游批次
旅游日期
成团航班信息
团号
团长
姓名
护照全名
证件号
护照号
证件有效期结束
性别
生日
年龄
饮食禁忌
重大疾病
- 如果同一个 sheet 同时存在明确 Booking 核心字段组合,应优先标记为待确认而不是直接排除。Booking 核心字段包括:
酒店 / Hotel / โรงแรม
酒店回应状况 / Hotel Status / สถานะ
备注 / Remark / หมายเหตุ
入住 / Check In / วันเช็คอิน
退房 / Check Out / วันเช็คเอาท์
房型 / Room Type
房数 / Rooms
团号 / Group Code
- 如果 workbook 中全部有效 sheet 都是
PASSENGER_ROSTER,则整份附件排除。 - 如果 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 或后续管理配置可以显式指定月份窗口:
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 时,默认按以下规则:
- 取基准月份
base_month。 - AgentBus 链路的
base_month优先来自 SourceMessage 的payload_received_at或 AgentBus 邮件received_at,并按酒店本地时区转换为业务月份。 - Debug EML 链路的
base_month按本系统 Debug 上传运行创建时间计算,不再尝试按 EML 原始收件时间计算。 - 如果来源接收时间缺失,再使用系统当前时间。
- 以
base_month为终点,向前取lookback_months=6个自然月作为候选窗口,包含基准月。 - 从文件实际存在且落在候选窗口内的月份中,按月份倒序选择最新
max_selected_months=3个。 - 如果候选窗口内实际存在月份少于 3 个,有几个处理几个,并返回
MATCHED_MONTHS_LESS_THAN_LIMITwarning。 - 如果候选窗口内没有任何月份,返回
NO_MATCHED_MONTH_SHEETwarning,不回退到 6 个月之前的旧 sheet。
示例:
邮件接收时间:2026-07-19
base_month:2026-07
lookback_months:6
候选窗口:2026-02 ~ 2026-07
文件实际月份:2026-03、2026-04
最终处理月份:2026-03、2026-04
如果文件实际月份为:
2026-03、2026-04、2026-05、2026-06
最终处理:
2026-04、2026-05、2026-06
中文说明:这里的“最近几个月”不要由 SuperAgent 猜,应由后端配置或调试页面参数确定。生产链路建议先用默认两段式规则,Debug 链路后续可允许调试人员手动覆盖。
6. 高亮行抽取规则
V1 只抽取单元格背景色,不抽取字体颜色。
推荐 Apache POI 判断口径:
- 只把
FillPatternType.SOLID_FOREGROUND且前景色不是默认、自动、白色或主题默认色的单元格视为背景色标记。 - 忽略空白列、样式污染列和 Excel
max_col虚高带来的尾部空列。 - 先识别表头行和有效业务列,再只扫描业务列范围。
- 表头自身背景色不代表业务高亮,应从数据行开始判断。
- 一行只要任一业务列有有效背景色,就作为高亮业务行返回。
- 返回整行业务字段,同时返回
highlight_cells[],说明哪些列触发了高亮。
建议保留颜色原始值,统一为 ARGB / RGB 字符串:
{
"column": "G",
"header": "Remark",
"value": "Need confirm surcharge",
"fill_color": "FFFFFF00"
}
7. 输出 JSON 契约
后端发给 SuperAgent 的 AgentBus Outlook-like payload 建议增加:
{
"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 自动分发
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 上传
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 业务流程内,因为当前识别规则和字段归一化明显属于预订业务语义:
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 和测试机 AgentBus 自动分发增强已可用于验证样例 Excel 与 SuperAgent 结果稳定性;生产仍保持默认关闭,生产开启需要单独确认。
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_LIMITwarning。 - 候选窗口内没有实际存在月份时,不回退到更早 sheet,并返回
NO_MATCHED_MONTH_SHEETwarning。 - 未选中 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 页面。
CP2:Debug EML 预览和 payload 增强(已实现)
- Debug EML 上传后执行预处理。
- Debug 响应和 SSE 事件返回安全
attachment_extractions[]预览。 - 调用 SuperAgent 时在
agentbus_like_payload中包含该字段。 - 前端仍只调用本项目后端。
CP3:AgentBus 自动分发增强(已实现)
- AgentBus dispatch worker 在调用 SuperAgent 前读取 SourceMessage 已保存附件引用,并通过后端对象存储端口下载 Excel 内容。
- 复用
ReservationBookingExcelAttachmentExtractionService执行同一预处理,非空结果追加到发给 SuperAgent 的 AgentBus Outlook-like payload。 - 测试机 AgentBus 增强已开启;生产链路默认配置关闭,生产开启需单独确认。
- 附件读取或解析失败时追加安全跳过结果 / warning 并继续调用 SuperAgent;日志和 payload 不写完整附件 URL、签名参数、API Key、Cookie 或 Secret。
CP4:可选持久化和运营查询(暂不推进)
当前 CP4 不进入近期开发计划。如果后续需要追踪 Excel 解析历史,再单独设计持久化表,例如:
workflow_reservation_booking_excel_import_batch
workflow_reservation_booking_excel_import_row
V1 不要求落库,避免在规则未稳定前引入长期数据模型。