关键要点
- 离线语音助手栈:whisper.cpp → Ollama LLM → Piper TTS,由Python脚本编排。 三个组件均免费开源,安装后完全离线运行。
- 台式机GPU(RTX 3060 12 GB)端到端延迟:1–2秒。 与Alexa和Google Assistant相当。使用Whisper small和Llama 3.1 8B可达到此结果。
- Raspberry Pi 5(8 GB)可用但速度较慢。 使用Phi-3 mini 3.8B和Whisper base时延迟为5–8秒。适合免手操作查询,不适合对话式交互。
- Mac Mini M5(24 GB统一内存)是质量与静音的最佳平衡。 空闲时无风扇静音运行,Llama 3.1 8B约50 token/秒,Whisper large-v3通过Metal实现10倍实时处理速度。延迟1–1.5秒。
- 添加唤醒词避免持续运行Whisper。 OpenWakeWord(MIT,免费,支持自定义唤醒词)是最佳开源选项。Porcupine(Picovoice)个人使用免费套餐支持"Hey Jarvis"等预置唤醒词。
- 静音时Whisper幻觉是最常见的流水线bug。 Whisper会将静音转写为填充词或训练数据中的引用。在将音频传给Whisper前设置最小音频能量阈值,并在whisper.cpp中配置
--no-speech-threshold 0.6。 - 此配置运行时产生零网络流量。 组装完成后用Wireshark验证。音频、转写结果和LLM查询均不离开本机。
快速事实
- STT层: whisper.cpp(Apple Silicon和嵌入式设备最佳选择)或faster-whisper(NVIDIA GPU Python流水线最佳选择)。
- LLM层: Ollama + Llama 3.1 8B(推荐)、Phi-4(更轻量,质量好)或Mistral 7B(与Llama 3.1 8B质量相当)。
- TTS层: Piper(最快,纯CPU,Pi上实时运行)、Coqui TTS(质量更好,需要GPU)。
- 唤醒词选项: OpenWakeWord(MIT,完全离线)、Porcupine(免费套餐,1个自定义唤醒词)。
- 最低硬件: Raspberry Pi 5(8 GB RAM,~$100)延迟5–8秒。
- 推荐硬件: Mac Mini M5 24 GB(~$600)或RTX 3060 12 GB台式机(~$800)延迟1–2秒。
- 语言支持: Whisper支持99种语言。Piper提供20+语言语音包。LLM语言性能因模型而异。
为何构建本地语音助手?
Alexa、Siri和Google Assistant都通过云服务器路由您的语音 — 您的音频由服务商转写、处理并记录。本地语音助手在您的硬件上完成所有处理。
- 隐私: 音频不离开您的家。无唤醒词音频存储在云端。服务器上无会话历史。对医疗工作者、律师、记者和任何有敏感工作的人至关重要。
- 成本: 无订阅费。Alexa+每月$4.99,Google One每月$1.99–$9.99。本地助手只有一次性硬件成本。
- 自定义: 选择唤醒词、个性、系统提示词和功能。添加自定义命令,连接本地家庭自动化系统,与本地API集成。
- 离线运行: 无需网络即可工作。停电(配UPS)+ 断网:本地助手仍然运行。适用于山间小屋、偏远地区和应急准备。
- 放弃的功能: 网络搜索、与专有云的智能家居集成、与云服务的日历同步,以及让Alexa/Siri在边缘情况下表现流畅的多年RLHF调优积累。
三层架构
离线语音助手由三个独立层组成,通过Python编排器连接。
📍 简单一句话
麦克风 → whisper.cpp(STT)→ Ollama LLM → Piper TTS → 扬声器:50行Python编排器连接的三个独立组件。
💬 简单来说
类似电话接力:您说话,Whisper记录文字,LLM想出回复并写下来,Piper通过扬声器朗读。每个步骤是独立程序,Python在它们之间传递文本。
- 第1层 — STT(语音识别): whisper.cpp或faster-whisper。将麦克风音频转换为文本。离线运行,无需网络。
- 第2层 — LLM(推理): 提供Llama 3.1 8B、Phi-4或Mistral 7B的Ollama。接收转写文本 + 会话历史 + 系统提示词并生成响应。离线运行,无需网络。
- 第3层 — TTS(文字转语音): Piper或Coqui TTS。将LLM响应文本转换为音频并通过扬声器播放。离线运行,无需网络。
- 编排器: 连接三者的Python脚本:从麦克风采集音频 → 传给STT → 将转写结果传给LLM → 将响应传给TTS → 播放音频。
- 可选唤醒词: 持续运行的轻量检测器(OpenWakeWord、Porcupine),仅在检测到唤醒词时触发完整流水线。没有它,编排器将持续运行whisper.cpp — 消耗更多CPU/GPU并产生更多误触发。
硬件要求
按延迟和成本排列的四个硬件配置,均支持完整的Whisper + LLM + Piper栈。
| 配置 | STT模型 | LLM模型 | TTS | 总费用 | 端到端延迟 |
|---|---|---|---|---|---|
| Raspberry Pi 5(8 GB) | Whisper base(CPU) | Phi-3 mini 3.8B Q4 | Piper(CPU) | ~$100 | 5–8秒 |
| 迷你主机(16 GB RAM) | Whisper small(CPU) | Llama 3.1 8B Q4(CPU) | Piper(CPU) | ~$300 | 3–5秒 |
| 台式机(RTX 3060 12 GB) | Whisper large-v3(GPU) | Llama 3.1 8B Q4(GPU) | Piper或Coqui(CPU/GPU) | ~$800 | 1–2秒 |
| Mac Mini M5(24 GB) | Whisper large-v3(Metal) | Llama 3.1 8B(Metal) | Piper(CPU) | ~$600 | 1–1.5秒 |
💡Tip: Mac Mini M5是实现2秒以内延迟最具成本效益的选择。空闲时无风扇静音,可在统一内存上同时运行Whisper Metal和Ollama,无需管理NVIDIA驱动。
步骤1:设置语音识别
Apple Silicon和嵌入式硬件安装whisper.cpp;NVIDIA GPU配置安装faster-whisper。
- 安装whisper.cpp:
git clone https://github.com/ggerganov/whisper.cpp && cd whisper.cpp && make -j4 - 下载模型:
bash ./models/download-ggml-model.sh small(small = WER 3.4%,速度与精度的良好平衡) - 测试转写:
./main -m models/ggml-small.bin -f test.wav— 应产生准确的文本输出。 - 在Mac上启用Metal:
make -j4 WHISPER_COREML=1然后bash models/generate-coreml-model.sh small - Whisper模型选择: Raspberry Pi用base(1 GB RAM,低延迟),均衡选择用small(2 GB RAM,WER 3.4%),最高精度用large-v3(需10 GB显存/内存)。
- 配置静音抑制: 添加
--no-speech-threshold 0.6 --suppress-blank标志,避免将静音转写为幻觉文本。 - 用10秒录音测试: 录制测试短语,验证Whisper准确转写。检查噪音和安静语音两种条件。
步骤2:设置本地LLM
安装Ollama并拉取LLM模型。配置语音助手行为的系统提示词 — 简短响应、无Markdown、合适的个性。
- 安装Ollama: 从ollama.com下载。支持macOS、Linux和Windows。2分钟内完成安装。
- 拉取模型:
ollama pull llama3.1:8b(推荐)或ollama pull phi4(更轻量,适合16 GB RAM系统)。 - 测试:
ollama run llama3.1:8b "What is the capital of France?"— 验证响应准确且快速。 - 语音系统提示词: 使用简短、指令性的系统提示词:"你是一个有用的语音助手。保持回答简洁 — 最多1–3句话。不要使用列表、Markdown或格式。像对话一样自然地说话。"
- 温度: 将温度设置为0.3–0.5以获得更可预测、更符合事实的响应。较低的温度减少语音响应中的幻觉。
- 最大token数: 用
--num-predict 150限制响应长度 — 长响应增加TTS时间,在语音交互中显得不自然。
步骤3:设置文字转语音
在所有硬件配置上安装Piper。包括Raspberry Pi在内的CPU上实时运行,提供20+语言语音包,无需GPU。
- 安装Piper:
pip install piper-tts - 下载语音:
piper --download-dir voices --update-voices --voice en_US-lessac-medium(或从Hugging Face的Piper voices页面获取任意语音)。 - 测试:
echo "Hello, how can I help you today?" | piper --model voices/en_US-lessac-medium.onnx --output-raw | aplay -r 22050 -f S16_LE -c 1 - 音频输出: Piper输出原始PCM或WAV。管道至
aplay(Linux)、afplay(Mac),或使用sounddevicePython库实现跨平台播放。 - 替代方案(更高质量): Coqui VITS后端 — 安装
pip install TTS,使用tts --model_name tts_models/en/vctk/vits。需要约2 GB显存;比Piper慢2–3倍但音质明显更自然。 - 语音选择: 语音助手选择中等质量语音而非高质量 — 中等质量速度更快,通过扬声器播放时差异可忽略不计。
步骤4:连接流水线
Python编排器连接STT → LLM → TTS。脚本从麦克风采集音频,用Whisper转写,将文本发送给Ollama,用Piper将响应转换为语音并播放。
#!/usr/bin/env python3
"""Minimal offline voice assistant: Whisper STT + Ollama LLM + Piper TTS."""
import subprocess
import tempfile
import sounddevice as sd
import soundfile as sf
import numpy as np
import requests
import json
SAMPLE_RATE = 16000
RECORD_SECONDS = 5
OLLAMA_URL = "http://localhost:11434/api/generate"
WHISPER_BIN = "./whisper.cpp/main"
WHISPER_MODEL = "./whisper.cpp/models/ggml-small.bin"
PIPER_BIN = "piper"
PIPER_VOICE = "voices/en_US-lessac-medium.onnx"
SYSTEM_PROMPT = (
"You are a helpful voice assistant. Keep responses to 1-3 sentences. "
"Never use markdown, bullet points, or formatting. Speak naturally."
)
conversation_history = []
def record_audio(seconds: int = RECORD_SECONDS) -> np.ndarray:
print("Listening...")
audio = sd.rec(int(seconds * SAMPLE_RATE), samplerate=SAMPLE_RATE, channels=1, dtype="int16")
sd.wait()
return audio
def transcribe(audio: np.ndarray) -> str:
with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as f:
sf.write(f.name, audio, SAMPLE_RATE)
result = subprocess.run(
[WHISPER_BIN, "-m", WHISPER_MODEL, "-f", f.name, "--no-timestamps", "--no-prints"],
capture_output=True, text=True
)
return result.stdout.strip()
def ask_llm(text: str) -> str:
conversation_history.append({"role": "user", "content": text})
response = requests.post(OLLAMA_URL, json={
"model": "llama3.1:8b",
"system": SYSTEM_PROMPT,
"messages": conversation_history,
"stream": False,
})
reply = response.json()["message"]["content"]
conversation_history.append({"role": "assistant", "content": reply})
return reply
def speak(text: str) -> None:
with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as f:
subprocess.run(
f'echo "{text}" | {PIPER_BIN} --model {PIPER_VOICE} --output_file {f.name}',
shell=True, check=True
)
data, sr = sf.read(f.name)
sd.play(data, sr)
sd.wait()
def main():
print("Voice assistant ready. Press Ctrl+C to stop.")
while True:
audio = record_audio()
transcript = transcribe(audio)
if not transcript or len(transcript) < 3:
continue
print(f"You: {transcript}")
response = ask_llm(transcript)
print(f"Assistant: {response}")
speak(response)
if __name__ == "__main__":
main()📌Note: 这是一个为清晰度设计的最简流水线 — 录制固定时长音频。生产环境中,使用VAD(语音活动检测)录制到语音结束而非固定时长。faster-whisper包含Silero VAD;whisper.cpp使用--stream模式或通过webrtcvad Python库实现WebRTC VAD。
步骤5:唤醒词检测
唤醒词检测器持续运行轻量模型,仅在检测到选定短语时触发完整流水线。 没有它,Whisper将持续运行 — 消耗更多CPU/GPU并在背景噪音上产生更多误触发。
- OpenWakeWord(MIT许可证): 完全开源,在CPU上运行,支持通过微调自定义唤醒词短语。安装:
pip install openwakeword。在Raspberry Pi上运行。完全离线开源配置的最佳选择。 - Porcupine(Picovoice): 专有但个人使用有免费套餐。预置唤醒词包括"Alexa"、"Hey Siri"、"Ok Google"和"Hey Jarvis"等自定义选项。准确率高,误触发率低。安装:
pip install pvporcupine。 - 集成模式: 在循环中运行OpenWakeWord/Porcupine。检测到唤醒词时播放"叮"声(用户反馈),然后为单次查询触发Whisper + LLM + TTS流水线。TTS播放后返回唤醒词监听。
- 常时运行功耗: 唤醒词检测在Raspberry Pi 5上使用约2–5% CPU — 可忽略不计。可以以最低功耗全天候运行助手。
- 自定义唤醒词(OpenWakeWord): 用文字转语音生成唤醒短语的500个正样本和500个负样本音频,然后在CPU上用不到30分钟微调OpenWakeWord。常见英语单词的准确率与Porcupine相当。
延迟优化
1–2秒目标在台式机硬件上通过正确配置可以实现。 延迟分布在三个层:
📍 简单一句话
STT增加0.2–0.5秒,LLM首token延迟增加0.5–1.5秒,TTS增加0.1–0.3秒 — 台式机GPU总计1–2秒。
💬 简单来说
LLM是最大瓶颈。最有效的优化是在LLM生成token的同时开始流式传输TTS输出 — 用户在LLM写完之前就开始听到答案。
- STT优化(约0.2–0.5秒): 使用Whisper small而非large-v3。在传给Whisper前用VAD剪除静音 — 更短的音频 = 更快的转写。
- LLM优化(首token约0.5–1.5秒): 启动时预加载模型(Ollama自动完成)。使用Q4_K_M量化获得最佳速度/质量平衡。用
--num-predict 100–150限制响应长度。 - 流式LLM → TTS: 逐token流式传输LLM输出。在每个完整句子(句号/问号结尾检测)开始TTS。这将感知延迟减少0.3–0.7秒 — 用户在LLM仍在生成结尾时就开始听到答案开头。
- TTS优化(约0.1–0.3秒): Piper在50ms内生成首段音频。启动时预初始化Piper。使用
--output-raw在生成时流式传输音频而非等待完整文件。 - 保持模型在内存中: Ollama自动将模型保持在显存中预热状态。流模式加载的whisper.cpp保持在内存中。避免在查询之间重新加载模型。
- 各硬件配置目标延迟: Pi 5:5–8秒(非对话式可接受)。迷你主机CPU:3–5秒(对话式临界值)。台式机GPU:1–2秒(自然流畅)。Mac M5:1–1.5秒(优秀)。
隐私与安全
正确组装的本地语音助手在运行时产生零网络流量。 所有处理 — 音频采集、语音识别、LLM推理和TTS — 完全在您的硬件上运行。
- 用Wireshark验证: 在与助手对话时在网络接口上运行Wireshark。应看到来自助手进程的零数据包。任何意外流量表明配置有误 — 如果您有公网IP,检查Ollama的外部API是否已禁用。
- 无音频存储: whisper.cpp和faster-whisper默认不写入音频文件 — 在内存中处理。本指南中的Python编排器为whisper.cpp写入临时WAV文件,转写后删除。
- 无会话历史存储: 示例脚本中的会话历史仅在内存中,重启时重置。如需持久历史,使用本地数据库和静态加密实现显式存储。
- 合规性: 因所有处理在本地进行且数据不离开网络,内部使用的本地语音助手无需数据处理协议。与第三方无数据控制者/处理者关系。中国《数据安全法》(2021年)要求对重要数据进行分级分类管理,医疗、法律、金融等敏感语音数据在本地处理可有效避免跨境数据传输合规风险。
- 网络隔离: 为最大化隐私,添加防火墙规则阻止来自助手进程的出站流量。Ollama和whisper.cpp在模型下载后不需要网络访问,可正常运行。
常见问题
本地语音助手能用于智能家居控制吗?
可以,如果您的智能家居系统有本地API。Home Assistant(HASS)有出色的本地集成功能 — 您可以在LLM解释命令后从编排器调用HASS REST API。LLM作为意图解析器:「打开客厅灯」→ 结构化JSON → HASS API调用。对于没有本地API支持的专有智能家居系统(Ring、Nest、Philips Hue云端),无法在没有互联网的情况下进行本地集成。
本地语音助手支持多少种语言?
Whisper支持99种语言的语音识别。Piper提供20+语言语音包用于TTS。LLM的语言支持取决于模型 — Llama 3.1 8B处理英语、法语、德语、西班牙语、意大利语、葡萄牙语以及部分日语/中文。对于较少见语言的完整多语言支持,选择专门针对这些语言训练的模型。
实现2秒以内延迟的最低硬件配置是?
Mac Mini M5(24 GB,~$600)或配备NVIDIA RTX 3060 12 GB的台式机(GPU约$400,总计约$800)均可实现1–2秒延迟。关键要求:Llama 3.1 8B(Q4)需8+ GB GPU显存,Whisper需Metal或CUDA加速。16 GB RAM纯CPU配置(迷你主机,~$300)可实现3–5秒 — 可用但低于"感觉自然"的阈值。
Whisper + LLM + Piper流水线在Windows上能运行吗?
可以。whisper.cpp有使用cmake和Visual Studio的Windows构建说明。Ollama在Windows 10/11上原生运行并支持NVIDIA GPU。Piper有Windows二进制文件。Python编排器在Windows上使用sounddevice进行音频采集。Windows上的主要复杂性是从源码构建whisper.cpp — 或者在有NVIDIA GPU的Windows上使用faster-whisper(pip install,无需构建)。
如何为本地语音助手添加网络搜索功能?
通过在编排器中集成本地搜索工具来添加网络搜索。选项:(1)使用DuckDuckGo API(免费,无需账号)进行通用查询 — 解析结果并注入LLM提示词。(2)使用本地新闻RSS源获取时事。(3)使用带有自有文档集合的本地RAG系统(AnythingLLM、PrivateGPT)进行领域特定搜索。LLM随后使用检索的上下文准确回答问题。根据搜索方式增加0.5–2秒延迟。
参考资料
- GitHub上的whisper.cpp — 源码、构建说明、流模式文档。
- ollama.com上的Ollama — 安装、模型库、API参考。
- GitHub上的Piper TTS — 源码、语音包下载、Raspberry Pi配置指南。
- GitHub上的OpenWakeWord — 源码、自定义唤醒词训练指南、支持的架构。
- Picovoice的Porcupine — 唤醒词SDK、免费套餐条款、Python SDK文档。
- Picovoice Console — 为Porcupine个人使用创建免费套餐API密钥。