Ollama + Open WebUI - ローカルLLM完全構築ガイド2025
プライバシー重視のローカルLLM環境をOllamaとOpen WebUIで構築する完全ガイド。DeepSeek-R1、Llama 3.3、日本語モデルの設定からRAG統合まで実践的に解説します。
n8nのSelf-hosted AI Starter Kitは、Ollama、Qdrant、n8nを組み合わせた完全ローカルAIシステム。プライバシー保護、コスト削減、カスタマイズ性を実現しながら、LLM・RAG・ワークフロー自動化を一元管理。Docker Composeでの快速セットアップから本番運用まで、企業AI導入の決定版。
n8n の Self-hosted AI Starter Kit は、プライバシーを重視しながら AI システムを構築したい組織や個人にとって、革命的なソリューションです。Ollama、Qdrant、n8n を組み合わせたこの Docker Compose テンプレートは、ローカル環境での完全な AI 開発環境を素早く構築できる、まさに次世代の AI インフラストラクチャの雛形です。
Self-hosted AI Starter Kit は、クラウド AI サービスに依存することなく、完全にコントロール可能な AI システムを構築するための包括的なソリューションです:
コンポーネント | 役割 | 特徴 | 代替手段 |
---|---|---|---|
n8n | ワークフローオーケストレーション | 400+統合、AIコンポーネント | Zapier, Pipedream |
Ollama | ローカルLLM実行 | クロスプラットフォーム、高性能 | llama.cpp, GPT4All |
Qdrant | ベクターデータベース | 高速RAG、スケーラブル | ChromaDB, Pinecone |
PostgreSQL | リレーショナルDB | 安定性、データ保護 | MySQL, SQLite |
Nvidia GPU環境
# システム要件
- Nvidia GPU (推奨: 8GB+ VRAM)
- Docker 20.10+
- Docker Compose v2.0+
- Nvidia Container Toolkit
# Nvidia Container Toolkitのインストール
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
sudo apt-get update
sudo apt-get install -y nvidia-container-toolkit
sudo systemctl restart docker
AMD GPU (Linux)環境
# システム要件
- AMD GPU (推奨: 8GB+ VRAM)
- Linux OS (Ubuntu 20.04+)
- ROCm 5.0+
- Docker 20.10+
# ROCmのインストール
wget https://repo.radeon.com/amdgpu-install/22.20.3/ubuntu/focal/amdgpu-install_22.20.50203-1_all.deb
sudo apt install ./amdgpu-install_22.20.50203-1_all.deb
sudo amdgpu-install --usecase=dkms,rocm
# DockerでROCmを使用するための設定
sudo usermod -a -G render,video $LOGNAME
Mac/Apple Silicon環境
# システム要件
- macOS 12.0+ (Monterey)
- Apple Silicon (M1/M2/M3) または Intel Mac
- 16GB+ RAM (推奨: 32GB)
- Docker Desktop for Mac
# Docker Desktopのインストール
# https://www.docker.com/products/docker-desktopからダウンロード
# Docker Desktop設定
# Resources > Advanced:
# - Memory: 8GB+
# - CPUs: 4+
# - Disk image size: 100GB+
CPUのみ環境
# システム要件
- 16GB+ RAM (推奨: 32GB)
- 8+ CPUコア
- 100GB+ ストレージ
- Docker 20.10+
# 注意: CPUのみの場合、モデルの実行速度が
# GPUに比べて大幅に遅くなります
# 小さなモデル(7Bパラメータ以下)が推奨です
# Self-hosted AI Starter Kitのクローン
git clone https://github.com/n8n-io/self-hosted-ai-starter-kit.git
cd self-hosted-ai-starter-kit
# 環境変数の設定
cp .env.example .env
# 基本設定でサービスを起動
docker compose up -d
# サービスの状態確認
docker compose ps
# ログの確認
docker compose logs -f
初回起動時は、各コンポーネントのイメージダウンロードと初期化に数分かかります。
起動完了後、以下の URL で各サービスにアクセスできます:
http://localhost:5678
http://localhost:6333/dashboard
http://localhost:11434
localhost:5432
(ユーザー: postgres, パスワード: changeme)# Ollamaコンテナに接続
docker compose exec ollama bash
# 主要な日本語対応モデルのインストール
# 軽量モデル (推奨: 初心者、リソース制約あり)
ollama pull llama3.2:3b # 3Bパラメータ、高速
ollama pull gemma2:2b # 2Bパラメータ、超軽量
# 中程度モデル (推奨: バランス重視)
ollama pull llama3.1:8b # 8Bパラメータ、高品質
ollama pull codellama:7b # コード生成特化
ollama pull mistral:7b # 多言語対応
# 高性能モデル (推奨: GPU環境、高品質重視)
ollama pull llama3.1:70b # 70Bパラメータ、最高品質
ollama pull codellama:34b # 大規模コードモデル
# 日本語特化モデル
ollama pull elyza:7b # ELYZA-japanese-Llama-2-7b
# インストール済みモデルの一覧
ollama list
# 基本的なモデル実行
ollama run llama3.1:8b
# GPUメモリとコンテキストサイズを最適化
# Modelfileでカスタム設定
cat > /tmp/optimized-llama3.1.Modelfile << 'EOF'
FROM llama3.1:8b
# コンテキストウィンドウを拡大
PARAMETER num_ctx 4096
# レスポンスの初期値を最適化
PARAMETER temperature 0.7
PARAMETER top_p 0.9
PARAMETER repeat_penalty 1.1
# システムプロンプトで日本語対応を強化
SYSTEM """
あなたは日本語で応答するアシスタントです。
丁寧で分かりやすい回答を心がけてください。
"""
EOF
# 最適化モデルを作成
ollama create optimized-llama3.1 -f /tmp/optimized-llama3.1.Modelfile
# 基本的なモデル実行
ollama run llama3.1:8b
# GPUメモリとコンテキストサイズを最適化
# Modelfileでカスタム設定
cat > /tmp/optimized-llama3.1.Modelfile << 'EOF'
FROM llama3.1:8b
# コンテキストウィンドウを拡大
PARAMETER num_ctx 4096
# レスポンスの初期値を最適化
PARAMETER temperature 0.7
PARAMETER top_p 0.9
PARAMETER repeat_penalty 1.1
# システムプロンプトで日本語対応を強化
SYSTEM """
あなたは日本語で応答するアシスタントです。
丁寧で分かりやすい回答を心がけてください。
"""
EOF
# 最適化モデルを作成
ollama create optimized-llama3.1 -f /tmp/optimized-llama3.1.Modelfile
n8n のブラウザインターフェースで、以下の手順で AI ワークフローを作成します:
Webhook、Schedule、Manualなどのトリガーを設定
AIモデルとの連携を設定
ベクター検索とコンテキスト生成
Slack、Email、Databaseなどへの出力
{
"name": "Simple AI Chatbot",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "chat",
"responseMode": "responseNode",
"options": {}
},
"id": "webhook-trigger",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"position": [240, 300]
},
{
"parameters": {
"resource": "chat",
"operation": "message",
"model": "llama3.1:8b",
"prompt": "={{ $json.message }}",
"options": {
"temperature": 0.7,
"maxTokens": 500
}
},
"id": "ollama-chat",
"name": "Ollama Chat",
"type": "n8n-nodes-base.ollama",
"position": [460, 300]
},
{
"parameters": {
"respondWith": "json",
"responseBody": {
"response": "={{ $json.response }}",
"model": "={{ $json.model }}",
"timestamp": "={{ new Date().toISOString() }}"
}
},
"id": "respond-to-webhook",
"name": "Response",
"type": "n8n-nodes-base.respondToWebhook",
"position": [680, 300]
}
],
"connections": {
"Webhook": {
"main": [[{"node": "Ollama Chat", "type": "main", "index": 0}]]
},
"Ollama Chat": {
"main": [[{"node": "Response", "type": "main", "index": 0}]]
}
}
}
// n8nコードノードでの高度なRAG処理
// 文書のチャンキングとエンベディング
const documents = $json.documents;
const chunkSize = 1000;
const overlap = 200;
// テキストをチャンクに分割
function chunkText(text, chunkSize, overlap) {
const chunks = [];
let start = 0;
while (start < text.length) {
const end = Math.min(start + chunkSize, text.length);
const chunk = text.slice(start, end);
chunks.push(chunk);
start = end - overlap;
}
return chunks;
}
// 文書を処理してQdrantに保存するデータを準備
const processedDocuments = documents.map((doc, docIndex) => {
const chunks = chunkText(doc.content, chunkSize, overlap);
return chunks.map((chunk, chunkIndex) => ({
id: `doc_${docIndex}_chunk_${chunkIndex}`,
text: chunk,
metadata: {
source: doc.source || 'unknown',
title: doc.title || 'Untitled',
docIndex,
chunkIndex,
totalChunks: chunks.length
}
}));
}).flat();
// コンテキストを清浄してプロンプトを生成
function generateRAGPrompt(query, relevantChunks) {
const context = relevantChunks
.map((chunk, index) => `コンテキスト${index + 1}: ${chunk.text}`)
.join('\n\n');
return `以下のコンテキスト情報を参考にして、ユーザーの質問に答えてください。
コンテキスト情報:
${context}
ユーザーの質問: ${query}
回答のガイドライン:
- コンテキスト情報に基づいて回答する
- 情報が不十分な場合はその旨を明記する
- 正確で分かりやすい日本語で応答する
回答:`;
}
return [{
processedDocuments,
totalChunks: processedDocuments.length
}];
# PythonでQdrantを操作する例
from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams, PointStruct
from sentence_transformers import SentenceTransformer
import uuid
# Qdrantクライアントの初期化
client = QdrantClient(
host="localhost",
port=6333
)
# エンベディングモデルの初期化
embedding_model = SentenceTransformer('all-MiniLM-L6-v2')
vector_size = embedding_model.get_sentence_embedding_dimension()
# コレクションの作成
collection_name = "company_knowledge_base"
try:
client.create_collection(
collection_name=collection_name,
vectors_config=VectorParams(
size=vector_size,
distance=Distance.COSINE
)
)
print(f"コレクション '{collection_name}' を作成しました")
except Exception as e:
print(f"コレクションは既に存在します: {e}")
# 文書のインデックシング
def index_documents(documents):
"""文書をベクター化してQdrantに保存"""
points = []
for i, doc in enumerate(documents):
# テキストをエンベディング
vector = embedding_model.encode(doc['text']).tolist()
# ポイントを作成
point = PointStruct(
id=str(uuid.uuid4()),
vector=vector,
payload={
"text": doc['text'],
"metadata": doc.get('metadata', {}),
"indexed_at": datetime.now().isoformat()
}
)
points.append(point)
# バッチでアップロード
client.upsert(
collection_name=collection_name,
points=points
)
print(f"{len(points)}件の文書をインデックシングしました")
# セマンティック検索
def semantic_search(query, limit=5):
"""クエリに関連する文書を検索"""
# クエリをエンベディング
query_vector = embedding_model.encode(query).tolist()
# 検索実行
results = client.search(
collection_name=collection_name,
query_vector=query_vector,
limit=limit,
with_payload=True
)
# 結果を整形
formatted_results = []
for result in results:
formatted_results.append({
"id": result.id,
"score": result.score,
"text": result.payload["text"],
"metadata": result.payload.get("metadata", {})
})
return formatted_results
# サンプルデータのインデックシング
sample_documents = [
{
"text": "AIエンジニアリングは機械学習モデルを実用的なシステムに統合する分野です。",
"metadata": {"category": "technology", "source": "company_wiki"}
},
{
"text": "RAGシステムは検索と生成を組み合わせた手法で、正確性と関連性を向上させます。",
"metadata": {"category": "AI", "source": "technical_docs"}
},
{
"text": "当社のセキュリティポリシーでは、すべてのデータは暗号化され、アクセスログが記録されます。",
"metadata": {"category": "security", "source": "policy_docs"}
}
]
index_documents(sample_documents)
# 検索テスト
query = "AI技術について教えてください"
results = semantic_search(query)
print(f"クエリ: {query}")
print("検索結果:")
for i, result in enumerate(results, 1):
print(f"{i}. スコア: {result['score']:.3f}")
print(f" テキスト: {result['text']}")
print(f" メタデータ: {result['metadata']}")
print()
機能 | 使用技術 | メリット | 適用シーン |
---|---|---|---|
PDFアップロード | n8n Webhook | ブラウザから簡単アップロード | 契約書、報告書 |
OCRテキスト抽出 | Tesseract + PyPDF | 高精度テキスト化 | スキャン文書、手書き |
意味解析 | Ollama + Llama3.1 | 精度高い内容理解 | 法的文書、技術仕様 |
サマリ生成 | RAG + LLM | 重要ポイント自動抽出 | 会議資料、レポート |
ナレッジ管理 | Qdrant + Embedding | 組織内知識蓄積 | 社内マニュアル |
# docker-compose.security.yml
# セキュリティ強化版の設定
version: '3.8'
services:
# リバースプロキシでSSL終端とアクセス制御
nginx-proxy:
image: nginx:alpine
ports:
- "443:443"
- "80:80"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- ./ssl:/etc/nginx/ssl
depends_on:
- n8n
- qdrant
networks:
- ai-network
# n8nにアクセス制御と暗号化を追加
n8n:
image: n8nio/n8n:latest
environment:
- N8N_BASIC_AUTH_ACTIVE=true
- N8N_BASIC_AUTH_USER=${N8N_ADMIN_USER}
- N8N_BASIC_AUTH_PASSWORD=${N8N_ADMIN_PASSWORD}
- N8N_PROTOCOL=https
- N8N_HOST=${N8N_HOST}
- N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_PORT=5432
- DB_POSTGRESDB_DATABASE=${POSTGRES_DB}
- DB_POSTGRESDB_USER=${POSTGRES_USER}
- DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}
volumes:
- n8n_data:/home/node/.n8n
depends_on:
- postgres
networks:
- ai-network
restart: unless-stopped
# PostgreSQLのセキュリティ強化
postgres:
image: postgres:15-alpine
environment:
- POSTGRES_DB=${POSTGRES_DB}
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_INITDB_ARGS=--auth-host=scram-sha-256
volumes:
- postgres_data:/var/lib/postgresql/data
- ./postgres/postgresql.conf:/etc/postgresql/postgresql.conf
command: [
"postgres",
"-c", "config_file=/etc/postgresql/postgresql.conf",
"-c", "log_statement=all",
"-c", "log_destination=stderr",
"-c", "logging_collector=on"
]
networks:
- ai-network
restart: unless-stopped
# Qdrantのアクセス制御
qdrant:
image: qdrant/qdrant:latest
environment:
- QDRANT__SERVICE__API_KEY=${QDRANT_API_KEY}
- QDRANT__SERVICE__ENABLE_CORS=false
- QDRANT__CLUSTER__ENABLED=false
volumes:
- qdrant_data:/qdrant/storage
- ./qdrant/config.yaml:/qdrant/config/production.yaml
networks:
- ai-network
restart: unless-stopped
# OllamaのTLS設定
ollama:
image: ollama/ollama:latest
environment:
- OLLAMA_HOST=0.0.0.0:11434
- OLLAMA_ORIGINS=https://${N8N_HOST}
volumes:
- ollama_data:/root/.ollama
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
networks:
- ai-network
restart: unless-stopped
volumes:
n8n_data:
driver: local
driver_opts:
type: none
o: bind
device: ./data/n8n
postgres_data:
driver: local
driver_opts:
type: none
o: bind
device: ./data/postgres
qdrant_data:
driver: local
driver_opts:
type: none
o: bind
device: ./data/qdrant
ollama_data:
driver: local
driver_opts:
type: none
o: bind
device: ./data/ollama
networks:
ai-network:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/16
# docker-compose.cluster.yml
# クラスター構成版
version: '3.8'
services:
# ロードバランサー
haproxy:
image: haproxy:alpine
ports:
- "80:80"
- "443:443"
- "8404:8404" # HAProxy stats
volumes:
- ./haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
depends_on:
- n8n-1
- n8n-2
- ollama-1
- ollama-2
networks:
- ai-cluster
# n8nインスタンスのクラスター構成
n8n-1:
image: n8nio/n8n:latest
environment:
- N8N_HOST=n8n-cluster.local
- EXECUTIONS_MODE=queue
- QUEUE_BULL_REDIS_HOST=redis
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
depends_on:
- postgres
- redis
networks:
- ai-cluster
deploy:
replicas: 2
n8n-2:
image: n8nio/n8n:latest
environment:
- N8N_HOST=n8n-cluster.local
- EXECUTIONS_MODE=queue
- QUEUE_BULL_REDIS_HOST=redis
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
depends_on:
- postgres
- redis
networks:
- ai-cluster
# Ollamaインスタンスの複数化
ollama-1:
image: ollama/ollama:latest
environment:
- OLLAMA_HOST=0.0.0.0:11434
volumes:
- ollama_1_data:/root/.ollama
deploy:
resources:
reservations:
devices:
- driver: nvidia
device_ids: ['0'] # GPU 0
capabilities: [gpu]
networks:
- ai-cluster
ollama-2:
image: ollama/ollama:latest
environment:
- OLLAMA_HOST=0.0.0.0:11434
volumes:
- ollama_2_data:/root/.ollama
deploy:
resources:
reservations:
devices:
- driver: nvidia
device_ids: ['1'] # GPU 1
capabilities: [gpu]
networks:
- ai-cluster
# Qdrantクラスター構成
qdrant-1:
image: qdrant/qdrant:latest
environment:
- QDRANT__CLUSTER__ENABLED=true
- QDRANT__CLUSTER__NODE_ID=1
- QDRANT__CLUSTER__CONSENSUS__TICK_PERIOD_MS=100
volumes:
- qdrant_1_data:/qdrant/storage
networks:
- ai-cluster
qdrant-2:
image: qdrant/qdrant:latest
environment:
- QDRANT__CLUSTER__ENABLED=true
- QDRANT__CLUSTER__NODE_ID=2
- QDRANT__CLUSTER__CONSENSUS__TICK_PERIOD_MS=100
volumes:
- qdrant_2_data:/qdrant/storage
networks:
- ai-cluster
# Redisクラスター (キュー管理)
redis:
image: redis:7-alpine
command: redis-server --appendonly yes
volumes:
- redis_data:/data
networks:
- ai-cluster
# PostgreSQLレプリケーション
postgres:
image: postgres:15-alpine
environment:
- POSTGRES_DB=${POSTGRES_DB}
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_REPLICATION_MODE=master
- POSTGRES_REPLICATION_USER=replicator
- POSTGRES_REPLICATION_PASSWORD=${POSTGRES_REPLICATION_PASSWORD}
volumes:
- postgres_master_data:/var/lib/postgresql/data
networks:
- ai-cluster
volumes:
ollama_1_data:
ollama_2_data:
qdrant_1_data:
qdrant_2_data:
redis_data:
postgres_master_data:
networks:
ai-cluster:
driver: overlay
attachable: true
# monitoring/docker-compose.monitoring.yml
# Prometheus + Grafanaによる監視システム
version: '3.8'
services:
prometheus:
image: prom/prometheus:latest
ports:
- "9090:9090"
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--web.console.libraries=/etc/prometheus/console_libraries'
- '--web.console.templates=/etc/prometheus/consoles'
- '--storage.tsdb.retention.time=200h'
- '--web.enable-lifecycle'
networks:
- ai-monitoring
grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
volumes:
- grafana_data:/var/lib/grafana
- ./grafana/dashboards:/etc/grafana/provisioning/dashboards
- ./grafana/datasources:/etc/grafana/provisioning/datasources
networks:
- ai-monitoring
node-exporter:
image: prom/node-exporter:latest
ports:
- "9100:9100"
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
command:
- '--path.procfs=/host/proc'
- '--path.rootfs=/rootfs'
- '--path.sysfs=/host/sys'
- '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
networks:
- ai-monitoring
# AIシステム用カスタムメトリクス
ai-metrics-exporter:
build:
context: ./metrics-exporter
dockerfile: Dockerfile
ports:
- "9200:9200"
environment:
- OLLAMA_URL=http://ollama:11434
- QDRANT_URL=http://qdrant:6333
- N8N_URL=http://n8n:5678
networks:
- ai-monitoring
- ai-network
volumes:
prometheus_data:
grafana_data:
networks:
ai-monitoring:
driver: bridge
ai-network:
external: true
項目 | クラウドAI | Self-hosted AI | 節約率 |
---|---|---|---|
月額ランニングコスト (1000リクエスト) | $150-300 | $50-80 | 60-70% |
初期セットアップ | $0 | $500-2000 | - |
データプライバシーリスク | 高 | なし | 100% |
カスタマイズ性 | 低 | 高 | 大幅向上 |
ベンダー依存 | あり | なし | リスク減 |
Self-hosted AI Starter Kit は、AI システムのプライベート化とコスト最適化を同時に実現する、次世代 AI インフラの決定版です:
特に、データプライバシーが重要な金融、医療、法務、政府機関などの組織や、独自の AI 機能で競争優位を築きたい企業にとって、Self-hosted AI Starter Kit は理想的なソリューションです。
今すぐ始めて、あなたの組織のデジタル変革を加速させましょう。