Skip to content

ハイブリッド構成: Module-LLM Whisper(ja) + Mac bridge Claude + VOICEVOX

初出: 2026-05-25 — Issue #52 / PR #51 の続き

結論

Module-LLM の LLM (qwen 0.5B / TinySwallow 1.5B) は実用不可 (精度低 or 推論 2分超)。 Module-LLM は「日本語 ASR + KWS + VAD」のためだけに使い、LLM/TTS は Mac Studio bridge に任せる のが最適解。

実測 7 秒で日本語発話まで完結

[ユーザー] HELLO + 日本語で発話
     ↓ マイク (Module-LLM)
[KWS → VAD → Whisper(ja)] Module-LLM オンデバイス
     ↓ テキスト
[WSS agent.run] CoreS3 → Mac bridge

[Claude API] Mac bridge
     ↓ 応答テキスト
[VOICEVOX 満別花丸] Mac bridge → PCM
     ↓ tts.start / バイナリ chunk / tts.end
[M5.Speaker.playRaw] CoreS3
     ↓ 🦆🔊
[満別花丸の声で発話]

検証ログ (2026-05-25 20:41)

firmware 起動

[main] kws_work_id=kws.1000 OK
[main] vad_work_id=vad.1001 OK
[main] whisper_work_id=whisper.1002 OK (lang=ja)
[main] llm_work_id=llm.1003 (model=tinyswallow-1.5b-ax630c)  ← setup は成功するが使わない
[main] try melotts model=...  ← 失敗するが使わない
[main] voice pipeline ready, wake=HELLO
[wss] connected to /stackchan/ws

発話 → 応答 (1 ターン分)

CoreS3 シリアル:

[wake] keyword detected
[asr] 聞こえてますか?日本語です私の声が聞こえてますかスタッフクチャン.
[wss] agent.done backend=claude
[wss] tts.start sr=24000 bps=16 ch=1 total=300032
[wss] tts.end received=300032 bytes
[tts] playRaw samples=150016 sr=24000 ok=1

Mac bridge:

[bridge] connected device=? session=00488dd4-...
[tts] synthesizing (41 chars): はい、聞こえてますよ。ぼくはドナック、緑の帽子の相棒です。今日は何をしましょうか。...
[tts] WAV ready: 300032B pcm @ 24000Hz (6251ms) synth=818ms

体感レイテンシ

発話開始から応答発話まで ~7 秒 (ユーザー実測)。

区間推定時間
発話 → ASR 完了1-2 秒 (Whisper-tiny on AX630C)
ASR → Claude 応答テキスト3-4 秒 (Claude API)
Claude → VOICEVOX 合成0.8 秒 (実測 818ms)
PCM 送信 + 再生開始1-2 秒
合計~7 秒

なぜこの構成に落ち着いたか

検証で除外された案:

結果理由
Module-LLM 単体完結 (TinySwallow + MeloTTS)TinySwallow 推論 2 分超、MeloTTS は同時 RAM 不足
Module-LLM 単体完結 (qwen 0.5B + MeloTTS)⚠️日本語精度低、過去ログで「中国語ナンセンス」
全 Mac (CoreS3 マイク → PCM ストリーム)firmware 大改修必要 (PCM ストリーミング新規実装)
案 A: ASR=Module-LLM, LLM=Claude, TTS=VOICEVOX動いた、コード変更最小

firmware の主要変更点

firmware/src/main.cpp の ASR ハンドラ:

cpp
// Before (Module-LLM オンデバイス LLM):
String full_response;
module_llm.llm.inferenceAndWaitResult(llm_work_id, asr.c_str(),
    [&full_response](String& token) { full_response += token; });
wsRequestTts(full_response);  // bridge VOICEVOX 経由

// After (Claude 直送):
wsAskClaude(asr);  // 既存の serial CLI `claude:` と同じ経路

LLM/MeloTTS の setup 自体は残してあるが使用しない (将来「オフラインで qwen 0.5B 縮退モード」用の予備)。

bridge 側の役割

mac-studio/bridge/src/server.ts:

  • 既存の agent.run ハンドラがそのまま使える
  • Claude 応答後に VOICEVOX で TTS → tts.start/chunk/end を返す経路は PR #51 のまま

tts.synthesize 単独経路も追加実装してあり (firmware で wsRequestTts 関数として残存)、将来オンデバイス LLM が高速化したら活用可能。

Module-LLM の役割 (再定義)

機能状態
マイク (PDM)✅ メイン入力デバイス
KWS ("HELLO")✅ 使う
VAD✅ 使う
Whisper(ja) ASR本構成の核
LLM (qwen / TinySwallow)⚪ install 済だが今は使わない
MeloTTS ja-jp⚪ install 済だが今は使わない
YOLO / Camera(将来用、未使用)

つまり 「優秀な音声入力デバイス + 将来の NPU 推論オフロード予備」 として保持。

未解決事項 / 今後の課題

  • ASR の誤認識: 「スタッフクチャン」「日本語です私の声が聞こえてますか」など句読点崩れ。Whisper-tiny の限界。whisper-base (公式 repo にある) で改善するかは別検証
  • wake word の精度: 英語 "HELLO" 固定。ESP-SR で日本語 "Hi, Stack Chan" 化は別 issue
  • Module-LLM body の USB-C は ADB と StackFlow UART で干渉: ADB 接続中は CoreS3 ↔ Module-LLM の UART 通信が不安定 (要追加検証)
  • system prompt は Mac 側 backends/claude.ts で管理: Donack キャラクター prompt は bridge 側に集中

関連

aieo-product / stack-chan project