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

21 KiB
Raw Blame History

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
旅游批次
旅游日期
成团航班信息
团号
团长
姓名
护照全名
证件号
护照号
证件有效期结束
性别
生日
年龄
饮食禁忌
重大疾病
  1. 如果同一个 sheet 同时存在明确 Booking 核心字段组合应优先标记为待确认而不是直接排除。Booking 核心字段包括:
酒店 / Hotel / โรงแรม
酒店回应状况 / Hotel Status / สถานะ
备注 / Remark / หมายเหตุ
入住 / Check In / วันเช็คอิน
退房 / Check Out / วันเช็คเอาท์
房型 / Room Type
房数 / Rooms
团号 / Group Code
  1. 如果 workbook 中全部有效 sheet 都是 PASSENGER_ROSTER,则整份附件排除。
  2. 如果 workbook 中部分 sheet 是人员名单、部分 sheet 是 Booking 表,应只排除人员名单 sheet继续处理其他 sheet。

中文说明:第一种表格的排除重点是“字段组合”,不是文件名。后续即使文件名变化,只要字段结构是旅行名单,仍应排除。

4.2 第二、第三种表格识别规则

BOOKING_SURCHARGE 推荐同时参考:

  • 表头或正文出现 附加费春节新年SurchargeGala DinnerCompulsory 等关键词。
  • 存在酒店、入住 / 退房、房型、房数、费用、备注等 Booking 或费用相关字段。
  • 文件名可作为辅助信号,但不能单独决定类型。

BOOKING_UPDATE 推荐同时参考:

  • sheet 名或文件名出现 BOOKINGUPDATE BOOKINGWYNDHAM、月份标识等关键词。
  • 存在团号、酒店、入住 / 退房、房型、房数、酒店回应状态、备注等 Booking 更新相关字段。
  • 多 sheet 且 sheet 名形如 BOOKING 01-2026BOOKING 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-YYYYYYYY-MMMMM 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。

示例:

邮件接收时间2026-07-19
base_month2026-07
lookback_months6
候选窗口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_ROSTERNO_MATCHED_MONTH_SHEETUNKNOWN_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_ROSTERBOOKING_SURCHARGEBOOKING_UPDATEUNKNOWN

依赖方向:

  • 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 解析历史,再单独设计持久化表,例如:

workflow_reservation_booking_excel_import_batch
workflow_reservation_booking_excel_import_row

V1 不要求落库,避免在规则未稳定前引入长期数据模型。