实现 Booking Excel 预处理接入 SuperAgent

This commit is contained in:
andy
2026-07-20 00:32:01 +07:00
parent b7b04cf1ac
commit d1955f5097
45 changed files with 2955 additions and 10 deletions

View File

@@ -61,6 +61,7 @@
| `requirements/M008-excel-to-pdf-conversion-v1.md` | 当前有效 | M008 Excel 转 PDF 文件转换能力方案,记录 LibreOffice headless、手动上传转换、邮件附件自动派生 PDF 和部署要求CP2 已实现手动上传后端接口。 |
| `requirements/M009-manual-invoice-generation-v1.md` | 当前有效 | M009 Manual Invoice 手工开票生成方案;后端 CP2 已支持无订单 / 无任务手工填写、填充 Excel 模板、转 PDF、OSS 输出和生成记录。 |
| `requirements/M010-rooming-list-excel-generation-v1.md` | 当前有效 | M010 Rooming List Excel 生成方案;后端 CP1 已支持前端上传来源名单和手工字段,同步生成 `.xlsx` 直接下载,不落库、不上传 OSS。 |
| `requirements/M011-booking-excel-pre-superagent-enrichment-v1.md` | 当前有效 | M011 Booking Excel 附件预处理方案CP1/CP2/CP3 已支持 Debug EML 和 AgentBus dispatch 调 SuperAgent 前排除人员名单类 Excel、抽取 Booking / 附加费类 Excel 高亮行并追加 `attachment_extractions[]`;生产 AgentBus 增强默认关闭。 |
## 集成契约

View File

@@ -48,6 +48,7 @@
| 订单任务多卡模型 V4 | `docs/project/requirements/M002-v4-order-task-card-domain-model-cp2.md` | 当前 V4 主入口后端已开放工作台统一列表、V4 订单任务列表 / 详情、卡片确认、复核解阻、S10/S99 来源通知详情和 ack前端已完成 V4 页面第一版、目录 lookup 接入、订单详情 V4 时间线消费和系统设置目录管理 CP1。 |
| Manual Invoice 手工开票生成 | `docs/project/requirements/M009-manual-invoice-generation-v1.md` | 当前有效;后端 CP2 已支持无订单 / 无任务手工填写字段、填 Excel 模板、转 PDF、OSS 输出和生成记录。 |
| Rooming List Excel 生成 | `docs/project/requirements/M010-rooming-list-excel-generation-v1.md` | 当前有效;后端 CP1 已支持前端上传来源名单并填写目标字段,同步生成 `.xlsx` 直接下载;前端 V1 已新增 `/reservation/rooming-lists/new`,按 Blob 下载处理,不落库、不上传 OSS。 |
| Booking Excel 附件预处理 | `docs/project/requirements/M011-booking-excel-pre-superagent-enrichment-v1.md` | 当前有效Debug EML 和 AgentBus dispatch 已支持调 SuperAgent 前排除人员名单类 Excel、抽取 Booking / 附加费类 Excel 高亮行并生成 `attachment_extractions[]`;生产 AgentBus 增强默认关闭。 |
| 订单任务主流程 V2 | `docs/project/requirements/M002-order-task-workflow-v2.md` | 已实现阶段记录,保留用于理解当前代码中的 S000/S999、订单任务流转和 OPERA 模拟骨架。 |
| 后端 checkpoint | `docs/project/requirements/M002-backend-checkpoint-plan.md` | 阶段记录,用于理解后端拆分和验收。 |
| 前端可用接口与待补接口 | `docs/project/frontend-backend/frontend-to-backend-api-requests.md` | 前后端协作清单,已区分可用、后置和历史候选路径,不替代后端权威契约。 |
@@ -64,6 +65,8 @@
- 任务卡字段控件契约 V1 后端第一版已完成,任务详情 `fields[]` 已返回 `control_type/edit_scope/write_target/options_source/raw_readonly/control_hint`;前端后续按契约接入,不要硬编码 PMS 房型、Rate Code 或未冻结枚举。
- Manual Invoice 第一阶段按 M009 推进:后端已提供 `POST /api/reservation/invoices/manual-generations`,前端已新增 `/reservation/invoices/new` 手工开票页面,并已按 `invoice.html` 原型的三段式业务结构对齐;页面可以不依赖订单或任务,用户手工填写 / 选择字段后由后端业务接口填充 Excel 模板并生成 PDF前端不得直接调用 M008 的调试上传转换接口来完成业务开票。侧边栏入口仍以登录后端返回的 menus 为准,建议后续在菜单管理中配置 `RESERVATION_MANUAL_INVOICE` / `/reservation/invoices/new` / `RESERVATION_INVOICE_GENERATE`
- Rooming List Excel 后端 CP1 和前端 V1 已按 M010 落地:接口为 `POST /api/reservation/rooming-lists/generations`,前端页面为 `/reservation/rooming-lists/new`,上传来源名单、填写每房人数和目标列字段,后端同步返回 `.xlsx` 下载;该能力不依赖订单或任务,第一版不落库、不上传 OSS权限码为 `RESERVATION_ROOMING_LIST_GENERATE`
- Booking Excel 附件预处理已按 M011 落地 CP1/CP2/CP3Debug EML 和 AgentBus dispatch 调用 SuperAgent 前由后端解析 Excel 附件,排除人员名单类文件,只把 Booking Update / 附加费表的高亮行业务摘要追加为 `attachment_extractions[]`第一版不新增前端普通业务入口AgentBus 增强生产默认关闭。
- Reservation V4 目录管理后台 CP1 已前后端接入:系统设置下新增 `/system/reservation-catalogs`,需要登录用户具备 `RESERVATION_CATALOG_MANAGE`;前端可维护 Account、Room Type、Rate Code 的列表、新增、启用 / 停用,并明确提示停用目录不再进入普通 V4 任务卡 lookup。
## 6. 前端开发注意事项

View File

@@ -328,6 +328,7 @@ run_label: 可选调试标签
- `external_message_id` 是后端生成的 Debug 独立 ID格式类似 `debug-eml-run-{debugRunId}-{sha256前缀}`;原始邮件 `Message-ID` 不再放入 `agentbus_like_payload`,需要排查时看原始 EML OSS 文件和后端 Debug run / SuperAgent metadata。
- 邮件会话解析支持 `References``In-Reply-To``Thread-Index`,但 Debug EML 的 `external_message_id` 不使用原始 `Message-ID` 做幂等。
- `agentbus_like_payload` 是后端发送给 SuperAgent 的 AgentBus Outlook-like 主输入,前端只做只读展示;该对象会包含普通 `reply_policy.mode=manual``reply_policy.final_only=true`,但不再包含 `schema_version``source.provider=DEBUG_EML_UPLOAD``debug_context` 或旧的 Debug 专属 `reply_policy.mode=debug_only`
- M011 Debug EML 开关启用后,后端会在 `agentbus_like_payload.attachment_extractions[]` 和 Debug 响应中返回 Booking Excel 附件预处理结果AgentBus dispatch 开关启用后,后端会在调用 SuperAgent 前把同结构结果追加到后台分发 payload。前端只做只读调试展示不允许编辑后重新提交也不得把其中的附件 URL、客户敏感字段或解析 JSON 写入普通日志、埋点、localStorage 或 URL query。
- Debug 来源版本仍由后端 SourceMessage payload 表 `schemaVersion=debug-eml-upload-v1` 记录,前端页面不要再依赖 `agentbus_like_payload.schema_version`
- 第一版只返回 SuperAgent 结果,不创建订单、不创建任务、不调用任务结果通知接口。
- `X-TH-Hotel-Debug-Upload-Key` 只能由调试人员在受控环境手动提供,不能放入 `VITE_*`、源码、构建产物、URL query、localStorage、错误上报或普通日志。

View File

@@ -141,6 +141,7 @@ export async function uploadDebugEml(input: {
| `html_sanitize_required` | boolean | 当前为 `true`,提醒前端不要直接信任原始 HTML。 |
| `html_render_mode` | string | 当前可能为 `SANITIZED_HTML``TEXT_ONLY`。 |
| `agentbus_like_payload` | object | 后端发送给 SuperAgent 的 AgentBus Outlook-like 主 payload只读展示。 |
| `attachment_extractions[]` | array | M011 启用时返回的 Booking Excel 附件预处理安全预览,内容与 `agentbus_like_payload.attachment_extractions[]` 对齐;未启用或无匹配附件时为空或不返回。 |
| `superagent_session_id` | string | SuperAgent session ID。 |
| `superagent_run_id` | string | SuperAgent run ID。 |
| `superagent_raw_answer` | string | SuperAgent 最终原始文本回答。 |
@@ -165,6 +166,7 @@ export async function uploadDebugEml(input: {
- 邮件正文 iframe / 富文本预览优先使用 `html_body_sanitized`
- `html_body_with_oss_urls` 可以放在“原始处理 HTML”折叠面板中不作为默认渲染内容。
- `agentbus_like_payload` 不包含 Debug 专属字段,不再包含 `schema_version``source.provider=DEBUG_EML_UPLOAD``source.original_message_id``debug_context` 或旧的 Debug 专属 `reply_policy.mode=debug_only`;当前会包含普通 `reply_policy.mode=manual``reply_policy.final_only=true`
- M011 Debug EML 开关启用后,`agentbus_like_payload` 可能追加 `attachment_extractions[]`,用于让 SuperAgent 在不直接打开整份 Excel 的情况下读取 Booking Update / 附加费表中的高亮业务行。前端只能格式化展示该 JSON不做业务保存、人工确认或二次提交。
- 原始邮件 `Message-ID` 不作为 Debug 外部消息 ID也不进入 SuperAgent 主 payload需要排查时看原始 EML OSS 文件和后端 Debug run / SuperAgent metadata。
- `external_message_id` 是 Debug 链路生成的独立 ID不等同于原始 `Message-ID`
- `superagent_parsed_json` 有值时优先展示格式化 JSON没有值时展示 `superagent_raw_answer`

View File

@@ -477,6 +477,28 @@ AgentBus 新业务 frame
- dispatch 成功不代表已经创建订单或任务。
- 任务创建仍由 SuperAgent 后续调用本系统任务结果通知接口或 MCP 写入工具触发。
M011 CP3 已在 worker 调用 SuperAgent Open API 前增加可配置的 Booking Excel 附件预处理:
```text
SourceMessage payload + 附件引用
→ 识别 Excel 附件类型
→ 排除 PASSENGER_ROSTER 人员名单
→ 按月份窗口抽取 BOOKING_SURCHARGE / BOOKING_UPDATE 高亮行
→ 把 attachment_extractions[] 追加到发给 SuperAgent 的 AgentBus Outlook-like payload
```
中文说明:该预处理只增强 SuperAgent 输入证据,不改变 SourceMessage Inbox 的来源事实定位,也不直接创建订单、任务或客户回复。解析失败第一版建议写入安全 warning 并按配置决定是否继续调用 SuperAgent日志和 dispatch run 不得保存完整附件 URL、签名参数、API Key、Cookie、Secret 或整份 Excel 内容。详细规则见
`docs/project/requirements/M011-booking-excel-pre-superagent-enrichment-v1.md`
开启方式:
```text
AGENTBUS_TEST_SUPERAGENT_DISPATCH_INCLUDE_BOOKING_EXCEL_EXTRACTIONS=true
RESERVATION_BOOKING_EXCEL_EXTRACTION_ENABLED=true
```
中文说明:`agentbus.superagent-dispatch.include-booking-excel-extractions` 只控制 AgentBus worker 是否把抽取结果追加给 SuperAgent`reservation.booking-excel-extraction.enabled` 是解析服务总开关。两者必须同时开启才会产生有效高亮行结果,生产环境默认关闭。
当前表名为 `platform_superagent_dispatch_run`,详细字段、状态流转、错误分类和验收标准见
`docs/project/requirements/M007-agentbus-superagent-auto-dispatch-v1.md`

View File

@@ -107,6 +107,7 @@ Debug 页面上传 .eml
→ debug run 标记为 CAPTURING_SOURCE_MESSAGE
→ 调用 SourceMessageCaptureService 写入 SourceMessage Inbox
→ debug run 标记为 SOURCE_CAPTURED
→ M011 Debug 开关启用时,对 Excel 附件做 Booking 高亮行预处理,并把 attachment_extractions[] 追加到 payload
→ debug run 标记为 CALLING_SUPERAGENT
→ 调用 SuperAgent Open API 创建 session
→ 调用 messages/stream 发送邮件 payload
@@ -120,6 +121,7 @@ Debug 页面上传 .eml
- SourceMessage Inbox 仍然只表达来源事实,不表达 AI 结论、订单归属或任务状态。
- Debug 上传链路不能伪装成 AgentBus必须在 `provider``schema_version` 或 debug run 中留下可追溯来源。
- SuperAgent 返回内容第一版只作为调试展示,不进入 M002 订单任务主流程。
- M011 的 Excel 附件预处理只作为 SuperAgent 输入增强和 Debug 预览,不直接创建订单或任务;详细规则见 `docs/project/requirements/M011-booking-excel-pre-superagent-enrichment-v1.md`
## 6. 后端接口设计
@@ -156,6 +158,7 @@ Header: X-TH-Hotel-Debug-Upload-Key: <DEBUG_EML_UPLOAD_ACCESS_KEY>
| `html_sanitize_required` | 固定提示前端 HTML 需要按安全策略展示 |
| `html_render_mode` | HTML 推荐渲染模式,当前优先返回 `SANITIZED_HTML` |
| `agentbus_like_payload` | 发送给 SuperAgent 的 AgentBus Outlook-like 结构化邮件 payloadDebug 来源版本仍由 SourceMessage payload 表 `schemaVersion=debug-eml-upload-v1` 记录,不放入主 payload |
| `attachment_extractions[]` | M011 Debug 开关启用时返回 Booking Excel 附件预处理安全预览,内容与 `agentbus_like_payload.attachment_extractions[]` 对齐 |
| `superagent_session_id` | SuperAgent Open API session ID失败时为空 |
| `superagent_run_id` | SuperAgent 返回的 run ID失败时为空 |
| `superagent_raw_answer` | SuperAgent 最终文本回答 |

View File

@@ -20,6 +20,7 @@ M001 已完成 AgentBus 邮件来源事实入库M004 已完成 Debug EML 人
AgentBus WebSocket 收到邮件
→ 写入 SourceMessage Inbox
→ 创建 SuperAgent dispatch / outbox 记录
→ M011 CP3 开启时worker 对 Excel 附件做 Booking 高亮行预处理
→ 异步 worker 调用 SuperAgent Open API
→ 保存 session_id / run_id / raw_answer / parsed_json / 状态
→ 等待 SuperAgent 通过现有任务结果通知接口或 MCP 提交业务结果
@@ -35,6 +36,7 @@ AgentBus WebSocket 收到邮件
- Debug EML 链路和生产自动分发链路复用 SuperAgent Open API client但运行记录表和 provider 必须区分。
- SuperAgent 返回内容只能保存为外部能力输出,不直接改变业务最终状态。
- 业务任务创建继续依赖 SuperAgent 后续调用本系统任务结果通知接口或 MCP 工具。
- M011 已在 Debug EML 和 AgentBus dispatch 链路验证 `attachment_extractions[]` 结构AgentBus worker 调用 SuperAgent 前追加该字段由独立配置控制,生产链路默认关闭。
## 3. 触发规则
@@ -124,6 +126,8 @@ KEY idx_dispatch_external_message (hotel_id, external_message_id)
| `agentbus.superagent-dispatch.lock-ttl` | `5m` | worker 处理锁有效期 |
| `agentbus.superagent-dispatch.initial-backoff` | `30s` | 首次失败后的重试等待时间 |
| `agentbus.superagent-dispatch.max-backoff` | `15m` | 最大重试等待时间 |
| `agentbus.superagent-dispatch.include-booking-excel-extractions` | `false` | M011 CP3是否在调用 SuperAgent 前追加 Booking Excel 高亮行预处理结果 |
| `agentbus.superagent-dispatch.booking-excel-download-max-size` | `10MB` | M011 CP3worker 读取单个 Excel 附件的最大大小 |
| `superagent.open-api.agentbus-external-subject-id` | `th-hotel-agentbus-source-message` | AgentBus 自动分发创建 session 时使用的 external subject id |
| `superagent.open-api.sse-recovery-max-attempts` | `5` | SSE 断流恢复最大次数 |
@@ -133,6 +137,8 @@ KEY idx_dispatch_external_message (hotel_id, external_message_id)
AgentBus 自动分发发送给 SuperAgent 的 message 第一版应基于 SourceMessage 原始 payload 构造。Debug EML 发送给 SuperAgent 的 `agentbus_like_payload` 也按 AgentBus Outlook-like 主结构组装,并包含 `reply_policy.mode``reply_policy.final_only`Debug EML V1 暂用 `mode=manual``final_only=true`,不能再使用旧的 Debug 专属 `debug_only`。Debug 来源区分仍保留在 SourceMessage `provider=DEBUG_EML_UPLOAD`、payload 表 `schemaVersion=debug-eml-upload-v1` 和 Open API metadata 中,不混入主 payload。后续 AgentBus 明确真实 `reply_policy.mode` 枚举后Debug EML 和实时链路需要一起对齐。
AgentBus 开启 M011 CP3 时message 主 payload 会追加 `attachment_extractions[]`。该字段只包含被识别为 Booking Update / Booking Surcharge 的高亮行安全摘要,以及人员名单类 Excel、附件读取失败或解析失败的安全排除结果 / warning不包含整份 Excel、完整附件 URL、OSS 签名参数、API Key、Cookie 或 Secret。详细契约见 `docs/project/requirements/M011-booking-excel-pre-superagent-enrichment-v1.md`
发送 metadata 建议包含:
```json
@@ -214,6 +220,7 @@ RUNNING / RETRYABLE_FAILED
- 新增 `SuperAgentDispatchRunEntity`、Mapper、Repository、Service 和配置类。
- AgentBus 捕获 `AGENTBUS + RECEIVED` 后,在配置开启时幂等创建 dispatch run重复投递可补偿缺失 outbox。
- worker 处理 `PENDING / RETRYABLE_FAILED / 锁已过期 RUNNING`,调用共享 SuperAgent Open API client。
- M011 CP3 已接入 worker配置开启时读取 SourceMessage 附件 URL下载 Excel 字节,复用 Booking Excel 预处理服务,并把非空 `attachment_extractions[]` 追加到发给 SuperAgent 的主 payload。
- Open API client 支持 `Content-Location``run_id`、SSE `id``Last-Event-ID``GET /runs/{run_id}``GET /runs/{run_id}/events` 恢复。
- Debug EML 继续复用共享 Open API client。
- dispatch 成功保存 session、run、last event id、raw answer、parsed json、trace 摘要和状态。

View File

@@ -0,0 +1,418 @@
# 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 不要求落库,避免在规则未稳定前引入长期数据模型。

View File

@@ -119,6 +119,7 @@
| SuperAgent Open API Client | `INTERNAL_ONLY` | 只能后端 Adapter 使用Secret 不出后端 | 通过 debug run 或 dispatch run 追踪 |
| OSS Adapter | `INTERNAL_ONLY` | 前端只能拿后端返回的安全 URL不能拿 OSS Secret | 上传和读取入口记录安全摘要 |
| AgentBus dispatch worker | `INTERNAL_ONLY` | 只由后端调度或受控管理入口触发 | `platform_superagent_dispatch_run` |
| Booking Excel 附件预处理 | `INTERNAL_ONLY` | M011 CP1 / CP2 / CP3 已接入 Debug EML 与 AgentBus dispatch只允许后端在调用 SuperAgent 前通过 Service / Port 使用,不单独暴露给前端或第三方 | 记录安全 warning、附件名、hash 前缀、sheet 名、行号和高亮业务行摘要;不得记录完整 Excel、完整附件 URL、签名参数、API Key、Cookie、Secret 或名单类客户敏感原文 |
| Flyway / bootstrap 初始化 | `INTERNAL_ONLY` | 不提供运行时外部接口 | 通过部署记录和数据库 history 追踪 |
| 未来 OPERA / OHIP Adapter | `INTERNAL_ONLY` | 浏览器不得直接调用;只能业务服务触发 | 必须记录操作、attempt 和外部结果摘要 |