Files
th-hotel-simple/docs/import/20260718/0718-M002-V4-Agent回调草案审查与最新答复.md
2026-07-18 17:01:12 +07:00

542 lines
23 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.

# 0718 M002 V4 Agent 回调草案审查与最新答复
日期2026-07-18
审查对象:`M002-v4-agent-callback-field-contract-draft.md` 0.1
适用范围0718 业务基线下Agent → Adapter / MCP → 信息系统的业务回调字段
## 1. 最重要的修正Basic Information 是订单级数据
最新确认如下:
- 一笔订单只有一份 Basic Information。
- Basic Information 跟随订单,不跟随具体 Event。
- Basic Information 不是 `event_type`,但它是订单任务中的一张独立可确认、独立锁定任务卡。
- 同一订单下即使同时有 Update、Trace、Rooming List、Payment也只显示一张 Basic Information 卡。
- 一封邮件可能包含多笔订单,因此 Basic Information 也不能放成整个结果包唯一的一份。
### 与此前结构是否吻合
分两层看:
- 页面和业务结果吻合:此前信息系统会按 `order_ref` 聚合,同一订单最终只显示一张 Basic Information。
- Agent 回调字段归属不完全吻合:此前要求每个 Event 重复输出 `account_code`,再由系统校验同单一致。这能得到一张卡,但数据本身仍跟着 Event 重复不能准确表达“Basic Information 属于订单”。
因此,最新规则正式改为:
- `account_code` 不再放在每个 Event 上。
- 每个 `order_ref` 只提供一份订单级 Basic Information 数据。
- Event 通过 `order_ref` 关联该订单,不复制 Account。
- Market、Source 仍由信息系统目录派生,不由 Agent 输出。
## 2. 推荐的 V4 结果包骨架
以下是当前最容易表达业务语义、同时保留 `source_message + message_events[]` 的推荐结构:
```json
{
"route_code": null,
"source_message": {
"source_message_id": "AAMkAG...",
"conversation_id": "thread-001",
"subject": "Booking update",
"sender": "op@example.com",
"sent_at": "2026-07-18T02:10:00Z",
"body": "original current email body",
"attachments": []
},
"order_contexts": [
{
"order_ref": "order-1",
"basic_information": {
"account_code": "ACCOUNT_CODE",
"manual_review": null
}
}
],
"message_events": [
{
"order_ref": "order-1",
"event_type": "UPDATE_BOOKING",
"target_order": {
"booking_type": "GROUP",
"locator_type": "GROUP_CODE",
"locator_value": "LLTQ260510QVIPA"
},
"after": {
"arrival_date": "2026-07-27",
"departure_date": "2026-07-30"
},
"manual_review": null
},
{
"order_ref": "order-1",
"event_type": "PAYMENT",
"target_order": {
"booking_type": "GROUP",
"locator_type": "GROUP_CODE",
"locator_value": "LLTQ260510QVIPA"
},
"attachment_ids": ["att-1"],
"manual_review": null
}
]
}
```
说明:
- `order_contexts` 是本答复采用的推荐工作字段名;它表达“一封邮件结果包内的订单级数据集合”。最终技术命名可由 SuperAgent、Adapter、MCP Schema 和信息系统统一,但不能改变订单级归属。
- 每个非 S10 订单至少有一个非空 `order_ref`,并且在 `order_contexts[]` 中只能出现一次。
- 每个具体 Event 必须引用一个已存在的 `order_ref`
- 同一订单的多个 Event 使用同一个 `order_ref`;不同订单使用不同值。
- `order_ref` 只在当前结果包内有效,不是 PMS 订单键、系统订单 ID、任务 ID或幂等键。
- 当前继续保留 Event 自己的 `target_order`,由信息系统按它查单;相同 `order_ref` 下的非空 `target_order` 必须一致。
## 3. Basic Information 的最终字段责任
订单级结构:
```json
{
"order_ref": "order-1",
"basic_information": {
"account_code": "ACCOUNT_CODE | null",
"manual_review": null
}
}
```
规则:
- `account_code` 是信息系统 Account 目录中的稳定 code不是自由文本或显示名称。
- Agent 可依据发件人和历史业务信息判断 Account但不重复输出 sender。
- Agent 无法可靠确定 Account 时,输出 `account_code=null`,并在同一个 `basic_information` 对象中输出 `manual_review=true`
- Basic Information 的人工复核只作用于 Basic Information 卡,不要求同订单所有 Event 都变成 `manual_review=true`
- 信息系统根据 Account 目录带出 Market 和 Source。
- 用户只能从信息系统已有 Account、Market、Source 中受控改选;不存在 Manual 或自由输入。
- Agent 给出非空 code、但信息系统运行时目录不存在该值时属于系统目录 / 契约校验问题Basic Information 卡阻止确认并显示字段错误,但不得反向篡改 Agent 原始 `manual_review`
- 同一封邮件的不同 `order_ref` 可以对应不同 Account。
删除旧规则:
- 不再要求每个 Event 都携带 `account_code`
- 不再要求信息系统比较同一 `order_ref` 下多个 Event 的 Account 是否冲突。
- 不因 Event 数量创建多份 Basic Information。
## 4. source_message 最终业务内容
当前邮件在包级只出现一次,业务最小字段为:
```json
{
"source_message_id": "string",
"conversation_id": "string | null",
"subject": "string | null",
"sender": "string | null",
"sent_at": "ISO-8601 string | null",
"body": "string | null",
"attachments": []
}
```
草案需要修正:
- 不拆 `sender.display / sender.address``sender` 直接使用邮件监听提供的单一值。
- 不同时输出 `text_body``html_body`;只保留监听到的当前邮件单一原文 `body`
- Agent 不摘要、清洗、翻译或改写 `body`
- `received_at` 不是当前页面和业务处理必需字段;若基础设施需要,可作为内部技术元数据,不进入业务必传。
- 完整历史邮件线程不嵌入当前结果包;信息系统通过 `conversation_id` 查询。
- 标题、发件人、时间、正文、附件字段始终保留;极端不可得时字段值为 null不删除字段或猜值。
## 5. 附件结构
当前附件 item 维持:
```json
{
"id": "att-1",
"name": "payment-slip.jpg",
"content_type": "image/jpeg",
"url": "https://upstream-storage/...",
"size": 251524
}
```
- `id / name / content_type / url` 必填。
- `size` 可选。
- URL 由上游邮件监听或文件存储层提供Agent 只原样转发,不生成、拼接、刷新或签发。
- Payment 只按 ID 引用附件,不在 Event 内复制文件名、类型、URL 或完整对象。
## 6. Event 公共结构
每个具体业务 Event 的公共字段为:
```json
{
"order_ref": "order-1",
"event_type": "...",
"target_order": {
"booking_type": "GROUP | FIT | null",
"locator_type": "GROUP_CODE | BOOKING_CODE | CONFIRMATION_NUMBER | null",
"locator_value": "string | null"
},
"manual_review": null
}
```
不再属于 Event 公共字段:
- `account_code`:改为订单级 Basic Information。
- `payload`:当前目标契约直接使用各 Event 的专属业务字段,不再增加一层无业务含义的通用 payload。
- `evidence`:不是信息系统页面业务必传;如 Agent 内部需要,可留在内部诊断,不驱动页面业务。
- `event_index`:数组顺序不承载业务顺序,页面顺序由信息系统按固定卡片规则决定。
- `event_id`:不是业务字段;只有真实 transport / 幂等机制需要时才由技术契约另行增加,不能代替 `order_ref`
## 7. event_type 最终枚举
只保留:
```text
NEW_BOOKING
UPDATE_BOOKING
CANCEL_BOOKING
TRACE_RESERVATION_NOTES
ROOMING_LIST
PAYMENT
```
- Basic Information 不是 Event。
- 邮件展示卡不是 Event`source_message` 固定生成。
- S10 是包级纯通知路由,不属于上述业务枚举。
- S99、Fallback、`Need Manual Review`、独立 Voucher、Payment Evidence、Voucher Received 均不再作为新 Agent 输出。
## 8. target_order 最终规则
| 场景 | `booking_type` | `locator_type` | `locator_value` |
|---|---|---|---|
| Group 的所有业务 | `GROUP` | `GROUP_CODE` | Group Code即 Block Name |
| Fit New以及与该 New 同包同目标的 Trace | `FIT` | `BOOKING_CODE` | Booking Code |
| 当前无 PMS API、尚无真实 Confirmation Number 的 Fit 后续业务 | `FIT` | `BOOKING_CODE` | 查询信息系统本地订单投影 |
| 已取得真实 Confirmation Number 的 Fit 后续业务 | `FIT` | `CONFIRMATION_NUMBER` | PMS Confirmation Number |
规则:
- 当前包内同订单归组使用 `order_ref`,不是使用相同 `target_order` 或相同 null。
- `target_order` 用于信息系统查单和绑定订单。
- 定位值未解决时保留原 Event未知字段为 nullEvent 的 `manual_review=true`
- Agent 能判断多个 Event 属于同单但定位未解决时,仍使用相同 `order_ref`
- Agent 连是否同单都无法判断时,使用不同 `order_ref`,不能把相同 null 合并。
- 不输出 `case_keys`、定位候选数组、原因码或 `missing_fields[]`
- AMEND GROUP CODE 统一走 S10不形成 Update Event。
## 9. 各 Event 最新字段
### 9.1 NEW_BOOKING
```json
{
"order_ref": "order-1",
"event_type": "NEW_BOOKING",
"target_order": {},
"arrival_date": "YYYY-MM-DD | null",
"departure_date": "YYYY-MM-DD | null",
"rate_code": "RATE_CODE | null",
"room_items": [
{
"room_type_code": "ROOM_TYPE_CODE | null",
"room_count": 1
}
],
"manual_review": null
}
```
Group 条件字段:
```json
{
"booking_scenario": "STANDARD | PROPOSAL"
}
```
Fit 条件字段:
```json
{
"guest_name": "REAL GUEST NAME | null"
}
```
修正草案:
- 删除 `booking_name`Group Code 已在 `target_order.locator_value`,同时作为 Block Name。
- 删除独立 `booking_code`Fit Booking Code 也在 `target_order.locator_value`
- `proposal` 改为 Group 专用受控 `booking_scenario=STANDARD | PROPOSAL`
- `room_type` 使用受控 `room_type_code`
- `room_quantity` 使用 `room_count`
- 删除 `adult_per_room`Adult 由信息系统按 RoomType 映射派生。
- Agent 不输出 Nights、Breakfast、Group Booking Status、Block ID 或 Confirmation Number。
- `room_items=[]` 只能用于表示已识别 New 但完整房型清单未解决,并必须 `manual_review=true`;最终 validator 需按这一规则固定。
### 9.2 UPDATE_BOOKING
```json
{
"order_ref": "order-1",
"event_type": "UPDATE_BOOKING",
"target_order": {},
"after": {
"guest_name": "NEW NAME | null",
"arrival_date": "YYYY-MM-DD | null",
"departure_date": "YYYY-MM-DD | null",
"room_items": [
{
"room_type_code": "ROOM_TYPE_CODE | null",
"room_count": 1
}
]
},
"manual_review": null
}
```
规则:
- `after` 是稀疏对象;字段缺省表示本次不修改。
- 字段存在但为 null表示已识别要改该字段、但目标值未解决同时 `manual_review=true`null 不表示清空。
- `guest_name` 只用于 Fit Name 更新,不使用 `booking_name`
- 只要修改涉及房型或房量,`after.room_items[]` 必须是修改后的完整房型清单,不是变化行。
- 如果只能识别局部房型变化、无法形成完整目标清单,建议固定为 `after.room_items=null + manual_review=true`,禁止确认直到人工补全。
- Rate Code 不允许出现在 Update。若 Agent 仍输出,按业务契约错误处理,不能静默忽略后继续执行。
- Before、原订单和完整最新订单由信息系统查单后生成不由 Agent 输出。
### 9.3 CANCEL_BOOKING
```json
{
"order_ref": "order-1",
"event_type": "CANCEL_BOOKING",
"target_order": {},
"manual_review": null
}
```
- `CANCEL_BOOKING` 本身已经表示整单取消。
- 删除 `cancel_scope``cancel_reason``after` 和当前订单快照。
- 减少房量、删除房型、修改日期或修改 Fit Name 属于 Update不是 Cancel。
### 9.4 TRACE_RESERVATION_NOTES
```json
{
"order_ref": "order-1",
"event_type": "TRACE_RESERVATION_NOTES",
"target_order": {},
"trace_items": [
{
"item_type": "GENERAL",
"text": "HONEYMOON SETUP",
"department_code": "FO"
},
{
"item_type": "EXTRA_BED",
"target_room_type_code": "TWN",
"extra_bed_room_count": 1,
"department_code": "FO+HSK"
}
],
"manual_review": null
}
```
修正草案:
- 使用 `item_type=GENERAL | EXTRA_BED`,不使用 `trace_type=NORMAL`
- GENERAL 输出 `text + department_code`
- EXTRA_BED 不输出自由 `content`;信息系统固定显示 `SET EXTRA BED`
- EXTRA_BED 不输出 `adult_after_extra_bed`;信息系统按当前 / 基础 Adult +1 计算,页面确认前允许用户纠正。
- Department code 由 Agent 必传,值来自信息系统维护的受控部门目录或组合目录。
- 加床目标房型不在当前订单时Trace 卡不能确认,并提示用户核对目标房型和订单关联;只有订单定位本身不可信时,才触发共享查单门槛阻断整个订单上下文。
### 9.5 ROOMING_LIST
当前最小 Event
```json
{
"order_ref": "order-1",
"event_type": "ROOMING_LIST",
"target_order": {
"booking_type": "GROUP",
"locator_type": "GROUP_CODE",
"locator_value": "GROUP-CODE"
},
"manual_review": null
}
```
- 只适用于 Group。
- 当前 Agent 只需识别这是 Rooming List 任务。
- 不输出 `rows[]`、逐人名单、同住分组、18 列、Excel 或 PMS 导入参数。
- 当前也不要求 Rooming List Event 单独输出 `attachment_ids[]`;原附件已经在包级 `source_message.attachments[]`,只在邮件展示卡查看。
- 页面固定展示 12 个必填字段表头的标准表格示意,当前内容不代表附件已经真实转换。
- 未来取得 PMS API 后,按真实接口重新冻结住客与执行参数,不直接恢复草案中的 rows。
### 9.6 PAYMENT
```json
{
"order_ref": "order-1",
"event_type": "PAYMENT",
"target_order": {},
"attachment_ids": ["att-1", "att-2"],
"manual_review": null
}
```
- `account_code` 已移至订单级 Basic Information不在 Payment 重复。
- 一笔订单多份凭证放在同一个 Payment Event。
- `attachment_ids[]` 没有业务顺序,每个 ID 必须引用同包附件。
- 不输出金额、日期、付款人、交易号、银行账号、付款状态、Department 或完整附件对象。
- 推荐把“正常 Payment 的 `attachment_ids[]` 至少一项”设为 validator 规则。
- 如果 Agent 输出 PAYMENT 但没有任何附件 ID而来源附件实际存在属于 Agent 契约错误,不能创建一张正常空 Payment 卡。
- 如果来源本身没有可用于当前图片卡的付款凭证,无法形成 Payment 任务,则按 S10 展示原邮件。
- 如果附件 metadata 存在但 URL 读取失败,属于附件 / 存储技术异常,不应伪装成人工复核字段。
## 10. manual_review 最终规则
唯一合法值:
```json
null
```
或:
```json
true
```
规则:
- 正常数据为 null不使用 false。
- Event 的人工复核只属于该 Event 对应任务卡。
- Basic Information 的人工复核放在订单级 `basic_information.manual_review`,只属于 Basic Information 卡。
- 未解决值放在原业务字段位置,例如 `rate_code=null``room_type_code=null``account_code=null`
- `manual_review=true` 必须至少能由当前对象中的一个 null、空清单或其他 Schema 可识别未解决值解释。
- 所有字段完整合法却只给 true属于 Agent 契约异常。
- 不输出 `manual_review_info``reason_code``visible_message``missing_fields[]`、JSON Pointer、候选或建议动作。
- 信息系统依据条件必填、Account / RoomType / Rate Code 目录、日期 / 数量规则和查单结果生成字段级错误路径、错误码与页面提示。
- 信息系统查单 0 / 多笔或目录运行时校验失败,不反向修改 Agent 原始 `manual_review`
因此,草案第 16 节的扩展 `manual_review_info` 整节应删除。
## 11. S10 纯通知
业务语义已经冻结:
```json
{
"route_code": "S10",
"source_message": {},
"order_contexts": [],
"message_events": []
}
```
- 只显示邮件展示卡。
- 不显示 Basic Information、房间信息或其他业务卡。
- 不需要 `order_ref``target_order`、Account 或业务字段。
- 用户点击“确认”后任务完成。
- 不提供人工终止。
- 不调用 PMS不修改订单。
- 不输出 S99、Fallback、原因码、通知说明或 `Need Manual Review`
`route_code` 是当前推荐工作字段名;最终 discriminator 的技术命名仍需 Adapter / MCP Schema 统一,但 S10 的业务语义不再有歧义。
## 12. 技术异常
下列情况不生成酒店用户可见任务,也不转换成 S10 或人工复核:
- 非法 JSON
- 输出不符合 Schema
- Event 引用了不存在的 `order_ref`
- 同一 `order_ref` 下出现冲突的非空 `target_order`
- Rate Code 出现在 Update
- `manual_review=true` 但没有任何可识别的未解决字段;
- Adapter 转换失败;
- MCP 提交失败;
- Agent / Skill 执行异常;
- 附件 metadata 存在但存储 URL 无法读取。
后台 debug、告警和技术重试接口属于技术运维需求不进入本次业务回调也不在酒店用户任务卡上增加“重试”。
## 13. 对草案第 20 节 18 个问题的逐项答复
| # | 草案问题 | 最新答案 |
|---:|---|---|
| 1 | `message_events` 字段名是否冻结 | 业务上继续使用事件数组;`message_events` 可作为 V4 工作字段名。新增订单级 `order_contexts[]` 表达每笔订单的 Basic Information。最终 transport key 需四方 Schema 一致 |
| 2 | `route_code=S10` 与 S99 | S10 是唯一纯通知S99 完全删除。`route_code` 可作为当前工作 key最终 discriminator 只需技术对齐 |
| 3 | `source_message_id` 是否对应 `external_message_id` | 业务要求是当前邮件稳定 ID是否映射 AgentBus `external_message_id` 属于 Adapter 技术映射,必须以真实上游契约核对 |
| 4 | source_message 字段 | 固定业务内容为邮件 ID、会话 ID、subject、单值 sender、sent_at、单一 body、attachments不拆 text / HTMLreceived_at 非业务必传 |
| 5 | event_type 完整枚举 | 已冻结为 New、Update、Cancel、Trace、Rooming List、Payment 六种 |
| 6 | account_code 包级还是 Event 级 | 两者都不是;它是订单级 Basic Information 字段,每个 `order_ref` 只出现一次 |
| 7 | 同订单多个 Event 的 Account 冲突 | 新结构不再重复,所以正常情况下不存在;旧输入冲突由 Adapter 拒绝 / 迁移,不让信息系统或用户任选 |
| 8 | 是否扩展 manual_review | 不扩展,只允许 null / true字段级问题由系统按 Schema 和目录生成 |
| 9 | locator_value=null 如何归组 | 使用非空包内 `order_ref`;同单同值,不同订单不同值,不按相同 null 合并 |
| 10 | 无 API Fit 后续只有 Booking Code | 允许临时查询本地订单投影;取得真实 Confirmation Number 后切换正式定位,不生成假编号 |
| 11 | New Booking 字段 | 使用 dates、订单级 rate_code、完整 room_items、Group booking_scenario、Fit guest_name删除 booking_name、独立 booking_code 和 Adult |
| 12 | Update 是否给完整 After | `after` 整体是稀疏对象;但只要涉及房型 / 房量,`after.room_items` 必须是修改后的完整清单 |
| 13 | Update 出现 Rate Code | 业务契约错误,不静默忽略,不允许正常执行 |
| 14 | Cancel 是否需要 cancel_scope | 不需要;`CANCEL_BOOKING` 已表示整单取消,也不输出 cancel_reason |
| 15 | Trace 字段与 Department 来源 | 使用 GENERAL / EXTRA_BED itemDepartment 是 Agent 必传的系统受控 code固定加床文案和 Adult 由系统派生 |
| 16 | Rooming List 是否允许不输出 rows | 不只是允许,而是当前明确不要求 rows只输出最小 Group Rooming List Event页面显示表头示意 |
| 17 | Payment attachment_ids 为空 | 推荐正常 Payment 必须非空空引用属于无法形成正常图片卡。按来源情况进入契约错误、S10 或附件技术异常,不使用复杂人工复核对象 |
| 18 | 技术异常是否需要后台重试 | 不属于本轮业务契约;可另做开发 / 运维需求,但不得生成用户业务任务或卡片重试按钮 |
## 14. 草案各章节的处理结论
| 草案章节 | 处理 |
|---|---|
| 第 3 节总体结论 | 将“相同 target_order 聚合”改为“按 source_message_id + order_ref 聚合,再按 target_order 查单”;增加订单级 Basic Information 集合 |
| 第 4 节包级结构 | 改成单值 sender、单一 body删除业务必传 text_body、html_body、received_at |
| 第 5 节附件 | 基本正确,保留 |
| 第 6 节 Event 通用结构 | 删除 Event account_code、通用 payload、业务 evidence、event_indexevent_id 仅可作为待证实 transport 字段 |
| 第 7 节 target_order | 增加 order_ref 归组和无 API Fit Booking Code 临时定位AMEND GROUP CODE 冻结为 S10 |
| 第 8 节枚举 | 六种枚举正式冻结 |
| 第 9 节 Basic Information | 改为每个 order_ref 一份订单级对象,不再 Event 级重复 |
| 第 10 节 New | 按第 9.1 节整体替换 |
| 第 11 节 Update | 按第 9.2 节整体替换 |
| 第 12 节 Cancel | 删除整个 cancel payload保留最小 Event |
| 第 13 节 Trace | 按第 9.4 节整体替换,删除 Agent Adult 与固定加床文案 |
| 第 14 节 Rooming List | 删除 rows 和 Event attachment_ids改为当前最小 Event |
| 第 15 节 Payment | 删除 Event account_code保留非空附件 ID 集合 |
| 第 16 节 manual_review | 删除 manual_review_info、reason_code、visible_message 和 missing_fields |
| 第 17 节 S10 | 业务处理正确,补充无订单级数据 |
| 第 18 节技术异常 | 基本正确;后台重试另立技术需求 |
| 第 19 节后端建模 | 不再按 target_order 直接分组;先按 order_ref 形成订单任务,再按 target_order 查单;每个订单只补一张 Basic Information |
## 15. 目前仍需技术团队最终对齐的内容
业务规则已经足够让开发进行领域建模。以下剩余项是技术接口命名或运行机制,不应再次让业务方决定页面含义:
1. `order_contexts``message_events` 和 S10 discriminator 的最终 JSON key。
2. `source_message_id` 到 AgentBus / SourceMessage Inbox 字段的真实映射。
3. `conversation_id``sent_at` 等 key 与时间格式的最终机器 Schema。
4. Payment 附件引用 key 是否最终命名为 `attachment_ids`
5. 无附件、监听失败、附件 metadata 存在但 URL 读取失败的 transport 错误码。
6. `event_id` / 幂等键是否为运行时必需;如需增加,它只属于 transport不是页面业务字段。
7. Department、Account、RoomType、Rate Code 等受控目录的真实 code 集合和版本管理。
8. Adapter、MCP Schema、信息系统 DTO 与 validator 的版本切换方式。
9. 技术失败后台、告警和开发重试入口是否建设。
这些技术项不会改变以下业务事实:一封邮件一个结果包、一个 `order_ref` 一笔订单、一笔订单一张 Basic Information、每个 Event 一张对应业务任务卡、每张卡独立确认并永久锁定。
## 16. 最终结论
开发草案已经覆盖了大部分讨论主题,但不能直接冻结为 V4 Schema。主要原因不是缺少问题而是其中多项“当前建议”已经被最新业务共识明确否决或替代。
开发可按本文继续推进业务模型和页面数据模型;正式实现 Agent 回调前,还需要由 SuperAgent、Adapter、MCP Schema 和信息系统共同完成第 15 节的技术 key 与运行契约对齐。