目錄

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)

重點:

  1. 把模型的回應(包含 tool_calls)加回 messages。
  2. 每個工具的執行結果用 role: "tool" 加回去。
  3. 再呼叫一次 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日