
MiniMind-O实时打断是如何实现的VAD驱动的近似双工交互全解析【免费下载链接】minimind-o️ A 0.1B Omni model trained from scratch, capable of listening, speaking, and seeing!项目地址: https://gitcode.com/gh_mirrors/mi/minimind-oMiniMind-O 是一个仅 0.1B 参数的端到端 Omni 模型支持文本、语音、图像输入与流式语音输出。它的实时打断barge-in机制并不复杂用 Silero VAD 以 64ms 为窗口持续监听麦克风一旦检测到模型正在说话 用户正在说话就立即中止当前生成、停止本地播放让系统从 speaking 状态退回 listening 状态——整个过程无需语义理解纯工程闭环延迟极低。这就是所谓近似双工模型在说话的同时始终听得见你。为什么能被打断是语音助手的关键体验传统语音助手是回合制的你说完 → 等模型答完 → 再轮到你。这种模式下你无法中途改口、追问或说停。真正自然的对话要求双工能力即双方可以同时收发语音。完整双工如 Moshi 的内外双通路实现复杂而 MiniMind-O 选择了一条更务实的路线听VAD 始终在线持续接收麦克风音频说Talker 流式生成 24 kHz 语音并即时播放打断两者冲突时用户插话立刻 abort 生成官方实时交互时序图完整展示了这一闭环上图下半部分 Barge-in turn-taking 正是本文要拆解的核心用户第 1 句说完后进入 silence模型 prefill 并开始 reply当用户在模型说话期间再次开口speech_start系统触发 interrupt、abort 当前回复随后重新 prefill 生成新回复。架构定位VAD 是零耦合的纯工程层在 model/model_omni.py 中实时打断相关代码被明确标注为与模型本体零耦合纯工程层SileroVADmodel/model_omni.py用 ONNX Runtime 加载 model/vad/silero_vad.onnx输入 16 kHz 音频块输出当前块是语音的概率RealtimeSessionmodel/model_omni.py状态机管理 listening / speaking / generating / interrupt 四个标志位并缓存用户语音模型本体的 Thinker–Talker 双路径架构Thinker 负责语义理解Talker 通过 MTP 预测 8 层 Mimi codes见下图打断逻辑完全发生在模型之外实时打断是如何实现的4 个关键步骤① 以 64ms 小窗口持续喂给 VAD浏览器端把麦克风音频重采样到 16 kHz按 4096 采样256ms打包成 Int16 二进制帧通过 WebSocket 发送到服务端/ws/realtime路由。服务端RealtimeSession.push_chunk再把数据切成1024 采样 ≈ 64ms的小窗口逐块跑 VAD概率 0.8threshold→ 判定为语音否则视为静音小窗口是低延迟打断的关键——用户开口后最多 ~64ms 就能被检测到。② 环形缓冲保住语音开头的每一毫秒人在开口瞬间第一两个窗口往往还没超过阈值音量渐强。RealtimeSession用一个 1 帧的ring环形缓冲记住开口前的最后 64ms 音频一旦判定开始说话就把它拼回缓冲头部self.buffer self.ring self.buffer。这避免了每个句子的第一个音节被切掉。③ 打断判定generating × speaking interrupt打断逻辑就一行核心判断model/model_omni.py如果self.generating and self.speaking模型正在生成语音且用户正在说话→ 置interrupt True返回interrupt服务端生成循环在每个 token 步调用poll_interrupt()一旦发现队列里有音频块触发打断立即break退出run_generate不再 flush 剩余音频并通过{type: done, interrupted: True}通知前端。④ 语音结束判定800ms 静音才交棒反过来用户说完话时VAD 需要连续800msmin_silence_ms静音才返回speech_end避免句内自然停顿被误判为说完同时tail_silence会把尾部冗余静音从缓冲中裁掉让送入模型的音频更紧凑。之后RealtimeSession.get_audio()交出完整语音进入 prefill–reply 流程。前端配合打断听起来像真的打断只靠服务端 break 是不够的——扬声器里已经播出的声音必须也立刻停掉。前端 webui/web_demo.html 用一条 WebSocket 消息流串起完整状态机服务端消息前端动作vad speakingtrue立即stopPcm()停止助手播放切到 listening 状态generating进入 thinking清空本轮缓冲pcm追加播放 24 kHz 语音块done interruptedtrue再次stopPcm()彻底掐断残留声音配合 UI 上的 idle → listening → thinking → speaking 四态切换用户能清晰感受到一开口它就闭嘴了。近似双工的另一半低延迟流式语音打断之所以能无缝还因为语音链路本身够快TTFT ≈ 140ms / TTFA ≈ 260ms见实时交互时序图上半场文本 token 一边生成Talker 一边通过 MTP 延迟调度7补齐 8 层 Mimi codesMimi 解码器按4 帧约 320ms一小块增量解码出波形重叠 2 帧缓解块边界断裂播放不必等回答结束可调参数与当前局限想调优打断体验主要动这几个参数threshold 0.8model/model_omni.pyVAD 语音概率阈值调高更不容易误打断调低更灵敏min_speech_ms 128/min_silence_ms 800最短语音 / 判停静音时长--audio_chunk_frameswebui/web_demo.py播放块大小4 为低延迟默认值播放卡顿可调大到 8/12需要说明的是当前打断检测仍是简单 VAD 阈值还谈不上语义级打断——模型不会判断用户这句话是不是冲自己说的背景人声也可能触发 abort。这正是官方在实时交互章节中承认的改进方向。但就工程闭环而言从 speaking 退回 listening 再处理下一轮输入的路径已经完整跑通这也是理解 Moshi、Mini-Omni 等双工系统前一个足够透明、可以逐行读懂的基线。【免费下载链接】minimind-o️ A 0.1B Omni model trained from scratch, capable of listening, speaking, and seeing!项目地址: https://gitcode.com/gh_mirrors/mi/minimind-o创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考