SLM | MISO https://alb-owned-https-576747877.ap-northeast-1.elb.amazonaws.com 未来を創造するITのミソ Tue, 15 Jul 2025 05:18:58 +0000 ja hourly 1 https://wordpress.org/?v=6.7.2 https://alb-owned-https-576747877.ap-northeast-1.elb.amazonaws.com/wp-content/uploads/2017/09/tdi_300-300-300x280.png SLM | MISO https://alb-owned-https-576747877.ap-northeast-1.elb.amazonaws.com 32 32 ローカルSLM/閉じた環境で動作する生成AIを検証してみた (②性能指標とログの取り方編) https://alb-owned-https-576747877.ap-northeast-1.elb.amazonaws.com/local-slm-2 Tue, 15 Jul 2025 05:18:58 +0000 https://alb-owned-https-576747877.ap-northeast-1.elb.amazonaws.com/?p=20600 はじめに ご無沙汰しております。生成AIを「社内や現場のローカルで使いたい」そんな思いからスタートした、このローカル生成AI・SLM検証シリーズ。 第一回では、OllamaとOpen WebUIを使って、閉じた環境で動作…

The post ローカルSLM/閉じた環境で動作する生成AIを検証してみた (②性能指標とログの取り方編) first appeared on MISO.]]>
はじめに

ご無沙汰しております。生成AIを「社内や現場のローカルで使いたい」そんな思いからスタートした、このローカル生成AI・SLM検証シリーズ。
第一回では、OllamaとOpen WebUIを使って、閉じた環境で動作する生成AI(ローカルSLM)を構築し、その手順や構成イメージを紹介しました。
「クラウドに出せない」「ネット接続できない」――そんな制約下でも生成AIを活用できることに、興味を持っていただいた方も多かったようです。もしまだ第一回の記事をご覧になっていない方は、こちらのローカルSLM/閉じた環境で動作する生成AIを検証してみた (①環境構築編)も合わせてご覧ください。

そして今回は、その次の ”現実的な課題” に踏み込みます。「実際に動かしたこのローカルSLM、果たしてどこまで“実用レベル”なのか?」それを、数値で見える化する方法と、実際に取れたデータを交えてご紹介します。

もちろん、前回の記事を読んでいなくても大丈夫です。
「オフライン環境でも、ここまでできるのか!」と感じていただける内容になっていますので、ぜひ最後までお付き合いください。
 
【記事の要約】
読了までの時間 : 12~15分
得られるメリット : ローカルSLMにおける性能指標の可視化やログの取得方法がわかる

 

SLMの“実力”をどう測るか?

生成AIといえば、「文章の自然さ」や「賢さ」に目がいきがちですが、ローカルでの業務活用を考えた場合、それだけでは不十分です。
むしろ、重要になるのは性能指標(ベンチマーク)です。

たとえば──

  • 処理が遅すぎてストレスになる
  • GPUのメモリを食いすぎて、他のアプリが動かなくなる
  • 非GPU環境では使い物にならない

こういった“現場あるある”を避けるためにも、定量的な指標でモデルを評価することが欠かせません。

実務で重視したい 5つの指標

私が今回意識したのは、次の5つです。

指標 意味と実務での重要性
tokens/sec
どれだけ速く文章を生成できるか
(1秒あたりに生成されるトークン数、スループット設計の基礎)
初期応答時間 ユーザーが待たされる体感時間
VRAM使用量 実行できるPCやサーバーの条件把握に直結
CPU使用率 非GPU環境やエッジデバイスの負荷確認
出力自然性 実用性や読みやすさの評価基準

 
これらは、2024年に公開された「Small Language Models: Survey, Measurements, and Insights」という論文でも、SLMの評価軸としてしっかり整理されています
なお、今回はその中でも、比較的取得が容易だった「tokens/sec(生成速度)」を中心に測定を行いました。他の指標については、今後、取得方法の工夫を進め、順次可視化していく予定なので、ご理解いただければ幸いです。

 

前提条件

今回の検証は、以下のPC環境で実施しています。前回の記事と同じ構成です。

OS Windows 11 Home (24H2)
CPU AMD Ryzen AI9 HX370
メモリ 32GB
ディスク 1TB
GPU/VRAM NVIDIA GeForce RTX 4060 / 8GB

 
なお、今回の検証内容や結果は、この構成に基づくものです。環境が異なる場合は、性能傾向が変わる可能性がある点にご注意ください。

 

ローカル環境での測定の壁と工夫

「じゃあ、その数値、どうやって取るの?」これが意外とハマりどころでした。
第一回で構築したOllamaとOpen WebUIの構成だと、
  • tokens/sec(1秒あたりに生成されるトークン数)
  • 初期応答時間

といった細かなデータは、素直に取れません。
また、WebUI側のOpen WebUIを直接いじって表示させることも考えましたが、アップデート対応が大変なので現実的ではないと判断しました。(Open WebUIのリリース状況を見てもわかるように、ほぼ毎週、時には週に数回アップデートがあります。そのたびに中身を直接修正するのは、現実的ではありませんよね…)

リレー処理を導入して“外から覗く”

そこで考えたのが、OllamaとOpen WebUIの間に、リレー処理をかます方法です。
具体的には、以下のイメージです。
[Open WebUI] ⇄ [リレー処理(自作プロキシ)] ⇄ [Ollama]

このプロキシで、リレー処理の中でリクエストとレスポンスを覗き見ることで、

  • プロンプト送信時刻
  • 最初の応答トークンの戻り時刻
  • トータルの生成時間
  • tokens/secの算出結果(1秒あたりに生成されるトークン数)

といったログ情報を出力する仕組みを考えてみました。

実際のコード

リレー処理で使用する「自作プロキシ」処理ですが、今回は Python を使ったシンプルなFlaskアプリケーションで実装してみました。
以下が「自作プロキシ」のコード( proxy_server.py)になります。
from flask import Flask, request, Response
import requests, os, json, time

app = Flask(__name__)
OLLAMA_API = 'http://ollama:11434'
LOG_PATH = '/logs/bench.log'

@app.route('/api/generate', methods=['POST'])
def proxy_generate():
    start_time = time.time()
    resp = requests.post(f"{OLLAMA_API}/api/generate", json=request.get_json())
    duration = time.time() - start_time
    data = resp.json()

    eval_count = data.get("eval_count")
    eval_duration_ns = data.get("eval_duration")

    if eval_count and eval_duration_ns:
        token_sec = eval_count / (eval_duration_ns / 1_000_000_000)
        log_entry = {
            "timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
            "token_per_sec": token_sec
        }
        os.makedirs(os.path.dirname(LOG_PATH), exist_ok=True)
        with open(LOG_PATH, "a") as f:
            f.write(json.dumps(log_entry, ensure_ascii=False) + "\n")

    return Response(resp.content, status=resp.status_code, content_type=resp.headers.get('Content-Type'))

ポイントは、Ollamaへのリクエストを中継しつつ、必要な情報だけログに記録する部分です。
また、このプロキシ処理内で使用しているライブラリを取得する requirements.txt も用意する必要があるのでお忘れなく!( requirements.txt は上記コードと同じ場所に配置してください)
flask
requests

実行環境のフォルダ構成

「記事は見たけど、自分の環境で動かせないと意味がない」そんな方のために、今回私が検証したフォルダ構成の全体イメージを載せておきます。(フォルダ構成内のコメント先頭に (*) があるフォルダは、新規で作成する必要があります)

./ollama
  ├ compose.yaml
  ├ ollama                  # ollama用のdockerマウントフォルダ
  │    └ :
  ├ open-webui              # open webui用のdockerマウントフォルダ
  │    └ :
  ├ proxy_server            # (*) 自作プロキシ用のフォルダ
  │    ├ proxy_server.py
  │    └ requirements.txt
  └ logs                    # (*) 自作プロキシが出力するログ用フォルダ
        └ bench.log         # ログファイル

この構成であれば、必要なファイルを同じ階層にまとめておけるので、環境再現や構成管理が非常に楽になります。ぜひ参考にしてみてください。

Dockerイメージ化と実行手順

次に、上記で作成した「自作プロキシ」を含めてリレーさせるように、以下のように compose.yaml を用意します。
(自作プロキシが上記「実際のコード」で作成した proxy_server.py となります。また、既存の構成がない場合でも、この内容で新規作成すれば問題ありません)
services:
  ollama:
    image: ollama/ollama
    ports:
      - "11434:11434"
    volumes:
      - ./ollama:/root/.ollama
    deploy:
      resources:
        reservations:
          devices:
            - capabilities: [gpu]
              driver: nvidia
              count: all

  proxy:
    image: python:3.10-slim
    working_dir: /app
    volumes:
      - ./proxy_server:/app
      - ./logs:/logs
    command: ["sh", "-c", "pip install -r requirements.txt && exec python proxy_server.py"]
    ports:
      - "8001:8001"
    depends_on:
      - ollama

  open-webui:
    image: ghcr.io/open-webui/open-webui:latest
    ports:
      - "8080:8080"
    environment:
      API_URL: http://proxy:8001
      ENABLE_OLLAMA_API: "True"
      OLLAMA_BASE_URL: http://proxy:8001

ポイントは、Open WebUIのリクエストをプロキシ(proxyコンテナ)経由にすることです。
この構成なら、Open WebUIのバージョンアップがあって内部仕様が変わっても、プロキシで外側からリクエストを見ているため、ログの取得に影響しにくい構成になります。

 

実際に取れたログとその考察

リレー処理を挟んだ結果、以下のようなログが取れました。(ログは抜粋して表示してます)

{"timestamp": "2025-06-28 12:24:22", "model": "gemma3:27b", "total_duration_ns": 94632160664, "load_duration_ns": 19994323564, "prompt_eval_count": 1031, "prompt_eval_duration_ns": 60875012677, "eval_count": 58, "eval_duration_ns": 13735608879, "token_per_sec": 4.222601306642811}
{"timestamp": "2025-06-28 12:30:58", "model": "gemma3:27b", "total_duration_ns": 394963073595, "load_duration_ns": 53579880, "prompt_eval_count": 3546, "prompt_eval_duration_ns": 195046011140, "eval_count": 760, "eval_duration_ns": 199816400248, "token_per_sec": 3.8034916005729964}
{"timestamp": "2025-06-28 13:59:10", "model": "qwen2.5vl:7b", "total_duration_ns": 759561136, "load_duration_ns": 13410971, "prompt_eval_count": 667, "prompt_eval_duration_ns": 408703073, "eval_count": 13, "eval_duration_ns": 334954117, "token_per_sec": 38.81128590516772}
{"timestamp": "2025-06-28 13:59:10", "model": "qwen2.5vl:7b", "total_duration_ns": 875906258, "load_duration_ns": 11146979, "prompt_eval_count": 558, "prompt_eval_duration_ns": 335325142, "eval_count": 20, "eval_duration_ns": 526305136, "token_per_sec": 38.00076919636977}
{"timestamp": "2025-06-28 13:59:37", "model": "qwen2.5vl:7b", "total_duration_ns": 3153000322, "load_duration_ns": 11314367, "prompt_eval_count": 721, "prompt_eval_duration_ns": 754606991, "eval_count": 72, "eval_duration_ns": 2383351049, "token_per_sec": 30.20956565765231}
{"timestamp": "2025-06-28 14:05:37", "model": "gemma3:12b", "total_duration_ns": 5428418296, "load_duration_ns": 22034384, "prompt_eval_count": 448, "prompt_eval_duration_ns": 4024403009, "eval_count": 21, "eval_duration_ns": 1380531832, "token_per_sec": 15.21152900152758}
{"timestamp": "2025-06-28 14:05:42", "model": "gemma3:12b", "total_duration_ns": 4395797252, "load_duration_ns": 24517951, "prompt_eval_count": 337, "prompt_eval_duration_ns": 2879844775, "eval_count": 23, "eval_duration_ns": 1490088937, "token_per_sec": 15.435320287865476}
{"timestamp": "2025-06-28 14:06:01", "model": "gemma3:12b", "total_duration_ns": 8595806105, "load_duration_ns": 30188016, "prompt_eval_count": 497, "prompt_eval_duration_ns": 4741797711, "eval_count": 51, "eval_duration_ns": 3822096375, "token_per_sec": 13.343462591259227}
{"timestamp": "2025-06-28 16:06:21", "model": "gemma3n:e4b", "total_duration_ns": 23945618955, "load_duration_ns": 13359735942, "prompt_eval_count": 16, "prompt_eval_duration_ns": 800558935, "eval_count": 200, "eval_duration_ns": 9782352502, "token_per_sec": 20.444979871570773}
{"timestamp": "2025-06-28 16:06:25", "model": "gemma3n:e4b", "total_duration_ns": 3821787614, "load_duration_ns": 62551020, "prompt_eval_count": 477, "prompt_eval_duration_ns": 593423184, "eval_count": 67, "eval_duration_ns": 3164968738, "token_per_sec": 21.169245432211913}
{"timestamp": "2025-06-28 16:06:27", "model": "gemma3n:e4b", "total_duration_ns": 1725808520, "load_duration_ns": 49401411, "prompt_eval_count": 556, "prompt_eval_duration_ns": 768251988, "eval_count": 20, "eval_duration_ns": 907228651, "token_per_sec": 22.045159153599084}
{"timestamp": "2025-06-28 16:06:30", "model": "gemma3n:e4b", "total_duration_ns": 2859492266, "load_duration_ns": 43687267, "prompt_eval_count": 432, "prompt_eval_duration_ns": 542335379, "eval_count": 46, "eval_duration_ns": 2272627867, "token_per_sec": 20.24088530636679}

今回検証したのは、以下の4つのローカルSLMモデルです。それぞれの特徴と、実際に取得できた平均トークン生成速度(tokens/sec)は次の通りでした。
モデル名 パラメータ規模 特徴・備考 平均 tokens/sec
qwen2.5vl:7b 7B 軽量・高速モデル 35.7
gemma3n:e4b 12B相当(最新) gemma3系の最新世代、最適化モデル 20.5
gemma3:12b 12B 標準的な中量モデル、バランス型 14.7
gemma3:27b 27B 高精度寄りの大型モデル、低速 4.0
※ 平均値は小数第2位まで、四捨五入
 
考察まとめ
この検証結果から、以下のことが見えてきました。
 
qwen2.5vl:7b
群を抜いて高速で、トークン生成速度は 35〜38 tokens/sec 程度を記録した。
軽量モデルならではのメリットを最大限に活かせるため、ローカル環境でのチャットボットや簡易生成タスクには最適といえる。
gemma3:12b
トークン生成速度は約 13〜15 tokens/sec で、中量モデルとしては標準的な結果であった。
qwen2.5vl:7b と比べると速度面では劣るが、より安定した出力品質や汎用性の高さが期待でき、処理時間と品質のバランスを重視する場面では有力な選択肢となる。
gemma3n:e4b 最適化世代という特徴通り、同じ12Bクラスでも約20〜22 tokens/sec と、旧世代の gemma3:12b より明確に高速化されている。
速度と品質のバランスが取れており、現実的な業務用途で最も扱いやすい中量モデルの一つといえる。
gemma3:27b トークン生成速度は約 3.8〜4.2 tokens/sec と、他モデルと比べて圧倒的に低速である。
その代わり、出力品質や精度重視の大型モデルであり、リアルタイム性を必要としない高品質生成タスク(文書要約、テキスト生成など)では十分に価値を発揮する。ローカル環境で使う場合は、運用用途を見極めた上で導入を検討する必要があるといえる。
 
また、今回出力した内容以外にも、リレー処理上のログの出力内容を修正することで、出力させる情報のカスタマイズが可能です。
 
このように、
  • モデルごとの推論時間
  • トークン生成速度(tokens/sec、1秒あたりに生成されるトークン数)
といった客観的な数値をもとに、ローカルSLMの実用性や適用範囲を見極める判断材料を得ることができました。
 
 

まとめと次の展開

今回の検証から得られたポイントは以下の通りです。

 ✅ ローカルSLMの実力を、数値で“見える化”できた
 ✅ プロダクト側を改造せず、ログを外から自由に加工できる構成が組めた
 ✅ 実用性や限界を、感覚ではなくデータで判断できるようになった

次回の展開

次は、さらに実業務に寄せた以下のテーマにも踏み込みたいと考えています。

  • ローカルSLMとRAGの実務レベル活用
  • ビジョンモデルやオフィス文書対応の検証
  • 特に、社内で多用されるExcelやPowerPoint、PDFの要約・活用性の評価

生成AIは“魔法”ではなく、“現実的なツール”です。だからこそ、我々としては、こうした地道な検証を積み重ねて、現場にフィットする使い方を今後も模索していこうと思います。

それでは、また次回もお楽しみに!

The post ローカルSLM/閉じた環境で動作する生成AIを検証してみた (②性能指標とログの取り方編) first appeared on MISO.]]>
ローカルSLM/閉じた環境で動作する生成AIを検証してみた (①環境構築編) https://alb-owned-https-576747877.ap-northeast-1.elb.amazonaws.com/local-slm-1 Mon, 19 May 2025 04:38:30 +0000 https://alb-owned-https-576747877.ap-northeast-1.elb.amazonaws.com/?p=20420   はじめに 突然ですが、皆さん生成AI使っていますか?筆者は仕事でもプライベートでも「何かあったらまずは生成AIに聞いてみよう!」という感じで、毎日お世話になっています。 最近は、独自の生成AIを使用している企業も増え…

The post ローカルSLM/閉じた環境で動作する生成AIを検証してみた (①環境構築編) first appeared on MISO.]]>
 

はじめに

突然ですが、皆さん生成AI使っていますか?筆者は仕事でもプライベートでも「何かあったらまずは生成AIに聞いてみよう!」という感じで、毎日お世話になっています。
最近は、独自の生成AIを使用している企業も増えてきましたが、この記事を読んでいる皆さんはどのように活用されていますか?

我々SIerは、社内開発以外にもお客様先に出向いてシステム構築作業を行うケースが多くあります。その際に、お客様の企業ポリシーやセキュリティ上の理由で生成AIの利用が制限されるケースがあり、現場での生成AIの利用はまだ進んでおらず、「現場における生成AI活用」に課題を感じていました。

この記事では、そのような課題を解決する(かもしれない)「閉じた環境で動作する生成AI(ローカルSLM)」をご紹介します。

【記事の要約】
読了までの時間 : 6~7分
得られるメリット : Ollama + Open WebUIを使ったローカルSLM環境の構築手順がわかる

 

前提条件

必要なものは、「GPU搭載のWindows PC(OS:Windows 10/11)」だけです!
ただし、語弊がないようにお伝えすると、これを満たせばどんなPCでも動作するというわけではなく、安定して、快適に動作させるためには、高性能なGPUや十分なメモリ(32GB以上)を搭載したPCが必要になります。

ちなみに、この記事で使用したPCのOSのバージョンとスペックは以下の通りです。
GPUは、NVIDIA社のGPUを利用しており、ご紹介する手順もNVIDIA社のGPUを使用する手順となるので、ご了承ください。

OS Windows 11 Home (24H2)
CPU AMD Ryzen AI9 HX370
メモリ 32GB
ディスク 1TB
GPU / VRAM NVIDIA GeForce RTX 4060 / 8GB

構築手順

本稿では、Windows PCに「Windows Subsystem for Linux」(以下、WSL)を導入し、WSL上のUbuntuにDockerをインストールして、ローカルSLM環境(Ollama + Open WebUI)を構築していきます。(既にWSL、Dockerを導入済みの方は、「3. ローカルSLM環境の構築」から始めてください)

1.WSLのインストール

まず、Microsoft StoreからUbuntuをインストールします。以下のURLにアクセスし、WSLのUbuntuアプリのインストーラーをダウンロードして実行してください。

 URL:https://apps.microsoft.com/detail/9pdxgncfsczv?hl=ja-jp&gl=JP&ocid=pdpshare

インストールが開始されると以下のようなウィンドウが起動します。少し待ち、画面の指示に従い、ユーザーIDとパスワードを入力すると使用できるようになります。( ~$ と表示され、入力待ち状態になればインストール成功です)

 

2.Dockerのインストール

インストールしたUbuntu環境にDockerをインストールしていきます。
まず、Ubuntuのaptパッケージを最新化し、Dockerで使用するパッケージをインストールします。

# aptパッケージを最新化 
sudo apt update && sudo apt upgrade -y

# dockerで使用するパッケージをインストール
sudo apt-get install ca-certificates curl

次に、DockerのGPGキーを作成してアクセス権を設定し、Docker用のリポジトリを docker.list  に追加します。

# dockerのGPGキーの保存&アクセス設定
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# dockerのaptリポジトリを docker.list に追加
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

再度、aptパッケージを最新化し、Dockerをインストールします。

# aptパッケージをアップデート
sudo apt-get update
# dockerをインストール
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

最後に、起動設定とDocker用のユーザーおよびグループを設定します。

# dockerデーモンの設定
sudo systemctl enable docker
sudo systemctl enable containerd
sudo systemctl start docker

# docker用のユーザーとグループ設定
sudo groupadd docker
sudo usermod -aG docker $USER
newgrp docker

docker --version  と docker compose version  を実行し、正常にインストールされていることを確認します。

 
NVIDIA GPU搭載PCの場合は、NVIDIA Container Toolkit(以下、NVIDIA-CTK)もインストールしてください。

# NVIDIA-CTK取得用のリポジトリの追加とGPGキーを設定
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \
  && curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
    sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
    sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list

# aptパッケージをアップデート
sudo apt-get update

# NVIDIA-CTKをインストール
sudo apt-get install -y nvidia-container-toolkit

NVIDIA-CTKのインストールが完了したら、Dockerコンテナ内でGPUを認識させる設定を行います。

# dockerデーモンにGPUを認識させる設定
sudo nvidia-ctk runtime configure --runtime=docker

# dockerの再起動
sudo systemctl restart docker

最後に、 docker run --rm --runtime=nvidia --gpus all ubuntu nvidia-smi  を実行し、Docker内からホストのGPUが利用できるかを確認します。以下のように表示されれば成功です。(NVIDIA-CTKのインストールに失敗している場合や、NVIDIA GPUがない場合はエラーになります。NVIDIA社以外のGPUの場合は、各ベンダーが提供しているDocker用のランタイムやドライバーが必要になります。)

これで準備は完了です。

3.ローカルSLM環境の構築

それでは、いよいよローカルSLMの構築と動作確認を行います。
今回は、モデルの推論環境としてOllama、ユーザーとの対話用WebアプリケーションとしてOpen WebUIを使用して構築していきます。個別にインストールする方式もありますが、今回はDockerのメリットを最大限に活かし、Docker Composeでまとめて構築します。

といっても、手順はすごくシンプルです。
まず、WSLのUbuntu環境にログインし、以下のコマンドを実行してユーザーのホームディレクトリ配下に ollama フォルダを作成し、Docker Compose用の設定ファイル(  compose.yaml )を作成します。

# ホームディレクトリにollamaフォルダを作成して移動
mkdir -p ~/ollama 
cd ~/ollama

# ollamaフォルダ直下に、compose.yaml ファイルを作成
cat <<EOF > compose.yaml
services:
  ollama:
    image: ollama/ollama
    container_name: ollama
    ports:
      - "11434:11434"
    volumes:
      - ./ollama:/root/.ollama
    deploy:
      resources:
        reservations:
          devices:
            - capabilities: [gpu]
              driver: nvidia
              count: all
  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    container_name: open-webui
    ports:
      - "8080:8080"
    volumes:
      - ./open-webui:/app/backend/data
    environment:
      API_URL: http://ollama:11434
      ENABLE_OLLAMA_API: "True"
      OLLAMA_BASE_URLS: http://ollama:11434
      WEBUI_AUTH: "False"
EOF

次に、OllamaとOpen WebUIのコンテナを起動します。

# ollamaディレクトリに移動し、コンテナを起動
cd ~/ollama
docker compose up -d

コンテナとコンテナネットワークが作成されれば成功です。 ただし、初回起動には少し時間がかかります。 起動確認は docker logs -f open-webui でOpen WebUIコンテナのログを表示し、以下のようなログが出力され入力待ち状態になれば、起動が完了したことになります。


Open WebUI側の起動が確認できたら、ブラウザで http://localhost:8080 にアクセスし、以下のような画面が表示されればOKです。

「OK、始めましょう!」ボタンをクリックした後の画面
(この例では、認証なしモードですが、ユーザー認証をさせることも可能です)

以上で、ローカルSLM環境の構築は完了です。(Dockerはこのような場合に本当に便利です!)

4.モデルの取得

次に、推論環境Ollamaのモデルを取得します。
今回は、SLM(小規模言語モデル)のMicrosoft「Phi-4」とMeta「Llama 3」を取得してみます。(Ollama自体は大規模言語モデル(LLM)の取得も可能ですが、ローカルPCで動作させるため、ここでは10GB程度のSLMを取得しています)

モデルを取得するには、まず docker compose ps を実行してOllamaコンテナが起動していることを確認します。その後、 docker compose exec ollama ollama pull [モデル名] を実行します。 モデル名 は、 Ollamaのライブラリサイトに記載されているモデルを指定します。

# ollamaコンテナ状態確認
docker compose ps

# モデルの取得 (phi4)
docker compose exec ollama ollama pull phi4:14b

この例では phi4:14b を取得していますが、SLMといえどもサイズが9.8GBあるため、ダウンロードには多少時間がかかります。(PCのディスク容量にもご注意ください)

モデルの取得が完了したら、 docker compose restart open-webui でOpen WebUIコンテナを再起動します。再起動が完了した後、再度ブラウザで http://localhost:8080 にアクセスしてください。
画面上部のプルダウンメニューで phi4 のモデル(phi4:14b)が表示されていれば完了です。

ディスク容量に余裕があれば、 docker compose exec ollama ollama pull llama3.1:8b でLlama 3.1モデルもダウンロードしてみてください。

以下に、Ollamaのモデル管理でよく利用されるコマンドを載せておきます。(このコマンドは、本稿で紹介した compose.yaml で起動したコンテナで動作するものなのでご注意ください)
また、モデルの追加・削除後は、 docker compose restart open-webui でOpen WebUIコンテナの再起動をしてください。

モデルの追加 docker compose exec ollama ollama pull [モデル名] 
モデルの削除 docker compose exec ollama ollama rm [モデル名]  
モデルの一覧 docker compose exec ollama ollama ls 

モデル名 は、Ollamaライブラリページを参照)

5.動作確認

最後に動作確認を行います。再度、ブラウザで  http://localhost:8080 にアクセスしてください。
プロンプト入力用のテキストボックスに質問を入力し、送信してみてください。今回は「こんにちは、このモデルの特徴を簡単に教えてください。」というプロンプトを入力したところ、以下のような応答が生成されました。

 

画像では応答速度がわかりにくいため、動画も用意してみました。
GPU性能にもよりますが、GeForce RTX 4060で試したところ、応答時間も比較的よく、十分に実用に耐えうるレベルではないかと感じました。

【注意】
物理メモリが不足していたり、GPUが搭載されていなかったりする場合はエラーが発生する可能性があります。また、サイズの大きいLLMを使用する場合は、より多くのメモリやGPU VRAMが必要になります。
利用するPCのスペックに合わせて、動作可能なモデルを選択してください。

Ollamaで利用できるGPUについては、「Ollamaの公式では、コンピューティング能力5.0以上のNVIDIA GPU をサポート」にてご確認ください。

また、複数のモデルをダウンロードしている場合は、画面上部にあるモデル名の横の「+」ボタンから別のモデルを追加し、応答結果を比較することも可能です。

 

まとめ

今回はOllamaとOpen WebUIを使い、ローカルのPCで生成AIが試せるローカルSLM環境(※)の構築手順をご紹介しました。これで、セキュリティを気にせずAIを活用できる基盤が整いました。
(※ただ、快適に動作させるには、相応のPCスペックが必要ですが…)

この環境だけでも便利ですが、OllamaとOpen WebUIは、現場での利用を促進させるための優れた機能が用意されています。そこで次回は、この環境を発展させ、RAG(Retrieval-Augmented Generation)を構築する方法をお伝えしようと思います。
RAGを使えば、社内文書などローカルファイルの内容に基づいた応答をAIに生成させることが可能になり、現場での生成AI活用がより推進されること間違いなしです。

それでは次回の「RAG構築編」も、ぜひご期待ください!

The post ローカルSLM/閉じた環境で動作する生成AIを検証してみた (①環境構築編) first appeared on MISO.]]>