メインコンテンツへスキップ
見出し画像

【配布】エッジAI用分散サーバー作ってみた ~llamacpp x GemmaでローカルAI APIを構築~

    こんにちはRcatです。
    先日、こちらの記事で量子化された小型のAIを自分のパソコンで動かしてみました。
    結果としてCPUでも実用レベル。GPUなら運用できるレベルの性能を確認することができました。

    今回はこの時に作ったスクリプトを少々改装して自宅専用のAIサーバーにしてみましたので、解説と配布を行おうと思います。


    はじめに

    利用規約

    情報や作品の活用時は事前に利用規約をご確認ください。

    コメントについて

    利用規約のガイドラインを確認の上コメントしてください。
    則っていないコメントは削除します。


    概要

    エッジAIって何?

    エッジとは先端のことです。つまり大きなサーバーではなく、個々の端末の中で動くAIという意味になります。
    とはいえ、さすがにモバイル端末で動かすというのはなかなかなので、今回は個人が持っているパソコンをエッジと定義します。

    スマホでも最近は動きますが、それなりに高性能なスマートフォンでもさすがに多少のストレスがあります。
    そもそもバッテリーをバカ食いするので、スマホで動かす意味が今のところはあまりない気がします。




    仕様

    今回作成したAIサーバーの仕様は次の通りです。
    特に処理の移譲に関しては工夫した点となります。こうすることで、CPUでは処理が遅いので複数のコンピューターでjobを分散したり、GPUのあるコンピューターを優先的に使ったりできます。

    • 言語

      • Python

    • OS

      • Windows11

      • Linux (Ubuntu)

    • インターフェース

      • WEB API

      • WEBブラウザ

      • コマンドライン

    • 対応プロセッサ

      • CPU (Intel N100, Ryzen5 3600, Ryzen AI MAX+395で確認済み)

      • GPU (CUDA, RCOmで確認済み)

      • (ライブラリ的にはNPUも行けるらしい)

    • ライブラリ

      • llamacpp

    • モデル
      モデルに関しては前回の記事をご確認ください。

      • Gemma3 4b-it-qat-Q4_K_M

    • その他

      • スケールアウト可能
        同じローカルネットワーク上に、このプログラムを実行しているパソコンがあれば、jobを移譲することが可能です。




    機能紹介

    まずは本ツールでできることを紹介します。

    コマンドラインを使ったチャット

    基本中の基本ですね。サーバーにしなくても、コマンドラインでやり取りすることができます。なお、履歴を保持しているわけではないので、1回きりのお話になります。

    R:\Rcat>start.bat -p "こんにちわ" --temperature 0.1 --top_p 0.95 --max_tokens 1024 --model "R:\llamacppエッジAIサーバー\gemma-3-4b-it-qat-Q4_K_M.gguf"
     
    2025-07-05 16:09:55,620 INFO llama_cpp_test モデルをロード中: gemma-3-4b-it-qat-Q4_K_M.gguf
    2025-07-05 16:09:57,431 INFO llama_cpp_test モデルのロードが完了しました。
    2025-07-05 16:09:57,433 INFO llama_cpp_test ストリーミングモードで応答を生成中...
    
    こんにちは!何かお手伝いできることはありますか? どんなことでもお気軽にご質問ください。 😊

    引数紹介

    • -p プロンプト
      モデルに渡すプロントを指定します。これは必須です。

    • --systemprompt システムプロンプト
      システムプロンプト指定します。省略可能です。

    • --temperature
      temperature パラメーターです。省略可能です。

    • --top_p
      top_pパラメーターです。省略可能です。

    • --max_tokens
      max_tokens パラメーターです。省略可能です。

    • --model
      読み込むモデルをフルパスで選択します。
      省略した場合、プログラム内に書いてあるデータを読み込みます。私の環境以外だと多分合わないはずなので、ほぼ確実に指定してください

    Webサーバー化して使う

    実行時の引数を変更することで、Webサーバーとして実行できます。

    Rcat>start.bat -s --port 80 --model "R:\llamacppエッジAIサーバー\gemma-3-4b-it-qat-Q4_K_M.gguf"
    
    2025-07-05 16:14:23,892 INFO llama_cpp_test モデルをロード中: gemma-3-4b-it-qat-Q4_K_M.gguf
    2025-07-05 16:14:25,676 INFO llama_cpp_test モデルのロードが完了しました。
    この機能はLinux (POSIX) 環境でのみサポートされています。
     * Serving Flask app 'llama_cpp_test'
     * Debug mode: off
    WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
     * Running on all addresses (0.0.0.0)
     * Running on http://127.0.0.1:80
     * Running on http://192.168.0.199:80
    Press CTRL+C to quit

    "Running on http://XXX.XXX.XXX.XXX:XX"という表記が出てくるので、ここにアクセスすればブラウザから使えます。

    画像

    引数紹介

    • -s --server
      サーバー化するオプションです。最優先で認識されます。

    • --port
      ポート番号を指定します。省略可能です。

    • --master
      マスターサーバーとして起動します。これを指定したサーバーだけが外部のノードに対して移譲する機能が使えます。

    • --priority
      分散処理時の優先順位。小さい方が優先度が高く、キューの条件が同じ場合の選択に使用される。詳しくは分散処理へ。

    • --cpu
      Linuxのみ。cpulimitコマンドを使ってCPU使用率を制限します。--cpucoreオプションと併用。省略可能

    • --cpucore
      --cpuとセット。CPUのコア数を指定。入力を間違えると正確にCPU使用率制限できない。

    WEB画面で使う

    サーバー化した状態でアクセスすると以下のような画面になります。ここに入力することで、簡単にAIとチャットすることができます。

    画像

    翻訳機能を使う

    右上に小さく翻訳というリンクがあるのでクリックすると翻訳に切り替わります。
    こちらはシステムプロンプトに事前に指示が書いてあるだけですが、入力するだけで英語に翻訳できるようにしてあります。ちゃんと翻訳してくれるかはモデルの精度次第です。

    画像




    APIを使う

    一番の目的はこれでしょう。
    これを使うことで完全にローカルで別のプログラムからAIを呼び出すことができます。

    チャットAPI

    チャットをするためのcgiです。
    必要なパラメーターをJSONボディとしてPOSTします。

    エンドポイント /CGI_DoChat

    パラメーターは全て任意です。必要なところだけ指定するようにしてください。

    {
    "system_prompt": "システムプロンプト"
    "user_prompt": "ユーザープロンプト"
    "max_tokens": int #最大トークン数 8192
    "temperature": float #温度パラメーター 1.0
    "top_p": float #トップPパラメーター 0.95
    "top_k": float #トップKパラメーター 40
    }

    Pythonでの実行例

    >>> import requests
    >>> body = {
    ... "system_prompt":"ユーザーの入力を中国語に翻訳してください",
    ... "user_prompt":"ねこはもふもふで癒されます"
    ... }
    >>> resp = requests.post(url="http://localhost/CGI_DoChat",json=body)
    >>> print(resp.json().get("response"))
    猫很软萌,让人感到放松。(Māo hěn ruǎnméng, ràng rén gǎndào ràngshuǎn.)
    
    または、少しくだけた表現なら:
    
    猫咪超萌,超级治愈!(Māo mī chāo méng, chūjí zhìyù!)
    
    **解説:**
    
    * **猫 (māo):** 猫
    * **很 (hěn):** とても
    * **软萌 (ruǎnméng):** ふわふわでかわいい、可愛らしい
    * **放松 (rǎngshuǎn):** リラックスする、癒し
    * **治愈 (zhìyù):** 癒す
    * **猫咪 (māo mī):** 猫(可愛らしい言い方)
    * **超萌 (chāo méng):** 超可愛(「超」は強調のため)
    * **超级 (chūjí):** とても(強調のため)
    
    どちらの翻訳も元の文のニュアンスを捉えています。状況や伝えたい感じによって使い分けてください。
    
    >>> import json
    >>> json.dumps(resp.json(),indent=2,ensure_ascii=False)                                                                 '{\n  "first": 0.30786895751953125,\n  "response": "猫很软萌,让人感到放松。(Māo hěn ruǎnméng, ràng rén gǎndào ràngshuǎn.)\\n\\nまたは、少しくだけた表現なら:\\n\\n猫咪超萌,超级治愈!(Māo mī chāo méng, chūjí zhìyù!)\\n\\n**解説:**\\n\\n* *
    *猫 (māo):** 猫\\n* **很 (hěn):** とても\\n* **软萌 (ruǎnméng):** ふわふわでかわいい、可愛らしい\\n* **放松 (rǎngshuǎn):** リラックスする、癒し\\n* **治愈 (zhìyù):** 癒す\\n* **猫咪 (māo mī):** 猫(可愛らしい言い方)\\n* **超萌 (chāo méng):** 超可愛(「超」は強調のため)\\n* **超级 (chūjí):** とても(強調のため)\\n\\nどちらの翻訳も元の文のニュアンスを捉えています。状況や伝えたい感じによって使い分けてください。",\n  "time": 5.457850456237793,\n  "tokens": 270\n}'             >>> print(json.dumps(resp.json(),indent=2,ensure_ascii=False))                                                          {
      "first": 0.30786895751953125,
      "response": "猫很软萌,让人感到放松。(Māo hěn ruǎnméng, ràng rén gǎndào ràngshuǎn.)\n\nまたは、少しくだけた表現なら:\
    n\n猫咪超萌,超级治愈!(Māo mī chāo méng, chūjí zhìyù!)\n\n**解説:**\n\n* **猫 (māo):** 猫\n* **很 (hěn):** とても\n* **软萌 (ruǎnméng):** ふわふわでかわいい、可愛らしい\n* **放松 (rǎngshuǎn):** リラックスする、癒し\n* **治愈 (zhìyù):** 癒 す\n* **猫咪 (māo mī):** 猫(可愛らしい言い方)\n* **超萌 (chāo méng):** 超可愛(「超」は強調のため)\n* **超级 (chūjí):** とても(強調のため)\n\nどちらの翻訳も元の文のニュアンスを捉えています。状況や伝えたい感じによって使い分けてください 。",                                                                                                                      "time": 5.457850456237793,
      "tokens": 270
    }

    応答もJSONです。
    responseキーの中にAIの応答の文字列が入っています。それ以外は処理時間やトークンなどが入っています。この場合は5秒ですね。

    翻訳API

    翻訳をするためのAPIです。
    テキストだけでいい場合はGETでも可能

    エンドポイント /CGI_Translate

    パラメーター

    {
    "text": "翻訳したい文字列"
    "max_tokens": int #最大トークン数 4192
    "temperature": float #温度パラメーター 0.5
    "top_p": float #トップPパラメーター 0.95
    }

    GETで実行した例

    画像

    情報取得API

    これはこの後紹介する分散処理用のAPIです。
    サーバーの優先度、キュー残り、実行状態の3種類の情報が返されます。

    画像

    ちなみにですが、AIの処理は重いので並列実行はできません。
    複数同時にリクエストを受け付けた場合はキューに格納し、先頭から順番に処理していくような仕組みになっています。
    他のノードがある場合は、一番空いてるところに委譲します。空いてなければ自分で実行という感じです。キューの数が同じになるように動作します。
    10個以上貯まってくると過負荷ということでエラーを返すようになっています。




    活用事例

    Discord BotをAI化

    やっぱりこれでしょう。プライベートなメッセージで翻訳や要約をさせたい時、外部のサーバーに委託するのは抵抗があります。
    しかし、自分のサーバーならどうでしょう?何も気にせず実行できますよね。

    特定のリアクションに反応して翻訳を実行する例

    画像




    導入方法

    パッケージ内容の確認

    配布は再下部で行っております。
    パッケージ内容は以下のようになっています。

    画像

    モデルの配置

    まず、最初にAIのモデルを用意してください。
    ダウンロードできたらこのフォルダ、あるいは好きなところに置いてください。
    配置した場所に対して--model引数を使ってモデルをセレクトできます。

    画像

    モデルのダウンロード方法はこちらの記事で紹介しています。自分のパソコンのスペックにあったものを選んでください。

    Pythonのインストール方法

    本作はPythonでできていますので、必ず導入をしてください

    環境の構築

    Windowsの場合はstart.bat、Linuxの場合はstart.shを実行すれば自動で仮想環境が作成され、ライブラリのインストールが始まります。
    この時にパラメーターもきちんと指定した上で、起動すれば正常な動作を確認することができるはずです。
    パラメーターを指定しなかった場合は環境構築後落ちます。

    ※配布パッケージで全自動実行確認をしているのはWindowsとなります。

    画像

    Windowsの方はサーバーとして起動するバッジも同梱しています。好きな方をご利用ください。なお、サーバーとして使う場合もモデルの指定が必要なので、中身の部分を少し書き換えてください。

    画像

    GPUを使う場合

    先ほどの記事でも紹介していますが、GPUを使う場合は自分でライブラリをビルドする必要があります。ビルド方向につきましては、上の記事で紹介しています。
    そのため、自動環境構築は行わず、自分で仮想環境を作った後、先にこのライブラリだけビルドした上で、残りのライブラリをインストールするようにしてください。
    一度入れてしまうとアンインストールなど発生し面倒です。

    RCOm(Radeon)で使う場合

    こちらの記事ではRyzen AI MAX+ 395の内蔵GPUであるRadeon 8060Sを使っています。
    使い方次第ではRTX4070を超えるらしい化け物です。



    分散処理を行う

    本ツールは分散処理に対応しています。
    分散と言っても1つの入力を分担して処理するわけではなく、ジョブごとに別のコンピューターで実行するという話です。
    先ほど紹介したwebapiはこの分散にも利用されています。

    簡単に言えばこういう構成でこういうことができます。

    単体時
    メインのAIサーバーが頑張るがCPUなので処理が遅い
    たまに使うくらいなら問題ない感じ。

    画像

    ノード起動時
    サブのAIノートが立ち上がっている時は、処理を外部に委託。
    もちろんサブノートが利用されている間は自らも処理する。
    GPUを使用して高速に処理するサブノードが1台あるだけで全然違う。

    画像

    理論上はサブノードは複数立ち上げることができます。
    GPUが無くても数の暴力で並列処理は可能です。

    画像

    分散処理を有効にする

    この処理を使用するには外部のノードを検索するための追加モジュールが必要です。
    こちらの記事で配布しているM-Searchモジュールになります。

    あるいは直接ソースコードを書き換えてノードを書き込んでください。
    このリストにIPアドレスとポート番号のセットを入れておけば認識されます。

    画像

    M-Searchはダウンロード後、本ツールのフォルダの中に入れてください。

    画像

    分散処理可能モードで起動するには--masterパラメーターを指定します。

    >start.bat -s --priority 100 --master --model "もでる☆"

    分担する側は優先度だけ指定します。
    以下の場合はマスターの方よりも低いので、こっちが優先的に処理を持ってく感じですね。

    >start.bat -s --priority 0 --model <>

    ノードモードで起動時に、モデルのロードの後に"M-SEARCHサーバー起動"という文字が増えます。
    これが出てくれば分散ノードとして起動しています。

    画像

    あとはマスター側に連続で入力すると、分散の方とマスターと両方で同時に処理が行われるのが確認できると思います。

    分散処理の基準について

    以下の条件でジョブが振り分けされます。
    上の方が優先度が高いです。

    1. キューが空いてるノード(マスター以外)
      すでにキューがあった場合は一番少ないノードに割り振りされます。
      マスターは全キューを持った状態なので一番最後になります。

    2. 実行状態でないノード
      全てのキューが空でない場合、実行状態でないノードが選択されます。

    3. 優先度の設定
      全ての条件が同じだった場合、優先度を使用して割振りします。


    まとめ

    今回は量子化LLMを使った個人AIサーバーを作成しました。
    とうとう自宅で常時LLMが稼働する時代が来ましたね。
    これで利用規約を気にすることなくどんな内容でも入力が可能です!
    適度にモラルを守りつつ使いましょう。


    配布情報

    配布URL

    以下のURLより配布しています。
    利用規約に同意の上ご利用ください。

    https://script.google.com/macros/s/AKfycbxdcr8pnazR7RbjaSICTtaNWfN7h_rjQrKlZ3h9CZpPRFzRILk1OGc8mZqKbF-NXNO9/exec?name=ローカルエッジAIサーバー


    リンク集

    【Linux】Systemd追加支援スクリプト

    【Windows】タスクスケジューラーの追加方法

    LoggingBOTの導入方法

    ミニPCにLinuxをインストール


     
     
    モノづくりが趣味。 "売ってないなら自分で作ればいいじゃない"をコンセプトに、機械/電気/AI/プログラム/ネットワーク 全部やります。 記事執筆はAI不使用。 ご連絡や利用規約はプロフィール記事参照。

    あなたへのおすすめ