本地语音 AI 助手技术方案:基于 MLX 与 Qwen 实现

2026-09-16 📁 技术方案

本文基于 Sandeep Aggarwal 的 Jarvis 项目 整理为技术方案文档。

1. 概述与目标

1.1 项目背景

需要构建一个完全运行在本地 Mac 上的语音 AI 助手,具备持续聆听、唤醒词激活、任务执行和打断处理能力。核心约束条件为:

1.2 运行环境

项目规格
硬件MacBook Air M2, 24 GB 统一内存
操作系统macOS (Apple Silicon)
推理框架MLX (Apple 机器学习框架)
语言模型Qwen3.5-4B-MLX-4bit
编程语言Python 3 (asyncio)

2. 系统架构

2.1 架构总览

系统由 7 个核心组件构成,通过 Python asyncio 事件循环串联为流式管线:

架构图:0916-1365294-d3a110-arch.html(独立 HTML 文件,浏览器打开可查看完整架构图并导出 PNG/PDF)

2.2 组件职责

组件职责关键技术
WakeWordDetector监听唤醒词 “Jarvis”,触发激活本地关键词检测
SpeechListener持续采集音频,执行 AEC 和 VADAEC: 内置音频运行时;VAD: 静音/噪声过滤
STT Engine将语音实时转写为文字RealtimeSTT + faster-whisper
TaskManager管理任务队列、优先级、取消令牌asyncio 队列 + cancellation tokens
InterruptionHandler对新语音进行分类,决定打断策略5 种动作:IGNORE / QUEUE / CANCEL_AND_RUN / MERGE / MODIFY_QUEUED
LLM Engine理解指令、选择工具、生成响应MLX + Qwen3.5-4B-MLX-4bit
TTS Worker将文本响应合成为语音输出专用 TTS 工作线程

2.3 数据流

麦克风输入
  → SpeechListener(AEC 消除回声 → VAD 检测语音段)
    → STT Engine(语音 → 文本)
      → TaskManager(入队 / 打断判定)
        → LLM Engine(理解意图 → 工具调用 → 生成回复)
          → TTS Worker(文本 → 语音波形)
            → 扬声器输出

打断处理为并行路径:用户新语音被 SpeechListener 捕获后,InterruptionHandler 根据当前任务状态决定合并、取消、排队或忽略。

3. 核心组件设计

3.1 LLM 引擎

模型选型

在 24 GB M2 MacBook Air 上的测试结论:

候选模型判定原因
Qwen3.5-4B-MLX-4bit选用速度与能力的最佳平衡,约 30 token/s
更大参数模型不选用显存不足,响应延迟不可接受
更小模型不选用理解能力不足,无法可靠完成任务

部署命令

mlx_lm.server --model "mlx-community/Qwen3.5-4B-MLX-4bit" \
  --max-tokens 20000 \
  --chat-template-args '{"enable_thinking":false}'

关键参数说明:

性能指标

系统提示词设计

语音助手场景下,系统提示词应极致精简。每个多余 token 都会增加首 token 延迟。

You are Jarvis, a voice-controlled personal assistant.
Answer using tools. Call speak_async once with the final response.

资源约束

3.2 音频管线

声学回声消除(AEC)

问题:扬声器输出的助手语音被麦克风重新捕获,形成自激反馈循环。

方案:使用操作系统音频运行时内置的 AEC 模块。

配置:

参数值
采样率16,000 Hz
帧大小160
流延迟10 ms

语音活动检测(VAD)

目的:区分有效语音与静音/背景噪声,避免将噪声送入 STT 管线造成资源浪费和错误转录。

机制:检测语音段的起止边界,仅在检测到有效语音时触发 STT。

语音转文字(STT)

现状:不存在开箱即用、完美无缺的免费本地 STT 模型。

选型:RealtimeSTT(封装 faster-whisper),在准确性和推理速度之间取得了可接受的平衡。

实践建议:较长的自然语句转录准确率显著高于短促短语。例如:

3.3 任务管理与中断处理

中断处理模型

语音助手区别于"录音机"式逐条执行的关键能力。当用户在执行中发出新指令时,系统必须判定新指令的意图。

五种中断动作:

动作触发条件系统行为
IGNORE识别为背景闲聊丢弃,继续当前任务
QUEUE独立的新请求追加到待处理队列
CANCEL_AND_RUN用户明确要求切换取消当前任务,立即执行新任务
MERGE修改当前请求的参数更新当前任务上下文,继续执行
MODIFY_QUEUED编辑队列中的等待任务直接修改队列中指定任务的参数

实现机制:

典型交互场景

用户: “帮我找几家德里的好餐厅。”
  → TaskManager: 创建任务 T1,状态 RUNNING
  → LLM: 开始搜索工具调用...

用户: “算了,改成孟买吧。”
  → SpeechListener: 捕获新语音
  → STT: 转写为文本
  → InterruptionHandler: 分类为 MERGE
  → TaskManager: 向 T1 发送取消信号,创建新任务 T2(孟买 + 好餐厅)
    → LLM: 重新执行

3.4 开发方法论

慢速 LLM 的开发价值

开发阶段使用较慢的模型反直觉地有利于系统质量:

4. 关键设计决策与权衡

决策选择替代方案权衡
推理框架MLXllama.cpp, OllamaApple Silicon 原生优化,性能最优
模型Qwen3.5-4B-4bitLlama 3, Mistral4B 在 24GB M2 上速度与能力的平衡点
thinking 模式禁用启用牺牲复杂推理能力换取低延迟
STT 方案RealtimeSTTWhisperKit, 云端 API实时性优先,接受准确率非最优
系统提示词极简 2 句详细角色描述牺牲角色丰富度换取更低延迟
架构模式单体 asyncio 进程微服务 / 多进程简化部署,但单点故障风险

5. 性能指标

指标数值备注
LLM 推理速度~30 token/sM2, 24GB, Qwen3.5-4B-4bit
STT 实时性实时流式转录
端到端延迟< 2 秒含语音采集到 TTS 输出
内存占用< 20 GB含 MLX 服务器进程

6. 依赖与参考资源

资源用途
SandeepAggarwal/Jarvis参考实现源码
ml-explore/mlxApple Silicon 机器学习框架
mlx-community/Qwen3.5-4B-MLX-4bit量化模型
ml-explore/mlx-examplesmlx_lm.server 部署文档
KoljaB/RealtimeSTT实时语音转文字库

© 2026 Hot Ingest