重要なポイント
- オフライン音声アシスタントのスタックは:whisper.cpp → Ollama LLM → Piper TTS、Pythonスクリプトでオーケストレーションされます。 3つのコンポーネントはすべて無料のオープンソースであり、インストール後は完全にオフラインで動作します。
- デスクトップGPU(RTX 3060 12 GB)でのエンドツーエンドレイテンシ:1〜2秒。 AlexaやGoogle アシスタントと同等です。この結果には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トークン/秒で実行でき、Whisper large-v3はMetalで10倍のリアルタイム処理が可能。レイテンシは1〜1.5秒。
- Whisperを継続的に実行しないようウェイクワードを追加してください。 OpenWakeWord(MIT、無料、カスタムウェイクワード対応)がベストなオープンソースオプションです。Porcupine(Picovoice)は個人使用の無料枠があり、「Hey Jarvis」などの定義済みウェイクワードが使えます。
- 静寂時のWhisperハルシネーションは最も一般的なパイプラインのバグです。 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、約¥14,800)で5〜8秒レイテンシ。
- 推奨ハードウェア: Mac Mini M5 24 GB(約¥88,800)またはRTX 3060 12 GB搭載デスクトップ(約¥130,000)で1〜2秒レイテンシ。
- 言語: Whisperは99言語に対応。Piperは20以上の言語音声パックを提供。LLMの言語性能はモデルによって異なります。
なぜローカル音声アシスタントを構築するのか?
Alexa、Siri、Google アシスタントはすべてクラウドサーバー経由で音声を処理しています。あなたの音声はプロバイダーによって転写、処理、記録されます。ローカル音声アシスタントはすべての処理をあなたのハードウェア上で行います。
- プライバシー: 音声が自宅外に出ません。クラウドにウェイクワード音声は保存されません。サードパーティのサーバーに会話履歴はありません。医療従事者、弁護士、ジャーナリスト、機密業務を持つすべての人に重要です。
- コスト: サブスクリプション不要。Alexa+(旧Alexa Premium)は月額$4.99、Google Oneは月額$1.99〜$9.99かかります。ローカルアシスタントは一回きりのハードウェアコストです。
- カスタマイズ: ウェイクワード、個性、システムプロンプト、機能を選択できます。カスタムコマンドを追加し、ローカルホームオートメーションシステムに接続し、ローカルAPIと統合できます。
- オフライン動作: インターネットなしで動作します。停電(UPSあり)+インターネット障害でもローカルアシスタントは動き続けます。山小屋、遠隔地、緊急時対策に有用です。
- 失うもの: ウェブ検索、独自クラウドを使うスマートホーム統合、クラウドサービスとのカレンダー同期、AlexaやSiriのエッジケースを滑らかにしているRLHFチューニングの積み重ね。
三層アーキテクチャ
オフライン音声アシスタントは、Pythonオーケストレーターによって接続された3つの独立したレイヤーで構成されています。
📍 一文で説明
マイク → whisper.cpp(STT) → Ollama LLM → Piper TTS → スピーカー:50行のPythonオーケストレーターでつながれた3つの独立したコンポーネント。
💬 簡潔に説明
電話リレーのようなものです。あなたが話すと、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の応答テキストを音声に変換し、スピーカーから再生します。オフラインで動作し、ネットワーク不要です。
- オーケストレーター: 3つを接続するPythonスクリプト:マイクから音声をキャプチャ → STTに渡す → LLMに転写結果を渡す → TTSに応答を渡す → 音声を再生。
- オプションのウェイクワード: 選択したフレーズが検出された場合のみフルパイプラインをトリガーする軽量の常時動作検出器(OpenWakeWord、Porcupine)。これがないと、オーケストレーターはwhisper.cppを継続的に実行し、CPUやGPUを消費し、バックグラウンドノイズによる誤検知が増えます。
ハードウェア要件
レイテンシとコスト順に並べた4つのハードウェア構成。すべてWhisper + LLM + Piperのフルスタックをサポートします。
| 構成 | STTモデル | LLMモデル | TTS | 合計費用 | エンドツーエンドレイテンシ |
|---|---|---|---|---|---|
| Raspberry Pi 5(8 GB) | Whisper base(CPU) | Phi-3 mini 3.8B Q4 | Piper(CPU) | 約¥14,800 | 5〜8秒 |
| ミニPC(16 GB RAM) | Whisper small(CPU) | Llama 3.1 8B Q4(CPU) | Piper(CPU) | 約¥43,000 | 3〜5秒 |
| デスクトップ(RTX 3060 12 GB) | Whisper large-v3(GPU) | Llama 3.1 8B Q4(GPU) | Piper または Coqui(CPU/GPU) | 約¥130,000 | 1〜2秒 |
| Mac Mini M5(24 GB) | Whisper large-v3(Metal) | Llama 3.1 8B(Metal) | Piper(CPU) | 約¥88,800 | 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にはWhisper base(1 GB RAM、低レイテンシ)、バランス重視にはsmall(2 GB RAM、WER 3.4%)、最高精度にはlarge-v3(VRAM/RAM 10 GB必要)。
- 無音抑制の設定: 無音をハルシネーションとして転写しないよう
--no-speech-threshold 0.6 --suppress-blankフラグを追加します。 - 10秒録音でのテスト: テストフレーズを録音し、Whisperが正確に転写することを確認します。ノイズ条件と静かな音声の両方を確認してください。
ステップ2:ローカルLLMのセットアップ
Ollamaをインストールし、LLMモデルを取得します。音声アシスタントの動作用システムプロンプトを設定します。短い応答、マークダウンなし、適切な個性が必要です。
- 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文。箇条書き、マークダウン、書式は使用しないでください。会話のように自然に話してください。」
- 温度: より予測可能で事実に基づく応答のために温度を0.3〜0.5に設定します。低い温度は音声応答のハルシネーションを減らします。
- 最大トークン数:
--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 VRAMが必要で、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パイプラインを1つのクエリ用にトリガーします。TTS再生後、ウェイクワード待機に戻ります。
- 常時稼働電力: ウェイクワード検出はRaspberry Pi 5でCPUの約2〜5%を使用し、無視できる程度です。最小限の消費電力でアシスタントを24時間365日稼働させることができます。
- カスタムウェイクワード(OpenWakeWord): テキスト読み上げを使ってウェイクフレーズの500のポジティブと500のネガティブ音声サンプルを生成し、CPU上で30分未満でOpenWakeWordをファインチューニングします。一般的な英語単語ではPorcupineと同等の精度が得られます。
レイテンシ最適化
1〜2秒の目標はデスクトップハードウェアで適切な設定により達成可能です。 レイテンシは3つのレイヤーに分散しています:
📍 一文で説明
STTが0.2〜0.5秒、LLMの初回トークンレイテンシが0.5〜1.5秒、TTSが0.1〜0.3秒 — デスクトップGPUで合計1〜2秒。
💬 簡潔に説明
LLMが最大のボトルネックです。最も効果的な最適化は、LLMがトークンを生成するにつれてTTS出力をストリーミング開始することです。LLMが書き終わる前にユーザーが答えを聞き始めます。
- STT最適化(約0.2〜0.5秒): large-v3の代わりにWhisper smallを使用します。無音をトリムしてからWhisperに渡すためにVADを使用します。短い音声 = 高速な転写。
- LLM最適化(初回トークン約0.5〜1.5秒): 起動時にモデルをプリロードします(Ollamaは自動的に行います)。速度と品質のベストバランスにはQ4_K_M量子化を使用します。応答長を制限するには
--num-predict 100〜150を設定します。 - ストリーミングLLM → TTS: LLMの出力をトークンごとにストリーミングします。完成した各文(ピリオドや疑問符の終わりで検出)でTTSを開始します。これにより知覚されるレイテンシが0.3〜0.7秒削減されます。LLMが残りを生成している間にユーザーは答えの最初を聞き始めます。
- TTS最適化(約0.1〜0.3秒): Piperは50ms以内に最初の音声を生成します。起動時にPiperを事前初期化します。完全なファイルを待つのではなく、生成しながら音声をストリーミングするために
--output-rawを使用します。 - モデルをメモリに保持: OllamaはVRAM内のモデルを自動的にウォーム状態に保ちます。ストリームモードで読み込まれたwhisper.cppはメモリに残ります。クエリ間でのモデルリロードを避けます。
- ハードウェア構成別の目標レイテンシ: Pi 5:5〜8秒(会話型以外では許容範囲)。ミニPC CPU:3〜5秒(会話型の境界線)。デスクトップGPU:1〜2秒(自然な感じ)。Mac M5:1〜1.5秒(優秀)。
プライバシーとセキュリティ
正しく組み立てられたローカル音声アシスタントは、動作中にネットワークトラフィックをゼロに保ちます。 音声キャプチャ、音声認識、LLM推論、TTSを含むすべての処理はハードウェア上で実行されます。
- Wiresharkで確認: アシスタントとの会話中にネットワークインターフェイスでWiresharkを実行します。アシスタントプロセスからのパケットがゼロであることを確認してください。予期しないトラフィックは設定ミスを示します。パブリックIPを持つ場合は、OllamaのextternalAPIが無効化されていることを確認してください。
- 音声の保存なし: whisper.cppもfaster-whisperも、デフォルトでは音声ファイルを書き込みません。メモリで処理します。このガイドのPythonオーケストレーターは、whisper.cpp用に一時的なWAVファイルを書き込みますが、転写後に削除されます。
- 会話履歴の保存なし: サンプルスクリプトの会話履歴はメモリのみで、再起動するとリセットされます。永続的な履歴には、ローカルデータベースと保存時の暗号化を使った明示的なストレージを実装してください。
- プライバシーコンプライアンス: すべての処理がローカルで行われ、データがネットワーク外に出ないため、内部使用のローカル音声アシスタントにはデータ処理契約が不要です。サードパーティとのデータ管理者/処理者関係はありません。経済産業省(METI)のAIガバナンスガイドラインは、医療・法律・金融などの機密データに対してローカル処理を推奨しています。
- ネットワーク分離: 最大のプライバシーのために、アシスタントプロセスからのアウトバウンドトラフィックをブロックするファイアウォールルールを追加します。OllamaとWhisper.cppはモデルダウンロード後はネットワークアクセスが不要なため、正常に機能します。
よくある質問
ローカル音声アシスタントをスマートホーム制御に使用できますか?
はい、スマートホームシステムにローカルAPIがある場合は可能です。Home Assistant(HASS)は優れたローカル統合機能を持っています。LLMがコマンドを解釈した後、オーケストレーターからHASS REST APIを呼び出せます。LLMはインテントパーサーとして機能します:「リビングルームの照明をつけて」→ 構造化JSON → HASS APIコール。ローカルAPIサポートなしの独自スマートホームシステム(Ring、Nest、Philips Hueクラウド)では、インターネットなしのローカル統合はできません。
ローカル音声アシスタントは何か国語に対応していますか?
Whisperは音声認識で99言語に対応しています。Piperは20以上の言語音声パックを提供しています。LLMの言語対応はモデルによって異なります。Llama 3.1 8Bは英語、フランス語、ドイツ語、スペイン語、イタリア語、ポルトガル語、および一部の日本語/中国語を処理できます。マイナー言語での完全な多言語対応には、それらの言語専用に訓練されたモデルを選択してください。
2秒以下のレイテンシを達成するための最小ハードウェアは?
Mac Mini M5(24 GB、約¥88,800)またはNVIDIA RTX 3060 12 GBを搭載したデスクトップ(合計約¥130,000)は、どちらも1〜2秒のレイテンシを達成します。主な要件は:Llama 3.1 8B(Q4)用に8 GB以上のGPU VRAM、WhisperのMetalまたはCUDAアクセラレーション。16 GB RAMのCPUのみのセットアップ(ミニPC、約¥43,000)では3〜5秒を達成しますが、「自然に感じる」閾値を下回ります。
Whisper + LLM + PiperパイプラインはWindowsで動作しますか?
はい。whisper.cppにはcmakeとVisual Studioを使ったWindowsビルド手順があります。OllamaはNVIDIA GPUサポートでWindows 10/11上でネイティブに動作します。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キーを作成。