Files
th-hotel-simple/docs/project/integrations/superagent-mcp/submit-payload-mapping.md
2026-07-12 19:39:14 +08:00

355 lines
11 KiB
Markdown
Raw Permalink 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.

# TH Hotel MCP Submit Payload Mapping
## 1. 文档信息
| 项目 | 内容 |
| --- | --- |
| 文档版本 | 0.2 |
| 日期 | 2026-07-12 |
| 状态 | 已落地第一版 |
| 适用范围 | `th_hotel_submit_task_results` 的 V3/P0.1 payload adapter、schema validator 和一次提交规则 |
## 2. 核心原则
`th_hotel_submit_task_results` 接收的是 SuperAgent 已经冻结的业务结果。MCP 层只负责把业务结果转换为本系统可接收的提交 payload不重新解释业务含义不调用 Skill不根据字段名猜测任务类型。
目标链路:
```text
SuperAgent 业务结果
-> MCP Submit Payload Adapter
-> MCP Submit Schema Validator
-> ReservationAiTaskIntakeService
-> MCP tool result
```
实现位置:
```text
server/src/main/java/cn/nianxx/thhotel/integrations/mcp/superagent/service/SuperAgentMcpSubmitPayloadAdapter.java
server/src/main/java/cn/nianxx/thhotel/integrations/mcp/superagent/service/impl/SuperAgentMcpSubmitPayloadAdapterImpl.java
```
## 3. 支持的输入形态
| 形态 | 判断方式 | 处理方式 |
| --- | --- | --- |
| V3 业务根 | 包含 `message_events` | 校验根结构、source message、event transport 字段和关系索引,再按 `message_events[]` 顺序映射 `source_event_index`event 业务合法性仍交给业务入站层落 `adapter_contract_error` |
| V3 S10/S99 入口通知 | 包含 `route_code` 或入口通知 `result_type` | 校验 S10/S99 根字段和 source message 后透传给业务入站服务 |
| V2 兼容任务结果 | 包含 `ai_task_results` | 保留旧 `source_message_id + ai_task_results[]` 兼容路径,并在 MCP 层校验完整 item schema |
未知根字段会在 MCP 层被拒绝,错误码为 `MCP_SUBMIT_PAYLOAD_INVALID`
`source_message_id` 缺失或整个 `source_message` 缺失属于既有基础设施输入错误MCP adapter 不改写该错误通道;业务入站服务会返回 `MISSING_SOURCE_MESSAGE_ID`
V3 业务根和 S10/S99 如果携带 MCP schema 中的兼容字段 `hotel_id``source_provider``source_channel`adapter 会接受并在转交业务入站层前移除。业务定位仍以系统酒店和 `source_message.source_message_id` 为准。
## 4. source_message_id 定义
| 字段 | 规则 |
| --- | --- |
| `source_message.source_message_id` | V3 必填;必须来自 AgentBus 原始 payload 的外部消息 ID对应 `platform_source_message_inbox.external_message_id` |
| `source_message_id` | V2 兼容必填;同样对应 `platform_source_message_inbox.external_message_id` |
| `hotel_id` | SuperAgent 正式提交不需要传;本系统按平台唯一 ACTIVE 酒店解析 |
`source_message_id` 不是本系统数据库主键,也不是 `platform_source_message_inbox.id`
## 5. source_event_index 映射
SuperAgent 业务结果中的 `E1``E_CHILD_1``E_PARENT` 等值只是 Agent 内部事件 ID不能直接当成本系统的 `source_event_index`
MCP adapter 按 `message_events[]` 数组顺序生成一基数字索引:
| 业务事件 ID | 数组位置 | 本系统 `source_event_index` |
| --- | --- | --- |
| `E_CHILD_1` | 第 1 个 event | `1` |
| `E_CHILD_2` | 第 2 个 event | `2` |
| `E_PARENT` | 第 3 个 event | `3` |
| `E_TRACE` | 第 4 个 event | `4` |
映射规则:
- `message_events[].source_event_index` 输出为数字。
- `related_source_event_index` 输出为字符串数字,例如 `"1"`
- `parent_source_event_index` 输出为数字。
- `related_source_event_indices[]` 输出为字符串数字数组,保持原顺序。
- 悬空引用、重复引用、缺失事件 ID 都在 MCP 层拒绝。
- MCP tool result 会返回 `mapping_diagnostics.source_event_index_mapping[]`,记录原始事件 ID 到本系统索引的映射;该诊断不写入 `workflow_reservation_ai_transition.ai_payload_json`
## 6. ai_task_results[] 兼容 item schema
V2 兼容路径仍保留,`ai_task_results[]` item 以 REST 总契约为准。当前 MCP `tools/list` 已暴露 item schemaadapter 也会在提交业务层前校验必填字段、字段类型、允许 `result_type`、未知字段和根级 `extraction_warnings`
必填字段:
- `source_event_index`
- `catalog_code`
- `skill_id`
- `result_type`
- `task_type`
允许的 `result_type`
- `normal_task`
- `manual_review`
- `informational_message`,仅历史兼容
建议 item 结构:
```json
{
"source_event_index": 1,
"catalog_code": "S01",
"skill_id": "S01_new_booking_skill",
"result_type": "normal_task",
"task_type": "New Booking",
"task_subtype": "new_fit_reservation",
"current_or_history": "current",
"case_keys": {
"group_code": null,
"confirmation_number": null,
"reservation_number": null,
"block_code": null
},
"relevant_message_excerpt": "Please create a new booking.",
"attachments": [],
"file_references": [],
"context_used": {},
"extracted_fields": {},
"manual_review": null,
"additional_operations": [],
"idempotency_key": null
}
```
新数据优先使用 V3 业务根或 V3 S10/S99不建议继续新增 V2 `ai_task_results[]`
## 7. extraction_warnings 规则
| 形态 | 规则 |
| --- | --- |
| V3 业务根 | `extraction_warnings` 必须存在且为数组,无警告传 `[]` |
| V2 兼容 | `extraction_warnings` 可存在且为数组;缺省由业务层按空数组处理 |
MCP 层不解释 warning 语义,不因为 warning 自动创建任务。
## 8. 成功示例Parent Split
提交给 MCP tool 的业务结果可以使用 Agent 内部事件 ID
```json
{
"source_message": {
"source_message_id": "mail-20260712-parent-split-001",
"subject": "Parent split booking request",
"from": "agent@example.test",
"cc": [],
"received_at": "2026-07-12T04:00:00Z",
"source_channel": "Email"
},
"message_events": [
{
"event_type": "New Booking",
"event_role": "travel_agent_request",
"source_event_index": "E_CHILD_1",
"current_or_history": "current",
"case_keys": {
"group_code": "CHILD-A",
"confirmation_number": null,
"reservation_number": null,
"block_code": null
},
"relevant_message_excerpt": "Create child group A.",
"attachments": [],
"file_references": [],
"context_used": {},
"extracted_fields": {
"booking_object_type": "Group Block"
},
"manual_review": null
},
{
"event_type": "New Booking",
"event_role": "travel_agent_request",
"source_event_index": "E_CHILD_2",
"current_or_history": "current",
"case_keys": {
"group_code": "CHILD-B",
"confirmation_number": null,
"reservation_number": null,
"block_code": null
},
"relevant_message_excerpt": "Create child group B.",
"attachments": [],
"file_references": [],
"context_used": {},
"extracted_fields": {
"booking_object_type": "Group Block"
},
"manual_review": null
},
{
"event_type": "Cancel Allotment",
"event_role": "travel_agent_request",
"source_event_index": "E_PARENT",
"current_or_history": "current",
"case_keys": {
"group_code": "PARENT",
"confirmation_number": null,
"reservation_number": null,
"block_code": "PARENT"
},
"relevant_message_excerpt": "Release parent after child split.",
"attachments": [],
"file_references": [],
"context_used": {},
"related_event_type": "New Booking",
"requires_downstream_hard_validation": true,
"related_source_event_indices": ["E_CHILD_1", "E_CHILD_2"],
"extracted_fields": {
"relationship_type": "linked_parent_release_after_child_split",
"parent_group_code": "PARENT",
"cancel_scope": "entire_allotment_control_block",
"parent_release_or_cancel_candidate": true,
"release_reason": "parent_to_child_allocation_split",
"allocation_split_from_parent": true,
"child_group_codes": ["CHILD-A", "CHILD-B"]
},
"manual_review": null
}
],
"case_candidates": [],
"extraction_warnings": [],
"unhandled_current_intents": []
}
```
MCP adapter 进入业务层前会把父事件关系映射为:
```json
{
"source_event_index": 3,
"related_source_event_indices": ["1", "2"]
}
```
MCP tool result 同时返回非业务诊断:
```json
{
"mapping_diagnostics": {
"mapping_policy": "message_events_array_order_1_based",
"source_event_index_mapping": [
{
"original_source_event_index": "E_CHILD_1",
"mapped_source_event_index": 1
},
{
"original_source_event_index": "E_CHILD_2",
"mapped_source_event_index": 2
},
{
"original_source_event_index": "E_PARENT",
"mapped_source_event_index": 3
}
]
}
}
```
## 9. 成功示例:跨 Child Trace
当 Trace 覆盖完整 Parent split 的全部 Child 时,不能只绑定第一个 Child。业务结果应保留全部 Child 引用:
```json
{
"event_type": "Trace",
"source_event_index": "E_TRACE",
"related_source_event_indices": ["E_CHILD_1", "E_CHILD_2"],
"extracted_fields": {
"trace_subtype": "general_request"
}
}
```
MCP adapter 会把它映射为:
```json
{
"source_event_index": 4,
"related_source_event_indices": ["1", "2"]
}
```
## 10. 拒绝示例
未知字段:
```json
{
"source_message": {},
"message_events": [],
"case_candidates": [],
"extraction_warnings": [],
"unhandled_current_intents": [],
"unexpected_root": true
}
```
返回:
```json
{
"isError": true,
"structuredContent": {
"success": false,
"error": {
"code": "MCP_SUBMIT_PAYLOAD_INVALID",
"details": {
"field": "unexpected_root"
}
}
}
}
```
悬空关系:
```json
{
"related_source_event_indices": ["E_CHILD_1", "E_UNKNOWN_CHILD"]
}
```
同样返回 `MCP_SUBMIT_PAYLOAD_INVALID``details.field=related_source_event_indices`,不会调用业务写入 Service。
## 11. 一次提交和失败不重试
当前 MCP endpoint 与后端业务 Service 同进程:
- adapter 校验失败时,不调用 `ReservationAiTaskIntakeService`
- adapter 校验通过后,只调用一次 `ReservationAiTaskIntakeService.accept`
- MCP endpoint 不做自动重试。
- 业务结果不会因为 MCP 响应被回写或污染。
当前回归测试:
```text
./mvnw -Dtest=SuperAgentMcpControllerTest,SuperAgentMcpSubmitEnabledControllerTest test
```
覆盖内容:
- `tools/list` 暴露 V3 submit schema。
- `tools/list` 暴露 V2 `ai_task_results[]` item schema 和 V3 `relationship_type`
- 缺失 `source_message_id` 或整个 `source_message` 保持既有 `MISSING_SOURCE_MESSAGE_ID` 错误。
- 未知根字段在业务层前被拒绝。
- V2 item 缺必填字段在业务层前被拒绝。
- 悬空 `related_source_event_indices` 在业务层前被拒绝。
- 重复 `related_source_event_indices` 在业务层前被拒绝。
- `E_CHILD_1/E_CHILD_2/E_PARENT` 按数组顺序映射为 `1/2/3`
- 跨 Child Trace 关系映射为完整 `["1", "2"]`,不压缩到第一个 Child。
- S10/S99 可通过 MCP 写入工具创建只读来源消息任务。
- V3 event 业务契约错误由业务入站层保存为 `adapter_contract_error` transition。
- 合法 Parent split 只创建一个 AI batch并返回 `accepted_count=3`