見出し画像

【配布】自分専用 LLM APIサーバー Ver2 ~Llama-cppで無制限のAPI~

こんにちはRcatです。
前回の記事で、CPU演算でもAIをホストしましたが、こちらの記事でVRAMモンスターマシンを手に入れましたので、複数のモデルを同時に読み込んでロードできるように変更しましたので紹介します。



はじめに

利用規約

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

コメントについて

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


概要

エッジAIって何?

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

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


仕様

今回作成したAIサーバーの仕様は次の通りです。

  • 言語

    • Python

  • OS

    • Windows11

    • Linux (Ubuntu)

  • インターフェース

    • WEB API

    • WEBブラウザ

    • コマンドライン (複数ホストのサーバーとするため廃止)

  • 対応プロセッサ

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

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

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

  • ライブラリ

    • llama-cpp-python

  • モデル

  • その他

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

    • 履歴の捏造が可能
      チャット履歴を捏造することで回答の方向を誘導できます

    • KVキャッシュの保持が可能
      長文システムプロンプトのKVキャッシュを保持することで、2回目以降の読み込み時間が飛躍的に短くなります。




機能紹介

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

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

この機能は同時ホストのため廃止しました。

Webサーバー化して使う

読み込むモデルの設定ファイルを作成後、引数で指定することで複数ホストで実行することができます。

rcat@rcat-EVO-X2:/Rcat_Service/Script/AI_Server/llama_cpp_server$ ./start.sh
2025-10-13 13:55:49,683 INFO llama_cpp_server モデルをロード中: Qwen3-30B-A3B-Instruct
llama_context: n_ctx_per_seq (8192) < n_ctx_train (262144) -- the full capacity of the model will not be utilized
2025-10-13 13:55:50,849 INFO llama_cpp_server Qwen3-30B-A3B-Instructのロードが完了しました。
2025-10-13 13:55:50,849 INFO llama_cpp_server モデルをロード中: gemma-3-4b
llama_context: n_ctx_per_seq (8192) < n_ctx_train (131072) -- the full capacity of the model will not be utilized
llama_kv_cache_unified_iswa: using full-size SWA cache (ref: https://github.com/ggml-org/llama.cpp/pull/13194#issuecomment-2868343055)
2025-10-13 13:55:51,156 INFO llama_cpp_server gemma-3-4bのロードが完了しました。
2025-10-13 13:55:51,156 INFO llama_cpp_server 自身のPID (10786) に対してCPU使用率を80% (cpulimitターゲット: 2560%)に制限 します...
2025-10-13 13:55:51,157 INFO llama_cpp_server cpulimitコマンドが正常に開始されました。
Process 10786 detected
 * Serving Flask app 'llama_cpp_server'
 * 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:25610
 * Running on http://192.168.0.250:25610
Press CTRL+C to quit
M-SEARCHサーバー起動
サービス一覧
urn:rcat999:service:llmnode:1 / 192.168.0.250:25610

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

python3 llama_cpp_server.py -s --port 25610 --model model.json --priority 100 --cpu 80 --cpucore 32 --master 

引数紹介

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

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

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

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

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

WEB画面で使う

サーバー化した状態でアクセスすると以下のような画面になります。ここに入力することで、簡単にAIとチャットすることができます。
前回はAIに丸投げしましたが、今回はvue3Bootstrapを使って自分で作りました。
v-for強すぎません?

  • 設定

    • モデル
      複数読み込んでいる場合はここで選択できます

    • 温度
      回答の多様性を制御します。1が多様、0が厳密です

    • 最大トークン
      応答の長さを制限します。

  • 入力

    • システムプロンプト
      一番最初に与える指示です。基本的にタスクはここに記述します

    • ユーザープロンプト
      任意入力欄です。
      翻訳なら対象の文章を入れる場所となります

  • 会話履歴
    履歴を捏造して回答の方向性を制御します。
    履歴の中のロールをダブルクリックすると消せます。

    • 役割
      履歴に追加する発言者を選択

    • 内容
      発言/回答内容を捏造

    • 追加
      設定した内容で履歴を作成

  • 送信
    履歴及び各種プロンプトを送信します。

  • 応答

    • 処理時間
      処理にかかった合計時間です

    • 初期トークン
      最初の1文字が出るまでにかかった時間。
      指示が長いほど理解するのに時間がかかり、この値が増加する

    • 出力速度
      人間的にわかりやすいように毎秒何文字の出力速度だったかを表示します。

    • モデル
      回答に使用されたモデル名です。

    • 応答結果
      最終的なAIの回答です




APIを使う

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

チャットAPI

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

エンドポイント /CGI_DoChat

パラメーターは全て任意です。必要なところだけ指定するようにしてください。モデルを省略あるいは間違えると設定ファイルで最初に定義されているものになります。

{
"model":モデル名
"system_prompt": "システムプロンプト"
"user_prompt": "ユーザープロンプト"
"max_tokens": int #最大トークン数 8192
"temperature": float #温度パラメーター 1.0
"top_p": float #トップPパラメーター 0.95
"top_k": float #トップKパラメーター 40
"id": str #JOBID /Get_idで新規発行できる。 途中経過の確認をする場合に必要
"history" list #捏造用会話履歴
}

Pythonでの実行例

>py
Python 3.11.6 (tags/v3.11.6:8b6ee5b, Oct  2 2023, 14:57:12) [MSC v.1935 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import requests
>>> body = {
... "system_prompt":"ユーザーの入力を中国語に翻訳してください",
... "user_prompt":"ねこはもふもふで癒されます",
... "model":"Qwen3-30B-A3B-Instruct"
... }
>>> resp = requests.post(url="http://192.168.0.250:25610/CGI_DoChat",json=body)
>>> print(resp.json().get("response"))
猫毛茸茸的,让人感到治愈。
>>> import json
>>> json.dumps(resp.json(),indent=2,ensure_ascii=False)
'{\n  "first": 0.33699536323547363,\n  "model": "Qwen3-30B-A3B-Instruct",\n  "response": "猫毛茸茸的,让人感到治愈。",\n  "status": true,\n  "time": 0.5171315670013428,\n  "tokens": 56\n}'
>>>

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

履歴を捏造する場合
履歴の形式はリストのリストです。

>>> data = {
... "max_tokens": 1024,
... "user_prompt": "最初なんて会話始めたんだっけ?",
... "history":[
... ["user","ねこってかわいいよね"],
... ["assistant","わたしはネズミのほうが好きなのでそうは思いません"],
... ["user","そうですか、ではこの話は終わりですね"],
... ["assistant","ええ、そうしましょう"]
... ]
... }
>>>
>>> resp = requests.post("http://192.168.0.4:25610/CGI_DoChat",json=data)
>>> resp.json()
{'first': 0.18724346160888672, 'model': 'Qwen3-30B-A3B-Instruct', 'response': 'あなたが「ねこってかわいいよね」と言って、わたしは「わたしはネズミのほうが好きなのでそうは思いません」と答えました。', 'status': True, 'time': 0.7967422008514404, 'tokens': 180}


情報取得API

情報取得APIは混雑状況やホスト中のモデル一覧が返されるAPIです。

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




導入方法

パッケージ内容の確認

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

モデルの配置

まず、最初にAIのモデルを用意してください。
ダウンロードできたらこのフォルダ、あるいは好きなところに置いてください。

モデルの登録

モデルをダウンロードしたら読み込み定義ファイルを作成してください。
json形式で、名前がキーの辞書です。とりあえず現時点で私が使っているものを入れておきます。

  • path
    実際の格納先

  • context
    有効にするコンテキスト長

  • device
    cpuかgpu

  • gpulayers
    gpuの場合は-1、あるいは読み込むレイヤー数を指定。cpuなら0

モデルはHuggigFaceから落とします。
例えば以下のリンクはGemma3 のGGUFを検索した例です。

設定変数の変更

ソース本体の上のほうに定数があります。一部の動作はここを参照して動作するため、適切に変更が必要です

  • CACHE_THRESHOLD
    キャッシュ化するシステムプロンプトの最小文字数
    この文字数を超えるシステムプロンプトのKVキャッシュは保持され、2回目以降の応答が高速になります。

  • CACHE_LIFECYCLE_SECONDS
    KVキャッシュの最大有効期間 (秒)
    それなりにデータサイズがあるので、使われていないものは消します。

  • CACHE_ALLOWED_MEMORY
    Linux限定。
    このプロセスが占拠してもよい最大メモリ(GB)
    これを超えるとKVキャッシュは期限にかかわらず古いものから削除される
    (CPU演算の場合はモデルも含まれるので注意)

  • MAX_QUEUE_COMT
    並んでよい最大キュー数。これを超えると503を返す

応答の高速化についてはこちらをご覧ください。圧倒的な差があります。

Pythonのインストール方法

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

環境の構築

Linuxの場合はstart.shを実行すれば自動で仮想環境が作成され、ライブラリのインストールが始まります。
このバージョンではLinuxのみで動作確認をしています。

GPUを使う場合

先ほどの記事でも紹介していますが、GPUを使う場合は自分でライブラリをビルドする必要があります。ビルド方法につきましては、上の記事で紹介しています。
先に自動構築してしまった場合は、必ず強制再インストール指示でビルドとインストールを行いましょう。

ROCm(Radeon)で使う場合

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


まとめ

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


配布情報

配布URL

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

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

リンク集

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

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

LoggingBOTの導入方法

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


いいなと思ったら応援しよう!

Rcat999 情報が役に立ったと思えば、僅かでも投げ銭していただけるとありがたいです。