問題の概要:OllamaのAPIレスポンスが異常に遅い
Ollamaを利用してローカルLLM(大規模言語モデル)のAPIサーバーを立ち上げ、アプリケーションからリクエストを送信している際に、レスポンスが非常に遅くなる問題が発生することがあります。具体的には、以下のような症状が確認されます。
- シンプルなプロンプトに対する応答に数十秒かかる
- ストリーミング出力が途切れ途切れになり、体感速度が低下する
- 同時に複数リクエストを送ると、著しくパフォーマンスが落ちる
- ターミナルで直接
ollama runコマンドを実行するよりも、API経由の方が明らかに遅い
例えば、cURLやPythonのrequestsライブラリで以下のようなリクエストを送った場合、応答が返ってくるまでに異常な待ち時間が発生します。
# 遅延が発生する可能性のあるAPIリクエスト例
curl http://localhost:11434/api/generate -d '{
"model": "llama3.2",
"prompt": "こんにちは、調子はどうですか?",
"stream": false
}'
この問題は、開発中のアプリケーションのユーザー体験を損ねるだけでなく、バッチ処理の効率にも悪影響を及ぼします。
原因の解説:なぜOllamaのレスポンスは遅くなるのか?
OllamaのAPIレスポンスが遅くなる原因は、主に以下の4つのカテゴリに分類できます。単一の原因であることもあれば、複数が組み合わさっている場合もあります。
1. モデルパラメータとコンテキスト設定の不最適化
デフォルトのモデル設定が、ご使用のハードウェア(特にGPU VRAMやシステムRAM)に対して過大である可能性があります。num_ctx(コンテキストウィンドウサイズ)やnum_predict(最大出力トークン数)が大きすぎると、メモリ転送や計算に時間がかかり、遅延の原因となります。
2. システムリソースの不足または競合
Ollamaはデフォルトで可能な限りGPUを利用しようとしますが、VRAMが不足している場合、システムRAMとの間でメモリのスワッピングが発生し、大幅な速度低下を招きます。また、他のアプリケーションがCPUやGPUを占有している場合も同様です。
3. ネットワークとAPIサーバー設定の問題
Ollamaサーバー自体の設定や、クライアントからのネットワーク接続に問題があるケースです。特に、Dockerコンテナ内で実行している場合や、リバースプロキシを経由している場合に発生しやすいです。
4. ストリーミングモードの挙動
APIで"stream": trueを設定している場合、クライアント側の処理(例:バッファリング、一行ごとのパース)がボトルネックとなり、体感速度が低下しているように感じられることがあります。
解決方法:ステップバイステップでパフォーマンスをチューニング
以下の手順を上から順に試し、改善度合いを確認しながら進めてください。
ステップ1: モデル設定の見直しと最適化(Modelfileの作成)
最も効果が高いのが、ハードウェアに合わせたモデルパラメータの設定です。OllamaではModelfileを作成し、ollama createコマンドでカスタムモデルとして登録することで細かい制御が可能です。
まず、現在のモデルの詳細を確認します。
ollama show llama3.2 --modelfile
次に、以下の内容のModelfile.customというファイルを作成します。値はお使いの環境に合わせて調整してください(例:GPU VRAMが8GBの場合)。
FROM llama3.2
# システムプロンプトの設定(オプション)
SYSTEM "あなたは親切で有能なアシスタントです。回答は簡潔に。"
# 重要なパラメータ: コンテキストサイズを減らす(デフォルトは8192など大きい)
PARAMETER num_ctx 4096
# 重要なパラメータ: 1回の処理で扱うバッチサイズ
PARAMETER num_batch 512
# 重要なパラメータ: レイヤーをGPUに置く数(-1は可能な限り全て)
PARAMETER num_gpu -1
# 温度パラメータ(ランダム性)。低いほど高速で決定論的になる傾向
PARAMETER temperature 0.7
# 出力トークン数の制限
PARAMETER num_predict 512
カスタムモデルを作成して使用します。
ollama create tuned-model -f ./Modelfile.custom
ollama run tuned-model
# APIでは "model": "tuned-model" を指定
ステップ2: Ollamaサーバー起動オプションの調整
Ollamaサーバーを再起動し、リソース使用量を明示的に指定します。まず、実行中のOllamaを停止します。
ollama serve
# Ctrl+Cで停止した後、環境変数を設定して再起動
Linux/macOSの場合:
OLLAMA_NUM_PARALLEL=2 OLLAMA_HOST=0.0.0.0:11434 ollama serve
Windows (PowerShell)の場合:
$env:OLLAMA_NUM_PARALLEL=2
$env:OLLAMA_HOST="0.0.0.0:11434"
ollama serve
主要な環境変数:
OLLAMA_NUM_PARALLEL: 並列処理数。CPUコア数に応じて調整(通常2-4)。OLLAMA_HOST: バインドするアドレス。OLLAMA_GPU_LAYERS: GPUにオフロードするレイヤー数を強制指定。OLLAMA_KEEP_ALIVE: モデルをメモリに保持する時間。頻繁に使う場合は値を大きく。
ステップ3: システムリソースの監視と最適化
Ollama実行中に、リソースがボトルネックになっていないかを確認します。
GPUメモリ使用量の確認(nvidia-smiが利用可能な場合):
nvidia-smi
一般的なシステムモニタリング:
# Linux/macOS
htop
# または
top
# Ollamaプロセスの詳細確認 (Linux/macOS)
ps aux | grep ollama
VRAM不足が疑われる場合は、Modelfileのnum_gpuパラメータを減らし、一部のレイヤーをCPUで処理させることを検討します(例:PARAMETER num_gpu 20)。
ステップ4: APIリクエストの最適化
クライアント側のAPIリクエストも見直します。不要なパラメータを送信していないか、ストリーミングモードを正しく扱えているか確認します。
非ストリーミングリクエスト(完了まで待つ): シンプルで確実。
import requests
import json
response = requests.post('http://localhost:11434/api/generate',
json={
'model': 'tuned-model',
'prompt': '量子コンピューティングについて簡単に説明してください。',
'stream': False, # 非ストリーミング
'options': {
'num_predict': 100
}
})
result = response.json()
print(result['response'])
ストリーミングリクエスト: 体感速度向上に有効だが、クライアント側の処理が必要。
import requests
import json
response = requests.post('http://localhost:11434/api/generate',
json={
'model': 'tuned-model',
'prompt': '量子コンピューティングについて簡単に説明してください。',
'stream': True # ストリーミング有効
},
stream=True)
for line in response.iter_lines():
if line:
decoded_line = line.decode('utf-8')
json_data = json.loads(decoded_line)
if 'response' in json_data:
print(json_data['response'], end='', flush=True) # flushが重要
Pythonではflush=Trueを指定して即時表示させることが体感速度向上に寄与します。
コード例・コマンド例:パフォーマンス計測スクリプト
チューニングの前後で実際にどれだけ改善したかを計測するためのシンプルなPythonスクリプトです。
import requests
import json
import time
def benchmark_ollama(model_name, prompt, stream=False, num_requests=3):
"""Ollama APIのレスポンス時間を計測する"""
url = "http://localhost:11434/api/generate"
headers = {'Content-Type': 'application/json'}
total_time = 0
for i in range(num_requests):
data = {
"model": model_name,
"prompt": prompt,
"stream": stream,
"options": {"temperature": 0.7}
}
start_time = time.time()
response = requests.post(url, headers=headers, data=json.dumps(data), stream=stream)
if stream:
# ストリーミングレスポンスの場合は全てのチャンクを受信
for _ in response.iter_lines():
pass
else:
# 非ストリーミングの場合はJSONを読み込み
_ = response.json()
elapsed = time.time() - start_time
total_time += elapsed
print(f"リクエスト {i+1}: {elapsed:.2f} 秒")
avg_time = total_time / num_requests
print(f"nモデル '{model_name}' の平均レスポンス時間: {avg_time:.2f} 秒")
return avg_time
# チューニング前後のモデルで計測
print("=== チューニング前(オリジナルモデル)===")
benchmark_ollama("llama3.2", "こんにちは、自己紹介をしてください。", stream=False)
print("n=== チューニング後(カスタムモデル)===")
benchmark_ollama("tuned-model", "こんにちは、自己紹介をしてください。", stream=False)
まとめ・補足情報
OllamaのAPIレスポンスが遅い問題は、「モデル設定」「システムリソース」「API通信」の3つの観点から体系的にチューニングすることで、ほとんどの場合大幅に改善できます。
最終チェックリスト:
- モデルはハードウェアに合っていますか? 7Bパラメータモデルですら8GB VRAMでは厳しい場合があります。小さなモデル(例:
llama3.2:1b,phi3:mini)への変更も検討しましょう。 - Modelfileで
num_ctxとnum_batchを下げましたか? これが最も効果的な場合が多いです。 - Ollamaサーバーは十分なリソースで動いていますか? 他の重いアプリケーション(ゲーム、動画編集ソフト等)を終了させてみてください。
- ストリーミングを正しく扱えていますか? 体感速度向上のためにはストリーミング(
"stream": true)が有効ですが、クライアント側の実装も重要です。
補足:Docker環境での注意点
DockerでOllamaを実行している場合、ホストとのリソース割り当て(特にGPU)が正しく行われているか確認が必要です。docker run時に--gpus allフラグを忘れていないか、またホストのポート(11434)が他のサービスと競合していないかを確認してください。
OllamaはローカルLLM利用の強力なツールですが、そのパフォーマンスは環境に大きく依存します。本ガイドを参考に、ご自身の開発環境に最適な設定を見つけて、快適なAIアプリケーション開発をお楽しみください。