開發文件

工具呼叫

工具呼叫(Function Calling)讓模型按你定義的格式請求呼叫外部函式,比如查天氣、查資料庫、執行程式碼。模型只負責決定「呼叫哪個工具、傳什麼參數」,真正執行由你的程式碼完成。

基本流程

  1. 在請求裡用 JSON Schema 描述可用的工具。
  2. 模型判斷需要時,回傳工具名和參數,而不是直接回答。
  3. 你的程式碼執行工具,把結果作為新訊息發回。
  4. 模型根據結果給出最終回答。如果還需要別的工具,會繼續請求,迴圈直到完成。

OpenAI 相容格式

tools_openai.py
import json
from openai import OpenAI

client = OpenAI(api_key="sk-...", base_url="https://api.flyrouter.ai/v1")

tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "查詢某個城市目前的天氣",
        "parameters": {
            "type": "object",
            "properties": {"city": {"type": "string", "description": "城市名,如 北京"}},
            "required": ["city"],
        },
    },
}]

messages = [{"role": "user", "content": "上海現在天氣怎麼樣?"}]
resp = client.chat.completions.create(model="gpt-6.1-sol", messages=messages, tools=tools)
msg = resp.choices[0].message

if msg.tool_calls:
    messages.append(msg)
    for call in msg.tool_calls:
        args = json.loads(call.function.arguments)
        result = {"city": args["city"], "weather": "多雲", "temperature": 22}  # 換成你的實作
        messages.append({"role": "tool", "tool_call_id": call.id, "content": json.dumps(result, ensure_ascii=False)})
    resp = client.chat.completions.create(model="gpt-6.1-sol", messages=messages, tools=tools)

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

Anthropic 原生格式

Claude 的工具定義用 input_schema,模型請求呼叫時回傳 tool_use 內容區塊,你用 tool_result 區塊回傳結果:

tools_claude.py
from anthropic import Anthropic

client = Anthropic(api_key="sk-...", base_url="https://api.flyrouter.ai")

tools = [{
    "name": "get_weather",
    "description": "查詢某個城市目前的天氣",
    "input_schema": {
        "type": "object",
        "properties": {"city": {"type": "string"}},
        "required": ["city"],
    },
}]

messages = [{"role": "user", "content": "上海現在天氣怎麼樣?"}]
resp = client.messages.create(model="claude-sonnet-5-5", max_tokens=4096, tools=tools, messages=messages)

while resp.stop_reason == "tool_use":
    messages.append({"role": "assistant", "content": resp.content})
    results = []
    for block in resp.content:
        if block.type == "tool_use":
            output = '{"weather": "多雲", "temperature": 22}'  # 換成你的實作
            results.append({"type": "tool_result", "tool_use_id": block.id, "content": output})
    messages.append({"role": "user", "content": results})
    resp = client.messages.create(model="claude-sonnet-5-5", max_tokens=4096, tools=tools, messages=messages)

print(next(b.text for b in resp.content if b.type == "text"))

實用建議

  • 把 description 寫清楚:工具做什麼、什麼時候該用、參數格式,這比任何參數都影響呼叫品質。
  • 並行呼叫:模型可能一次請求多個工具。請全部執行,並把所有結果放在同一條訊息裡回傳。
  • 執行失敗也要回傳:OpenAI 格式回傳錯誤說明;Anthropic 格式在 tool_result 上加 "is_error": true。不要直接丟掉。
  • 參數一律按 JSON 解析:用 json.loads / JSON.parse 解析參數,不要對原始字串做匹配。

新款 Claude 不支援強制呼叫

claude-opus-5-5、claude-sonnet-5-5、claude-fable-5-1 不接受 tool_choice 為 any 或指定工具(會回傳 400)。請使用預設的 auto,並在提示詞裡說明應該呼叫哪個工具;需要保證參數嚴格符合 Schema 時,在工具定義上加 "strict": true。

FlyRouter

一組 Key,直飛全球大型模型