この記事の要点
• 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 ランタイム比較
| 項目 | Ollama | llama.cpp | LM Studio | vLLM |
|---|---|---|---|---|
| インストール | 非常に簡単 | ビルド必要 | GUI | Python 必要 |
| API | REST + OpenAI 互換 | CLI / server | REST | REST |
| 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 |
|---|---|---|
| 3B | Q4_K_M | 4GB 以上 |
| 7B | Q4_K_M | 8GB 以上 |
| 13B | Q4_K_M | 16GB 以上 |
| 70B | Q4_K_M | 48GB 以上 |
チューニングパラメータ
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 活用の最初の一歩として最適な選択肢です。