こんにちは。
AIソリューション事業部のAIおじさんです。
エンジニアではないのですが、AI好きのおじさんとして便利ツールを作ったりしています。
自分のPCに話しかけたら、AIが答えてくれる。しかもクラウドを一切使わず、完全に手元だけで動く。
これ、ロマンじゃないですか?
前回の記事でOllama + Qwen3を使ったローカルLLM環境を構築しました。記事の最後に「次は音声会話に挑戦したい」と書いたので、今回はその続編です。
Qwen3-ASR(音声認識)と Ollama(ローカルLLM)を組み合わせて、完全オフラインで動く音声チャットAIを作ってみました。Apple Silicon Mac で動かしているので、MチップのMacユーザーの参考になれば。
作りたいもの
最終的に目指しているのはこんな構成です。
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ マイク │────▶│ STT │────▶│ LLM │────▶│ TTS │
│ 入力 │ │ (Qwen3-ASR) │ │ (Ollama) │ │ (Qwen3-TTS) │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
│ │ │
▼ ▼ ▼
テキスト変換 応答生成 音声再生
今回は STT(音声認識)→ LLM(応答生成) までを実装しました。TTSは次回以降で追加予定です。
STT(Speech-to-Text)とは
STTは「Speech-to-Text」の略で、音声をテキストに変換する技術です。日本語では「音声認識」とも呼ばれます。
身近な例だと:
- iPhoneの音声入力
- YouTubeの自動字幕
- Alexaやスマートスピーカー
これらはすべてSTT技術を使っています。
クラウドSTT vs ローカルSTT
| クラウドSTT | ローカルSTT | |
|---|---|---|
| 例 | Google Speech-to-Text, Whisper API | Whisper.cpp, Qwen3-ASR |
| 精度 | 高い | モデルによる(最近は遜色ない) |
| 速度 | ネット依存 | PC性能依存 |
| プライバシー | 音声データがサーバーに送られる | 完全にローカルで完結 |
| コスト | 従量課金 | 無料(電気代のみ) |
今回使う Qwen3-ASR は、ローカルで動作しながらも52言語に対応しており、日本語の認識精度も高いモデルです。
ローカルLLMとは
LLM(Large Language Model)は、ChatGPTのようにテキストで会話できるAIモデルのことです。
通常、ChatGPTやClaudeを使うにはインターネット経由でAPIを叩く必要がありますが、ローカルLLMは自分のPC上でモデルを動かします。
ローカルLLMのメリット
- 完全オフライン: ネットなしで動く
- プライバシー: 会話内容が外部に送信されない
- 無料: API料金がかからない
- カスタマイズ: ファインチューニングも自由
Ollamaとは
Ollamaは、ローカルLLMを簡単に動かすためのツールです。前回の記事でセットアップ方法を詳しく書きましたが、簡単におさらいすると:
# 公式サイトからダウンロード(Homebrew版はQwen3と相性問題あり)
curl -L -o /tmp/Ollama.zip "https://ollama.com/download/Ollama-darwin.zip"
unzip -o /tmp/Ollama.zip -d /tmp/
mv /tmp/Ollama.app /Applications/
open /Applications/Ollama.app
# モデルをダウンロードして実行
ollama run qwen3:4b-instruct
注意: Homebrew版のOllamaはQwen3でMetal周りのエラーが出ることがあります。公式版を使いましょう。
Ollamaが対応しているモデルは多数あり、今回は日本語性能が良い Qwen3 シリーズを使いました。qwen3:4b-instruct はThinking機能がないシンプル版で、即座に回答が返ってきます。
HuggingFaceとは
HuggingFaceは、AIモデルの「GitHub」のような存在です。
世界中の研究者や企業が作ったAIモデルが公開されていて、誰でも無料でダウンロードして使えます。今回使う Qwen3-ASR も HuggingFace で公開されています。
https://huggingface.co/Qwen/Qwen3-ASR-1.7B
モデルをダウンロードするには、Pythonライブラリ経由で自動取得するか、huggingface-cli を使います。今回は qwen-asr ライブラリが初回実行時に自動でダウンロードしてくれるので、特に意識する必要はありません。
使った技術
| コンポーネント | 使ったもの | 特徴 |
|---|---|---|
| 音声認識(STT) | Qwen3-ASR-1.7B | 52言語対応、HuggingFaceで公開 |
| 対話生成(LLM) | qwen3:4b-instruct (Ollama) | 軽量で高速、日本語対応、即応答 |
| 実行環境 | Apple Silicon (MPS) | GPU活用で快適に動作 |
全部ローカルで完結するので、ネット環境がなくても動きます。
環境構築
1. Miniforgeをインストール
Python環境の管理には Miniforge(conda)を使いました。
brew install --cask miniforge
conda init zsh
# ターミナルを再起動
2. Python環境を作成
conda create -n voice-ai python=3.12 -y
conda activate voice-ai
3. 必要なライブラリをインストール
# PyTorch(Apple Silicon用)
pip install torch torchvision torchaudio
# Qwen3-ASR と Ollama クライアント
pip install -U qwen-asr ollama
# 音声入出力用
pip install sounddevice soundfile
4. Ollamaのセットアップ
前回の記事でセットアップ済みの場合はスキップしてOK。まだの場合は公式版をインストールします。
# 公式版をダウンロード&インストール
curl -L -o /tmp/Ollama.zip "https://ollama.com/download/Ollama-darwin.zip"
unzip -o /tmp/Ollama.zip -d /tmp/
mv /tmp/Ollama.app /Applications/
open /Applications/Ollama.app
# モデルをダウンロード
ollama pull qwen3:4b-instruct
これだけで準備完了です。STTモデル(約3.4GB)は初回実行時にHuggingFaceから自動ダウンロードされます。
実装したもの
プロジェクト構造
local_llm_dev/
├── src/
│ ├── stt.py # 音声認識エンジン
│ ├── llm.py # LLMラッパー(ストリーミング対応)
│ └── pipeline.py # STT→LLM統合パイプライン
└── examples/
├── record_and_transcribe.py # 録音→認識
└── voice_chat.py # 音声チャット
STTエンジン
src/stt.py では、Qwen3-ASRをラップした STTEngine クラスを実装。Apple Silicon の場合は自動で MPS(Metal Performance Shaders)を使うようにしています。
from src.stt import STTEngine
with STTEngine() as engine:
result = engine.transcribe("audio.wav", language="Japanese")
print(result["text"])
ポイントは dtype の自動変換。MPS は bfloat16 に対応していないので、自動で float16 に変換しています。
「こんんいちは。お元気ですか」と話しかけてみました。
ちゃんと音声認識してテキストに変換されています。
LLMエンジン
src/llm.py では Ollama を使った LLMEngine クラスを実装。会話履歴の管理とストリーミング出力に対応しています。
from src.llm import LLMEngine
llm = LLMEngine(model="qwen3:4b-instruct")
# 通常の応答
response = llm.chat("こんにちは!")
print(response)
# ストリーミング
for chunk in llm.chat_stream("今日の天気は?"):
print(chunk, end="", flush=True)
パイプライン
src/pipeline.py で STT と LLM を繋いで、一連の流れを実現しています。
マイク入力 → 録音 → STT → テキスト → LLM → 応答
動かしてみた
音声チャットを起動
conda activate voice-ai
python examples/voice_chat.py --stream
実際の動作
🎤 録音: 5秒
📝 認識結果: こんにちは。お元気ですか。今何をしています。
🤖 LLM応答: こんにちは!お元気です。今、日本語でお手伝いしています。
5秒制限をつけているため、いま何をしています「か?」の前に切れてしまいました。
ちゃんと日本語を認識して、自然な返答が返ってきました。
自分のPCに話しかけて、ローカルで動いているAIが答えてくれる。この体験、なかなか感動します。
テキストモードでデバッグ
マイクなしで試したい場合はテキストモードも用意しています。
python examples/voice_chat.py --text-mode
技術的なポイント
Apple Silicon での動作
- デバイス: MPS(Metal Performance Shaders)を使用
- dtype: bfloat16 → float16 に自動変換(MPS非対応のため)
- メモリ: Unified Memory なので VRAM を気にしなくていい
モデルサイズ
- Qwen3-ASR-1.7B: 約3.4GB(HuggingFaceから初回ダウンロード)
- qwen3:4b-instruct: 約2.5GB(Ollama経由)
16GB メモリの Mac なら余裕で動きます。
まとめ
前回構築した Ollama + Qwen3 環境に、Qwen3-ASR を追加して音声入力に対応させました。Apple Silicon Mac 上で完全ローカルな音声チャットAIが動いています。
正直、実用性だけで言えばChatGPTのアプリで音声会話すればいい話です。でも、自分のマシンだけで完結する音声AIを動かすというロマン。これが楽しいんですよね。
今後やりたいこと:
- TTS(Qwen3-TTS)を追加して音声で応答させる
- リアルタイム認識の改善
- より自然な会話フロー
完全ローカルでの音声AIは、思ったより手軽に始められます。興味のある方はぜひ試してみてください。

