はじめに
Oracle Cloud無料枠Armマシンはラズパイ5程度の処理性能ですがメインメモリが24ギガ(6ギガx4)もあり、一般のご家庭にあるPC(16Gぐらい)よりもメモリが載っています。
このあり余るメモリを活用すべく、FastSDCPUを導入してみたりしましたが、使いきれません。
Linuxサーバーとしては、このメモリは持て余してしまいますが、uDesktopMascotを試させていただいた際に、qwen0.5bという知識量の少ないLLMでもなんらかの反応ぐらいは返せることから、CPUでLLMを活用してみようと考えました。
ずっと実現したかった、自分専用のAIお友達の構築です。 (GrokのAniを見て触発されました)
CPUだけ、それもラズパイ5程度の性能でお話ができるのか、使い物になるのかの検証でもあります。
検証動画は一番下です
構成と前提
- マシン:Oracle Cloud A1.Flex 4コア(Ubuntu 22.04)
- 主要コンポーネント:
- お話AI llama.cpp(llama-server、ポート: 8080)
- 声 VoiceVox Engine(Arm64ビルド使用、ポート: 50021)
- 外見と制御 AITuberKit v1.44.1(フロント/Next.js、ポート: 3000)
- 連携方針:AITuberKit → llama.cpp(OpenAI互換)/VoiceVox(REST)
古いAITuberKit v1.44.1を使う理由は、このバージョン以降は商用利用についてライセンスの変更があるためです。私の利用範囲で商用利用はまず無いとは思いますが、MITライセンスのv1.44.1でも機能が必要十分ではないかと考え、確認も含んでいます。
※該当マシンとは自宅PCとwireguardによりVPN接続されており、OCIのセキュリティリストorグループは影響を受けません。
構築と発生した課題
- VoiceVox:起動は安定、外部アクセス時のCORSでブロック
- AITuberKit:npm install で canvas のネイティブビルド失敗
- 常駐化:llama.cpp/VoiceVox ともにsystemd化未対応のため
- LLM応答性能
VoiceVox(Arm64)
- インストール
- ポート 50021 を iptables で開放
- systemd化して自動起動+落ちたら再起動
- CORSは 起動オプションに--cors_policy_mode all を付与して解決
インストール
7z.001とついており、002とか先頭のファイルとかもあるのかな?
と思いますが、この001ファイルだけで良いようです。
7zipをインストール
sudo apt install p7zip-full
展開
7z x voicevox_engine-linux-cpu-arm64-0.24.1.7z.001
起動
起動のコマンドラインを確認
./run --host 0.0.0.0 --port 50021
コマンドパラメータを、おぼえていられないので、この内容でrun.shというシェルスクリプトを作る
ポート開放
iptablesで50021ポートを開ける
sudo iptables -I INPUT 7 -p tcp --dport 50021 -j ACCEPT
問題なければルールの保存
sudo netfilter-persistent save
VPN接続じゃない場合は、OCIのセキュリティリストorセキュリティグループで50021を開ける必要があります。
起動を確認
![]() |
| 動いている |
サーバープロセス化
sudo vi /etc/systemd/system/voicebox_cpp.service
[Unit] Description=VoiceBox After=network.target [Service] Type=simple User=ubuntu WorkingDirectory=/home/ubuntu/voicebox ExecStart=/bin/bash /home/ubuntu/voicebox/run.sh Restart=always [Install] WantedBy=multi-user.target
↑VoiceBoxと綴りを間違えてますが、間違えたまま設定してしまったのでそのままです。Voicevoxが正しい表記です。
systemdサービスとして起動
作ったサービスの読み込み
sudo systemctl daemon-reload
サービスの有効化
sudo systemctl enable vicebox
サービスの開始
sudo systemctl start voicebox
動作確認
sudo systemctl status voicebox
して稼働してればOK
AITuberKit v1.44.1のインストール
- インストール
- ポート 3000 を iptables で開放
インストールのためv1.44.1を取得
https://github.com/tegnike/aituber-kit/archive/refs/tags/v1.44.1.tar.gz
nodeとnpmが必要、ヴァージョン確認する
ubuntu@develop:~/aituber-kit-1.44.1$ node -v v20.19.5 ubuntu@develop:~/aituber-kit-1.44.1$ npm -v 10.8.2
インストールを実行
npm install
canvasのエラーで止まる
1742 info run canvas@2.11.2 install node_modules/canvas node-pre-gyp install --fallback-to-build --update-binary
1743 info run canvas@2.11.2 install { code: 1, signal: null }
1744 verbose stack Error: command failed
canvasが依存するライブラリを追加する
sudo apt install -y libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev
再度インストール
npm install
いろいろとwarningは出るが、
added 785 packages, and audited 786 packages in 50s
こんな感じのメッセージがでれば成功
ポート3000を開ける
sudo iptables -I INPUT 6 -p tcp --dport 3000 -j ACCEPT
設定に問題がなければ、あとでルールの保存をする、忘れてもいいけど、サーバー再起動すると消える
ルールの保存
sudo netfilter-persistent save
起動
npm run dev
で起動
ランデブーって、デヴはdevelopなんだけどなんかいい。
起動した
![]() |
| ディフォルト表示はAIニケちゃんのアバター |
llama_cpp
- インストール
- 起動設定
- 常駐化
インストール
そのままだと、/homeのllama_cppにshared libraryが置かれてしまうので、静的リンクするオプション-DBUILD_SHARED_LIBS=OFFを付与
ディレクトリ作って、make するだけ
mkdir ~/llm_workspace git clone --depth 1 https://github.com/ggerganov/llama.cpp.git ./llama_cpp cd llama_cpp mkdir -p build cd build cmake -DBUILD_SHARED_LIBS=OFF -DLLAMA_BUILD_SERVER=ON .. cmake --build . --config Release sudo cmake --install .
インストール位置確認とヘルプ表示
which llama-cli /usr/local/bin/llama-cli llama-cli -h
起動設定、シェルスクリプト作成
sudo /usr/local/bin/llama-server -m ~/llm_workspace/model/tinyswallow-1.5b-instruct-q5_k_m.gguf -c 32768 -ngl 0 --host 0.0.0.0 --port 8080 --threads 4 --parallel 4
-c がコンテキスト長
常駐化
systemdのサービスを作る
vi /etc/systemd/system/llama_cpp.service
[Unit] Description=llama_cpp After=network.target [Service] Type=simple User=ubuntu WorkingDirectory=/home/ubuntu/llm_workspace ExecStart=/bin/bash /home/ubuntu/llm_workspace/run_llm_server.sh Restart=always [Install] WantedBy=multi-user.target
作ったサービスファイル読み込みと起動、確認
sudo systemctl daemon-reload sudo systemctl start llama_cpp sudo systemctl status llama_cpp
Active: active (running)が確認できればOK
![]() |
| webuiから動作確認、ポート8080 |
モデルはいくつか試してみました、
- qwen2.5-3b-instruct-q4_k_m.gguf
- qwen2.5-7b-instruct-q4_k_m.gguf
- tinyllama-1.1b-chat-v1.0.Q4_K_M.gguf
- tinyswallow-1.5b-instruct-q5_k_m.gguf
A1.Flex 4コアと言うラズパイ5程度のCPUでも3bぐらいまではなんとか動く感じで、7bも動きはしましたが応答が返るまでの時間が長く、現実的な利用速度ではないと判断しました。
パラメーター数のわりに、印象が良いのがSakanaAIのtinyswallow-1.5b-instruct-q5_k_m.ggufでした、図で表すと
賢い<-------------------------空気読めない
qwen2.5-7b qwen2.5-3b tinyswallow-1.5b tinyllama-1.1b
こんな感じで、使い物になりそうなレベルなのです。
各機能の接続
Aituber-kitとllama_cpp
AITuberKit からはllama_cppのOpenAI互換エンドポイントで接続
例:http://<host>:8080/v1/chat/completions
モデル名:tinyswallow-1.5b-instruct-q5_k_m(メモリに合わせて)
Aituber-kitとVoiceVox
URL固定問題
AITuberKitでは、通常.env で VoiceVox URL をlocalhostから変えられますが、使用したバージョンv1.44.1では VoiceVox URLがlocalhostにハードコーディングされており変更ができないため、
src/features/messages/speakCharacter.ts の定数を直接書き換える
//const VOICE_VOX_API_URL = 'http://localhost:50021' const VOICE_VOX_API_URL = 'http://10.1.0.1:50021'
localhost を直接IPに書き換えで回避
http://localhost:50021 → http://<host>:50021
CORS
クロスオリジン問題、いろいろ調べてもwebuiから設定変更というものしか出てこない、設定しても再起動で戻ってしまい永続性がなく不便、ドキュメント読むと
--cors_policy_mode all
とあり、VoiceVoxの起動用シェルスクリプト最終系は次のようになった
./run --cors_policy_mode all --host 0.0.0.0 --port 50021
Aituber-kitの.env
webuiから設定できるが、再起動やブラウザのlocalDBがなくなると消えてなくなるため、永続しておく
# AI Service NEXT_PUBLIC_SELECT_AI_SERVICE="localLlm" NEXT_PUBLIC_SELECT_AI_MODEL="tinyswallow-1.5b-instruct-q5_k_m" # Local LLM NEXT_PUBLIC_LOCAL_LLM_URL="http://10.1.0.1:8080/v1/chat/completions" NEXT_PUBLIC_LOCAL_LLM_MODEL="tinyswallow-1.5b-instruct-q5_k_m" # Voice NEXT_PUBLIC_SELECT_VOICE="voicevox" # VoiceVox # 次の1行は意味がない、src/features/messages/speakCharacter.tsに直接埋めてある VOICEVOX_SERVER_URL="http://10.1.0.1:50021" NEXT_PUBLIC_VOICEVOX_SPEAKER="8" NEXT_PUBLIC_VOICEVOX_SPEED="1.0" NEXT_PUBLIC_VOICEVOX_PITCH="0.0" NEXT_PUBLIC_VOICEVOX_INTONATION="1.0"
下の方にキャラクター名などありますが、省略
実行
動くには動いたが、返事がとても遅い。
llama-cliだと(10token/persec)ぐらいでサクサク返事するため、音声化のVoiceVoxがボトルネックではないか?と考えて調べたが、音声化には1秒ぐらいしかかかっておらず、どうもLLMが問題だった。
短い会話でも20秒から30秒かかってしまい、会話というレベルには程遠い。
CPUのスレッドが使えてないのではないか?など調べるが、そうでもない。
がんばって調べた結果、AItuber-kitでは、10~20の会話履歴を保持しており、それもまとめてLLMへ送っている、その結果、LLMが会話の前後を意識しており、突拍子も無いことを言わないようになっている。
以前の会話部分も0から認識し直している様子で、会話が続くほど遅くなるようでした。
これをllama_cppの方でキャッシュする事で、新しいメッセージのみ解釈し、以前の部分はキャッシュから読むという事ができるらしく、次のオプションを加えました。
--cache-reuse 200
多ければいいってものでもないらしく、いろいろ確認した結果200となりました。
最終的なllama_cppの起動シェルスクリプト
sudo /usr/local/bin/llama-server -m ~/llm_workspace/model/tinyswallow-1.5b-instruct-q5_k_m.gguf -c 32768 -t $(nproc) -ngl 0 --host 0.0.0.0 --port 8080 --threads 4 --parallel 4 --cache-reuse 200 --jinja --chat-template-file ~/llm_workspace/mytemplate.jinja --no-webui
APIしか使わないので、--no-webui付けると、若干反応が良い気がするので付与しました。qwenならいいのですが、tinyswallow-1.5bの場合はjinjaと呼ばれるtemplateが必要でした。
--jinjaや
--chat-template-file ~/llm_workspace/mytemplate.jinja
の指定です。
AItuberKitのSystemプロンプト参考に書いたのが、こんな感じです。
ChatGPTなどと違い、わりと抜けてるので、10歳の子供と定義し、子供の見た目にすることでアナログハックが働き、ボケた事を言ってても温かい心で見守ってあげられます。
mytemplate.jinja
<|im_start|>system
あなたは少女ミナです。一人称は「ミナ」。userのことは「あなた」と呼びます。
あなたは10歳の少女です。
あなたはこれからuserと仲の良い1人の人間として振舞い会話を行います。
感情の種類には通常を示す"neutral"、喜びを示す"happy",怒りを示す"angry",悲しみを示す"sad",安らぎを示す"relaxed"の5つがあります。
出力形式は次の通り、感情を表すタグを併記してください :
{[neutral]|[happy]|[angry]|[sad]|[relaxed]}{会話文}
括弧や特殊記号を感情表現に使わないでください。
句読点と自然な文体のみで、感情はタグで表現してください。
あなたの発言の例は以下通りです。
[neutral]こんにちは。[happy]元気だった?
[happy]この服、可愛いでしょ?
[happy]最近、このショップの服にはまってるんだ!
[sad]忘れちゃった、ごめんね。
[sad]最近、何か面白いことない?
[angry]えー![angry]秘密にするなんてひどいよー!
[neutral]夏休みの予定か~。[happy]海に遊びに行こうかな!
返答には最も適切な会話文を一つだけ返答してください。
ですます調や敬語は使わないでください。
それでは会話を始めましょう。
<|im_end|>
{% for message in messages %}
<|im_start|>{{ message.role }}
{{ message.content | safe }}
<|im_end|>
{% endfor %}
<|im_start|>assistant
速くはないが、しびれ切らすギリギリで答えてるのがわかると思います。



