
こんにちは、ソリューションアーキテクトの尾澤です。
この記事は「aptpod Advent Calendar 2025」の12月9日の記事です。
皆さんは ChatGPT や Gemini のような「LLMチャットツール」をどのように活用していますか?PDF資料を分析するためにNotebook LMのような「RAGツール」を活用する場面もあるでしょう。とても便利で、すでに仕事道具として手放せないという人も多いのではないでしょうか?
本記事では、これらのツールをSaaSに頼らずオンデバイスで動かせるように、必要な構成と手順を紹介していきます。
なぜオンデバイスなのか
オンデバイスでAIを動かすメリットは、大きく以下の3つが考えられます。
情報漏洩リスクの回避
SaaSは手軽で便利である一方、データが外部に送信されることが前提です。顧客資料・非公開の内部資料・個人情報などの機密データを「外部に出せない」という要件は珍しくありません。
また、今年2025年7月には、OpenAIのサム・アルトマンCEOが「ChatGPTには守秘義務がなく法的請求があれば会話内容が開示されるため、心の闇や秘密をすべてさらけ出すのはやめたほうがいい」と警告しています。
オンデバイスであれば、そもそもデータが外部に送信されることがないため、安心してAIを使えます。
外部依存の回避
SaaSを利用することは、サービス提供者によるモデル変更・料金改定・レートリミットなどに依存することにもなります。
オンデバイスであれば、そういった外部要因に影響されることなく、UIやツールチェーンを変更せずにモデルを入れ替えながらワークフローを維持できます。
オフライン・エッジ用途への転用
レイテンシ要件が厳しいユースケースや、ネットワーク帯域が弱い環境など、システム構成にSaaSを組み込めないことがあります。
オンデバイスであれば、場所を選ばずにAIを持ち込めます。
デメリット
最大のデメリットとして「SaaS独自のプロプライエタリなモデル」が使えないという点があります。
しかしその一方で、オープンなモデルが豊富なバリエーションで公開されています。 例えば、今年2025年8月にOpenAIが公開した「GPT-OSS」は、SaaSで提供していた「o3-mini」と同等の推論能力をベンチマークで示しており、こうした優れたモデルも次々と現れています。
このようなモデルを用途に応じて選定し、場合によっては追加でチューニングを行うことで、目的を実現することが十分に可能です。
オンデバイスAIの分野では、モデルの選択が重要なテーマになってきます。
動作環境
この記事では GPU を搭載した Windows 環境を前提に手順を紹介します。GPUの有無によって処理速度とユーザ体験が大きく変わるため、実用的な体験ができる環境で解説を進めます。
また、拡張性や可搬性を考慮して、すべてのコンポーネントをDockerコンテナで実行します。後述する docker-compose.yml はそのまま使えるようになっています。
本記事で使用した環境
- Windows 11
- CPU: Intel Core i7-14700F (2.10 GHz)
- GPU: NVIDIA GeForce RTX4070 Ti SUPER (16GB)
- RAM: 16GB
- Docker Desktop + NVIDIA Container Toolkit
実は、このGPU環境は、小学生の息子がマイクラのMODやらコマンドやらに興味を持ち始めたのをいいことに、それを口実にして家庭内稟議を通して購入したゲーミングPCです。 本当は私自身が、都市開発シミュレーションゲーム「Cities Skylines II」をやりたくて、虎視眈々と狙っていたのです。 この度、このマシンがゲーム以外の分野で活躍できることに興奮しております。
LLMチャットを動かす
それでは早速、LLMチャットを動かしていきましょう。
以下のGitリポジトリをダウンロードしてください。 https://github.com/shumaijp/local-llm-chat-docker-compose
services: ollama: # image: ollama/ollama:latest image: ollama/ollama:0.13.1 container_name: ollama-chat ports: - "11434:11434" volumes: - ollama-data:/root/.ollama deploy: resources: reservations: devices: - driver: nvidia count: 1 capabilities: [gpu] open-webui: # image: ghcr.io/open-webui/open-webui:main image: ghcr.io/open-webui/open-webui:v0.6.41 container_name: open-webui ports: - "3030:8080" environment: - OLLAMA_BASE_URL=http://ollama:11434 volumes: - open-webui-data:/app/backend/data depends_on: - ollama searxng: # image: searxng/searxng:latest image: searxng/searxng:2025.12.7-9d3ec9a2a container_name: searxng ports: - "8080:8080" volumes: - ./config/searxng:/etc/searxng:rw volumes: ollama-data: name: shared-ollama-data open-webui-data:
モデルエンジン
まずは、LLMの実行環境について説明します。
Ollamaとは
Ollamaは「LLM版のDocker」と表現すると分かりやすいかもしれません。Dockerがコンテナを対象とするように、OllamaはLLMを対象として、実行エンジン・CLIツール・公開リポジトリを提供します。
LLMのモデル入手
OllamaのリポジトリにあるLLMは以下のURLで確認できます。 https://ollama.com/library

それぞれのモデルには「8b」「20b」のようなタグが表記されています。タグにある数字はパラメータの数を示しており、AIモデルの脳細胞の数のようなものです。パラメータが多いほど賢く知識が豊富でアウトプットの質が高い反面、メモリやGPUなどのリソースをより多く消費します。
使用するときは「モデル名:タグ名」という形式で指定します。
今回はまず、軽量でポピュラーな「gemma2:2b」を使ってみます。コンテナを起動してCLIツールを使ってダウンロードしてみましょう。
docker compose up -d docker exec ollama-chat ollama pull gemma2:2b
動作確認
Ollamaコンテナが正しく動いているかCLIでAPIを叩いて確認してみましょう。
curl http://localhost:11434/api/generate \
-d '{"model": "gemma2:2b", "prompt": "Hello"}'
以下のように、レスポンスが返ってくれば正常に動いています。
{"model":"gemma2:2b","created_at":"2025-12-06T06:52:59.907909427Z","response":"Hello","done":false}
{"model":"gemma2:2b","created_at":"2025-12-06T06:52:59.980637427Z","response":"!","done":false}
{"model":"gemma2:2b","created_at":"2025-12-06T06:53:00.07509926Z","response":" 👋","done":false}
....
チャットUI
つぎに、UIについて説明します。
Open WebUIとは
Open WebUIは、LLMを「ChatGPTっぽい快適なUIで使えるようにする」ためのWebアプリです。
LLMが「バックエンド」、Open WebUIが「フロントエンド」という役割分担になっています。
Open WebUIの環境変数(OLLAMA_BASE_URL)でOllamaをバックエンドに指定することで、チャット画面の裏側でLLMへのAPIリクエストが走る仕組みになっています。
実際に使ってみる
コンテナが起動している状態で、 http://localhost:3030 にブラウザでアクセスしてみてください。
初回アクセス時は、ユーザ登録画面が表示されます。アカウントを作成してログインすると、下図のような ChatGPT ライクな画面が表示されます。
使用モデルが「gemma2:2b」になっていることを確認して、チャットを開始してみましょう。

違うモデルを使ってみる
動作確認のために軽量な「gemma」を使いましたが、他にもMicrosoftの「phi」、Metaの「llama」、Alibabaの「Qwen」など多くのLLMが公開されており、GGUF(GPT-Generated Unified Format)というファイルフォーマット規格によって、これらを同じプラットフォーム上で切り替えて使えるようになっています。
試しにOpenAIの「gpt-oss:20b」をダウンロードして使ってみましょう。
docker exec ollama-chat ollama pull gpt-oss:20b
ダウンロード済みのモデルは以下のコマンドで確認できます。
% docker exec ollama-chat ollama list NAME ID SIZE MODIFIED gpt-oss:20b 17052f91a42e 13 GB 3 minutes ago gemma2:2b 8ccf136fdd52 1.6 GB 4 hours ago
モデルを「gpt-oss:20b」に切り替えて、先ほどと同じプロンプトを投げてみましょう。

このように、モデルによって推論結果が大きく変わってきます。
検索機能をつける
ChatGPTなどのLLMチャットが、もともと学習していない情報をウェブ検索で補って回答してくれるようになってから、利便性がグッとあがりましたよね。
オンデバイスでも、インターネットに出られる環境であれば同じことが可能です。
ユーザアイコンをクリックしたメニューから「設定」→「管理者設定」に進んで「ウェブ検索」を有効にし、「ウェブ検索エンジン」を指定します。APIキーを用意すれば、GoogleやPerplexityなどのSaaSも使えますが、今回は情報漏洩リスクの回避もひとつのテーマなので、メタ検索エンジンである「SearXNG」を使ってみましょう。すでに docker-compose.yml に定義してあるコンテナのそのエンドポイント「http://searxng:8080」を指定して、設定を保存してください。

設定が終わったらプロンプトに戻ります。プロンプトの「Integration」のアイコンから「ウェブ検索」を有効にして、インターネットを参照しないとわからないようなことを尋ねてみましょう。

ウェブから情報を取得して回答してくれました。メタ検索エンジンの SearXNG を介しているので、Google等に直接ユーザのIPアドレスやクエリが送信されることはありません。
コンテナを終了する
使い終わったらコンテナを終了させておいてください。
docker compose down
本記事では、ユースケースごとの分かりやすさと学習のしやすさのため、LLMチャット用とRAGツール用でDocker Compose環境をそれぞれ分けて紹介しています。
このあと説明するRAGツールでもOllamaコンテナを使用しますが、両方のユースケースを同時に起動するとポートが衝突するため、それぞれ別タイミングで起動する前提としています。
RAGツールを動かす
チャットの次は、Notebook LMのようなRAGツールを動かしてみましょう。
RAGツールとは
ChatGPTやGeminiは使ったことあるけど、Notebook LMは使ったことないという人もいるかもしれません。
RAGツールは、特定のウェブページやファイルを読み込ませることで、LLMに対象ドメインを与えて使う仕組みです。 LLMチャットツールが「世界中の知識をもとに答えるAI」であるのに対して、RAGツールは「渡された資料を読んで答えるAI」です。
Googleの「Notebook LM」は、この代表的なツールです。
Open Notebookとは
Notebook LMのようなRAG体験をオンデバイスで再現できるのが 今回使用する「Open Notebook」です。
https://www.open-notebook.ai/
Open WebUIと同じように、裏側でLLMへのAPIリクエストが走る仕組みになっています。
以下のGitリポジトリをダウンロードしてください。 https://github.com/shumaijp/local-opennotebook-docker-compose
services: ollama: # image: ollama/ollama:latest image: ollama/ollama:0.13.1 container_name: ollama-rag ports: - "11434:11434" volumes: - ollama-data:/root/.ollama deploy: resources: reservations: devices: - driver: nvidia count: 1 capabilities: [gpu] open_notebook: # image: lfnovo/open_notebook:v1-latest-single image: lfnovo/open_notebook:1.2.3-single container_name: open-notebook ports: - "8502:8502" # Web UI - "5055:5055" # API environment: - API_URL=http://127.0.0.1:5055 - OLLAMA_API_BASE=http://ollama:11434 # Database connection (required) - SURREAL_URL=ws://localhost:8000/rpc - SURREAL_USER=root - SURREAL_PASSWORD=root - SURREAL_NAMESPACE=open_notebook - SURREAL_DATABASE=production volumes: - notebook-data:/app/data - surreal-data:/mydata depends_on: - ollama volumes: ollama-data: name: shared-ollama-data notebook-data: surreal-data:
なお、上記で使用しているイメージ(lfnovo/open_notebook:1.2.3-single)は、Open Notebookを構成するコンポーネントがすべて入っているオールインワン・イメージです。
中身は「フロントエンド」と「バックエンド(RAG)」と「データベース(SurrealDB)」で構成されており、バックエンドとデータベースだけ立ててAPI経由で活用する、という使い方も可能です。
初期設定
RAGを実現するためには、LLMの他に「埋め込みモデル(Embedding Model)」という別の役割のモデルが必要です。
埋め込みモデルとは
埋め込みモデルとは、テキストや画像などのデータを数値のベクトルに変換するモデルのことで、RAGが与えられた情報を解釈するために必要なものです。
意味的に近いデータがベクトル空間上でも近くに配置されることによって、データの類似性を理解できるようになるというものです。
埋め込みモデルの入手
それでは、コンテナを起動して埋め込みモデルをダウンロードしていきましょう。
今回は速度や精度のバランスが最も優れていると言われている「mxbai-embed-large」を使用します。
docker compose up -d docker exec ollama-rag ollama pull mxbai-embed-large
なお、今回のコンテナ構成では、Ollama用にダウンロードしたモデルは「ollama-data」という名前付きボリュームに格納されるようになっています。これにより、RAGツール用の「ollama-rag」コンテナと、先ほどのチャット用の「ollama-chat」コンテナは、ダウンロードしたモデルを共有できるようになっています。
それでは、 http://localhost:8502 にブラウザでアクセスしてみてください。

モデルの設定
Open WebUIと違ってモデルを使うための初期設定が必要です。
左ペインの「MANAGE」→「Models」から「Model Management」の画面を開きます。
まず、「API Providers」のセクションで「Ollama」が有効になっていることを確認してください。

「Default Model Assignments」のセクションで、Open Notebookが使用する様々なモデルを指定しますが、そのためにモデルをあらかじめ登録しておく必要があります。
「Language Models」のセクションで、ダウンロード済みの「gpt-oss:20b」を言語モデルに登録しましょう。「+ Add Model」をクリックし、Providerを「Ollama」、Model Nameに「gpt-oss:20b」を入力して「Add Model」してください。

「Embedding Models」のセクションで、ダウンロード済みの「mxbai-embed-large」を埋め込みモデルに登録しましょう。同じく画面下の「+ Add Model」をクリックし、Providerを「Ollama」、Model Nameに「mxbai-embed-large」を入力して「Add Model」してください。

「Default Model Assignments」のセクションに戻ると、登録したモデルを指定できるようになっているので、必須マークがついている Chat Model と Transformation Model に「gpt-oss:20b」を、Embedding Model に「mxbai-embed-large」を設定してください。

実際に使ってみる
それでは使ってみましょう。 本記事ではデモとして、MQTTのRFCドキュメントを分析対象にしてみます。
まず「+ New Notebook」からNotebookを作ります。

つぎに「+ Add Source」→「+ Add New Source」から、参照する資料をURL・ファイル・プレーンテキストのいずれかで追加します。 今回は、RFCのURL「https://www.rfc-editor.org/rfc/rfc9431.html」を指定します。

登録したSourceのベクトル解析が終わったら質問してみましょう。
あえて「MQTTの」とは言わずに「QoS 0/1/2 の違いを要約して」と入力してみると、ちゃんとRFCを読んで「MQTTのQoS」について回答してくれました。

一見あいまいな質問ですが、ChatGPTのように話題がズレることなく、与えられた情報の範囲内で答えを探してくれます。
このように、推論の前提となる情報源が「指定した資料」に限定されるため、一般的なLLMチャットにありがちなハルシネーションが起こりにくいのが、RAGの特徴です。
Macユーザの場合
本記事で解説したツールは、Apple Silicon Mac でも問題なく動作します。
手順もほぼ同じで、docker-compose.yml をGitリポジトリに用意した docker-compose-cpu.yml に読み替えるだけで動きます。
# GPU環境の場合 docker compose up -d # 非GPU環境の場合 docker compose -f docker-compose-cpu.yml up -d
ただし、macOSではApple SiliconのGPUをDockerから使えないため、同じモデルでも推論速度は大きく低下します。
OllamaをDockerではなくシステム上で動かすことで、Apple SiliconのGPUが活かされある程度のパフォーマンスは期待できます。
brew install ollama ollama serve
しかし、実際に普段業務で使用している M4 MacBook Pro でも試してみましたが、Metalサポートが進んでいるとはいえ、CUDA対応GPUに最適化されたモデルではやはり性能差は歴然です。
「まず手元の環境でLLMに触ってみたい」場合にはMacでも十分ですが、「日常的に生産性ツールとして使いたい」場合は、GPU環境のほうが圧倒的に快適です。
以下は「GPU Windows + Ollama on Docker」と「M4 Mac + Ollama on Docker」と「M4 Mac + Ollama on System」の3つの環境で同じプロンプトの性能を比較した表です。
| 環境 | gemma2:2b | gpt-oss:20b | 推論リソース |
|---|---|---|---|
| GPU Windows + Ollama on Docker | 6.24 tokens/sec | 2.11 tokens/sec | CUDA/GPU |
| M4 Mac + Ollama on System | 1.60 tokens/sec | 0.68 tokens/sec | Metal/GPU |
| M4 Mac + Ollama on Docker | 0.45 tokens/sec | 0.13 tokens/sec | CPU |
Apple Siliconの方向性
ただし、この結果は決して「Applie Siliconが遅い」という話ではありません。
Apple Siliconはそもそも「AIをオンデバイスで高速かつ省電力で動かすこと」をターゲットに設計されています。
そのため、Macユーザが本来とるべきアプローチは、NVIDIAスタックで学習したモデルをそのまま動かすことではなく、それをCore ML 形式に最適化して macOS / iOS / visionOS などで動かすことです。
ですので、前述の比較表は優劣を比較するためのものではなく、あくまで参考値として見ていただけると幸いです。
すでに、Meta・Mistral・Alibaba などの主要モデルが Core ML 版を公開しており、Apple Silicon 上での AI 活用は来年以降もさらに実用化が進んでいきそうだと感じています。
本記事では「NVIDIAスタックで学習されたモデルを動かす」という前提のため Core ML 最適化には触れていませんが、こちらの動向も把握しておくと良いと思います。
まとめ
LLMやRAGをオンデバイスで動かすことで、機密データをクラウドに出さずにAIの恩恵を受けられるだけでなく、それをそのままエッジに持ち込めるというメリットがあります。
これは産業IoTにおいても重要なテーマで、エッジ環境における「セキュリティ」「レイテンシ」「ネットワーク」などの要件を、AIにも適用できるということになります。
今回紹介した構成はデスクトップでの検証用途ですが、アプリケーション層とモデル層がAPI分離されているため、ゲートウェイやMEC環境への移植も可能です。
もし「こんなことをAIでできないか?」というアイデアが浮かんだ時、今回構築した環境がその入口になれば嬉しいです。