ローカルLLM開発環境構築完全ガイド - Ollama, llama.cpp, LM Studio徹底比較


はじめに

2026年現在、ローカル環境でLLM(大規模言語モデル)を実行することが一般的になりました。プライバシー保護、コスト削減、オフライン動作など、多くのメリットがあります。

なぜローカルLLMなのか

メリット:
✅ データがローカルに残る(プライバシー保護)
✅ API料金不要(ランニングコストゼロ)
✅ オフラインで動作
✅ カスタマイズ自由
✅ レスポンス速度の最適化可能

デメリット:
❌ 初期セットアップが必要
❌ GPUメモリが必要(大規模モデル)
❌ 最新の巨大モデルは動かせない

主要なツール比較

ツール難易度速度UIAPIおすすめ用途
Ollama速いCLI開発者向け
LM Studio最低速いGUI初心者向け
llama.cpp最速CLI上級者向け
GPT4All普通GUI×一般ユーザー向け

Ollama - 最もシンプルな選択肢

インストール

# macOS
brew install ollama

# Linux
curl -fsSL https://ollama.com/install.sh | sh

# Windows
# https://ollama.com/download からインストーラーをダウンロード

基本的な使い方

# モデルのダウンロードと実行
ollama run llama3.2

# チャット開始
>>> Hello!
Hi! How can I help you today?

>>> /bye

利用可能なモデル

# 人気モデル一覧
ollama list

# モデル検索
ollama search llama

# おすすめモデル
ollama pull llama3.2           # Meta Llama 3.2 (3B)
ollama pull llama3.2:70b       # Llama 3.2 70B(高性能)
ollama pull mistral            # Mistral 7B
ollama pull codellama          # Code Llama(コード特化)
ollama pull gemma2             # Google Gemma 2
ollama pull qwen2.5            # Alibaba Qwen 2.5
ollama pull phi3               # Microsoft Phi-3(軽量)

モデルサイズの選択

小規模(3-7B): メモリ8GB以上
  - llama3.2 (3B): 2GB VRAM
  - mistral (7B): 4GB VRAM
  - phi3 (3.8B): 2.3GB VRAM

中規模(13-34B): メモリ16GB以上
  - llama3.2:13b: 7GB VRAM
  - codellama:34b: 20GB VRAM

大規模(70B以上): メモリ48GB以上
  - llama3.2:70b: 40GB VRAM
  - 量子化版推奨

API統合

// Node.js
import fetch from 'node-fetch';

async function chat(prompt) {
  const response = await fetch('http://localhost:11434/api/generate', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      model: 'llama3.2',
      prompt: prompt,
      stream: false,
    }),
  });

  const data = await response.json();
  return data.response;
}

// 使用例
const answer = await chat('Explain quantum computing');
console.log(answer);
# Python
import requests

def chat(prompt: str) -> str:
    response = requests.post(
        'http://localhost:11434/api/generate',
        json={
            'model': 'llama3.2',
            'prompt': prompt,
            'stream': False,
        }
    )
    return response.json()['response']

# 使用例
answer = chat('Explain quantum computing')
print(answer)

ストリーミング対応

// TypeScript
async function* chatStream(prompt: string) {
  const response = await fetch('http://localhost:11434/api/generate', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      model: 'llama3.2',
      prompt: prompt,
      stream: true,
    }),
  });

  const reader = response.body!.getReader();
  const decoder = new TextDecoder();

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;

    const chunk = decoder.decode(value);
    const lines = chunk.split('\n').filter(Boolean);

    for (const line of lines) {
      const data = JSON.parse(line);
      if (data.response) {
        yield data.response;
      }
    }
  }
}

// 使用例
for await (const chunk of chatStream('Write a story')) {
  process.stdout.write(chunk);
}

Modelfile - カスタムモデル

# Modelfile
FROM llama3.2

# システムプロンプト
SYSTEM """
You are a helpful assistant specialized in TypeScript development.
Always provide code examples and explain best practices.
"""

# パラメータ
PARAMETER temperature 0.8
PARAMETER top_p 0.9
PARAMETER top_k 40

# テンプレート
TEMPLATE """
{{ if .System }}System: {{ .System }}{{ end }}
User: {{ .Prompt }}
Assistant:
"""
# カスタムモデル作成
ollama create typescript-expert -f Modelfile

# 使用
ollama run typescript-expert

マルチモーダル対応

# 画像認識モデル
ollama pull llava

# 画像を読み込んで質問
ollama run llava "What's in this image?" --image photo.jpg
// API経由
const fs = require('fs');

async function analyzeImage(imagePath, question) {
  const imageBase64 = fs.readFileSync(imagePath).toString('base64');

  const response = await fetch('http://localhost:11434/api/generate', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      model: 'llava',
      prompt: question,
      images: [imageBase64],
      stream: false,
    }),
  });

  const data = await response.json();
  return data.response;
}

const answer = await analyzeImage('photo.jpg', 'What objects are in this image?');
console.log(answer);

llama.cpp - 最高のパフォーマンス

ビルドとインストール

# macOS/Linux
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp
make

# GPUサポート(CUDA)
make LLAMA_CUDA=1

# GPUサポート(Metal - macOS)
make LLAMA_METAL=1

# GPUサポート(ROCm - AMD)
make LLAMA_HIPBLAS=1

モデルのダウンロード

# Hugging Faceからダウンロード
# 例: Llama 3.2 3B
wget https://huggingface.co/meta-llama/Llama-3.2-3B-Instruct-GGUF/resolve/main/llama-3.2-3b-instruct-q4_k_m.gguf

# 保存先
mkdir -p models
mv llama-3.2-3b-instruct-q4_k_m.gguf models/

実行

# 基本実行
./llama-cli \
  -m models/llama-3.2-3b-instruct-q4_k_m.gguf \
  -p "Explain quantum computing" \
  -n 512

# インタラクティブモード
./llama-cli \
  -m models/llama-3.2-3b-instruct-q4_k_m.gguf \
  --interactive

# GPUレイヤー数指定(高速化)
./llama-cli \
  -m models/llama-3.2-3b-instruct-q4_k_m.gguf \
  -ngl 32 \
  -p "Hello"

サーバーモード

# APIサーバー起動
./llama-server \
  -m models/llama-3.2-3b-instruct-q4_k_m.gguf \
  -ngl 32 \
  --host 0.0.0.0 \
  --port 8080

# テスト
curl http://localhost:8080/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "llama-3.2-3b",
    "messages": [
      {"role": "user", "content": "Hello!"}
    ]
  }'

パラメータチューニング

# 温度(ランダム性)
-temp 0.8

# Top-P(確率分布)
--top-p 0.9

# Top-K(候補数)
--top-k 40

# コンテキスト長
-c 4096

# バッチサイズ
-b 512

# スレッド数
-t 8

# 実例
./llama-cli \
  -m models/llama-3.2-3b-instruct-q4_k_m.gguf \
  -ngl 32 \
  -temp 0.7 \
  --top-p 0.9 \
  --top-k 40 \
  -c 8192 \
  -t 8 \
  -p "Write a story"

LM Studio - 初心者に最適

インストール

  1. https://lmstudio.ai/ からダウンロード
  2. インストーラー実行
  3. 起動してモデル検索

GUI操作

1. 左サイドバーで「Search」
2. モデル名入力(例: llama-3.2)
3. ダウンロードボタンクリック
4. 「Chat」タブで会話開始

ローカルサーバー起動

1. 「Local Server」タブ
2. モデル選択
3. 「Start Server」
4. http://localhost:1234 で起動

OpenAI互換API

// LM StudioはOpenAI APIと互換性あり
import OpenAI from 'openai';

const client = new OpenAI({
  baseURL: 'http://localhost:1234/v1',
  apiKey: 'not-needed',
});

async function chat(prompt: string) {
  const completion = await client.chat.completions.create({
    model: 'local-model',
    messages: [{ role: 'user', content: prompt }],
  });

  return completion.choices[0].message.content;
}

const answer = await chat('Explain TypeScript generics');
console.log(answer);

RAG(Retrieval-Augmented Generation)実装

シンプルなRAGシステム

// rag-simple.ts
import fs from 'fs';
import fetch from 'node-fetch';

// ドキュメント読み込み
function loadDocuments(dir: string): string[] {
  return fs.readdirSync(dir)
    .filter(file => file.endsWith('.txt'))
    .map(file => fs.readFileSync(`${dir}/${file}`, 'utf-8'));
}

// シンプルな検索(キーワードマッチ)
function search(query: string, documents: string[]): string[] {
  const keywords = query.toLowerCase().split(' ');

  return documents
    .filter(doc =>
      keywords.some(keyword => doc.toLowerCase().includes(keyword))
    )
    .slice(0, 3); // 上位3件
}

// RAGチャット
async function ragChat(query: string, documents: string[]) {
  // 関連ドキュメント検索
  const relevantDocs = search(query, documents);

  // コンテキスト作成
  const context = relevantDocs.join('\n\n---\n\n');

  // プロンプト作成
  const prompt = `
Context:
${context}

Question: ${query}

Answer based on the context above:
`;

  // LLMに送信
  const response = await fetch('http://localhost:11434/api/generate', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      model: 'llama3.2',
      prompt: prompt,
      stream: false,
    }),
  });

  const data = await response.json();
  return data.response;
}

// 使用例
const docs = loadDocuments('./knowledge');
const answer = await ragChat('What is TypeScript?', docs);
console.log(answer);

ベクトルDBを使ったRAG

npm install chromadb
// rag-vector.ts
import { ChromaClient } from 'chromadb';
import fetch from 'node-fetch';

const client = new ChromaClient();

// コレクション作成
async function createCollection() {
  return await client.createCollection({
    name: 'documents',
  });
}

// ドキュメント追加
async function addDocuments(collection: any, documents: string[]) {
  const ids = documents.map((_, i) => `doc_${i}`);

  await collection.add({
    ids: ids,
    documents: documents,
  });
}

// ベクトル検索
async function vectorSearch(collection: any, query: string) {
  const results = await collection.query({
    queryTexts: [query],
    nResults: 3,
  });

  return results.documents[0];
}

// RAGチャット
async function ragChatVector(query: string) {
  const collection = await client.getCollection({ name: 'documents' });

  // ベクトル検索
  const relevantDocs = await vectorSearch(collection, query);

  // コンテキスト作成
  const context = relevantDocs.join('\n\n---\n\n');

  // プロンプト作成
  const prompt = `
Context:
${context}

Question: ${query}

Answer based on the context above:
`;

  // LLMに送信
  const response = await fetch('http://localhost:11434/api/generate', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      model: 'llama3.2',
      prompt: prompt,
      stream: false,
    }),
  });

  const data = await response.json();
  return data.response;
}

パフォーマンス最適化

量子化(Quantization)

FP16: 高精度、メモリ大
  - 70Bモデル: 140GB

Q8: 8-bit量子化
  - 70Bモデル: 70GB

Q4_K_M: 4-bit量子化(推奨)
  - 70Bモデル: 40GB
  - 精度とサイズのバランス良好

Q2: 2-bit量子化
  - 70Bモデル: 20GB
  - 精度低下あり

GPU最適化

# Ollama(自動)
ollama run llama3.2

# llama.cpp
# -ngl でGPUレイヤー数指定
./llama-cli -m model.gguf -ngl 32

# 最適値の見つけ方
# 全レイヤーをGPUに: -ngl 99
# メモリ不足なら徐々に減らす

メモリ管理

# Ollama
# メモリ制限
OLLAMA_MAX_LOADED_MODELS=1 ollama serve

# llama.cpp
# コンテキスト長を減らす
./llama-cli -m model.gguf -c 2048

実践的なユースケース

コード生成アシスタント

// code-assistant.ts
import fetch from 'node-fetch';

async function generateCode(description: string, language: string) {
  const prompt = `
You are a code generation expert.

Task: Generate ${language} code for the following:
${description}

Requirements:
- Clean, readable code
- Add comments
- Follow best practices

Code:
`;

  const response = await fetch('http://localhost:11434/api/generate', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      model: 'codellama',
      prompt: prompt,
      stream: false,
    }),
  });

  const data = await response.json();
  return data.response;
}

// 使用例
const code = await generateCode(
  'Create a React component for a todo list',
  'TypeScript'
);
console.log(code);

ドキュメント要約

async function summarize(text: string) {
  const prompt = `
Summarize the following text in 3-5 bullet points:

${text}

Summary:
`;

  const response = await fetch('http://localhost:11434/api/generate', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      model: 'llama3.2',
      prompt: prompt,
      temperature: 0.3, // 低温度で安定した要約
      stream: false,
    }),
  });

  const data = await response.json();
  return data.response;
}

翻訳

async function translate(text: string, from: string, to: string) {
  const prompt = `
Translate the following text from ${from} to ${to}:

${text}

Translation:
`;

  const response = await fetch('http://localhost:11434/api/generate', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      model: 'llama3.2',
      prompt: prompt,
      temperature: 0.3,
      stream: false,
    }),
  });

  const data = await response.json();
  return data.response;
}

// 使用例
const translated = await translate(
  'Hello, how are you?',
  'English',
  'Japanese'
);

まとめ

ツール選択ガイド

初心者:
  → LM Studio(GUI、簡単)

開発者:
  → Ollama(CLI、API統合しやすい)

上級者/最高性能:
  → llama.cpp(最速、カスタマイズ自由)

おすすめモデル

汎用:
  - llama3.2 (3B): 軽量、高速
  - mistral (7B): バランス良好

コード:
  - codellama: コード生成特化

日本語:
  - qwen2.5: 日本語対応良好

画像認識:
  - llava: マルチモーダル

次のステップ

ローカルLLMで、プライバシーを守りながら開発を加速させましょう。