唤醒检测批量通信
本次优化减少主进程与常驻检测进程之间的通信。模型仍按原始帧顺序运行;不改变模型、阈值、声纹竞争规则、前端采集或 ASR 回放。Python worker 协议版本为 1,与定制 wheel 的版本检查独立,不要求更新 wheel。
调度与归属
| 参数 | 行为 |
|---|---|
| 目标批量 | 640 个 16kHz 采样,即 40ms;不切割原始帧 |
| 主动等待 | 最早帧首次入队后最多 30ms,新帧不刷新期限 |
| 大帧 | 512 采样及以上直接处理,仍排在已有音频之后 |
| 帧数上限 | 每批最多 16 帧 |
| 检测期限 | 沿用 detector 的批次预算,当前为 2 秒 |
| 容量 | 排队与处理中副本共同计入原有 wake_queue_bytes |
唯一的 _wake_task 在锁内领取音频,在锁外等待事件或执行检测。准备期间保存首次入队时间;不同 generation、standby_epoch 或不连续帧不合批。30ms 仅限制主动凑批,不保证包含调度、积压和推理的端到端延迟。
worker 在首次命中时停止,返回 WakeWordBatchResult(consumed_frames, detection)。无命中必须确认完整批次。命中范围不能超过已处理音频,关键词起点允许早于本批。单帧 feed() 包装批量入口,共享单次调用保护。
命中被接受后,未处理检测副本退出,完整原始音频继续走现有回放。命中被拒绝且仍属于同一待机轮次时,尾部优先续接,保留入队年龄及原批次检测期限。通信失败或处理确认非法时不重传。关麦、激活、轮次切换和失败唤醒等待任务;迟到结果不能再次激活。
非法确认和期限耗尽使用原不可用通知并有界关闭 detector。自动关闭与会话取消交错时,嵌套 finally 仍清理在途计数和任务引用。未完成资源关闭留给会话关闭路径处理,不把失败伪装为成功。
启用、回退与诊断
VoiceSessionActivationRuntimeConfig.wake_batching_enabled 默认为 true。对照或回退可在创建新 runtime 时设为 false,恢复单帧通信;这是内部配置,不新增用户设置。运行中不切换策略,协议更新或回退需要新 worker。禁用组批仍使用当前批量协议的单帧包装,不试探旧协议并重发。
NEKO_WAKE_WORD_DIAGNOSTICS=1 输出批次帧数、采样数、flush 原因、排队时间、超过主动等待期限的时间、通信耗时、处理确认及容量。scheduling_overrun_ms 也包含积压等待,不能解释为纯操作系统调度延迟。不新增原始音频、关键词或转写文本日志。
评估入口
新增 scripts/wake_word/evaluate_wake_runtime.py,与原离线模型评估脚本分开。它使用正式 activation runtime、controller 和真实检测子进程,通过本地 sink 接收回放,不连接云端 ASR。示例:
uv run python scripts/wake_word/evaluate_wake_runtime.py --model-dir <模型目录> --wav <16kHz单声道录音.wav> --source recording --paced --frame-samples 160 --repeats 2 --output <报告.json>用 --frame-samples 512 测试 32ms;可传多个采样数测试循环不规则分包。合成输入必须标为 --source synthetic。无 --paced 时只评估积压吞吐,不能当作实时响应延迟。
每个模式使用新会话,成对轮换 baseline/batch 顺序。报告分别记录尝试与完成的通信次数、确认处理帧数、主进程与子进程 CPU、采样 RSS、输入迟到、命中与激活时刻、状态及轮次、实际回放范围和摘要。指标采集失败仅标记不可用,不改变检测结果。
为隔离 KWS,脚本使用就绪声纹 stub 并发送 voice_activity=false。激活期间停止 KWS,但长录音会依照真实空闲策略重新待机;报告保留这些轮次,不宣称整段始终处于待机。CPU 不含准备和关闭;RSS 为采样值而非操作系统峰值;没有关键词结束标注时,音频起点到激活的时间不是关键词结束后的响应延迟。
本机定向验证(2026-09-24)
213 个相关测试通过,覆盖批量协议、确定性调度、确认与尾部、取消清理、容量和激活生命周期,以及独立 ASR/原生语音共用 Core 入口的完整回放。未跑全量测试。测试用可辨认 PCM 检查实际内容、顺序和一次交付。
真实模型经正式 runtime 的本机测量如下;每行环境声/静音为单组对照,不能视为稳定性能保证:
| 输入 | 单帧 → 组批通信次数 | 合计 CPU 时间 | 结果 |
|---|---|---|---|
| 34.03s 真实环境声,10ms 分包 | 3403 → 1074 | 2.391s → 1.844s,约降 23% | 确认处理帧数相同,无命中,均保持待机 |
| 20s 合成静音,10ms 分包 | 2000 → 633 | 1.109s → 1.016s,约降 8% | 确认处理帧数相同,无命中 |
| 真实唤醒短录音,10ms,两组 | 每组 159 → 50/51 | 录音过短,不据此推断 CPU 收益 | 均激活一次,模型采样范围一致 |
| 真实唤醒加指令,32ms | 40 → 40 | 不作收益承诺 | 均激活一次,模型采样范围一致 |
| 真实短唤醒词,489/490/160 采样循环 | 67 → 67 | 不作收益承诺 | 均激活一次,模型采样范围一致 |
环境声/静音中 worker 采样 RSS 约 112~113MB,没有证明内存下降。Windows 调度使不少批次不足四帧;模型仍处理全部原始帧。本轮结果不支持把此前原型的 37%~42% 推广为正式实现或整个后端的固定降幅。
网页、Electron、真实麦克风两条路由、游戏高负载及更大录音集的唤醒成功率和 P50/P95 延迟仍待人工验收。自动化路由回放通过不等于这些真实设备效果已验证。音频和原始测量报告保留在仓库外,未提交用户录音。
回归报告 / Regression Report
此前待机检测逐帧进行 IPC;现在将可合并帧批量发送,保留逐帧模型处理和原始回放,以降低通信开销。核心改动限于 activation 契约、Sherpa worker 和 activation runtime,未修改 Core 运行代码、声纹/唤醒阈值或端点策略。
Review 重点是命中后未处理尾部的唯一归属、同批次期限不刷新、队列与在途计数、取消期间清理,以及声纹和唤醒异步结果的竞争。新增主动等待可能改变两类检测结果到达顺序;保持既有先结算规则,不承诺竞争结果完全相同。实际 CPU 收益、误唤醒率和延迟仍以扩展实测为准。
