工具调用
OpenAI Function Tools / Anthropic Tool Use / Gemini Function Calling 跨 SDK 对照
工具调用
让模型决定何时调用你的代码逻辑 —— 查天气 / 查数据库 / 调用其他 API / 控制软件 ...
GPUShare 在 3 个 SDK 协议端点上都支持 function / tool 调用,但字段名跟 schema 形状不同。本页给跨 SDK 对照与最佳实践。
概念对照
| 概念 | OpenAI | Anthropic | Gemini |
|---|---|---|---|
| 工具列表字段 | tools | tools | tools |
| 单工具 wrapper | {type:"function","function":{...}} | 直接 {...} (不包 wrapper) | {functionDeclarations:[...]} |
| 参数 schema 字段 | function.parameters | input_schema | parameters |
| 模型选择策略 | tool_choice | tool_choice | toolConfig.functionCallingConfig |
| 模型工具调用响应 | message.tool_calls[i] | content[i] type:tool_use | parts[i].functionCall |
| 工具结果回填 | role:"tool" + tool_call_id | content type:tool_result + tool_use_id | parts[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。
注意事项
- 工具 schema 校验严格 ——
parameters必须是合法 JSON Schema,模型按它生成 arguments - arguments 是字符串 (OpenAI) / 是对象 (Anthropic / Gemini) —— 客户端解析方式不同
- 不要在工具结果里返回长 base64 图像 —— 会被算进下一轮 input tokens,极易爆账
- internal tools (
web_search/image_generation) 不需要你定义 schema,但必须配stream=true—— 详见 流式响应