工具调用
在 Token101 API 中使用函数调用和工具调用
工具调用
工具调用(也称函数调用)允许你定义模型可以调用的函数。模型不必用文本回答所有问题,而是可以返回结构化的函数调用,由你的代码负责实际执行。
Token101 在 Anthropic Messages API 和 OpenAI Chat Completions API 上均支持工具调用。
工作原理
- 你发送请求时,附带一组工具定义(名称、描述、参数)
- 模型根据用户请求判断是否需要调用工具
- 如果需要,模型返回工具调用(而非文本)
- 你的代码执行工具并将结果发回给模型
- 模型利用工具结果生成最终回复
Anthropic Messages API
定义工具
工具通过 tools 数组传入,每个工具包含 name(名称)、description(描述)和 input_schema(输入结构)。
import anthropic
import os
client = anthropic.Anthropic(
api_key=os.environ.get("TOKEN101_API_KEY"),
base_url="https://token.ppthub.shop/api",
)
tools = [
{
"name": "get_weather",
"description": "获取指定城市的当前天气。",
"input_schema": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称,例如:北京"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "温度单位"
}
},
"required": ["city"]
}
}
]
response = client.messages.create(
model="gpt-5.2",
max_tokens=1024,
tools=tools,
messages=[
{"role": "user", "content": "东京现在的天气怎么样?"}
]
)
print(response.stop_reason) # 工具被调用时为 "tool_use"
print(response.content)处理工具调用
当 stop_reason 为 "tool_use" 时,遍历内容块找出工具调用:
import json
def get_weather(city: str, unit: str = "celsius") -> dict:
# 你的实际实现
return {"city": city, "temperature": 22, "unit": unit, "condition": "晴"}
# 第一轮 — 模型决定调用工具
response = client.messages.create(
model="gpt-5.2",
max_tokens=1024,
tools=tools,
messages=[{"role": "user", "content": "东京现在的天气怎么样?"}]
)
# 收集工具调用
tool_calls = [block for block in response.content if block.type == "tool_use"]
if tool_calls:
# 执行所有工具调用
tool_results = []
for tool_call in tool_calls:
if tool_call.name == "get_weather":
result = get_weather(**tool_call.input)
tool_results.append({
"type": "tool_result",
"tool_use_id": tool_call.id,
"content": json.dumps(result, ensure_ascii=False)
})
# 第二轮 — 将结果发回模型
final_response = client.messages.create(
model="gpt-5.2",
max_tokens=1024,
tools=tools,
messages=[
{"role": "user", "content": "东京现在的天气怎么样?"},
{"role": "assistant", "content": response.content},
{"role": "user", "content": tool_results}
]
)
print(final_response.content[0].text)Node.js / TypeScript
import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic({
apiKey: process.env.TOKEN101_API_KEY,
baseURL: 'https://token.ppthub.shop/api',
});
const tools: Anthropic.Tool[] = [
{
name: 'get_weather',
description: '获取指定城市的当前天气。',
input_schema: {
type: 'object' as const,
properties: {
city: { type: 'string', description: '城市名称' },
},
required: ['city'],
},
},
];
const response = await client.messages.create({
model: 'gpt-5.2',
max_tokens: 1024,
tools,
messages: [{ role: 'user', content: '巴黎的天气怎么样?' }],
});
for (const block of response.content) {
if (block.type === 'tool_use') {
console.log(`调用工具:${block.name}`);
console.log('输入参数:', block.input);
}
}流式工具调用
工具参数通过 content_block_delta 事件(类型为 input_json_delta)流式传输:
with client.messages.stream(
model="gpt-5.2",
max_tokens=1024,
tools=tools,
messages=[{"role": "user", "content": "伦敦的天气怎么样?"}],
) as stream:
for event in stream:
if hasattr(event, 'type'):
if event.type == 'content_block_start' and hasattr(event, 'content_block'):
if event.content_block.type == 'tool_use':
print(f"工具:{event.content_block.name}")OpenAI Chat Completions API
定义工具
from openai import OpenAI
import os
import json
client = OpenAI(
api_key=os.environ.get("TOKEN101_API_KEY"),
base_url="https://token.ppthub.shop/api/v1",
)
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取指定城市的当前天气。",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"]
}
},
"required": ["city"]
}
}
}
]
response = client.chat.completions.create(
model="gpt-5.2",
messages=[{"role": "user", "content": "东京现在的天气怎么样?"}],
tools=tools,
tool_choice="auto" # 让模型自行决定
)
message = response.choices[0].message
print(message.tool_calls) # 工具调用列表,若未调用则为 None处理工具调用
def get_weather(city: str, unit: str = "celsius") -> dict:
return {"city": city, "temperature": 22, "unit": unit, "condition": "晴"}
messages = [{"role": "user", "content": "东京现在的天气怎么样?"}]
# 第一轮
response = client.chat.completions.create(
model="gpt-5.2",
messages=messages,
tools=tools,
tool_choice="auto"
)
assistant_message = response.choices[0].message
messages.append(assistant_message) # 将助手回复加入历史
if assistant_message.tool_calls:
for tool_call in assistant_message.tool_calls:
args = json.loads(tool_call.function.arguments)
if tool_call.function.name == "get_weather":
result = get_weather(**args)
# 追加工具结果
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": json.dumps(result, ensure_ascii=False)
})
# 第二轮 — 获取最终响应
final_response = client.chat.completions.create(
model="gpt-5.2",
messages=messages,
tools=tools
)
print(final_response.choices[0].message.content)Node.js / TypeScript
import OpenAI from 'openai';
const client = new OpenAI({
apiKey: process.env.TOKEN101_API_KEY,
baseURL: 'https://token.ppthub.shop/api/v1',
});
const tools: OpenAI.ChatCompletionTool[] = [
{
type: 'function',
function: {
name: 'get_weather',
description: '获取指定城市的当前天气。',
parameters: {
type: 'object',
properties: {
city: { type: 'string' },
},
required: ['city'],
},
},
},
];
const response = await client.chat.completions.create({
model: 'gpt-5.2',
messages: [{ role: 'user', content: '巴黎的天气怎么样?' }],
tools,
tool_choice: 'auto',
});
const message = response.choices[0].message;
if (message.tool_calls) {
for (const toolCall of message.tool_calls) {
console.log(`工具:${toolCall.function.name}`);
console.log('参数:', JSON.parse(toolCall.function.arguments));
}
}流式工具调用
const stream = await client.chat.completions.create({
model: 'gpt-5.2',
messages: [{ role: 'user', content: '伦敦的天气怎么样?' }],
tools,
stream: true,
});
let toolCallAccumulator = '';
for await (const chunk of stream) {
const delta = chunk.choices[0]?.delta;
if (delta?.tool_calls) {
for (const toolCall of delta.tool_calls) {
if (toolCall.function?.arguments) {
toolCallAccumulator += toolCall.function.arguments;
}
}
}
}
if (toolCallAccumulator) {
const args = JSON.parse(toolCallAccumulator);
console.log('工具参数:', args);
}字段参考
Anthropic 工具字段
| 字段 | 类型 | 说明 |
|---|---|---|
name | string | 工具名称(建议使用 snake_case) |
description | string | 工具用途说明 — 模型依据此判断何时调用 |
input_schema | object | 工具输入参数的 JSON Schema |
OpenAI 工具字段
| 字段 | 类型 | 说明 |
|---|---|---|
type | "function" | 固定为 "function" |
function.name | string | 函数名称 |
function.description | string | 函数用途说明 |
function.parameters | object | 参数的 JSON Schema |
tool_choice / tool_use 选项
| 值 | 行为 |
|---|---|
"auto"(OpenAI) | 由模型决定是否调用工具 |
"required"(OpenAI) | 模型必须调用至少一个工具 |
{"type": "none"}(OpenAI) | 禁用工具调用 |
{"type": "auto"}(Anthropic) | 由模型决定(默认) |
{"type": "any"}(Anthropic) | 必须调用至少一个工具 |
{"type": "tool", "name": "..."}(Anthropic) | 必须调用指定工具 |
使用建议
写清晰的描述 — 模型依据描述判断何时调用工具。请明确说明期望的输入以及工具会返回什么。
优雅地处理错误 — 工具调用可能失败。始终用 try/catch 包裹工具执行代码,并将有意义的错误信息返回给模型。
验证输入 — 即使定义了 Schema,模型有时仍可能传入非预期值。执行工具前请验证输入。
控制工具数量 — 工具过多可能降低准确率。对于复杂系统,建议只暴露当前任务所需的工具。
利用并行调用 — Anthropic 和 OpenAI 模型都支持在单次响应中调用多个工具。请在发送结果前处理所有工具调用。