最終更新: 2026-04-28
AIが会話しながら自分のペルソナを学ぶアプリを作った話——ローカルLLM+音声で実現した『関係性学習』 ローカルLLM環境の選び方
夜、仕事を一通り片付けて、部屋でコーヒーを淹れる。Macの前に座って「会話を始める」 Mac環境でのAI開発ツール比較ってボタンを押す。すると、AIが話しかけてくる。
「お疲れ〜、今日どんな感じだった?」
私は答える。今日やったこと、詰まったこと、なんとか片付けたこと。AIは相槌を打ちながら、時々だけ深掘りしてくる。ボタンを押す必要はなくて、喋り終わって1.5秒黙ると自動で録音が止まり、文字起こしされ、AIが返事を考えて、音声で喋り返す。その一連の流れが延々と続く——それだけ。
これを作った理由は一つ。「自分のことを毎回プロンプトに書くのが、だるい」
作ったものの中身
Pythonで動くTkinterアプリだ。使ってる部品はこれだけ。 Ollamaの日本語性能ランキング
- sounddevice: マイクからの音声取り込み
- faster-whisper(small, int8): ローカルで文字起こし。GPUなしのMacでも毎回15秒前後で動作
- Ollama + gemma4:e4b: ローカルのLLMで返事を生成
- AivisSpeech: ローカルで日本語の音声合成
- VAD(自作の簡易版): RMS閾値で無音を検出して自動停止
全部ローカルで動く。APIキーもクラウドも使ってない。ネットワークを切ってもそのまま動く。
画面は1ページ構成。話す相手を選んで、AIの声を選んで、会話を始めるだけ。会話ログが画面下に流れていき、裏側では録音ファイルが05_Capture/inbox_voice_raw/に溜まっていく。
会話が終わると、文字起こしして、ペルソナ抽出スクリプトが走る。このスクリプトがpersona_profile.jsonに追記する形式にしたから、次に会話を始めるとき、このファイルが自動的にプロンプトに注入される。つまり会話を重ねるほど、AIは私のことを知っていく。
一番のこだわり:会話中のフィードバック学習
最初のバージョンはAIがインタビュアーすぎた。「それどう思った?」「何が一番大変だった?」「どうやって乗り越えた?」——質問ばっかり。会話としては疲れる。
だから会話の途中でこう言った。「ちょっと質問多くない?普通にしゃべってよ」
そこでピンと来た。会話中のこういうダメ出しを、次回から本当に守らせればいいじゃん、って。
仕組みはシンプルだ。会話が終わったら、会話ログ全体をローカルのLLMに渡して、こう頼む。「この中で、相手がAIの話し方や振る舞いについて不満・指示・希望を言っている箇所を見つけて、『次回から守るべき指示』を1文にして抽出して」
返ってくるのは、短い指示の羅列。「質問は減らし、共感を増やす」「自然な会話の流れで話す」「相手の発言を理解した上で返答する」——こういう感じ。
これをJSONファイルに追記して、次に同じ人と会話するとき、プロンプトの冒頭に「相手からの過去の指示(絶対に守る)」として注入する。結果、AIは一晩にして「この人との話し方」を学んでいく。コードを一行も触らずに、会話の中でAIの振る舞いが変わる。
『ペルソナ学習』じゃなくて『関係性学習』だと気づいた
動かしているうちに、おもしろいことに気づいた。
話す相手ごとに別ファイルに分けてるから、同じLLMが相手によって違う顔を見せる。一ノ瀬泰斗と話すときは軽い口調、友達と話すときはもっとフランク、仕事相手と話すときは落ち着いた返し——全部同じgemma4:e4bなのに。
これって、人間の関係性と同じなんだよね。人が変わるんじゃなくて、関係が変わる。私は上司の前と親友の前で別人みたいに振る舞うけど、それは嘘をついてるわけじゃない。関係によって言葉の出方が変わるだけで。
このアプリは、その「関係ごとのAIの顔」を別ファイルで持てるようにしただけ、とも言える。ペルソナ学習って呼ぶより、関係性学習って呼ぶほうが正確。
実装で詰まった部分と解決策
いくつか詰まった箇所があるので、作ってみたい人向けに書いておく。
AIの声が録音に混ざる問題。AIが喋っている間にマイクが拾ってしまって、次の文字起こしがAIの声で汚染される。試したのはspeak_blockingを完了するまで次の録音を始めない、という対策。これでほぼ解決した。念のため、録音開始前に0.4秒の残響待ちも入れてる。
ハンズフリーのVAD。sounddeviceのInputStreamで100msごとにチャンクを読み、絶対値平均のRMSが閾値(350くらい)を超えたら発話開始と判断。その後、RMSが閾値を下回った状態が連続0.8秒続いたら、発話終了と判断。マイクに指を立てるとノイズで誤検出するから、初期化時に環境音レベルを3秒間で測定して閾値を自動調整する仕組みにした。
実際の測定では、quiet環境でRMS値が20~40、normal環境で50~100、speech区間で200~500という分布になった。350は「確実に人間の音声」の安全ラインだけど、環境によって調整が必要。
文字起こしのタイムラグ。faster-whisper small int8 で15秒の音声ファイルの処理に7~9秒かかる。これが遅いと会話のテンポが崩れる。Orin Nanoのような推論特化デバイスなら短縮できるけど、MacBook Proで今の構成なら、これが限界。
ここで試したのは、文字起こしの並列化。別プロセスで走らせて、UI更新を非ブロッキングにした。その結果、ユーザーが聞こえるレスポンスタイムは「喋った後、最大15秒」になった。十分実用的。
『ひとり言が資産になる』感覚
このアプリの面白さは、毎回の会話データが蓄積されていく点にある。
通常、会話ログは記録されて終わり。だけど私のアプリでは、会話ログから「AIが守るべき指示」と「私のペルソナ情報」が自動抽出されて、JSONファイルに追記される。つまり、ひとり言を喋るだけで、それが全部「次のAIとの関係性」に反映される——資産化される。
今、persona_profile.jsonには34の項目が溜まっている。「朝は目覚めが悪い」「コーヒー好き」「詰まった問題には別角度からのアプローチを好む」「やたらと細部にこだわる傾向」などなど。
これを読むだけで、私の思考パターンが見える。作り手として、AIがどう理解してるかを知られるのは面白い。時々ズレてることもあるけど——そういう時こそ、また会話するタネになる。
ローカルじゃないと意味がない
「ローカルのLLMでペルソナ学習」ってネタだけなら、OpenAIのAPIを使う方が楽だ。品質も上。
だけど、会話ログも、ペルソナファイルも、全部が自分のMacの中に入ってる。誰にも見られない。削除したければ削除できる。API経由なら、会話が全部サーバーに記録される——自分の内面の日記が、どこかの企業のサーバーに置かれる感覚。
私にはそれが合わなかった。ローカルじゃないと意味がない。
もう一つ、実装の自由度。Ollamaなら、モデルもプロンプトもファイル構成も、全部自分の手でいじれる。APIだと、提供されたインターフェースの枠内に閉じ込められる。創意工夫の余地が生まれない。
次にやりたいこと
今の形は、単一のLLMモデルで関係性を学習する仕組み。次は、その「関係性」をモデル間で共有できないか、って考えてる。
例えば、私と親友の関係性を学んだLLMがいるとする。その「話し方の指示」を、別のモデルにコピーすれば、新しいモデルも同じ関係性を再現できるはず。
それができれば、モデルの入れ替えが簡単になる。ollama switchコマンド一つで、新しいモデルに切り替えても、「この人との関係性」は保つ——そういう運用が可能になる。
ローカルAIの活用も、単なる「品質の代替え」から、「パーソナル性の保証」へ進化するタイミングだと感じてる。