Ollama: REST APIの基礎
REST APIはOllamaのユニバーサルインターフェース——言語もフレームワークも問わず、HTTPリクエストを送るだけで接続完了。
⚠️ 注意: OllamaのREST APIには組み込みの認証機能がない——サービスポートにアクセスできる人なら誰でも自由にモデルを呼び出し、インストール済みモデル一覧を閲覧できる。本番環境では、リバースプロキシ(Nginx/Caddyなど)でAPI Key認証を必ず追加すること。そうしないと、AIサービスが悪用・データ漏洩・リソース枯渇のリスクに晒される。
📋 前提条件: まず以下を習得していること
1. 学べること
/api/generateと/api/chatエンドポイントの比較- ストリーミングレスポンス(NDJSON)の解析方法
- 推論パラメータの調整(Temperature、Top_P、num_ctx)
- curlの実践:単発生成とマルチターン対話
- AliceのSupportBotプロトタイプAPIテスト
2. SaaS創業者のリアルな事例
(1) ペインポイント:手動返信の非効率性
AliceはGlobalShopというECプラットフォームを立ち上げた。50人のカスタマーサポートチームが毎日2,000件以上のチケットを処理している。各チケットの平均処理時間は8分、顧客の待ち時間は30分を超える。API経由でLLMをカスタマーサポートシステムに統合し、返信下書きを自動生成したい。
(2) ソリューション:REST APIで即座に返信生成
curlでOllama APIを呼び出すと、カスタマーサポートの返信下書きが3秒で生成される——担当者は確認するだけ:
BASH
curl http://localhost:11434/api/chat -d '{
"model": "qwen2.5",
"messages": [{"role": "user", "content": "Refund for order #12345"}]
}'
⚠️ 警告: Ollama APIには組み込み認証がない——ポートにアクセスできる人は誰でも呼び出せる。本番環境では、リバースプロキシ(Nginx/Caddy)でAPI Key認証を必ず追加すること。セキュリティ強化はレッスン20を参照。
💡 ヒント: ストリーミングAPI(
stream: true)はリアルタイム入力効果のあるチャットインターフェースに適し、非ストリーミング(stream: false)はバッチ処理やAPIバックエンド統合に適している。API統合では非ストリーミングが推奨——よりシンプル。
ℹ️ 情報: Ollamaのデフォルトは
http://127.0.0.1:11434で、ローカルマシンからのみアクセス可能。LANからのアクセスにはOLLAMA_HOST環境変数を設定するが、セキュリティリスクに注意。
3. APIエンドポイント完全ガイド
(1) 2つのコアエンドポイント比較
| 項目 | /api/generate |
/api/chat |
|---|---|---|
| 用途 | 単発テキスト生成 | マルチターン対話 |
| 入力 | model + prompt |
messages配列 |
| コンテキスト | 単一リクエスト | 会話履歴に対応 |
| APIマッピング | CLI ollama run |
CLI ollama chat |
| ユースケース | 生成・補完・翻訳 | カスタマーサポート・アシスタント・多段推論 |
sequenceDiagram
participant C as Client
participant O as Ollama Server
C->>O: POST /api/chat {messages, model, stream}
O-->>C: NDJSON {message, done: false}
O-->>C: NDJSON {message, done: false}
O-->>C: NDJSON {message, done: true, stats}
(2) 共通リクエストパラメータ
| パラメータ | 型 | デフォルト | 説明 |
|---|---|---|---|
model |
string | 必須 | モデル名 |
stream |
bool | true | ストリーム出力の有無 |
options |
object | — | 推論パラメータ(次節参照) |
format |
string | — | 出力形式:json |
keep_alive |
string | 5m |
モデルのメモリ保持時間 |
(3) ▶ サンプル:単発生成リクエスト
BASH
# Non-streaming generate request
curl http://localhost:11434/api/generate -d '{
"model": "llama3.2",
"prompt": "Write a haiku about coding",
"stream": false
}'
# Response (abbreviated)
# {
# "model": "llama3.2",
# "response": "Lines of logic flow,\nBug hides in the deep syntax—\nSemicolon found.",
# "done": true,
# "total_duration": 2500000000,
# "eval_count": 18
# }
出力:
TEXT
{"status":"ok","data":{}}
(4) ▶ サンプル:マルチターン対話リクエスト
BASH
# Chat with message history
curl http://localhost:11434/api/chat -d '{
"model": "qwen2.5",
"messages": [
{"role": "system", "content": "You are a helpful customer service agent."},
{"role": "user", "content": "I want to return my order #12345"},
{"role": "assistant", "content": "I can help with that. May I ask the reason for the return?"},
{"role": "user", "content": "The product arrived damaged"}
],
"stream": false
}'
出力:
TEXT
{"status":"ok","data":{}}
4. ストリーミングレスポンスの解析
💡 ヒント:ストリーミング(
stream: true)と非ストリーミング(stream: false)はそれぞれ用途がある——ストリーミングはチャットインターフェースのリアルタイム入力効果用で、ユーザーは完全なレスポンスを待たずにコンテンツを確認できる。非ストリーミングはバッチ処理やAPIバックエンド統合用で、完全なJSONレスポンスを取得する方がプログラム解析に容易。まず非ストリーミングでロジックを検証し、その後ストリーミングに切り替えてUXを最適化することを推奨。
(1) NDJSON形式の解説
ストリーミングレスポンスはNDJSON(Newline Delimited JSON)を使用し、1行に1つのJSONオブジェクト:
TEXT
{"model":"llama3.2","message":{"role":"assistant","content":"I"},"done":false}
{"model":"llama3.2","message":{"role":"assistant","content":" can"},"done":false}
{"model":"llama3.2","message":{"role":"assistant","content":" help"},"done":false}
{"model":"llama3.2","message":{"role":"assistant","content":""},"done":true,"total_duration":1500000000}
| フィールド | 説明 |
|---|---|
message.content |
このチャンクのテキスト断片 |
done |
最後のチャンクかどうか |
total_duration |
合計推論時間(ナノ秒) |
eval_count |
生成トークン数 |
prompt_eval_count |
入力トークン数 |
(2) ストリーミングと非ストリーミングの比較
| 項目 | ストリーミング(stream: true) | 非ストリーミング(stream: false) |
|---|---|---|
| ユーザー体験 | リアルタイムの1文字ずつ出力 | 完全なレスポンスを待機 |
| 初回トークンレイテンシ | 非常に低い(~200ms) | すべての生成完了まで待機 |
| 実装の複雑さ | NDJSON解析が必要 | JSONを直接読み取り |
| ユースケース | チャットインターフェース、リアルタイム表示 | バッチ処理、APIバックエンド |
(3) ▶ サンプル:ストリーミングレスポンスの解析
BASH
# Streaming request with real-time output
curl http://localhost:11434/api/chat -d '{
"model": "llama3.2",
"messages": [{"role": "user", "content": "Hello!"}],
"stream": true
}' | while read -r line; do
# Extract content field from each NDJSON line
echo "$line" | python3 -c "
import sys, json
data = json.load(sys.stdin)
if data.get('message', {}).get('content'):
print(data['message']['content'], end='', flush=True)
"
done
出力:
TEXT
{"status":"ok","data":{}}
5. 推論パラメータの調整
(1) コアパラメータ一覧
| パラメータ | 型 | 範囲 | デフォルト | 効果 |
|---|---|---|---|---|
temperature |
float | 0-2 | 0.8 | ランダム性の制御。低い値ほど決定的 |
top_p |
float | 0-1 | 0.9 | ニュークリウスサンプリング、候補トークン範囲を制限 |
top_k |
int | 1-100 | 40 | 上位K件の候補のみサンプリング |
num_ctx |
int | 128-131072 | 2048 | コンテキストウィンドウサイズ |
repeat_penalty |
float | 1-2 | 1.1 | 繰り返しペナルティ係数 |
seed |
int | 任意 | -1 | ランダムシード(-1 = ランダム) |
(2) シナリオ別パラメータ調整
| シナリオ | temperature | top_p | 備考 |
|---|---|---|---|
| コード生成 | 0.1-0.3 | 0.9 | 決定性と精度が必要 |
| カスタマーサポート返信 | 0.3-0.5 | 0.9 | 安定しつつ適度な変化を許容 |
| クリエイティブライティング | 0.7-1.0 | 0.95 | 多様性と創造性が必要 |
| データ分析 | 0.1-0.2 | 0.9 | 精密さが必須、ハルシネーション不可 |
⚠️ 警告:
num_ctxはメモリ使用量に直接影響する。8Bモデルでnum_ctx=8192は約6GB VRAMが必要、num_ctx=32768は約12GB VRAMが必要。必要に応じて設定し、むやみに増やさないこと。
(3) ▶ サンプル:パラメータ調整の比較
BASH
# Low temperature: deterministic output
curl http://localhost:11434/api/generate -d '{
"model": "llama3.2",
"prompt": "What is 2+2?",
"stream": false,
"options": {"temperature": 0.1}
}'
# Response: "2+2 equals 4."
# High temperature: creative output
curl http://localhost:11434/api/generate -d '{
"model": "llama3.2",
"prompt": "What is 2+2?",
"stream": false,
"options": {"temperature": 1.5}
}'
# Response: "In the realm of mathematics, 2+2 opens the door to 4..."
出力:
TEXT
{"status":"ok","data":{}}
(4) ▶ サンプル:JSON形式出力
BASH
# Force JSON output format
curl http://localhost:11434/api/chat -d '{
"model": "llama3.2",
"messages": [
{"role": "system", "content": "You are a product catalog API. Return JSON only."},
{"role": "user", "content": "List 3 laptops under $500"}
],
"format": "json",
"stream": false,
"options": {"temperature": 0.3}
}'
# Response is valid JSON
# {"products":[{"name":"Acer Aspire 5","price":449,"spec":"8GB RAM, 256GB SSD"},...]}
出力:
TEXT
{"status":"ok","data":{}}
6. 総合サンプル:SupportBotカスタマーサポートAPIプロトタイプ
💡 ヒント: 本番環境でAPIを呼び出す際、
keep_aliveパラメータ(例:"keep_alive": "5m")を必ず設定し、モデルの頻繁なロード/アンロードによるレスポンス遅延を防ぐこと。
BASH
#!/bin/bash
# ============================================
# Comprehensive: SupportBot API prototype
# Multi-turn customer service via REST API
# ============================================
API="http://localhost:11434/api/chat"
MODEL="qwen2.5"
# Function: Send a chat message and extract response
chat() {
local system_prompt="$1"
local user_msg="$2"
local temp="${3:-0.4}"
curl -s "$API" -d "$(cat <<EOF
{
"model": "$MODEL",
"messages": [
{"role": "system", "content": "$system_prompt"},
{"role": "user", "content": "$user_msg"}
],
"stream": false,
"options": {"temperature": $temp, "num_ctx": 4096}
}
EOF
)" | python3 -c "import sys,json; print(json.load(sys.stdin)['message']['content'])"
}
# Customer service system prompt
SYSTEM="You are SupportBot, a customer service agent for an e-commerce store. Be polite, concise, and helpful. If you cannot answer, say 'Let me connect you with a human agent.'"
# Simulate customer interactions
echo "=== Query 1: Order Status ==="
chat "$SYSTEM" "Where is my order #88765? It has been 5 days."
echo ""
echo "=== Query 2: Return Request ==="
chat "$SYSTEM" "I received a damaged item. Order #12345. I want a refund."
echo ""
echo "=== Query 3: Product Question ==="
chat "$SYSTEM" "Does the wireless headphone support Bluetooth 5.3?"
echo ""
echo "=== Benchmark ==="
time chat "$SYSTEM" "Hello" > /dev/null
💻 出力:
TEXT
=== Query 1: Order Status ===
I'd be happy to check on your order #88765. Based on our tracking system, your order is currently in transit and expected to arrive within 2-3 business days. You can track it at track.example.com/88765.
=== Query 2: Return Request ===
I'm sorry to hear about the damaged item. For order #12345, I've initiated a return request. You'll receive a prepaid shipping label via email within 24 hours. Once we receive the item, a full refund will be processed within 3-5 business days.
=== Query 3: Product Question ===
Yes, our wireless headphones support Bluetooth 5.3 with a range of up to 15 meters. They also feature active noise cancellation and 30-hour battery life.
❓ よくある質問
Q curlリクエストがconnection refusedを返すのはなぜ?
A Ollamaサービスが起動していない。
ollama serveを実行するか、systemdサービスが起動しているか確認:sudo systemctl status ollama。Q stream: trueとstream: falseはどちらを選ぶべき?
A フロントエンドのチャットインターフェースではリアルタイム入力効果を得るために
stream: trueを使用。バックエンドのバッチ処理では完全なレスポンスを直接取得するためにstream: falseを使用。API統合では非ストリーミングが推奨——よりシンプル。Q 出力長を制限するには?
A
num_predictパラメータを設定。例:"num_predict": 200で生成を200トークンに制限。これはトークン数であり文字数ではないことに注意。Q format: jsonは有効なJSON出力を保証する?
A ほとんどの場合機能するが、100%の保証はない。アプリケーション層でJSONバリデーションを追加し、パース失敗時にリトライまたはテキスト処理にフォールバックすることを推奨。
Q マルチターン対話はコンテキストをどう維持する?
A クライアント側で
messages配列を自前で管理し、毎回のリクエストで完全な会話履歴を送信する。Ollamaサーバーはセッション状態を保存しない。Q API呼び出しの同時実行制限はある?
A デフォルトでは一度に1つのリクエストのみ処理される。
OLLAMA_NUM_PARALLEL環境変数で同時実行数を増やせるが、より多くのVRAMが必要。パフォーマンスチューニングはレッスン19を参照。📖 まとめ
/api/generateは単発生成用、/api/chatはマルチターン対話に対応- ストリーミングレスポンスはNDJSON形式でチャンクごとに出力、チャットインターフェースに最適
- temperatureはランダム性を制御——低い値(0.1-0.3)はコード/分析、高い値は創造性に
format: jsonで構造化出力を強制できるが、アプリケーション層でのバリデーションが必要- カスタマーサポートシナリオではtemperature=0.3-0.5を推奨、安定性と自然さのバランス
- マルチターン対話はクライアント側でmessages配列を管理、サーバーはステートレス
📝 練習問題
- 基本(難易度 ⭐):curlで
/api/generateを呼び出して商品説明を生成し、stream: trueとstream: falseの両方を試して違いを観察する。 - 中級(難易度 ⭐⭐):
/api/chatを使って3ターンの対話を実装し、messages配列を手動で管理し、各ターンで完全な返信を出力する。 - 上級(難易度 ⭐⭐⭐):SupportBotのカスタマーサポートフローをシミュレートするShellスクリプトを作成——質問を受け取り、APIを呼び出し、JSON形式で分類結果(インテント+返信)を返し、リアルタイムストリーミング出力に対応する。