工具调用

OpenAI Function Tools / Anthropic Tool Use / Gemini Function Calling 跨 SDK 对照

工具调用

让模型决定何时调用你的代码逻辑 —— 查天气 / 查数据库 / 调用其他 API / 控制软件 ...

GPUShare 在 3 个 SDK 协议端点上都支持 function / tool 调用,但字段名跟 schema 形状不同。本页给跨 SDK 对照与最佳实践。

概念对照

概念OpenAIAnthropicGemini
工具列表字段toolstoolstools
单工具 wrapper{type:"function","function":{...}}直接 {...} (不包 wrapper){functionDeclarations:[...]}
参数 schema 字段function.parametersinput_schemaparameters
模型选择策略tool_choicetool_choicetoolConfig.functionCallingConfig
模型工具调用响应message.tool_calls[i]content[i] type:tool_useparts[i].functionCall
工具结果回填role:"tool" + tool_call_idcontent type:tool_result + tool_use_idparts[i].functionResponse

OpenAI Chat —— Function Tools

1. 定义工具

tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Get the current weather in a city",
        "parameters": {
            "type": "object",
            "properties": {
                "city": {"type": "string", "description": "City name"},
                "unit": {"type": "string", "enum": ["c", "f"], "default": "c"},
            },
            "required": ["city"],
        },
    },
}]

2. 发起调用

from openai import OpenAI
client = OpenAI(api_key="sk-gpushare-xxx", base_url="https://api.dflop.top/v1")

messages = [{"role": "user", "content": "Weather in Tokyo?"}]
resp = client.chat.completions.create(
    model="claude-sonnet-4-5-20250929",
    messages=messages,
    tools=tools,
)

3. 处理模型工具调用

choice = resp.choices[0]
if choice.finish_reason == "tool_calls":
    for tc in choice.message.tool_calls:
        args = json.loads(tc.function.arguments)
        result = get_weather(**args)  # 你的真实函数

        # 把工具结果回填,让模型续生成
        messages.append(choice.message)  # assistant 含 tool_calls
        messages.append({
            "role": "tool",
            "tool_call_id": tc.id,
            "content": json.dumps(result),
        })

    # 再发一轮拿最终回答
    final = client.chat.completions.create(
        model="claude-sonnet-4-5-20250929",
        messages=messages,
        tools=tools,
    )
    print(final.choices[0].message.content)

Anthropic Messages —— Tool Use

1. 定义工具

tools = [{
    "name": "get_weather",
    "description": "Get the current weather in a city",
    "input_schema": {
        "type": "object",
        "properties": {
            "city": {"type": "string"},
            "unit": {"type": "string", "enum": ["c", "f"]},
        },
        "required": ["city"],
    },
}]

2. 发起调用

from anthropic import Anthropic
client = Anthropic(api_key="sk-gpushare-xxx", base_url="https://api.dflop.top")

messages = [{"role": "user", "content": "Weather in Tokyo?"}]
resp = client.messages.create(
    model="claude-sonnet-4-5-20250929",
    max_tokens=1024,
    tools=tools,
    messages=messages,
)

3. 处理模型工具调用

if resp.stop_reason == "tool_use":
    tool_blocks = [b for b in resp.content if b.type == "tool_use"]
    tool_results = []
    for tb in tool_blocks:
        result = get_weather(**tb.input)
        tool_results.append({
            "type": "tool_result",
            "tool_use_id": tb.id,
            "content": json.dumps(result),
        })

    messages.append({"role": "assistant", "content": resp.content})
    messages.append({"role": "user", "content": tool_results})

    final = client.messages.create(
        model="claude-sonnet-4-5-20250929",
        max_tokens=1024,
        tools=tools,
        messages=messages,
    )

Gemini Native —— Function Calling

1. 定义工具

from google.genai import types

weather_tool = types.Tool(function_declarations=[
    types.FunctionDeclaration(
        name="get_weather",
        description="Get the current weather in a city",
        parameters={
            "type": "object",
            "properties": {
                "city": {"type": "string"},
                "unit": {"type": "string", "enum": ["c", "f"]},
            },
            "required": ["city"],
        },
    )
])

2. 发起调用

from google import genai
client = genai.Client(api_key="sk-gpushare-xxx", http_options={"base_url": "https://api.dflop.top"})

response = client.models.generate_content(
    model="gemini-2.5-pro",
    contents="Weather in Tokyo?",
    config=types.GenerateContentConfig(tools=[weather_tool]),
)

3. 处理模型工具调用

for part in response.candidates[0].content.parts:
    if part.function_call:
        fc = part.function_call
        result = get_weather(**dict(fc.args))
        # 后续轮把 functionResponse 包成 part 回填

跨厂商 + 工具调用

GPUShare 协议翻译层让你用任意 SDK 调任意模型,工具同样跨厂商可用:

# 用 OpenAI SDK 调 Claude 做工具调用
from openai import OpenAI
client = OpenAI(api_key="sk-gpushare-xxx", base_url="https://api.dflop.top/v1")

resp = client.chat.completions.create(
    model="claude-sonnet-4-5-20250929",  # Claude 走 T1 翻译
    messages=[{"role": "user", "content": "Weather in Tokyo?"}],
    tools=[{
        "type": "function",
        "function": {"name": "get_weather", "parameters": {...}},
    }],
)
# resp.choices[0].message.tool_calls 跟纯 OpenAI 一致

翻译层在响应 header 加 X-Protocol-Translation: openai_chat_to_anthropic_messages,你可以据此知晓走了哪条路径。

高级技巧

强制工具调用

# OpenAI: tool_choice 指定具体工具
tool_choice = {"type": "function", "function": {"name": "get_weather"}}

# Anthropic: tool_choice 限制必须用工具
tool_choice = {"type": "tool", "name": "get_weather"}

# Gemini: function_calling_config mode = ANY
config = types.GenerateContentConfig(
    tool_config=types.ToolConfig(
        function_calling_config=types.FunctionCallingConfig(mode="ANY")
    )
)

多个工具

3 家 SDK 都支持单次请求多个工具,模型可能一次性返回多个调用:

# OpenAI 一次 response 可能有 multiple tool_calls
for tc in resp.choices[0].message.tool_calls:
    handle(tc)

Stream 模式下的工具

工具调用可以配合 stream=true。增量 chunk 里的 delta.tool_calls 是字段级累加的(function.arguments 一次发一片),客户端需要拼接所有 chunk 才能拿到完整 JSON。

注意事项

  1. 工具 schema 校验严格 —— parameters 必须是合法 JSON Schema,模型按它生成 arguments
  2. arguments 是字符串 (OpenAI) / 是对象 (Anthropic / Gemini) —— 客户端解析方式不同
  3. 不要在工具结果里返回长 base64 图像 —— 会被算进下一轮 input tokens,极易爆账
  4. internal tools (web_search / image_generation) 不需要你定义 schema,但必须配 stream=true —— 详见 流式响应