Ollama 2025 - ローカルLLM実行環境のデファクトスタンダード

2026.04.10

公式ドキュメント

この記事の要点

• Ollamaはollama pullとollama runだけでローカルLLMを実行できるデファクトスタンダード
• REST APIとOpenAI互換APIを同時提供し、既存コードの移植が容易
• Modelfileによるカスタマイズ、ツール呼び出し、マルチモーダル対応も可能

Ollama はローカル環境で大規模言語モデル (LLM) を手軽に実行するためのランタイムです。Docker のようなシンプルなコマンドラインでモデルの取得・実行・配信ができ、Llama、Mistral、Gemma、Phi、Qwen などのオープンモデルを統一された REST API で扱えます。2025 年現在、オンプレミス / 開発端末で LLM を動かすためのデファクトスタンダードになっています。

Ollamaの概要

特徴

  • ollama pull / ollama run だけでモデルを取得・実行可能
  • REST API と OpenAI 互換 API を同時に提供
  • Modelfile によるカスタムモデル定義
  • macOS (Apple Silicon) / Linux / Windows 対応
  • GPU (CUDA, Metal, ROCm) 自動検出
  • ツール (function calling) / マルチモーダル対応

アーキテクチャ

flowchart TB
    CLI["ollama CLI"] --> Server["Ollama Server (localhost:11434)"]
    SDK["SDK / HTTP client"] --> Server
    Server --> Runtime["llama.cpp runtime"]
    Runtime --> GPU["GPU (Metal/CUDA/ROCm)"]
    Runtime --> CPU["CPU fallback"]
    Registry["registry.ollama.ai"] -. pull .-> Server

主要機能詳細

1. モデルの取得と実行

# モデルをダウンロード
ollama pull llama3.2
ollama pull qwen2.5:7b
ollama pull gemma2:9b

# 対話実行
ollama run llama3.2
>>> こんにちは、日本語で自己紹介してください

2. REST API

デフォルトで http://localhost:11434 にサーバーが立ち上がり、HTTP 経由で呼び出せます。

curl http://localhost:11434/api/generate -d '{
  "model": "llama3.2",
  "prompt": "Rustで素数判定する関数を書いて",
  "stream": false
}'
curl http://localhost:11434/api/chat -d '{
  "model": "llama3.2",
  "messages": [
    {"role": "system", "content": "あなたは親切なアシスタントです"},
    {"role": "user", "content": "TCPとUDPの違いを教えて"}
  ],
  "stream": false
}'

3. OpenAI 互換 API

// OpenAI SDK をそのまま利用
import OpenAI from 'openai';

const openai = new OpenAI({
  baseURL: 'http://localhost:11434/v1',
  apiKey: 'ollama', // 任意文字列
});

const res = await openai.chat.completions.create({
  model: 'llama3.2',
  messages: [
    { role: 'system', content: 'You are a helpful assistant.' },
    { role: 'user', content: 'What is WebAssembly?' },
  ],
});
console.log(res.choices[0].message.content);

4. Modelfile によるカスタマイズ

# Modelfile
FROM llama3.2

PARAMETER temperature 0.2
PARAMETER top_p 0.9
PARAMETER num_ctx 8192

SYSTEM """
You are a senior TypeScript engineer.
Always answer in Japanese with runnable code examples.
Prefer functional style and strict typing.
"""

TEMPLATE """{{ if .System }}<|system|>
{{ .System }}{{ end }}
<|user|>
{{ .Prompt }}
<|assistant|>
"""
ollama create ts-expert -f Modelfile
ollama run ts-expert

5. Embeddings API

const res = await fetch('http://localhost:11434/api/embed', {
  method: 'POST',
  body: JSON.stringify({
    model: 'nomic-embed-text',
    input: ['TypeScriptの型システムについて', 'React の新機能'],
  }),
});
const { embeddings } = await res.json();
console.log(embeddings[0].length); // ベクトル次元

6. ツール呼び出し (function calling)

import OpenAI from 'openai';

const openai = new OpenAI({
  baseURL: 'http://localhost:11434/v1',
  apiKey: 'ollama',
});

const tools = [
  {
    type: 'function' as const,
    function: {
      name: 'get_weather',
      description: 'Get current weather for a city',
      parameters: {
        type: 'object',
        properties: {
          city: { type: 'string' },
        },
        required: ['city'],
      },
    },
  },
];

const res = await openai.chat.completions.create({
  model: 'qwen2.5:7b',
  messages: [{ role: 'user', content: 'What is the weather in Tokyo?' }],
  tools,
});

console.log(res.choices[0].message.tool_calls);

実践サンプル

ポイント: Ollamaの Embeddings API とチャットAPIを組み合わせれば、外部サービスに依存しないローカルRAGシステムを構築できます。

ローカル RAG (Retrieval Augmented Generation)

// rag.ts - シンプルなローカルRAG
import fs from 'node:fs/promises';
import path from 'node:path';

const OLLAMA = 'http://localhost:11434';

async function embed(text: string): Promise<number[]> {
  const res = await fetch(`${OLLAMA}/api/embed`, {
    method: 'POST',
    body: JSON.stringify({ model: 'nomic-embed-text', input: text }),
  });
  const json = await res.json();
  return json.embeddings[0];
}

function cosine(a: number[], b: number[]): number {
  let dot = 0, na = 0, nb = 0;
  for (let i = 0; i < a.length; i++) {
    dot += a[i] * b[i];
    na += a[i] * a[i];
    nb += b[i] * b[i];
  }
  return dot / (Math.sqrt(na) * Math.sqrt(nb));
}

type Doc = { text: string; vec: number[] };

async function buildIndex(dir: string): Promise<Doc[]> {
  const files = await fs.readdir(dir);
  const docs: Doc[] = [];
  for (const f of files) {
    const text = await fs.readFile(path.join(dir, f), 'utf8');
    for (const chunk of text.match(/[\s\S]{1,800}/g) ?? []) {
      docs.push({ text: chunk, vec: await embed(chunk) });
    }
  }
  return docs;
}

async function query(docs: Doc[], question: string) {
  const qvec = await embed(question);
  const top = docs
    .map(d => ({ d, score: cosine(d.vec, qvec) }))
    .sort((a, b) => b.score - a.score)
    .slice(0, 3);

  const context = top.map(({ d }) => d.text).join('\n\n');
  const res = await fetch(`${OLLAMA}/api/chat`, {
    method: 'POST',
    body: JSON.stringify({
      model: 'llama3.2',
      stream: false,
      messages: [
        { role: 'system', content: `参考情報:\n${context}\n\nこの情報のみを根拠に回答してください。` },
        { role: 'user', content: question },
      ],
    }),
  });
  const json = await res.json();
  return json.message.content;
}

const docs = await buildIndex('./knowledge');
console.log(await query(docs, 'プロジェクトの技術スタックは?'));

ストリーミング応答

async function streamChat(prompt: string) {
  const res = await fetch('http://localhost:11434/api/chat', {
    method: 'POST',
    body: JSON.stringify({
      model: 'llama3.2',
      messages: [{ role: 'user', content: prompt }],
      stream: true,
    }),
  });

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

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    const lines = decoder.decode(value).split('\n').filter(Boolean);
    for (const line of lines) {
      const chunk = JSON.parse(line);
      process.stdout.write(chunk.message?.content ?? '');
      if (chunk.done) return;
    }
  }
}

await streamChat('TypeScriptとJavaScriptの違いを簡潔に説明して');

Docker での運用

# docker-compose.yml
services:
  ollama:
    image: ollama/ollama:latest
    ports:
      - "11434:11434"
    volumes:
      - ollama:/root/.ollama
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu]

  webui:
    image: ghcr.io/open-webui/open-webui:main
    ports:
      - "3000:8080"
    environment:
      - OLLAMA_BASE_URL=http://ollama:11434
    depends_on:
      - ollama
    volumes:
      - open-webui:/app/backend/data

volumes:
  ollama:
  open-webui:

比較表

ローカル LLM ランタイム比較

項目Ollamallama.cppLM StudiovLLM
インストール非常に簡単ビルド必要GUIPython 必要
APIREST + OpenAI 互換CLI / serverRESTREST
GPU自動検出手動設定自動要設定
モデルレジストリ公式ありなしありHuggingFace
サーバ運用systemd 可基本はGUI本格運用向け

ベストプラクティス

実践メモ: まずはllama3.2:3bから始めて、用途が固まったら上位モデルに切り替えましょう。Modelfileをリポジトリに含めると再現性が高まります。

1. 用途に応じたモデル選択

  • コード生成: qwen2.5-coder, deepseek-coder-v2
  • 軽量一般用途: llama3.2:3b, phi3:mini
  • 高品質対話: llama3.3:70b (GPU メモリが必要)
  • 埋め込み: nomic-embed-text, mxbai-embed-large

2. コンテキスト長とメモリのバランス

num_ctx を増やすとメモリ消費が急増します。必要最小限に抑えます。

3. Modelfile をリポジトリに含める

システムプロンプトやパラメータをコード化することで再現性を確保。

4. OpenAI 互換 API で実装をロックインしない

本番で OpenAI に切り替えられるよう、API 層を抽象化しておきます

5. 機密データをローカルで完結させる

社内ドキュメントの RAG はローカル Ollama で行うと情報漏洩リスクが下がります

注意点

注意: 大きなモデルは30GBを超えるため、ディスク容量に注意してください。OpenAI互換APIは完全互換ではなく、一部フィールドが未対応です。

  • Ollama はモデルファイルを ~/.ollama/models に展開するため、ディスク容量を圧迫しやすいです。大きなモデルは 30GB を超えます。
  • Apple Silicon では Metal 経由で GPU を使いますが、量子化レベル (q4_K_M など) によって品質と速度が変わります。
  • OpenAI 互換 API は完全互換ではなく、logprobs などの一部フィールドが未対応です。
  • マルチユーザ・本番運用は Ollama 単体ではなく、バックエンドに vLLM など専用推論サーバを置く選択肢も検討します。
  • モデルのライセンスはそれぞれ異なります (Llama 3 は商用可だが利用規約あり、Gemma も同様)。商用利用前に必ず確認してください。

導入手順

macOS

brew install ollama
ollama serve &
ollama pull llama3.2
ollama run llama3.2

Linux

curl -fsSL https://ollama.com/install.sh | sh
sudo systemctl enable --now ollama
ollama pull llama3.2

Windows

公式サイトから OllamaSetup.exe をダウンロードしてインストール。

GPU セットアップ

  • NVIDIA: 最新の CUDA ドライバが必要
  • AMD: ROCm 対応ディストリビューション
  • Apple Silicon: 追加設定不要 (Metal 自動検出)

パフォーマンス

モデルサイズとハードウェア要件の目安

モデルサイズ量子化推奨 RAM/VRAM
3BQ4_K_M4GB 以上
7BQ4_K_M8GB 以上
13BQ4_K_M16GB 以上
70BQ4_K_M48GB 以上

チューニングパラメータ

OLLAMA_NUM_PARALLEL=2 \
OLLAMA_MAX_LOADED_MODELS=2 \
OLLAMA_FLASH_ATTENTION=1 \
ollama serve
  • OLLAMA_NUM_PARALLEL: 同時リクエスト数
  • OLLAMA_MAX_LOADED_MODELS: メモリに常駐させるモデル数
  • OLLAMA_FLASH_ATTENTION: 対応 GPU での高速化

FAQ

Q: 本番運用に向いていますか? A: 開発や小規模な社内利用には適しますが、高スループットの本番推論には vLLM や専用の推論サーバを検討してください。

Q: どのモデルから始めるべき? A: 検証なら llama3.2:3b が軽量で扱いやすいです。用途が決まったら上位モデルに切り替えます。

Q: 商用利用できますか? A: ランタイムは MIT ライセンスですが、各モデルのライセンスに従う必要があります。

Q: ファインチューニングはできますか? A: Ollama 自体は LoRA 等のファインチューニングツールではありません。外部ツールで学習したモデルを Modelfile で読み込みます。

Q: マルチモーダルは? A: llava, llama3.2-vision などの対応モデルを使うと画像入力が扱えます。

さらなる活用例

LangChain との統合

import { ChatOllama } from '@langchain/ollama';
import { ChatPromptTemplate } from '@langchain/core/prompts';

const model = new ChatOllama({
  baseUrl: 'http://localhost:11434',
  model: 'llama3.2',
  temperature: 0.2,
});

const prompt = ChatPromptTemplate.fromMessages([
  ['system', 'You are a helpful senior engineer.'],
  ['user', '{question}'],
]);

const chain = prompt.pipe(model);
const res = await chain.invoke({ question: 'Explain CAP theorem.' });
console.log(res.content);

ローカルコードアシスタント

// code-review.ts
import fs from 'node:fs/promises';

async function reviewFile(path: string) {
  const code = await fs.readFile(path, 'utf8');
  const res = await fetch('http://localhost:11434/api/chat', {
    method: 'POST',
    body: JSON.stringify({
      model: 'qwen2.5-coder:7b',
      stream: false,
      messages: [
        {
          role: 'system',
          content: 'You are a strict code reviewer. Point out bugs, security issues, and style problems.',
        },
        { role: 'user', content: `Review the following TypeScript code:\n\n${code}` },
      ],
    }),
  });
  const json = await res.json();
  return json.message.content;
}

console.log(await reviewFile(process.argv[2]));

スロットリングと同時実行制御

class OllamaClient {
  private queue: Array<() => void> = [];
  private active = 0;
  constructor(private max: number) {}

  async chat(body: unknown): Promise<any> {
    if (this.active >= this.max) {
      await new Promise<void>(r => this.queue.push(r));
    }
    this.active++;
    try {
      const res = await fetch('http://localhost:11434/api/chat', {
        method: 'POST',
        body: JSON.stringify(body),
      });
      return res.json();
    } finally {
      this.active--;
      this.queue.shift()?.();
    }
  }
}

まとめ

Ollama はローカル LLM のハードルを劇的に下げ、開発者が安心して機密データを扱いながら LLM アプリケーションを構築できる環境を提供します。シンプルな CLI、REST + OpenAI 互換 API、Modelfile によるカスタマイズ、ツール呼び出し、マルチモーダル対応と、必要な機能が一通り揃っており、プロトタイピングから社内ツール運用まで幅広く使えます。オープンモデルのエコシステムが拡大し続けている今、Ollama は LLM 活用の最初の一歩として最適な選択肢です。

参考リソース

この技術を体系的に学びたいですか?

未来学では東証プライム上場企業のITエンジニアが24時間サポート。月額24,800円から、退会金0円のオンラインIT塾です。

メールで無料相談する
← 一覧に戻る