SynapseWire

打造本地 AI 語音助理:Whisper + Ollama + Piper 完整教程(2026)

手把手教你用 OpenAI Whisper 做語音辨識、Ollama 跑本地語言模型、Piper 做文字轉語音,打造一個完全離線的語音助理。

作者: SynapseWire 編輯部 發布於:
筆電螢幕顯示終端機語音助理日誌,桌上放著麥克風和耳機

Siri、Alexa、Google Assistant 這些語音助理有一個共同點:它們都會把你的聲音送到雲端伺服器。每一個指令、每一個問題、每一句凌晨兩點的低語,都是在別人的硬體上處理的。對於注重隱私的使用者、開發邊緣裝置產品的工程師,或者單純想要完全掌控自己 AI 技術棧的人來說,這是一個無法接受的代價。

好消息是,打造完全本地化的語音助理所需的工具已經成熟了。OpenAI 的 Whisper 可以在消費級硬體上跑語音辨識。Ollama 讓你在本地運行大型語言模型。Piper 提供快速、自然的文字轉語音功能。這三個工具串起來,就形成了一個能聽、能想、能說的完整管線——全程不需要網路連線。

這篇教程會從零開始帶你搭建這條管線。完成後,你會擁有一個完全在自己機器上運作的語音助理。

你會打造什麼

系統有三個核心組件:

  1. 語音轉文字(STT): OpenAI Whisper 把你說的話轉成文字
  2. 語言模型(LLM): Ollama 在本地跑語言模型,處理文字並生成回應
  3. 文字轉語音(TTS): Piper 把文字回應轉回語音

流程很簡單:你對著麥克風說話,Whisper 把語音轉成文字,LLM 生成回應,Piper 把回應念出來。全程本地運作,不需要 API 金鑰、不需要雲端服務、你的資料不會離開你的機器。

前置準備

你需要一台具備以下條件的機器:

  • Python 3.10 或更新版本
  • 至少 8GB 記憶體(建議 16GB 以跑更大的模型)
  • 正常運作的麥克風
  • macOS、Linux 或 Windows(WSL2)

本教程假設你有基本的命令列操作能力,但不需要 AI 或機器學習的經驗。

第一步:安裝 Ollama

Ollama 是在本地跑語言模型最簡單的方式。它自動處理模型下載、量化和 GPU 加速。

從官方網站安裝 Ollama:

# macOS / Linux
curl -fsSL https://ollama.com/install.sh | sh

# 或到 https://ollama.com/download 下載 Windows 版本

安裝完成後,拉取一個模型。語音助理需要速度快又夠聰明的模型,Llama 3.2 3B 是不錯的選擇:

ollama pull llama3.2:3b

測試一下:

ollama run llama3.2:3b "用一句話說你好。"

如果收到回應,Ollama 就準備好了。

第二步:安裝 Whisper

Whisper 是 OpenAI 開源的語音辨識模型。我們使用 faster-whisper 實作版本,速度是原版的 4 倍,記憶體用量也更低。

pip install faster-whisper

下載模型。base 模型速度夠快、準確度也夠用:

from faster_whisper import WhisperModel

model = WhisperModel("base", device="cpu", compute_type="int8")
segments, info = model.transcribe("test_audio.wav")
for segment in segments:
    print(segment.text)

如果你有 NVIDIA GPU,改用 device="cuda"compute_type="float16" 可以大幅加速轉錄。在 Apple Silicon 上,device="cpu" 搭配 compute_type="int8" 就能接近即時處理。

第三步:安裝 Piper

Piper 是一個快速的本地文字轉語音引擎。不需要 GPU 就能產生自然的語音。

pip install piper-tts

下載一個語音模型。Piper 提供多種語言的數十種語音:

# 瀏覽可用語音:https://rhasspy.github.io/piper-samples/
# 下載語音(範例:美式英語女聲)
python -m piper_download --voice en_US-lessac-medium

測試 TTS:

echo "你好,我是你的本地語音助理。" | piper --output_file test.wav

播放產生的 WAV 檔案,確認語音聽起來夠自然。

第四步:打造管線

現在把三個組件串成一個能用的助理。以下是把一切整合在一起的 Python 腳本:

import os
import tempfile
import subprocess
import sounddevice as sd
import numpy as np
from faster_whisper import WhisperModel
import ollama

# 設定
SAMPLE_RATE = 16000
DURATION = 5  # 錄音秒數
WHISPER_MODEL = "base"
LLM_MODEL = "llama3.2:3b"
PIPER_VOICE = "en_US-lessac-medium"

# 初始化 Whisper
whisper = WhisperModel(WHISPER_MODEL, device="cpu", compute_type="int8")

def record_audio():
    """從麥克風錄音。"""
    print("正在聆聽...(請開始說話)")
    audio = sd.rec(int(DURATION * SAMPLE_RATE), samplerate=SAMPLE_RATE, channels=1, dtype='float32')
    sd.wait()
    print("聆聽結束。")
    return audio.flatten()

def transcribe(audio):
    """用 Whisper 把語音轉成文字。"""
    with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as f:
        import wave
        with wave.open(f.name, 'w') as wav:
            wav.setnchannels(1)
            wav.setsampwidth(2)
            wav.setframerate(SAMPLE_RATE)
            wav.writeframes((audio * 32767).astype(np.int16).tobytes())
        
        segments, _ = whisper.transcribe(f.name)
        text = " ".join(segment.text for segment in segments)
    
    os.unlink(f.name)
    return text

def ask_llm(prompt):
    """把 prompt 傳給本地 LLM 取得回應。"""
    response = ollama.chat(model=LLM_MODEL, messages=[
        {"role": "system", "content": "你是一個有用的語音助理。回應要簡潔、口語化。"},
        {"role": "user", "content": prompt}
    ])
    return response["message"]["content"]

def speak(text):
    """用 Piper 把文字轉成語音。"""
    with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as f:
        subprocess.run(
            ["piper", "--model", PIPER_VOICE, "--output_file", f.name],
            input=text.encode(),
            capture_output=True
        )
        subprocess.run(["aplay", f.name])  # Linux;macOS 用 'afplay'
        os.unlink(f.name)

def main():
    print("本地語音助理已就緒。按 Ctrl+C 退出。")
    try:
        while True:
            audio = record_audio()
            text = transcribe(audio)
            if not text.strip():
                continue
            print(f"你說了:{text}")
            
            response = ask_llm(text)
            print(f"助理:{response}")
            
            speak(response)
    except KeyboardInterrupt:
        print("\n再見!")

if __name__ == "__main__":
    main()

安裝額外的依賴:

pip install sounddevice numpy

執行助理:

python assistant.py

第五步:優化與調校

基本管線跑起來了,但幾個調整可以大幅改善使用體驗。

語音活動偵測

目前的腳本不管有沒有在說話,都會固定錄 5 秒。加入語音活動偵測(VAD),在你停止說話時自動停止錄音:

# 安裝:pip install webrtcvad
import webrtcvad

def detect_silence(audio, sample_rate=16000, silence_threshold=0.01):
    """基於能量的簡易靜音偵測。"""
    frame_size = int(sample_rate * 0.03)  # 30ms 幀
    is_silent = True
    for i in range(0, len(audio) - frame_size, frame_size):
        frame = audio[i:i+frame_size]
        energy = np.sqrt(np.mean(frame**2))
        if energy > silence_threshold:
            is_silent = False
            break
    return is_silent

對話上下文

基本腳本把每個查詢當作獨立處理。為了更自然的體驗,保留對話歷史:

conversation_history = []

def ask_llm(prompt):
    global conversation_history
    conversation_history.append({"role": "user", "content": prompt})
    
    # 保留最近 10 輪對話作為上下文
    messages = [
        {"role": "system", "content": "你是一個有用的語音助理。回應要簡潔。"},
        *conversation_history[-10:]
    ]
    
    response = ollama.chat(model=LLM_MODEL, messages=messages)
    reply = response["message"]["content"]
    conversation_history.append({"role": "assistant", "content": reply})
    return reply

喚醒詞偵測

想要免手操作,可以加入像「嘿助理」這樣的喚醒詞。用 pvporcupine(有免費方案)或簡單的關鍵字偵測器:

pip install pvporcupine

這讓助理只在被叫到的時候才回應,不用一直錄音。

控制回應長度

LLM 有時候會生成太長的回應,念出來要等很久。在 system prompt 裡加限制:

system_prompt = """你是一個有用的語音助理。規則:
- 回應控制在 3 句話以內
- 用口語,不要用書面語
- 如果答案很簡單,就給簡單的答案
- 不要在語音回應中使用 Markdown、條列式或編號列表"""

硬體考量

效能很大程度取決於你的硬體:

  • 只有 CPU(8GB 記憶體): Whisper base + Llama 3.2 3B 可以正常運作。回應時間約 2-4 秒。
  • 只有 CPU(16GB 記憶體): 可以跑 Whisper medium + Llama 3.2 8B。比較慢但更強。
  • NVIDIA GPU(8GB+ VRAM): Whisper large-v3 + Llama 3.2 8B,回應幾乎即時。
  • Apple Silicon(M1/M2/M3): 搭配 Core ML 加速效能很好。Whisper base 可以即時處理。

如果記憶體有限,用量化模型。Ollama 對大部分模型自動使用 4-bit 量化,可以大幅降低記憶體用量。

常見問題

Whisper 很慢: 在 CPU 上用 compute_type="int8",或改用更小的模型(tiny 代替 base)。

沒有音訊輸入: 檢查麥克風權限。macOS 去「系統設定 > 隱私與安全性 > 麥克風」。Linux 用 arecord -l 確認。

Piper 聲音很機械: 換一個語音模型。medium 品質的語音比 low 品質好很多。

Ollama 卡住: 載入模型後的第一次推理比較慢,後續呼叫就很快了。如果持續卡住,檢查可用記憶體。

進階應用

這篇教程建的是基本管線。要擴展的話:

  • 加入工具調用: 讓 LLM 透過 Ollama 的 function calling 支援來呼叫天氣、日曆、網頁搜尋等函式
  • 多語言支援: 用 Whisper 的多語言模型搭配 Piper 的其他語言語音
  • 圖形介面: 用 Gradio 或 Streamlit 建一個簡單的網頁介面,提供視覺回饋
  • 邊緣部署: 把管線跑在 Raspberry Pi 5 上,做成專用硬體裝置

本地 AI 語音助理這個領域進展很快。一年前,在消費級硬體上跑這些模型還不太實際。今天,這已經是很直觀的事情了。工具只會越來越好。


延伸閱讀:2026 年完整本地 AI 環境搭建教學:Ollama + Open WebUI 從零開始 | 從零打造 MCP Server:Python 實戰教學(2026 完整版) | 用 n8n 打造 AI Agent 工作流:2026 完整教程

分享文章

留言評論

0 則評論

暫無評論,搶先發表你的看法吧!

相關文章