自分で作るJARVIS:Memo AIを深掘り - プライバシー最優先のローカル音声エージェント
システムタスクを実行し、コードを生成し、メモを取る──クラウドへ1バイトも送信せずに。
動機:なぜローカルへ?
Alexa、Siri、ChatGPT に対するあらゆる音声コマンドが遠隔のサーバに記録される時代において、プライバシーはまさに高級品になっています。私は「Privacy-by-Design(設計段階からのプライバシー)」なエージェントを作りたかった。そこで目指したのが Memo AI です。これは堅牢でフルスタックなアプリケーションで、音声の文字起こし、意図(インテント)検出、そしてシステムレベルの実行を、すべてローカルハードウェア上で完結させます。
アーキテクチャ:5層のパイプライン
ローカルのエージェントを作ることは、単にLLMを組み込むことではありません。人間の発話という「ごちゃごちゃした入力」をうまく扱い、正確なシステムコマンドへ変換できる、信頼できるパイプラインを作ることです。
1. イングェスション層(Streamlit と音声バッファ)
アプリケーションは Streamlit で構築したリアクティブなUIから始まります。streamlit-mic-recorder を使い、音声をブラウザから直接取得しました。生の音声はバイト列としてバッファされるため、初期段階では一時ファイルの後処理を手動で管理する必要がなく、すぐに処理へ回せます。
2. 文字起こし層(OpenAI Whisper)
音声を文字に変換するため、OpenAI の Whisper を組み込みました(速度と精度のバランスのため base モデルを使用)。
- 問題:Whisper は FFmpeg に依存しており、ユーザがインストールする際に「パス地獄」になりがちです。
- 解決策:static-ffmpeg を使い、必要なバイナリを実行時に環境へ動的に注入しました。システムレベルでのインストールは不要です。
3. 推論層(Ollama とインテント検出)
文字起こしされたテキストはローカルの Ollama インスタンス(Llama 3.2 または Phi-3 を実行)へ送られます。
ここで多くのエージェントが失敗します。理由は LLM が非決定的だからです。私は次の方法で解決しました:
- システムプロンプト:モデルに「JSONのみのエンジン」として振る舞わせる。
- Pydantic による検証:Python の Pydantic ライブラリを使い、LLM の生文字列を、(create_file、write_code などの)特定のインテントを持つ構造化オブジェクトとしてパースする。
4. アクション層(ツールディスパッチャ)
インテントが分類されたら、ディスパッチャがコマンドを Python の「Tool」に割り当てます。
- スクリプトが必要? → write_code ツールを起動します。
- 何かを覚えておきたい? → create_file ツールが担当します。 このモジュール構成により、将来的に「Web検索」や「メール送信」のような新機能を追加するのが簡単になります。
5. セキュリティと永続化層
AI の指示に基づいてコードを実行するのは危険です。私は Path Scoping(パススコープ)を実装しました。すべてのファイル操作は厳格なルートディレクトリ(/output)に照らして検証されます。もし LLM が C:/Windows/ へ書き込もうとした場合、システムは ValueError を発生させ、アクションをブロックします。
技術スタック
- フロントエンド: Streamlit
- 音声→テキスト: OpenAI Whisper
- 大規模言語モデル: Ollama(Llama 3.2 1B / 3B)
- 検証: Pydantic V2
- システムのつなぎ: Python 3.10+
最大の課題(そしてどう乗り越えたか)
課題1:「FP16」CPU の警告
NVIDIA の専用GPUがない標準的なノートPCで Whisper を動かすと、16ビット浮動小数点(FP16)がサポートされていないことに関する警告がよく出ます。
- 修正: CUDA が検出されない場合は FP32 をデフォルトにするチェックを stt.py モジュールに実装し、すべてのユーザにとってスムーズな体験を保証しました。
課題2:JSON 内の LLM ハルシネーション
ときどき LLM が JSON の周りに会話の“間”のような文言を付け足します(「もちろん!こちらがあなたのJSONです:…」のように)。
- 修正: intent.py において、文字列の分割と正規表現風のマーカー( ``` json)を使って、パースの前に余計な部分を取り除く堅牢な抽出ユーティリティを書きました。これにより、LLM がどれだけおしゃべりな性格でも、システムがほぼ「クラッシュしない」状態になります。
課題3:パストラバーサル(Path Traversal)のセキュリティ
AI にファイル名を生成させるのはセキュリティ上のリスクです。悪意あるプロンプトなら、AI をだまして ../../startup_script.py という名前のファイルを作らせることができてしまいます。
- 修正: os.path.abspath と Path.resolve() を使い、write() コマンドが呼ばれる前に、どのファイルの最終目的地が物理的に自分のプロジェクトの /output サンドボックス内に存在するかを保証しました。
今後の展望
Memo AI はまだ始まりにすぎません。次のステップは以下です:
- RAG(Retrieval-Augmented Generation):エージェントがローカルのPDFを「読む」ことを可能にし、質問に答えられるようにする。
- 音声フィードバック:Piper や Coqui のようなローカルモデルで Text-to-Speech(TTS)を追加し、エージェントが返事を話せるようにする。
- アクティブなツール連携:システムAPIと統合して、音量・明るさの制御やアプリの起動を行えるようにする。
結論
このプロジェクトを作ってわかったのは、強力なAIを作るのに巨大なクラウド予算は不要だということです。ローカルモデルを適切にオーケストレーションできれば、速く動き、無料で使えて、そして—最も重要なのは—完全に自分のものになるパーソナルアシスタントを作れます。
プロジェクトリポジトリへのリンク: https://github.com/priyanshsingh11/Memo-AI
役に立ちましたか? シェアしていただけると嬉しいです!



