言語を切り替える
テーマを切り替える

Ollama API 実践:Python と Node.js クライアント開発ガイド

ターミナルで ollama run gemma3 と打つと、画面に最初の返答が出力されます。ローカルモデルが動き出した瞬間です。

次に気になるのは、これを自分のプロジェクトに組み込めるかどうか。API キーも不要、課金も不要、ローカルで動く——これはかなり魅力的です。

ドキュメントをひと通り見てみると、公式が Python と JavaScript の SDK をそのまま提供していて、しかも OpenAI の SDK を 2 行書き換えるだけでも接続できることが分かりました。思っていたよりずっと簡単です。

ただ、簡単だからといって落とし穴がないわけではありません。ストリーミングレスポンスはどう蓄積するのか。ツール呼び出しの Agent Loop はどう書くのか。thinking モードで推論と回答をどう分けるのか。どれも一度はハマったポイントです。

この記事では、そうした落とし穴を埋めていきます。Python と Node.js の 2 言語を比較し、ネイティブ SDK と OpenAI 互換の 2 つの方式をどちらも分かりやすく解説して、完成度の高いクライアント開発ガイドをお届けします。

ちなみに、まだ Ollama を入れていない方は、まずシリーズ第 1 回の LangChain + Ollama 連携実践 を読んで、ローカルモデルを動かしておくとよいでしょう。


第 1 章:Ollama API の基礎

まずは API がどう動くのかを押さえましょう。

Ollama はデフォルトでローカルに REST API サービスを起動します。アドレスは http://localhost:11434/api です。ブラウザでこのアドレスを開くと、そっけなく「Ollama is running」と表示されます——これでサービスが正常に動いていると分かります。

主なエンドポイント

覚えておくべきコアエンドポイントは 2 つです。

エンドポイント用途特徴
/api/chatマルチターン対話messages 配列をサポートし、コンテキストを渡せる
/api/generateシングルターン生成シンプルで、一度きりのタスクに向く

もう 1 つ /v1/chat/completions があり、これは OpenAI 互換エンドポイントです。手元に既存の OpenAI プロジェクトがあれば、base_url を変えるだけで使えます。あとで詳しく説明します。

curl で試してみる

まずは最も原始的な方法で API を試します。

curl http://localhost:11434/api/chat -d '{
  "model": "gemma3",
  "messages": [
    { "role": "user", "content": "空はなぜ青いの?" }
  ]
}'

ターミナルに大量の JSON が出力されます。注目すべきは message.content フィールドで、そこにモデルの回答が入っています。

レスポンス構造はだいたいこんな形です。

{
  "model": "gemma3",
  "created_at": "2026-04-18T01:23:45.678Z",
  "message": {
    "role": "assistant",
    "content": "空が青く見えるのは主に..."
  },
  "done": true
}

done フィールドはとても重要です。ストリーミングのときは各 chunk の donefalse で、最後の chunk だけ true になります。これはあとでストリーミングを処理するときに使います。

ストリーミングレスポンス

デフォルトでは、API はモデルの生成が終わるまで待ってから一度に返します。しかし「タイプライター効果」をユーザーに見せたいなら、stream: true を付けます。

curl http://localhost:11434/api/chat -d '{
  "model": "gemma3",
  "messages": [{ "role": "user", "content": "空はなぜ青いの?" }],
  "stream": true
}'

今度はターミナルに JSON が 1 行ずつ出てきます。各行が小さな chunk なので、それらを集めて初めて完全な回答になります。

たしかに、こうした chunk を手動で処理するのは面倒です。これこそ公式が SDK を提供している理由で——こうした細かい処理を全部まとめてくれます。


第 2 章:Python SDK 完全実践

Python の SDK は公式がメンテナンスしていて、インストールはとても簡単です。

pip install ollama

入れたらすぐ使えます。Python 3.8+ に対応していて、この点も親切です。

基本呼び出し

最もシンプルな呼び出し方は、1 行で済みます。

from ollama import chat

response = chat(
  model='gemma3',
  messages=[{'role': 'user', 'content': '空はなぜ青いの?'}]
)

print(response.message.content)

これだけです。chat() 関数は SDK が提供するショートカットで、内部で自動的にデフォルトの Client を作り、ローカルの Ollama サービスに接続します。

接続パラメータをカスタマイズしたい場合——たとえば Ollama を別のマシンで動かしているとき——は、自分で Client を作れます。

from ollama import Client

client = Client(host='http://192.168.1.100:11434')
response = client.chat(model='gemma3', messages=[...])

ストリーミングレスポンス

ストリーミングは重要なポイントです。長く待たされた末に突然全部が出るのではなく、文字が少しずつ出てくる様子をユーザーに見せる必要があります。

from ollama import chat

stream = chat(
  model='gemma3',
  messages=[{'role': 'user', 'content': '空はなぜ青いの?'}],
  stream=True,
)

for chunk in stream:
  print(chunk['message']['content'], end='', flush=True)

ここに落とし穴があります。chunk はオブジェクトではなく辞書で返ってきます。なのでアクセス方法は chunk.message.content ではなく chunk['message']['content'] です。私も最初にここでハマり、エラーが出てしばらく原因が分かりませんでした。

非同期クライアント

アプリが非同期アーキテクチャの場合——たとえば FastAPI や aiohttp を使っているとき——は、非同期クライアントを使います。

import asyncio
from ollama import AsyncClient

async def main():
  client = AsyncClient()
  
  # 非ストリーミング
  response = await client.chat(
    model='gemma3',
    messages=[{'role': 'user', 'content': 'こんにちは'}]
  )
  print(response.message.content)
  
  # ストリーミング
  stream = await client.chat(
    model='gemma3',
    messages=[{'role': 'user', 'content': '空はなぜ青いの?'}],
    stream=True,
  )
  async for chunk in stream:
    print(chunk['message']['content'], end='', flush=True)

asyncio.run(main())

非同期ストリーミングは async generator を返すので、async for で反復します。同期版とロジックは同じで、awaitasync を加えるだけです。

Cloud Models

おもしろいことに、Ollama SDK はクラウドモデルもサポートしています。大きいモデルはローカルでは動かしきれないものもあります——たとえば 120B の gpt-oss——が、クラウドなら動きます。

from ollama import chat

response = chat(
  model='gpt-oss:120b-cloud',
  messages=[{'role': 'user', 'content': 'こんにちは'}]
)

モデル名に -cloud サフィックスを付けると、クラウド API 経由になります。もちろん Ollama のクラウドアカウントと API キーが必要で、設定方法はローカルとは少し違います。興味があれば公式ドキュメントを参照してください。

正直なところ、この機能はかなり実用的です。小さいモデルはローカルで動かしてコストを抑え、大きいモデルはクラウドで動かしてハードウェアを節約する。このハイブリッド方式はなかなか魅力的です。


第 3 章:Node.js SDK 完全実践

Node.js の SDK も同じくシンプルです。

npm i ollama

このパッケージは Node.js とブラウザ環境の両方に対応している点に注意してください。ブラウザ版は個別にインポートします。

// Node.js
import ollama from 'ollama'

// ブラウザ
import ollama from 'ollama/browser'

基本呼び出し

Node.js はデフォルトで非同期なので、書きやすいです。

import ollama from 'ollama'

const response = await ollama.chat({
  model: 'gemma3',
  messages: [{ role: 'user', content: '空はなぜ青いの?' }],
})

console.log(response.message.content)

Python 版と比べてみましょう。Python は辞書で messages を渡し、Node.js はオブジェクトで渡します。パラメータ名はほぼ同じなので、言語を変えても概念を学び直す必要はありません。

ストリーミングレスポンス

Node.js のストリーミング処理は、もともと非同期 generator です。

import ollama from 'ollama'

const stream = await ollama.chat({
  model: 'gemma3',
  messages: [{ role: 'user', content: '空はなぜ青いの?' }],
  stream: true,
})

for await (const chunk of stream) {
  process.stdout.write(chunk.message.content)
}

ここでは console.log ではなく process.stdout.write を使います。console.log は自動で改行してしまうからです。文字が 1 つ出るたびに改行されては困りますよね。

カスタム設定

SDK は host と headers のカスタマイズに対応しています。

import ollama from 'ollama'

// host をカスタマイズ
const client = new ollama.Ollama({ host: 'http://192.168.1.100:11434' })

// またはグローバル設定で
ollama.setDefaultHost('http://192.168.1.100:11434')

// headers を追加(たとえば認証)
const stream = await ollama.chat({
  model: 'gemma3',
  messages: [{ role: 'user', content: 'こんにちは' }],
  headers: { Authorization: 'Bearer xxx' },
})

headers パラメータはなかなか便利です。Ollama サービスの前段に認証プロキシを置いている場合、ここでトークンを渡せます。

ストリーミング生成のキャンセル

進行中のストリーミング生成をキャンセルできる abort() メソッドがあります。

import ollama from 'ollama'

const stream = await ollama.chat({
  model: 'gemma3',
  messages: [{ role: 'user', content: '長文を書いて...' }],
  stream: true,
})

// ユーザーが停止ボタンを押した
ollama.abort()

for await (const chunk of stream) {
  // abort 後はループが早めに終了する
  process.stdout.write(chunk.message.content)
}

この機能はチャット画面を作るときに欠かせません。モデルが冗長な文章を書き終えるのを待ちたくないユーザーは、ボタン 1 つで止められます。

ブラウザ版

ブラウザでの使い方も似ていますが、いくつか違いがあります。

import ollama from 'ollama/browser'

// ブラウザではストリーミングしか使えない。ネイティブ API が非ストリーミングのクロスオリジンに対応しないため
const stream = await ollama.chat({
  model: 'gemma3',
  messages: [{ role: 'user', content: 'こんにちは' }],
  stream: true,
})

for await (const chunk of stream) {
  document.getElementById('output').textContent += chunk.message.content
}

ブラウザ版には制約があります。必ずストリーミングモードを使うことです。Ollama API の非ストリーミングリクエストは大きな JSON を一度に返すため、クロスオリジンではタイムアウトやブロックが起きやすいからです。ストリーミングリクエストは chunk に分かれているので、問題はずっと少なくなります。

この設計は理にかなっています。ブラウザでチャット UI を作るなら、もともとストリーミング表示が必要だからです。


第 4 章:ツール呼び出し実践

ツール呼び出しはエージェントを作る基礎です。Ollama では、自分で定義した関数をモデルに呼び出させ、その戻り値をもとに回答の生成を続けさせられます。

Python SDK にはとても便利な特性があります。Python 関数をそのままツールとして渡すと、SDK が関数の docstring とパラメータの型を自動で解析してくれます。

Python 関数の自動解析

def get_weather(city: str) -> str:
  """指定した都市の天気情報を取得する

  Args:
    city: 都市名。例:「東京」「大阪」

  Returns:
    天気を表す文字列
  """
  # ダミーデータ
  weather_data = {
    '東京': '晴れ、気温 18°C',
    '大阪': '曇り、気温 22°C',
    '福岡': '雨、気温 26°C',
  }
  return weather_data.get(city, f'{city} の天気データが見つかりません')

from ollama import chat

response = chat(
  model='qwen3',
  messages=[{'role': 'user', 'content': '東京の今日の天気は?'}],
  tools=[get_weather],
)

print(response.message.content)

SDK が関数を自動でツール定義の形式に変換します。名前は関数名から、説明は docstring から、パラメータは型アノテーションから取ります。自分で JSON Schema を手書きする手間が省けます。

Agent Loop 方式

しかし、そう単純ではありません。モデルは複数のツールを呼ぶこともあれば、ツールを呼んだあとにさらに続けて呼びたがることもあります。これを処理するにはループが必要です。

それが Agent Loop です。

from ollama import chat

def add(a: int, b: int) -> int:
  """足し算"""
  return a + b

def multiply(a: int, b: int) -> int:
  """掛け算"""
  return a * b

tools = [add, multiply]
tool_map = {'add': add, 'multiply': multiply}

messages = [{'role': 'user', 'content': '(3 + 5) * 2 を計算して'}]

while True:
  response = chat(model='qwen3', messages=messages, tools=tools)

  if response.message.tool_calls:
    # モデルがツールを呼びたがっている
    for call in response.message.tool_calls:
      func_name = call.function.name
      func_args = call.function.arguments
      result = tool_map[func_name](**func_args)

      # ツール呼び出しの結果をメッセージ履歴に追加
      messages.append({
        'role': 'tool',
        'content': str(result),
        'tool_name': func_name,
      })
  else:
    # モデルがツールを呼ばなかった=終了
    print(response.message.content)
    break

ロジックはこうです。

  1. ツール定義を付けてモデルにメッセージを送る
  2. モデルが tool_calls を返したら、対応する関数を実行する
  3. 関数の結果をメッセージ履歴に戻して、再びモデルに送る
  4. モデルがツールを呼ばなくなるまで繰り返す

この方式はエージェントを作るときに欠かせません。ツール関数をいくつも定義しておけば、いつ・どれを・どの順で呼ぶかはモデルが自分で判断します。

thinking モード

一部のモデル——たとえば qwen3——は thinking モードに対応しています。モデルはまず「考えて」から回答を出します。

from ollama import chat

stream = chat(
  model='qwen3',
  messages=[{'role': 'user', 'content': '空はなぜ青いの?'}],
  stream=True,
  think=True,
)

thinking = ''
content = ''

for chunk in stream:
  if chunk.message.thinking:
    thinking += chunk.message.thinking
  elif chunk.message.content:
    content += chunk.message.content

print('=== 思考プロセス ===')
print(thinking)
print('=== 最終回答 ===')
print(content)

thinking モードでは、chunk に thinking フィールドが追加されます。思考内容と最終回答を別々に蓄積する必要があります。

この機能はなかなかおもしろいです。モデルがどう一歩ずつ答えを導いたのかが見えます。教育系アプリやプロンプトのデバッグにとても役立ちます。


第 5 章:ネイティブ SDK vs OpenAI 互換 API

ここまでで、選択肢は 2 つあります。

  1. Ollama ネイティブ SDK を使う(これまで説明したもの)
  2. OpenAI SDK を使い、アドレスを変えるだけで Ollama に接続する

どちらがよいかは状況次第です。

OpenAI 互換方式

手元に既存の OpenAI プロジェクトがあるなら、最も移行コストが低いのは base_url を変える方法です。

from openai import OpenAI

client = OpenAI(
  base_url='http://localhost:11434/v1',
  api_key='ollama',  # 必須だが無視される
)

response = client.chat.completions.create(
  model='gemma3',
  messages=[{'role': 'user', 'content': '空はなぜ青いの?'}],
)

print(response.choices[0].message.content)

これだけです。OpenAI SDK は裏で動いているのが Ollama だとはまったく気づきません。あくまで「OpenAI API」と話していると思っています。

Node.js 版も同じです。

import OpenAI from 'openai'

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

const completion = await client.chat.completions.create({
  model: 'gemma3',
  messages: [{ role: 'user', content: '空はなぜ青いの?' }],
})

console.log(completion.choices[0].message.content)

2 つの方式の比較

観点ネイティブ SDKOpenAI 互換
インストールpip install ollamaOpenAI SDK があればよい
ツール呼び出し関数の docstring を自動解析JSON Schema を手書き
ストリーミング辞書形式の chunk標準の OpenAI 形式
Cloud Models対応非対応
移行コスト新規はコストなし既存プロジェクトは極めて低い

選び方の指針

新規プロジェクト:ネイティブ SDK を使いましょう。

理由は次のとおりです。

  • ツール呼び出しが手軽。Python 関数をそのままツールとして渡せる
  • 対応機能が多い(Cloud Models、thinking モード)
  • ドキュメントとサンプルが公式のもので、困ったときに調べやすい

既存 OpenAI プロジェクトの移行:OpenAI 互換方式を使いましょう。

理由は次のとおりです。

  • 2 行変えるだけで動く
  • ロジックを書き直す必要がない
  • あとで OpenAI に戻したいときも簡単

ひとことでまとめると、ネイティブ SDK は機能が充実、OpenAI 互換は移行が速い。あなたのニーズ次第です。

正直、私はどちらも試しました。ネイティブ SDK のツール呼び出しはたしかに楽です——JSON Schema の定義を自分で書かなくても、関数の docstring を丁寧に書くだけで済みます。ただ、すでに OpenAI で動いているプロジェクトなら、Ollama を使うためだけに全面的にリファクタリングする必要はありません。


おわりに

ここまで色々話しましたが、いくつかの要点をまとめます。

基本呼び出し:Python も Node.js も SDK の作りが丁寧で、数行のコードで動きます。ストリーミングは stream=True で有効化するのを忘れずに。

ツール呼び出し:Agent Loop がコアの方式です——モデルがツールを呼ばなくなるまで tool_calls をループ処理します。Python SDK は関数をそのままツールとして渡せるので、JSON Schema を書く手間が省けます。

thinking モード:qwen3 などのモデルが対応し、モデルの思考プロセスを見られます。chunk の中で thinking と content のフィールドを別々に処理しましょう。

方式の選択:新規プロジェクトは機能が充実したネイティブ SDK、既存の OpenAI プロジェクトはアドレスを変えるだけの互換方式を。

次のステップとしては、こんなことをおすすめします。

  • まだ Ollama を入れていないなら、シリーズ第 1 回を読んでローカルモデルを動かす
  • プロジェクトに合う方式(ネイティブか OpenAI 互換か)を 1 つ選んで、実際に試してみる
  • 公式ドキュメントは更新され続け、新機能も次々と追加されるので、時間があるときに目を通す

ローカルで LLM を動かすことのハードルは、どんどん下がっています。Ollama は複雑な部分をシンプルな API の裏に隠してくれます。あなたは呼び出し方さえ知っていればよく、あとは任せられます。

これがこのシリーズの第 2 回でした。次回は Modelfile のカスタマイズについて——モデルを自分の望む形に仕立てる方法を解説します。

Ollama API クライアント開発

Python または Node.js の SDK で Ollama のローカルモデル API を呼び出すための完全ガイド

⏱️ 目安時間: 45 分

  1. 1

    ステップ1: SDK をインストールして基本呼び出しを試す

    Python ユーザーは `pip install ollama`、Node.js ユーザーは `npm i ollama` を実行します。

    インストールが終わったら、最もシンプルなコードで接続を確認しましょう。
    ```python
    from ollama import chat
    response = chat(model='gemma3', messages=[{'role': 'user', 'content': 'こんにちは'}])
    print(response.message.content)
    ```

    Ollama サービスが起動していること(デフォルトポートは 11434)と、対応するモデルがダウンロード済みであることを確認してください。
  2. 2

    ステップ2: ストリーミングレスポンスを実装する

    ストリーミングモードを有効にして、文字が少しずつ出力される様子をユーザーに見せます。

    ```python
    from ollama import chat
    stream = chat(model='gemma3', messages=[...], stream=True)
    for chunk in stream:
    print(chunk['message']['content'], end='', flush=True)
    ```

    chunk は辞書で返ってくる点に注意。`chunk['message']['content']` でアクセスします。
  3. 3

    ステップ3: ツール呼び出しを設定する(任意)

    Python 関数をツールとして定義すると、SDK が docstring と型アノテーションを自動で解析します。

    ```python
    def get_weather(city: str) -> str:
    """都市の天気情報を取得"""
    return f'{city}: 晴れ'

    response = chat(model='qwen3', messages=[...], tools=[get_weather])
    ```

    Agent Loop を実装すれば、モデルが最終回答を返すまで複数回のツール呼び出しを処理できます。
  4. 4

    ステップ4: ネイティブか OpenAI 互換かを選ぶ

    新規プロジェクトには機能が充実したネイティブ SDK(Cloud Models、thinking モード)がおすすめです。

    既存の OpenAI プロジェクトなら 2 行変えるだけ。
    ```python
    client = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')
    ```

    移行コストはごくわずかで、いつでも OpenAI に戻せます。

FAQ

Ollama API のデフォルトのポートとアドレスは?
Ollama はデフォルトで localhost:11434 に REST API サービスを起動します。コアエンドポイントは /api/chat(マルチターン対話)と /api/generate(シングルターン生成)で、OpenAI 互換用に /v1/chat/completions も用意されています。
Python SDK のストリーミングレスポンスはどんな型で返る?
Python SDK のストリーミングレスポンスはオブジェクトではなく辞書型で返ります。中身には chunk['message']['content'] でアクセスし、chunk.message.content ではアクセスできません。非同期クライアントは async generator を返すので、async for で反復します。
Node.js SDK はブラウザ環境でどんな制約がある?
ブラウザ版では必ずストリーミングモード(stream: true)を使う必要があります。非ストリーミングのリクエストは大きな JSON を一度に返すため、クロスオリジンではタイムアウトやブロックが起きやすいからです。インポート方法も異なり、ブラウザでは import ollama from 'ollama/browser' を使います。
Agent Loop 方式とは?
Agent Loop はツール呼び出しを処理するためのループ方式です。モデルにメッセージを送る → tool_calls が返ったか確認する → 対応する関数を実行する → 結果をメッセージ履歴に戻す → 再びモデルを呼ぶ、をモデルがツールを呼ばなくなるまで繰り返します。この方式はエージェント構築の基礎になります。
thinking モードで思考プロセスと最終回答を別々に取得するには?
thinking モードでは、ストリーミングの chunk に thinking フィールドが追加されます。別々に蓄積する必要があり、if chunk.message.thinking なら思考内容を、elif chunk.message.content なら最終回答を蓄積します。現状では qwen3 などのモデルがこの機能をサポートしています。
ネイティブ SDK と OpenAI 互換方式はどう選ぶ?
新規プロジェクトにはネイティブ SDK がおすすめです。ツール呼び出しで関数の docstring を自動解析でき、Cloud Models や thinking モードもサポートします。既存の OpenAI プロジェクトには互換方式がおすすめで、base_url を変えるだけと移行コストが極めて低く、あとで OpenAI に戻すのも簡単です。

4分で読めます · 公開日: 2026年4月18日 · 更新日: 2026年6月1日

関連記事

コメント

GitHubアカウントでログインしてコメントできます