# 飞控意图「播报—确认—执行」扩展规范 v1 > **已统括**:`dialog_result` 的权威形状与 `confirm` 字段见 **[`CLOUD_VOICE_DIALOG_v1.md`](./CLOUD_VOICE_DIALOG_v1.md)**。本文保留历史讨论(`flight_intent_pending`、`turn.confirmation` 等备选),新实现请以该文为准。 > **状态**:协议设计稿,供云端与机端/翻译桥**对齐实现**。 > **基础协议**:`proto_version: "1.0"`,`transport_profile: "text_uplink"`(不变)。 > **与 FLIGHT_INTENT 关系**:结构化 `flight_intent` 仍遵守 [`FLIGHT_INTENT_SCHEMA_v1.md`](./FLIGHT_INTENT_SCHEMA_v1.md);本规范仅增加**执行前门控**与**补充消息类型**。 --- ## 1. 背景与目标 ### 1.1 问题 本地 **ASR** 易产生错字、漏字,直接把一句话交给大模型再**立即**下发飞控,会出现「用户本意与结构化指令不一致」的安全与体验问题。 ### 1.2 目标 | 场景 | 行为 | |------|------| | **闲聊** | 与现网一致:`routing === "chitchat"`,无确认门控。 | | **飞控** | 云端产出**合法** `flight_intent` 后,**先**通过 TTS 播报一段**简短理解反馈**,机端**不得**在此时执行机动;仅在用户**口头确认**后,才进入「可执行」状态;用户可**取消**;**超时**则作废并提示重说。 | ### 1.3 非目标 - 不在云端做 ASR(仍由机端 STT 出字)。 - 不改变 `flight_intent` 的 JSON Schema(v1)。 - 不强制所有产品打开本能力:由 **能力协商** 决定(见 §4)。 --- ## 2. 术语 | 术语 | 含义 | |------|------| | **提案轮(proposal turn)** | 用户说一句后,云端判定为飞控并返回结构化意图,但标记为「待确认」的一轮。 | | **门控(gate)** | 在该状态下,机端**禁止**把 `flight_intent` 交给执行器。 | | **确认轮(confirmation turn)** | 用户在超时窗口内,通过约定话术(或显式消息)完成确认/取消/超时通知的交互。 | | **可执行回执(approved)** | 云端明确告知:本回合的 `flight_intent` **已获准执行**。 | --- ## 3. 行为摘要(产品话术) 默认文案(可由云端配置或模板生成,机端**以 TTS 实际播放为准**展示给用户): 1. **提案播报**(大模型或模板):用一两句话概括将要执行的操作(需与 `flight_intent.summary` 语义一致,可略作口语化),并提示如何确认/取消。 - 示例模板:「理解为:{summary}。若正确请说「确认确认」,若要取消请说「取消取消」。」 2. **用户说「确认确认」**(及 §7 同义表达):云端下发**可执行**回执 + 简短 TTS(如「好的,开始执行」);机端**此时**再将 `flight_intent` 交给桥/PX4。 3. **用户说「取消取消」**(及 §7 同义表达):云端下发取消回执 + TTS「已取消指令,请重新下发指令」;**不**执行机动,清除待确认状态。 4. **超时**(默认 **10 秒**,可协商):云端下发超时回执 + TTS「未收到确认指令,请重新下发指令」;**不**执行机动,清除待确认状态。 > **注意**:「确认/取消」的识别应在**确认轮**内优先于二次飞控解析,避免把「确认确认」误判为新的一条飞控句(实现见 §6)。 --- ## 4. 能力协商(必做) 为避免破坏旧客户端,本扩展 **默认关闭**。仅在双方声明一致后启用。 ### 4.1 `session.start`(客户端 → 云端) 在 `client` 或 `client.capabilities` 中增加**可选**字段(二选一实现方式,团队定稿后只保留一种以免分叉): **方案 A(推荐,挂在 `client` 下)** ```json { "type": "session.start", "proto_version": "1.0", "transport_profile": "text_uplink", "session_id": "...", "client": { "device_id": "...", "flight_intent_confirm": { "enabled": true, "timeout_sec": 10, "confirm_phrases": ["确认确认", "确认"], "cancel_phrases": ["取消取消", "取消"] } } } ``` | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | `flight_intent_confirm.enabled` | `boolean` | 是 | `true` 表示要求门控流程。 | | `flight_intent_confirm.timeout_sec` | `number` | 否 | 默认 `10`;建议范围 `5–30`。 | | `flight_intent_confirm.confirm_phrases` | `string[]` | 否 | 机端 STT 可能输出多种说法;云端可用来做包含/模糊匹配。 | | `flight_intent_confirm.cancel_phrases` | `string[]` | 否 | 同上。 | **方案 B**:单开关 `client.capabilities.require_flight_intent_confirm: true`,超时与短语全集由 `session.ready` 返回(云端主控)。 ### 4.2 `session.ready`(云端 → 客户端) 在 `server_caps` 中声明云端是否接受并生效该扩展: ```json { "type": "session.ready", "server_caps": { "flight_intent_confirm": true, "flight_intent_confirm_timeout_sec": 10 } } ``` 若客户端 `enabled: true` 但服务端 `flight_intent_confirm: false`,**回退为即时模式**(与历史行为一致:收到 `routing: flight_intent` 即允许机端执行,具体以产品文档为准)。 --- ## 5. `routing` 与 `flight_intent_gate`(提案轮) 当门控启用且本轮解析结果为飞控意图时,云端 **不得** 直接使用 `routing: "flight_intent"` 表示「可执行」。 ### 5.1 新路由枚举值(建议) 在原有 `flight_intent` / `chitchat` / `error` 上**增加**: | `routing` | `flight_intent` | 机端行为 | |-----------|-------------------|----------| | `flight_intent_pending` | 非 null,与 Schema v1 一致 | **禁止执行**;仅播放本回合 TTS;进入「待确认」状态。 | | `flight_intent` | 非 null | **允许执行**(仅出现在确认通过之后,或门控未启用时的历史路径)。 | | `chitchat` | null | 不变。 | (若团队希望少改枚举,也可用单一 `flight_intent` + 下表 `gate`,见 §5.2 备选。) ### 5.2 备选:保留 `routing: flight_intent`,用门控对象区分 `dialog_result` 增加**可选**对象: ```json "flight_intent_gate": { "phase": "pending_confirm", "proposal_turn_id": "<与 dialog_result.turn_id 相同>", "timeout_sec": 10, "deadline_unix_ms": 1735689600000 } ``` - `phase: pending_confirm`:**禁止执行**。 - 确认通过后同一 `flight_intent` 再次下发时:`phase: approved` 或**省略** `flight_intent_gate`(表示可执行)。 > **建议**:新实现优先采用 **`flight_intent_pending`**,机端状态机更简单;备选方案便于在极小改动下渐进上线。 ### 5.3 `dialog_result` 其它字段(提案轮) - `tts_hint.speak_summary_or_reply`: 仍为 `true`。 - **播报文本**:优先使用模型生成的 **简短确认话术**(≤ 约 80 字为宜),字段建议显式提供,便于机端记日志: - **建议新增可选字段** `confirm_prompt_text: string`(与 TTS 内容一致或为其上游文案)。 - `flight_intent.summary` 仍为 Schema 必填摘要;**执行器不得仅用 summary 驱机**,规则不变。 ### 5.4 `turn.complete` 提案轮在 TTS 结束后仍发送 `turn.complete`(与现协议一致)。机端收到后进入 **监听确认** 子状态,计时 `timeout_sec`。 --- ## 6. 确认轮:推荐消息 `turn.confirmation` 避免把「确认确认」再走一轮完整 LLM 飞控解析,推荐增加**专用上行**类型(与 `turn.text` 平级): ### 6.1 客户端 → 云端 ```json { "type": "turn.confirmation", "proto_version": "1.0", "transport_profile": "text_uplink", "turn_id": "<本确认轮新 UUID>", "relates_to_turn_id": "<提案轮 turn_id>", "outcome": "confirm" | "cancel" | "timeout", "text": "确认确认" } ``` | 字段 | 说明 | |------|------| | `relates_to_turn_id` | 必须等于最近一次 **`flight_intent_pending`**(或带 `pending_confirm` 门控)的 `dialog_result.turn_id`。 | | `outcome` | `confirm`:用户已确认;`cancel`:用户取消;`timeout`:**机端计时到期**主动上报(无用户话术)。 | | `text` | 机端 STT 原文;`outcome: timeout` 时可为空字符串。 | **兼容路径**:若暂不实现 `turn.confirmation`,可约定在待确认状态下,机端仍发 `turn.text`,云端对**短句**做 **规则优先**:先匹配确认/取消短语,再进入 LLM;该路径易与新型飞控口令冲突,**仅作过渡**。 ### 6.2 云端 → 客户端(确认结果) 对 `outcome: confirm`: - `routing: "flight_intent"` - `flight_intent`: 与提案轮**字节级一致**的 JSON(或可接受:关键 `actions` 一致 + 同一 `trace_id`) - TTS:简短执行提示 对 `outcome: cancel`: - `routing: "chitchat"`(或 `routing: "flight_intent_aborted"` 若实现枚举扩展) - `chat_reply`: 如「已取消指令,请重新下发指令」 - `flight_intent`: null 对 `outcome: timeout`(或云端本地计时触发,见 §8): - 同取消,文案改为「未收到确认指令,请重新下发指令」 随后 `tts_audio_chunk*`,`turn.complete`。 --- ## 7. 短语与同义(匹配策略) 云端与机端应使用**同一套**短语表(以 `session.start` 可选覆盖为准)。建议默认: | 意图 | 默认短语示例 | |------|----------------| | 确认 | `确认确认`、`确认`、`是的`、`执行` | | 取消 | `取消取消`、`取消`、`不要`、`算了` | **ASR 容错**:可对 `text` 做规范化(去空格、标点)与**子串包含**;条件具备时可做编辑距离阈值(产品配置)。**禁止**把长句闲聊误判为确认(例如:仅当 `len(text) <= 20` 且匹配规则时才生效,阈值可配置)。 --- ## 8. 超时由谁计时 | 方案 | 说明 | |------|------| | **A(推荐)** | **机端计时**:到期发送 `turn.confirmation` + `outcome: timeout`。实现简单,与离线片段无关。 | | **B** | **云端计时**:提案后服务端 `sleep(timeout)` 推送结果;需在会话层维护任务,断开连接时要取消任务。 | 规范上 **A/B 等价对外语义**;实现任择其一,但须在 `session.ready` 或产品文档中注明。 --- ## 9. 与大模型的分工 - **提案轮**:LLM 仍输出严格 `flight_intent` JSON(内部解析),并额外生成**一句**用户可听懂的**拟执行说明**(不得替代 JSON)。 - **确认轮**:**无需**再跑完整意图模型;云端仅做规则路由 + 固定/模板 TTS。 - 若 `turn.text` 误入确认轮且未匹配确认/取消:产品可选两种之一并在文档中写死: - **严格**:忽略或提示「请先确认或取消上一条指令」; - **宽松**:取消待确认状态并当作新轮用户话重新走 LLM(风险:状态复杂,慎用)。 --- ## 10. 状态机(机端参考) ```mermaid stateDiagram-v2 [*] --> Idle Idle --> PendingConfirm: dialog_result routing=flight_intent_pending PendingConfirm --> Execute: turn.confirmation confirm PendingConfirm --> Idle: turn.confirmation cancel PendingConfirm --> Idle: turn.confirmation timeout Idle --> Idle: chitchat as today Execute --> Idle: after bridge accepts ``` **禁止**:在 `PendingConfirm` 下将提案中的 `flight_intent` 写入执行队列。 --- ## 11. 安全与一致性与 `trace_id` - 提案与批准两轮宜共用同一 `flight_intent.trace_id`(若提案有 `trace_id`),便于日志与桥侧去重。 - 桥侧可对「同一 `trace_id` 第二次可执行下发」做幂等;若缺少 `trace_id`,建议云端在提案轮生成 UUID。 --- ## 12. 版本与兼容 | 项目 | 约定 | |------|------| | 本文 | **CLOUD_VOICE_FLIGHT_CONFIRM v1**(可与主协议 1.0 并列声明) | | 旧客户端 | 不发 `flight_intent_confirm` → 云端只发 `routing: flight_intent` → 行为与上线前一致。 | | 新客户端 + 旧云端 | `session.ready` 无 `flight_intent_confirm` → 机端按即时执行或本地拒绝(产品定)。 | --- ## 13. 实现清单(云端 / 机端) **云端** - [ ] 解析 `session.start` 门控配置;`session.ready` 宣告能力。 - [ ] 飞控且门控开启 → `flight_intent_pending` + 生成 `confirm_prompt_text` / TTS。 - [ ] 处理 `turn.confirmation`(及可选 `turn.text` 过渡规则)。 - [ ] 维护 `relates_to_turn_id → pending payload`(会话内字典,连接断开清理)。 **机端** - [ ] 根据 `session.ready` 决定是否进入门控 FSM。 - [ ] 对 `flight_intent_pending` **不执行**。 - [ ] 计时;回传 `turn.confirmation`。 - [ ] 仅在 `routing: flight_intent`(且非 pending)时送桥执行。 --- ## 14. 参考文档 - [`CLOUD Voice Protocol v1`](./CLOUD_VOICE_PROTOCOL_v1_text_uplink.md) - [`FLIGHT_INTENT_SCHEMA_v1.md`](./FLIGHT_INTENT_SCHEMA_v1.md) - [`PROJECT_SUMMARY_AND_DEPLOYMENT.md`](./PROJECT_SUMMARY_AND_DEPLOYMENT.md) --- **文档版本**:2026-04-08;修订可递增副版本并保留「breaking changes」小节。