开发文档

工具调用

工具调用(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,直飞全球大模型