DroneMind/voicellmcloud/docs/CLOUD_VOICE_FLIGHT_CONFIRM_v1.md
2026-04-14 10:08:41 +08:00

302 lines
13 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.

# 飞控意图「播报—确认—执行」扩展规范 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 Schemav1
- 不强制所有产品打开本能力:由 **能力协商** 决定(见 §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`;建议范围 `530`。 |
| `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」小节。