# 机端改造协议 — 「未唤醒不上云、不按量浪费」v1 本文档约定**机端**在与 `voicellmcloud` 对接时,如何满足产品原则: - **未唤醒**:不得触发**云端实时语音识别(Fun-ASR)**计费链路。 - **不按量浪费**:不在无业务需要时发送 `turn.audio.*`、不长期霸占 `turn.audio.start` 而不 `end`。 服务端**不实现**唤醒词校验;是否合规完全由**机端发送时机**保证。底层消息格式见 [`CLOUD_VOICE_PROTOCOL_pcm_asr_uplink_v1.md`](./CLOUD_VOICE_PROTOCOL_pcm_asr_uplink_v1.md) 与 [`API_SPECIFICATION.md`](./API_SPECIFICATION.md)。 --- ## 1. 术语:什么算「上云 ASR、会按量」 | 机端动作 | 服务端行为 | 计费/按量含义(以阿里云侧为准) | |----------|------------|----------------------------------| | 发送 **`turn.audio.start` → `chunk*` → `turn.audio.end`**(`pcm_asr_uplink`) | 建立 Fun-ASR 会话并完成一轮识别,再进 LLM/TTS | **视为使用云端 ASR**,应按厂商规则计费 | | 仅发送 **`turn.text`**(`text_uplink`) | 不调 Fun-ASR,直接 LLM/TTS | **不产生**本服务内的 Fun-ASR 调用 | | **`session.start` 本身** | 会话建立 | 不产生 ASR;仅有连接与后续消息 | **结论**:「未唤醒不上云」在工程上落实为:**未通过机端唤醒门闩前,不得发出完整一轮 `turn.audio.*`(至少不得发出可触发服务端 `Recognition.start` 的 `turn.audio.start`)。** --- ## 2. 两种合规模式(二选一或组合策略) ### 模式 A — 全程 `text_uplink`(零云端 ASR) - `session.start.transport_profile` = **`text_uplink`**。 - 唤醒词检测、指令句获取均在**机端**完成(本地 STT 或其它)。 - 仅在与云端对话时发送 **`turn.text`**。 - **适用**:不要求 Fun-ASR 质量、或本地 STT 已够用。 **合规要点**:在机端逻辑中,与现网一致 — **未命中唤醒**则 **不**将用户话投递 `command_queue` / **不**调用 `run_turn`,自然也不会发 `turn.text`。 --- ### 模式 B — `pcm_asr_uplink`,但「仅唤醒通过后再推音频」 - `session.start.transport_profile` = **`pcm_asr_uplink`**(与 [`CLOUD_VOICE_PROTOCOL_pcm_asr_uplink_v1.md`](./CLOUD_VOICE_PROTOCOL_pcm_asr_uplink_v1.md) 一致)。 - **禁止**:设备上电后、尚未通过唤醒检测时,对环境声做「习惯性」或「连续」`turn.audio.start`(例如每段 VAD 都上行)。 - **允许**:在机端状态机判定 **已唤醒且需要云端识别本轮用户话** 时,再对**本轮**语音: 1. 生成唯一 `turn_id`; 2. `turn.audio.start`; 3. 仅对本句有效 PCM 发送 `turn.audio.chunk`; 4. `turn.audio.end`。 **推荐实现顺序(与典型唤醒流程对齐)**: 1. **麦克风 → VAD/端点** 在机端切出「一句话」音频(或流式缓冲仅保留在 RAM,**不上传**)。 2. **可选 — 本地快速门闩**:用**本地 STT 或唤醒专用逻辑**判断本条是否含唤醒词、是否进入「指令/对话」状态(与贵司 `WakeWordDetector`、`_takeoff_only_command_worker` 阶段一致)。 3. **仅当**上述状态要求「本轮必须云端 Fun-ASR」时,再将**同一句** PCM 按 `turn.audio.*` 发送;否则**不发** `turn.audio.start`。 4. 若本轮仅需大模型、且已有可靠本地转写,可不走 ASR,改发 **`turn.text`**(`pcm_asr_uplink` 会话下仍允许调试/回退,见 pcm 协议 §5)。 **混合策略(质量与计费平衡)**:会话仍为 `pcm_asr_uplink`,但日常**只用** `turn.text`(本地 STT);仅在唤醒后、本地识别质量差或配置开关打开时,对**该轮**再发 `turn.audio.*`。 --- ## 3. 机端状态机约束(规范性) 下列阶段中 **不得** 发起新的 `turn.audio.start`(模式 B): - 用户话尚未通过**唤醒词检测**(对标:未命中 `WakeWordDetector.detect`)。 - 处于**问候播报 / 滴声等待**等阶段、且业务规定「只听确认、不新开识别轮」时(对标:`GREETING_WAIT` 等 — 以贵司 `main_app` 为准)。 - 上一轮 `turn.audio.start` 已发但**未**收到对应 `turn.complete` / 未 `end` 收尾前,**不得**并行第二路 `turn.audio.start`(服务端亦以 `pipeline_lock` 与其它检查约束并发)。 **允许**在**飞控口头确认窗**等业务阶段发送 `turn.text` 或 `turn.audio.*`,但必须仍遵循「每轮一个 `turn_id`、顺序完整」;若确认窗只吃短答,优先 `turn.text` 可降低 ASR 成本。 --- ## 4. 自检清单(交付前) - [ ] `pcm_asr_uplink` 下,**静默/未唤醒**时抓包:**无** `turn.audio.start`。 - [ ] 唤醒后**第一句**上云:有完整 `start → chunk* → end`,且 `turn_id` 与下行 `dialog_result` / `turn.complete` 一致。 - [ ] 误触麦或噪声段:机端 VAD 输出若**未过唤醒**,**不得**为降噪而「先试一发云端 ASR」。 - [ ] 日志可区分:**本地门闩拒绝** vs **已发云 ASR**(便于核对账单)。 --- ## 5. 与服务端能力的关系 - 服务端**信任**机端:收到合法 `turn.audio.end` 即认为本轮 ASR 结束并进入 LLM。 - 若产品将来需要**服务端强制唤醒词**,需另行增加协议字段或服务端策略;**当前版本无此能力**。 --- ## 6. 参考 - [`CLOUD_VOICE_PROTOCOL_pcm_asr_uplink_v1.md`](./CLOUD_VOICE_PROTOCOL_pcm_asr_uplink_v1.md) — PCM 上行帧格式与时序 - [`API_SPECIFICATION.md`](./API_SPECIFICATION.md) — 总接口说明 - [`CLOUD_VOICE_ASSISTANT_SESSION_v1.md`](./CLOUD_VOICE_ASSISTANT_SESSION_v1.md) — 唤醒后多轮「滴声—断句—上云—播报—分支」总方案(与小爱类 UX 对齐) - 机端参考实现目录:`Client/voice_drone_assistant/`(唤醒与命令线程:`voice_drone/main_app.py`、`voice_drone/core/wake_word.py`、`voice_drone/core/recognizer.py`)