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

Ollama API 呼び出し:curl から OpenAI SDK 互換インターフェースまで

深夜3時。ターミナルでその curl コマンドを見つめながら、頭の中はさっき踏んだ罠のことばかり——公式ドキュメント通りに書いたのに、なんで JSON には単語の半分しか返ってこないんだ?

原因はストリーミングレスポンスでした。Ollama はデフォルトで流れるように少しずつコンテンツを出力し、各 JSON オブジェクトには数文字しか含まれていません。これに2時間も悩まされました。

正直、ローカル LLM デプロイに関しては、Ollama は本当にハードルを下げてくれました。Docker の設定をいじる必要もなければ、GPU ドライバーの心配も不要——ダウンロード、インストール、実行の3ステップで完了。でも API の呼び出しとなると、多くの人が(私を含めて)最初は混乱しがち:一体いくつの呼び出し方法があるの?ネイティブ REST API と OpenAI SDK 互換インターフェースの違いは?ストリーミングレスポンスはどう処理する?

この記事は、私が踏んだ罠を整理したものです。皆さんが同じ道をたどらないよう、2つの呼び出し方法について、最も基本的な curl コマンドから OpenAI SDK へのゼロコード移行まで、ドキュメントに明記されていない小さな詳細も含めてお話しします。


Ollama API には2つのインターフェースがある

これ、本当にしばらく困惑しました。Ollama は実は2つの完全に異なる API インターフェースを提供しています:

ネイティブ REST APIhttp://localhost:11434/api/*

  • エンドポイント:/api/generate(テキスト生成)、/api/chat(会話)、/api/tags(モデル一覧)
  • デフォルトでストリーミングレスポンス(これが深夜3時の問題でした)
  • 直接 HTTP 呼び出し、SDK 不要

OpenAI 互換インターフェースhttp://localhost:11434/v1/*

  • エンドポイント:/v1/chat/completions/v1/completions/v1/models
  • OpenAI SDK と完全互換(Python、JavaScript どちらも直接使用可能)
  • 既存の OpenAI ツールエコシステムをサポート

なぜ2つもあるのかと思うかもしれません。実はそれぞれ用途があります。ネイティブ API はより軽量で直接的、独自の HTTP クライアントを書く場合に適しています;OpenAI 互換インターフェースは、既存の OpenAI SDK コードをそのまま使える——base_url を変更するだけで済みます。

正直、この設計は賢いです。シンプルな呼び出しを望む開発者にも、既に OpenAI エコシステムのコードを持つチームにも配慮しています。


ネイティブ REST API:curl から始める

まずネイティブ API から。これは実際かなり直接的で、標準的な REST インターフェースです。

基本的な curl 呼び出し

最もシンプルな例——テキスト生成:

curl http://localhost:11434/api/generate -d '{
  "model": "llama3.2",
  "prompt": "Why is the sky blue?",
  "stream": false
}'

そう、stream: false に注目してください。デフォルトでは Ollama はコンテンツをストリーミングで返します。完全な JSON レスポンスが欲しい場合、ストリーミングを明示的に無効にする必要があります。そうしないと、こんな出力の山を見ることに:

{"model":"llama3.2","response":"That","done":false}
{"model":"llama3.2","response":"'","done":false}
{"model":"llama3.2","response":"s","done":false}
{"model":"llama3.2","response":" a","done":false}
...
{"model":"llama3.2","response":"!","done":true}

各 JSON オブジェクトには数文字しか含まれておらず、トークンごとに出力されます。これがいわゆる NDJSON(Newline-Delimited JSON)形式——1行に1つの JSON オブジェクト。深夜3時の時は、これに気づかず普通の JSON としてパースして、最初のオブジェクトの “That” しか取得できませんでした。

チャットモードの方が実用的

単発生成は単純なタスクに適していますが、実際によく使われるのはチャットモードです:

curl http://localhost:11434/api/chat -d '{
  "model": "llama3.2",
  "messages": [
    { "role": "user", "content": "Hello!" }
  ],
  "stream": false
}'

messages 配列を維持して、会話履歴をすべて渡すことで、モデルがコンテキストを記憶できるようになります。これはチャットアプリケーションを構築する際に特に重要です。

インストール済みモデルの確認

ローカルにどのモデルがあるか確認したい場合:

curl http://localhost:11434/api/tags

返される JSON には、ダウンロード済みのすべてのモデルが、サイズ、更新日時、量子化レベルなどの情報とともに一覧表示されます。かなり便利です。


ストリーミングレスポンスの処理

これは特に説明が必要な部分です。Ollama のストリーミングレスポンスには特徴があります:完全なコンテンツを一度に返すのではなく、トークンごとに出力します。

Python でストリーミング処理

Python の requests ライブラリでストリーミングレスポンスを処理:

import requests
import json

url = "http://localhost:11434/api/chat"
payload = {
    "model": "llama3.2",
    "messages": [{"role": "user", "content": "Write a short poem"}],
    "stream": True
}

response = requests.post(url, json=payload, stream=True)
for line in response.iter_lines():
    if line:
        chunk = json.loads(line)
        print(chunk.get("message", {}).get("content", ""), end="", flush=True)

重要なポイントは response.iter_lines()——これで NDJSON ストリームを1行ずつ読み込めます。各チャンクには数文字しか含まれていない可能性があるため、完全な返信を得るには蓄積する必要があります。

JavaScript のストリーミング処理

フロントエンドで fetch API を使う場合も同様:

const response = await fetch('http://localhost:11434/api/chat', {
  method: 'POST',
  body: JSON.stringify({
    model: 'llama3.2',
    messages: [{ role: 'user', content: 'Hello!' }],
    stream: true
  })
});

const reader = response.body.getReader();
while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  const chunk = new TextDecoder().decode(value);
  // 各チャンクを処理...
}

正直、ストリーミング処理は非ストリーミングより少し面倒ですが、ユーザー体験ははるかに良いです——モデルが「思考」し出力しているのをリアルタイムで見られるので、長時間待って突然大量のテキストが表示されるのとは違います。


OpenAI SDK 互換インターフェース:ゼロコード移行

ここが私のお気に入りの部分です。Ollama は完全な OpenAI API 互換インターフェースを提供しており、既存のコードをほぼシームレスに移行できます。

Python OpenAI SDK の例

OpenAI の公式 SDK を直接使用:

from openai import OpenAI

client = OpenAI(
    base_url='http://localhost:11434/v1/',
    api_key='ollama'  # ローカルは検証しない、何でもOK
)

response = client.chat.completions.create(
    model="llama3.2",
    messages=[{"role": "user", "content": "Hello!"}]
)

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

ご覧の通り、唯一の変更は base_url を設定して api_key を適当に埋めること。他のコードは完全に変更ありません。

開発環境と本番環境の切り替え

この機能は特に実用的です。開発環境ではローカル Ollama、本番環境では OpenAI を使用できます:

# 開発環境 .env
OPENAI_API_KEY=anyrandomtext
LLM_ENDPOINT="http://localhost:11434/v1"
MODEL=llama3.2

# 本番環境 .env
OPENAI_API_KEY=sk-XXXXXXXXXXXXXXXXXXXXXXXX
LLM_ENDPOINT="https://api.openai.com/v1"
MODEL=gpt-3.5-turbo

コードでは環境変数から読み込むだけ:

import os
from openai import OpenAI

client = OpenAI(
    base_url=os.getenv('LLM_ENDPOINT'),
    api_key=os.getenv('OPENAI_API_KEY')
)

これで、開発中は OpenAI API を呼び出す費用がかからず、ローカルテストで十分;リリース時は環境変数を変更するだけで本物の OpenAI に切り替わります。

サポートされるエンドポイント

Ollama の OpenAI 互換インターフェースがサポートするエンドポイント:

エンドポイント機能サポート状況
/v1/chat/completionsチャット生成完全サポート
/v1/completionsテキスト補完完全サポート
/v1/modelsモデル一覧完全サポート
/v1/embeddingsテキスト埋め込み完全サポート
/v1/responses新レスポンス API完全サポート

まだ実験的な /v1/images/generations エンドポイントもありますが、安定性はまだ十分ではありません。

モデルのエイリアス

小さなテクニックがあります:モデルにエイリアスを付けられます。例えば、コードが GPT-3.5 を呼び出しているように見せたい場合:

ollama cp llama3.2 gpt-3.5-turbo

これで、コード内で model="gpt-3.5-turbo" と書いても、実際にはローカルの llama3.2 が使用されます。コード移行時にこのテクニックはかなり便利です。


2つの方法のどちらを選ぶ?

いろいろ話しましたが、どちらを使えばいいのかと思うかもしれません。

ネイティブ REST API が適している場面

これらの状況に適しています:

  • 最も軽量な呼び出し方法が必要
  • OpenAI SDK エコシステムが不要
  • 独自の HTTP クライアントを書く(組み込みデバイスや特殊な環境など)
  • ストリーミングレスポンスの詳細を正確に制御する必要がある

ネイティブ API はより直接的で、より低レベル。HTTP プロトコルに精通している場合、使いやすいでしょう。

OpenAI SDK 互換インターフェースが適している場面

これらの状況に適しています:

  • 既に OpenAI SDK ベースのコードがある
  • ローカルデプロイへの迅速な移行が必要
  • OpenAI ツールチェーンを使用(LangChain、LlamaIndex など)
  • 開発/本番環境間の切り替えが必要

要するに、「実用主義者」で、コードを変更したくないなら、OpenAI 互換インターフェースを使いましょう。

私の提案

正直、私は開発時に OpenAI SDK 互換インターフェースを使う方が好きです——コードの変更が少なく、ツールチェーンが使え、デバッグも便利。しかし、一部のシナリオではネイティブ API が確かに適しています。例えば、極めてシンプルな CLI ツールを書く場合や、OpenAI SDK をサポートしない環境で呼び出す必要がある場合など。


実践的なコードスニペット

最後に、私がよく使うコードスニペットをいくつか紹介します。

Python ストリーミングチャット(OpenAI SDK)

from openai import OpenAI

client = OpenAI(
    base_url='http://localhost:11434/v1/',
    api_key='ollama'
)

stream = client.chat.completions.create(
    model="llama3.2",
    messages=[{"role": "user", "content": "Write a poem"}],
    stream=True
)

for chunk in stream:
    if chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)

JavaScript 完全な会話(ネイティブ API)

async function chat(messages) {
  const response = await fetch('http://localhost:11434/api/chat', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      model: 'llama3.2',
      messages: messages,
      stream: false
    })
  });
  return await response.json();
}

// 会話履歴を維持
let conversation = [
  { role: 'user', content: 'Hello!' }
];

const result = await chat(conversation);
conversation.push({
  role: 'assistant',
  content: result.message.content
});

console.log(result.message.content);

ツール呼び出しの例

Ollama は Function Calling(ツール呼び出し)もサポートしています:

from openai import OpenAI

client = OpenAI(base_url='http://localhost:11434/v1/', api_key='ollama')

tools = [
  {
    "type": "function",
    "function": {
      "name": "get_weather",
      "description": "Get current weather",
      "parameters": {
        "type": "object",
        "properties": {
          "location": {"type": "string"}
        },
        "required": ["location"]
      }
    }
  }
]

response = client.chat.completions.create(
  model="llama3.2",
  messages=[{"role": "user", "content": "What's the weather in Tokyo?"}],
  tools=tools
)

if response.choices[0].message.tool_calls:
  print("Model wants to call:", response.choices[0].message.tool_calls[0].function.name)

いろいろ話しましたが

実際、Ollama の API 設計はかなりバランスが取れています——ネイティブ REST API の直接性と軽量さを提供しつつ、OpenAI SDK の利便性とエコシステム互換性も提供。2つの方法それぞれに適したシナリオがあり、重要なのはニーズに合わせることです。

Ollama を使い始めたばかりなら、まず OpenAI SDK 互換インターフェースを試してみることをお勧めします——習得が早く、コードの変更も少ない。慣れてきたら、具体的なニーズに応じてネイティブ API を使うかどうか決めればいいです。

あと一点:ストリーミングレスポンス処理は本当に罠になりやすいです。デフォルトはストリーミングなので、ストリーミングが不要なら明示的に stream: false を設定してください。そうしないと、私みたいに深夜3時に単語の半分を見つめ続けることになります。

Ollama API を呼び出す2つの方法

curl ネイティブ API から OpenAI SDK 互換インターフェースまでの完全な呼び出しフロー

⏱️ 目安時間: 10 分

  1. 1

    ステップ1: Ollama がインストールされ実行されていることを確認

    まず Ollama が正常に実行されているか確認:

    • ターミナルで実行:ollama list(ダウンロード済みモデルを表示)
    • またはアクセス:http://localhost:11434(Ollama is running が返されるはず)
    • デフォルトポート:11434
  2. 2

    ステップ2: 呼び出し方法を選択

    シナリオに応じて選択:

    • ネイティブ REST API:軽量な呼び出し、カスタムクライアントに適している
    • OpenAI SDK 互換:既存の OpenAI コード、迅速な移行に適している
  3. 3

    ステップ3: ネイティブ REST API を使用(curl 方法)

    最も基本的な curl 呼び出し:

    • テキスト生成:curl http://localhost:11434/api/generate -d '{"model": "llama3.2", "prompt": "...", "stream": false}'
    • チャットモード:curl http://localhost:11434/api/chat -d '{"model": "llama3.2", "messages": [...], "stream": false}'
    • 注意:デフォルトはストリーミングレスポンス、stream: false で無効化が必要
  4. 4

    ステップ4: OpenAI SDK 互換インターフェースを使用

    Python OpenAI SDK 呼び出し:

    • base_url='http://localhost:11434/v1/' を設定
    • api_key は何でもOK(ローカルは検証しない)
    • 他のコードは OpenAI と完全に同じ
    • 環境切り替え:base_url を変更するだけ(開発はローカル、本番は OpenAI)
  5. 5

    ステップ5: ストリーミングレスポンスを処理

    ストリーミングレスポンス処理のポイント:

    • Python:response.iter_lines() で NDJSON を1行ずつ読み込む
    • JavaScript:response.body.getReader() でストリーミング読み込み
    • 各チャンクには数文字しか含まれていない、完全な返信を蓄積する必要がある
    • 非ストリーミング:stream: false を設定して完全な JSON を取得

FAQ

Ollama のネイティブ API と OpenAI SDK 互換インターフェースの違いは?
ネイティブ API はより軽量で直接的、デフォルトでストリーミングレスポンス(NDJSON 形式)、カスタム HTTP クライアントに適しています。OpenAI SDK 互換インターフェースは OpenAI SDK と完全互換、base_url を変更するだけで、既存の OpenAI コードの迅速な移行に適しています。
Ollama API を呼び出したら単語の半分しか返ってこないのはなぜ?
これはストリーミングレスポンスのデフォルト動作です。Ollama はデフォルトで NDJSON 形式を使用し、トークンごとに出力します。各 JSON オブジェクトには数文字しか含まれていません。解決方法:

• stream: false を設定してストリーミングを無効化、完全な JSON を取得
• または NDJSON ストリームを正しく処理:1行ずつ読み込んでコンテンツを蓄積
開発環境でローカル Ollama、本番環境で OpenAI を使うには?
環境変数で切り替え:開発時は LLM_ENDPOINT="http://localhost:11434/v1" を設定、本番時は "https://api.openai.com/v1" を設定。コードでは環境変数から base_url を読み込むだけで、他のコードは完全に変更なし。
Ollama はどの OpenAI エンドポイントをサポートしている?
完全サポート:/v1/chat/completions、/v1/completions、/v1/models、/v1/embeddings、/v1/responses。実験的サポート:/v1/images/generations(安定性はまだ十分ではありません)。
Ollama モデルにエイリアスを付けられる?
はい。コマンドを使用:ollama cp llama3.2 gpt-3.5-turbo、これでコード内で model="gpt-3.5-turbo" と書いても、実際にはローカルの llama3.2 が使用されます。コード移行時にこのテクニックは便利です。
Ollama はツール呼び出し(Function Calling)をサポートしている?
はい。OpenAI SDK 互換インターフェースを通じて tools パラメータを使用でき、関数スキーマを定義すると、モデルは tool_calls フィールドを返して呼び出す関数を指示します。

参考資料

5 min read · 公開日: 2026年4月3日 · 更新日: 2026年4月5日

コメント

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

関連記事