目次
Ollama ツール呼び出しチュートリアル:Function Calling の使い方
言語モデルは今日の天気やデータベースの内容を知りませんし、正確な計算も得意ではありません。ツール呼び出し(tool calling、function calling とも呼ばれます)を使うと、モデルは「プログラムに関数の実行を依頼」し、その結果に基づいて回答できます。
ツールに対応したモデルのみ利用できます。ollama.com のモデルページには tools と表示されます。たとえば qwen3、llama3.1、gpt-oss、mistral などです。
動作の流れ
1. あなた:質問 + 使用可能なツールの説明 ──────────▶ モデル
2. モデル:「get_weather(city="東京") を呼び出してください」◀──
3. あなたのプログラムが get_weather("東京") を実行 → "24°C、曇り"
4. あなた:結果を送り返す ─────────────────────▶ モデル
5. モデル:「東京は現在 24 度で曇りです。薄手の上着を持っていくとよいでしょう。」
モデル自体がプログラムを実行することはありません。どのツールをどの引数で呼び出すかを決めるだけです。実際に実行するのはあなたのプログラムなので、実行できる処理を完全に制御できます。
Python の例
ollama Python パッケージでは、Python 関数をそのままツールとして渡せます。関数の型アノテーションと docstring から、ツールの説明が自動生成されます。
from ollama import chat
def get_weather(city: str) -> str:
"""
都市の現在の天気を調べます。
Args:
city: 都市名。例:「東京」
Returns:
天気の説明
"""
fake_data = {"東京": "24°C、曇り", "大阪": "29°C、晴れ"}
return fake_data.get(city, "データが見つかりません")
tools = {"get_weather": get_weather}
messages = [{"role": "user", "content": "東京と大阪の現在の天気は?"}]
response = chat(model="qwen3:8b", messages=messages, tools=[get_weather])
messages.append(response.message)
# モデルは一度に複数のツール呼び出しを要求することがあります
for call in response.message.tool_calls or []:
fn = tools[call.function.name]
result = fn(**call.function.arguments)
print(f"{call.function.name}({call.function.arguments}) を呼び出しました → {result}")
messages.append({"role": "tool", "tool_name": call.function.name, "content": str(result)})
final = chat(model="qwen3:8b", messages=messages)
print(final.message.content)
ポイント:
- モデルの応答(
tool_callsを含む)をmessagesに追加します。 - 各ツールの実行結果を
role: "tool"として追加します。 - もう一度
chatを呼び出すと、モデルは結果に基づいて回答します。
呼び出し回数をモデルに任せる
「まず為替レートを調べてから金額を計算する」など、複数のツールを続けて呼び出す必要がある質問もあります。モデルがツール呼び出しを要求しなくなるまで、ループで処理します。
from ollama import chat
def get_exchange_rate(currency: str) -> float:
"""外貨 1 単位を日本円に換算する為替レートを取得します。currency は USD、JPY などです。"""
return {"USD": 32.1, "JPY": 0.21}.get(currency.upper(), 0.0)
def multiply(a: float, b: float) -> float:
"""a と b を掛け算します。"""
return a * b
tools = {f.__name__: f for f in [get_exchange_rate, multiply]}
messages = [{"role": "user", "content": "350 米ドルはおよそ何円ですか?"}]
while True:
response = chat(model="qwen3:8b", messages=messages, tools=list(tools.values()))
messages.append(response.message)
if not response.message.tool_calls:
break
for call in response.message.tool_calls:
result = tools[call.function.name](**call.function.arguments)
messages.append({"role": "tool", "tool_name": call.function.name, "content": str(result)})
print(response.message.content)
実際に使うときは、モデルが無限ループに陥らないよう、呼び出し回数に上限を設けてください。
REST API でツールを定義する
Python パッケージを使わない場合は、JSON Schema でツールを記述します。
curl http://localhost:11434/api/chat -d '{
"model": "qwen3:8b",
"messages": [{ "role": "user", "content": "東京の天気は?" }],
"stream": false,
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"description": "都市の現在の天気を調べます",
"parameters": {
"type": "object",
"properties": {
"city": { "type": "string", "description": "都市名" }
},
"required": ["city"]
}
}
}]
}'
応答内の message.tool_calls:
"tool_calls": [
{ "function": { "name": "get_weather", "arguments": { "city": "東京" } } }
]
実行後、結果を {"role": "tool", "tool_name": "get_weather", "content": "24°C、曇り"} として messages に追加し、もう一度送信します。
ツールの説明を書く
モデルはツールの名前と説明だけを手掛かりに、いつ使うか、引数をどう指定するかを判断します。
- 関数名で用途が明確に伝わるようにします。
search_ordersはquery1より適切です。 - 説明には、どんな場合に使うか、引数の形式と例を明記します。
- 引数はできるだけ少なくし、型を明確にします。列挙型(enum)を使える場合は使います。
- ツールを増やしすぎないようにします。小型モデルはツールが十数個あると選択を誤りやすくなります。
セキュリティに関する注意
- ツールはユーザー入力に基づいてモデルが呼び出します。ユーザーが入力を制御できる場合、間接的にあなたのツールを呼び出せることになります。
- 任意のコードや SQL を実行したり、データを削除したりできるツールは提供しないでください。
- 支払い、メール送信、削除などの副作用を伴う操作は、実行前にユーザーの確認を求めてください。
- モデルが渡す引数を検証し、無条件に信頼しないでください。
更新日 2026年10月12日