Ollama がストリーミングツール呼び出しのサポートを追加
TL;DR
Ollama はストリーミングツール呼び出しを導入し、チャットアプリがモデルの出力をトークン単位で即座に受け取りながら、天気照会や数学計算などの関数を同時に実行できるようにしました。
ストリーミングツール呼び出しの機能
ストリーミングツール呼び出しにより、モデルは応答全体が完了するのを待たずに、通常のテキストと関数呼び出しを交互に生成できます。アプリケーションはユーザーに部分的なコンテンツを即座に表示でき、モデルが関数呼び出しを示すとすぐにツール(例:API呼び出し)を実行できます。
ツール呼び出しをサポートするモデル
以下の Ollama ホストモデルが新しいストリーミング機能と互換性があります:
- Qwen 3
- Devstral
- Qwen2.5 および Qwen2.5‑coder
- Llama 3.1
- Llama 4
- Ollama モデルライブラリの「ツール呼び出し」フィルターにリストアップされている追加モデル。
簡単なツール呼び出し例(天気)
get_current_weather 関数を使用して cURL リクエストで天気照会をストリーミングします。モデルが関数を呼び出すと、即座にインクリメンタルな JSON フラグメントと tool_calls フィールドが返されます。
{
"model": "qwen3",
"created_at": "2025-05-27T22:54:58.100509Z",
"message": {
"role": "assistant",
"content": "",
"tool_calls": [{
"function": {
"name": "get_current_weather",
"arguments": {"format": "celsius", "location": "Toronto"}
}
}]
},
"done": false
}
関数の結果が利用可能になると、ストリームは続きます。
Python SDK の使用方法
Python ライブラリ(pip install -U ollama)は、ネイティブな Python コールバックをツールとして受け入れます。以下の例では、add_two_numbers 関数を chat() に stream=True で渡しています。クライアントはストリーミングされたテキストを出力し、tool_calls が出現するタイミングで検出します。
from ollama import chat, ChatResponse
def add_two_numbers(a: int, b: int) -> int:
return a + b
messages = [{"role": "user", "content": "three minus one is what?"}]
response: ChatResponse = chat(model='qwen3', messages=messages, tools=[add_two_numbers], stream=True)
for chunk in response:
print(chunk.message.content, end='', flush=True)
if chunk.message.tool_calls:
print(chunk.message.tool_calls)
出力
[ToolCall(function=Function(name='add_two_numbers', arguments={'a': 3, 'b': 1}))]
JavaScript SDK の使用方法
JavaScript クライアント(npm i ollama)も同様に動作します。ツールスキーマを定義し、ollama.chat() でテキストとツール呼び出しの両方をストリーミングします。
import ollama from 'ollama';
const addTool = {
type: 'function',
function: {
name: 'addTwoNumbers',
description: 'Add two numbers together',
parameters: {
type: 'object',
required: ['a', 'b'],
properties: {
a: {type: 'number', description: 'The first number'},
b: {type: 'number', description: 'The second number'}
}
}
}
};
async function run(model) {
const messages = [{role: 'user', content: 'What is 2 plus 3?'}];
for await (const chunk of await ollama.chat({model, messages, tools: [addTool], stream: true})) {
if (chunk.message.tool_calls) {
console.log('Tool call:', chunk.message.tool_calls);
} else {
process.stdout.write(chunk.message.content);
}
}
}
run('qwen3').catch(console.error);
出力
Question: What is 2 plus 3?
Tool call: {function: {name: "addTwoNumbers", arguments: {a: 2, b: 3}}}
インクリメンタルパーサーの動作方法
背景
以前の Ollama バージョンでは、モデル出力をすべてバッファリングし、JSON としてパースしてからツール呼び出しを発行していました。この方法では、ツール呼び出しがテキストのどこにでも出現する可能性があるため、ストリーミングがブロックされていました。
インクリメンタルパース戦略
新しいパーサーは、各モデルのテンプレートを読み取り、ツール呼び出しのプレフィックス(例:特別なトークンや文字列)を認識します。これにより、以下のことが可能になります:
- モデルがトークンをストリーミングする際に、部分的なプレフィックスを検出できる。
- 通常のコンテンツと保留中のツール呼び出しを分離できる。
- モデルが期待されるプレフィックスなしで生の JSON オブジェクトを出力した場合、一般的な JSON 検出にフォールバックできる。
エッジケースの処理
モデルが以前に実行したツール呼び出しを繰り返す、または説明文の中に呼び出しを含める場合でも、パーサーのステートマシンは重複呼び出しを回避します。実証的なテストでは、不正なまたは重複する呼び出しが現在は単一の正しい実行にまで削減されています。
正確性の向上
以前は、モデルがナラティブ内で呼び出しを繰り返した場合、同じツール呼び出しが2回生成されることがありました。更新されたパーサーはプレフィックスをマッチさせ、JSON パースの状態を追跡するため、1回の呼び出しのみが発行されます。旧来の失敗例:
[TOOL_CALL] [{"name":"get_conditions","arguments":{"city":"Sydney"}}]
... (text) ...
[{"name":"get_conditions","arguments":{"city":"Sydney"}}]
現在のパーサーは単一の tool_calls エントリを返します。
モデルコンテキストプロトコル(MCP)とより大きなウィンドウ
ストリーミングツール呼び出しは、Ollama のモデルコンテキストプロトコル(MCP)と連携します。ユーザーからの報告では、コンテキストウィンドウを 32 k トークン以上に増やすと、ツール検出の信頼性と生成された回答の品質の両方が向上します。
cURL によるコンテキストウィンドウの調整
curl -X POST "http://localhost:11434/api/chat" -d '{
"model": "llama3.2",
"messages": [{"role": "user", "content": "why is the sky blue?"}],
"options": {"num_ctx": 32000}
}'
注:大きなウィンドウはメモリ消費を増加させます。
はじめ方
- 最新の Ollama リリースをダウンロード – https://ollama.com/download
- 言語固有の SDK をインストール – Python 用は
pip install -U ollama、JavaScript 用はnpm i ollama。 - API 呼び出しで
stream: trueフラグを使用し、モデルが呼び出す関数を記述するtools配列を含める。
参照
- ストリーミングツール呼び出しを実装したプルリクエスト: https://github.com/ollama/ollama/pull/10415
Sources
関連
- Dispatch
- Dispatch
- Dispatch
- Dispatch
- Dispatch