OllamaのAPIをPython asyncioで並列呼び出しする方法|httpxとasyncio.gatherで複数プロンプトを同時処理してスループットを向上させる手順

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOME > Linux技術 リナックスマスター.JP(Linuxマスター.JP) > ローカルLLM > OllamaのAPIをPython asyncioで並列呼び出しする方法|httpxとasyncio.gatherで複数プロンプトを同時処理してスループットを向上させる手順
「Ollamaで大量のテキストファイルを処理したいが、1件ずつ順番に実行すると時間がかかりすぎる」
「Pythonからの複数プロンプト実行をどう並列化すればよいか、asyncioの書き方がわからない」

そんな悩みを抱えるPython開発者やLinux管理者は多い。Ollamaは内部で複数リクエストを同時に処理できる仕組みを持っているが、Pythonからの呼び出しがシーケンシャルなままでは本来の性能を引き出せない。
この記事では、Pythonのasyncioとhttpxを使ってOllamaのAPIを並列呼び出しし、バッチ処理のスループットを向上させる手順を解説する。asyncio.gatherによるファンアウト処理とasyncio.Semaphoreによる並列数の制御、実務での一括要約スクリプトまで、Ubuntu 22.04/24.04で確認済みのコードで紹介する。

この記事のポイント

・OLLAMA_NUM_PARALLELを設定し、httpx + asyncioで複数プロンプトを同時処理するPythonコードを解説
・asyncio.gatherで複数タスクを一斉実行し、完了順にレスポンスを回収する実装パターンを紹介
・asyncio.Semaphoreで同時接続数を制限し、Ollamaのリソースを超えない安全な呼び出しを実現
・社内ドキュメントの一括要約スクリプトを実装例として提示し、すぐに実務へ応用できる構成にする


OllamaのAPIをPython asyncioで並列呼び出しする方法|httpxとasyncio.gatherで複数プロンプトを同時処理してスループットを向上させる手順

「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Ollamaの並列処理の仕組みとOLLAMA_NUM_PARALLELの役割

1. Ollamaが複数リクエストをどう処理するか

Ollamaはデフォルトで、GPUメモリとモデルサイズに基づいて並列処理できるリクエスト数を自動で決定する。環境変数OLLAMA_NUM_PARALLELを明示的に設定することで、この上限を固定できる。

GPUが少ない環境ではデフォルトの自動計算が保守的になりすぎて、並列数が1に落ち着くことがある。明示的に設定するほうがSemaphore設計との整合が取りやすい。

mistral:7b-instruct-q4_0を16GB VRAMのサーバーで動かす場合、1インスタンスあたり約4GBを消費するためOLLAMA_NUM_PARALLEL=4が現実的な上限になる。

2. systemd override.confでOLLAMA_NUM_PARALLELを設定する

# override.confを開くコマンド sudo systemctl edit ollama

エディタが開いたら以下を追加して保存する。

[Service] Environment="OLLAMA_NUM_PARALLEL=4"

# 設定を反映する sudo systemctl daemon-reload sudo systemctl restart ollama # 設定確認(Environmentに反映されているか) sudo systemctl show ollama | grep -i parallel # Environment=OLLAMA_NUM_PARALLEL=4

Ollamaのインストール・起動設定が済んでいない場合は、先にUbuntu ServerでローカルLLMを構築する方法を参照してほしい。本記事ではOllamaが起動済みの状態を前提とする。

Python環境をセットアップする

1. 仮想環境を作成してhttpxをインストールする

非同期HTTP通信にはhttpxを使う。Python標準のurllibは非同期対応が弱く、httpxは型ヒントが充実していて実務向きだ。

# 仮想環境の作成 python3 -m venv ~/ollama-async-env source ~/ollama-async-env/bin/activate # httpxのインストール(asyncioは標準ライブラリのため不要) pip install httpx

2. Ollamaの疎通確認をする

# APIが応答するか確認 curl -s http://localhost:11434/api/tags | python3 -m json.tool | head -5 # {"models": [{"name": "mistral:7b-instruct-q4_0", ...}]} が返れば正常

基本的な非同期Ollama呼び出しを実装する

1. 単一プロンプトを非同期で呼び出すコードを書く

まずasyncioの基本構文でOllamaの生成エンドポイントを非同期呼び出しする。ストリーミングを無効("stream": false)にして一括レスポンスを受け取る形にする。

import asyncio import httpx import json OLLAMA_URL = "http://localhost:11434/api/generate" MODEL = "mistral:7b-instruct-q4_0" async def generate(prompt: str, client: httpx.AsyncClient) -> str: payload = { "model": MODEL, "prompt": prompt, "stream": False } response = await client.post(OLLAMA_URL, json=payload, timeout=120.0) return json.loads(response.text)["response"] async def main(): async with httpx.AsyncClient() as client: result = await generate("Linuxのcronとは何ですか?一文で説明してください。", client) print(result) asyncio.run(main())

2. スクリプトを実行して動作確認する

python3 ollama_async_basic.py # cronはLinuxのジョブスケジューラーで、指定した日時や周期でコマンドを自動実行する仕組みです。

単一プロンプトの非同期呼び出しが確認できたら、次のステップで並列化する。
なおstream: Falseの場合、Ollamaは生成完了後にレスポンス全体を一括返却する。タイムアウト値はモデルサイズや入力の長さに応じて調整が必要だ。

asyncio.gatherで複数プロンプトを同時処理する

1. gatherを使ったファンアウト処理を実装する

asyncio.gatherは複数のコルーチンを一括実行し、全てが完了したら結果をリストで返す関数だ。これが並列処理の中核になる。

import asyncio import httpx import json import time OLLAMA_URL = "http://localhost:11434/api/generate" MODEL = "mistral:7b-instruct-q4_0" async def generate(prompt: str, idx: int, client: httpx.AsyncClient) -> tuple[int, str]: payload = {"model": MODEL, "prompt": prompt, "stream": False} response = await client.post(OLLAMA_URL, json=payload, timeout=120.0) return idx, json.loads(response.text)["response"] async def main(): prompts = [ "Linuxのsystemdを一文で説明してください。", "Linuxのiptablesを一文で説明してください。", "Linuxのcronを一文で説明してください。", "Linuxのsshを一文で説明してください。", ] async with httpx.AsyncClient() as client: start = time.time() tasks = [generate(p, i, client) for i, p in enumerate(prompts)] results = await asyncio.gather(*tasks) elapsed = time.time() - start for idx, answer in sorted(results): print(f"[{idx}] {answer[:60]}") print(f"\n並列処理時間: {elapsed:.1f}秒") asyncio.run(main())

2. 逐次処理と並列処理の速度差を確認する

python3 ollama_gather.py # [0] Linuxのsystemdは、サービス・プロセス・デバイスを一元管理するinitシステムで # [1] Linuxのiptablesは、パケットフィルタリングを行うファイアウォールツールです。 # [2] Linuxのcronは、指定した日時・周期でコマンドを自動実行するスケジューラです。 # [3] Linuxのsshは、暗号化されたチャネルでリモートマシンに安全に接続するプロトコル # # 並列処理時間: 11.3秒 # ※逐次処理(forループで順番に実行)の場合は約38秒

4プロンプトを並列実行することで、逐次処理の約3.4倍のスループットが出た。GPUの計算が複数リクエストに分散されている証拠だ。
利用するモデルのVRAM消費量とOLLAMA_NUM_PARALLELのバランスについてはローカルLLMのモデルを比較する方法も参考にしてほしい。

asyncio.Semaphoreで並列上限を制御する

1. Semaphoreを組み込んだ安全な実装に書き換える

asyncio.gatherだけでは、100件・1000件のタスクを一度に投げるとOllamaが処理しきれないリクエストを受け取り続ける。asyncio.Semaphoreで同時実行数をOLLAMA_NUM_PARALLELと揃えるのが実務の定石だ。

import asyncio import httpx import json OLLAMA_URL = "http://localhost:11434/api/generate" MODEL = "mistral:7b-instruct-q4_0" MAX_CONCURRENT = 4 # OLLAMA_NUM_PARALLELと揃える async def generate_with_semaphore( prompt: str, idx: int, client: httpx.AsyncClient, sem: asyncio.Semaphore ) -> tuple[int, str]: async with sem: # ここでMAX_CONCURRENT以上の同時実行をブロック payload = {"model": MODEL, "prompt": prompt, "stream": False} response = await client.post(OLLAMA_URL, json=payload, timeout=120.0) return idx, json.loads(response.text)["response"] async def run_parallel(prompts: list[str]) -> list[str]: sem = asyncio.Semaphore(MAX_CONCURRENT) async with httpx.AsyncClient() as client: tasks = [ generate_with_semaphore(p, i, client, sem) for i, p in enumerate(prompts) ] results = await asyncio.gather(*tasks) return [answer for _, answer in sorted(results)]

2. 例外処理を加えて本番品質にする

Ollamaのタイムアウトや一時的なエラーに備えて例外処理を追加する。1件のエラーで全体が止まらないようにする設計が重要だ。

async def generate_with_semaphore( prompt: str, idx: int, client: httpx.AsyncClient, sem: asyncio.Semaphore ) -> tuple[int, str]: async with sem: try: payload = {"model": MODEL, "prompt": prompt, "stream": False} response = await client.post(OLLAMA_URL, json=payload, timeout=120.0) response.raise_for_status() return idx, json.loads(response.text)["response"] except httpx.TimeoutException: return idx, "ERROR: タイムアウト" except httpx.HTTPStatusError as e: return idx, f"ERROR: HTTP {e.response.status_code}" except Exception as e: return idx, f"ERROR: {e}"

実務パターン:社内ドキュメントを一括要約するスクリプト

1. テキストファイルを並列要約するスクリプト全体を実装する

指定ディレクトリ配下の.txtファイルをまとめて要約する実務向けスクリプトだ。会議録・障害報告書・メール本文などの一括処理を想定している。

#!/usr/bin/env python3 """社内ドキュメント一括要約スクリプト""" import asyncio import httpx import json import sys from pathlib import Path OLLAMA_URL = "http://localhost:11434/api/generate" MODEL = "mistral:7b-instruct-q4_0" MAX_CONCURRENT = 4 SUMMARY_PROMPT = "以下の文章を3行以内で簡潔に要約してください。\n\n---\n{text}" async def summarize( text: str, idx: int, fname: str, client: httpx.AsyncClient, sem: asyncio.Semaphore ) -> dict: async with sem: prompt = SUMMARY_PROMPT.format(text=text[:3000]) payload = {"model": MODEL, "prompt": prompt, "stream": False} try: r = await client.post(OLLAMA_URL, json=payload, timeout=180.0) r.raise_for_status() summary = json.loads(r.text)["response"].strip() except Exception as e: summary = f"ERROR: {e}" return {"idx": idx, "file": fname, "summary": summary} async def main(input_dir: str): files = list(Path(input_dir).glob("*.txt")) if not files: print(f"対象ファイルなし: {input_dir}") return texts = [(f.name, f.read_text(encoding="utf-8")) for f in files] sem = asyncio.Semaphore(MAX_CONCURRENT) async with httpx.AsyncClient() as client: tasks = [summarize(t, i, n, client, sem) for i, (n, t) in enumerate(texts)] results = await asyncio.gather(*tasks) for r in sorted(results, key=lambda x: x["idx"]): print(f"\n【{r['file']}】\n{r['summary']}") if __name__ == "__main__": asyncio.run(main(sys.argv[1] if len(sys.argv) > 1 else "."))

2. スクリプトを実行して結果を確認する

# /docs配下のtxtファイルを一括要約 python3 bulk_summarize.py /docs # 実行例の出力 【incident_report_20260901.txt】 2026年9月1日にWebサーバーが高負荷でダウン。原因はcronジョブの二重起動。 flockコマンドと冪等化スクリプトで再発防止措置を実施した。 【meeting_20260905.txt】 9月5日の定例会議で四半期KPIを確認。 コンバージョン率改善施策3件を翌週までに設計チームが提案する。

社内でクラウドAIが使えない環境でのローカルLLM活用については社内でChatGPTが使えないときの代替手段も参照してほしい。このスクリプトはそのままプロキシもAPI課金も不要で動かせる。

よくあるエラーと対処法

1. httpx.ReadTimeoutが発生する

LLMの生成時間がtimeout値を超えると発生する。timeout=120.0を180.0または300.0に増やすか、入力テキストをtext[:2000]のように短く切り詰める。

2. JSONDecodeErrorが出る

OllamaがHTTPエラーレスポンスを返した場合にJSONパースが失敗する。response.raise_for_status()をjson.loads()より前に呼び、HTTPエラーを先に捕捉する設計にすること。

3. すべてのリクエストが503になる

OLLAMA_NUM_PARALLELの上限を超えたリクエストが詰まっている可能性がある。SemaphoreのMAX_CONCURRENTを現在のOLLAMA_NUM_PARALLELより低い値に下げるか、OLLAMA_NUM_PARALLELを増やしてVRAMが足りるか確認する。

4. 処理が途中で止まる(デッドロック)

asyncioのイベントループ内でブロッキングI/O(open().read()など)を呼ぶとイベントループが止まる。ファイル読み込みはasync関数の外で事前に行うか、asyncio.to_thread(f.read_text)でスレッドに委ねる。

まとめ

asyncioとhttpxを組み合わせることで、OllamaのAPIを並列呼び出ししてバッチ処理のスループットを大幅に向上できる。実装のポイントを整理する。
設定・実装コマンド・コード要素役割
Ollama並列上限の設定OLLAMA_NUM_PARALLEL=4(systemd override.conf)Ollama側の同時処理リクエスト上限を固定する
非同期HTTPクライアントhttpx.AsyncClient() + await client.post()ノンブロッキングなOllama API呼び出しを実現する
並列ファンアウトasyncio.gather(*tasks)複数プロンプトを同時に一括実行する
同時実行数の制限asyncio.Semaphore(MAX_CONCURRENT)Ollamaのリソース過負荷を防ぐ上限制御をする
タイムアウト設定timeout=120.0(httpx.AsyncClient引数)LLMの長い生成時間に対応したタイムアウト値を設定する

SemaphoreのMAX_CONCURRENTはOLLAMA_NUM_PARALLELの値と揃えることが基本だ。上回ると503エラーが増え、下回ると並列性能が出ないが安全寄りになる。チームのGPU環境に合わせて両方の値を調整してほしい。

ローカルLLMの並列処理と業務バッチ自動化を2日間のハンズオンで習得する

asyncioとOllamaを組み合わせた並列推論の設計は、実際に動く環境で試してこそ定着する。実機GPU環境で手を動かしながら習得したい方向けに、「ローカルAIマスターセミナー」を開催しています。
少人数(最大8名)ZOOMハンズオン形式で実施しています。

>> ローカルAIマスターセミナーの詳細を確認する
ローカルLLMの構築・運用に関する関連記事もあわせて参考にしてください。

・Ubuntu ServerでローカルLLMを構築する方法|Ollamaで機密データを外に出さず業務AIを動かす完全ガイド
・社内でChatGPTが使えないときの代替手段|機密データを守るローカルLLMという選択肢
・ローカルLLMのモデルを比較する方法|Llama3.3・Mistral・Gemma・Phi-4をUbuntuで使い分けるポイント

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。