302 lines
13 KiB
Markdown
302 lines
13 KiB
Markdown
# 飞控意图「播报—确认—执行」扩展规范 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」小节。
|