定义工具
指定工具 schema,编写有效的描述,并控制 Claude 何时调用你的工具。
选择模型
使用最新的 Claude Opus (4.7) 模型处理复杂工具和模糊查询;它能更好地处理多个工具,并在需要时寻求澄清。
使用 Claude Haiku 模型处理简单直接的工具,但请注意它们可能会推断缺失的参数。
如果将 Claude 与工具使用和扩展思考一起使用,请参阅扩展思考指南了解更多信息。
指定客户端工具
客户端工具(包括 Anthropic-schema 和用户定义的工具)在 API 请求的 tools 顶级参数中指定。每个工具定义包括:
| 参数 | 描述 |
|---|---|
name | 工具的名称。必须匹配正则表达式 ^[a-zA-Z0-9_-]{1,64}$。 |
description | 工具功能的详细纯文本描述,何时应该使用它,以及它的行为方式。 |
input_schema | 定义工具预期参数的 JSON Schema 对象。 |
input_examples | (可选)示例输入对象数组,帮助 Claude 理解如何使用该工具。请参阅提供工具使用示例。 |
有关任何工具定义上可用的完整可选属性集,包括 cache_control、strict、defer_loading 和 allowed_callers,请参阅工具参考。
简单工具定义示例
{
"name": "get_weather",
"description": "Get the current weather in a given location",
"input_schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "The unit of temperature, either 'celsius' or 'fahrenheit'"
}
},
"required": ["location"]
}
}
这个名为 get_weather 的工具期望一个输入对象,其中包含必需的 location 字符串和可选的 unit 字符串(必须是 "celsius" 或 "fahrenheit")。
工具使用系统提示
当你使用 tools 参数调用 Claude API 时,API 会从工具定义、工具配置和任何用户指定的系统提示构建一个特殊的系统提示。构建的提示旨在指示模型使用指定的工具,并为工具正常运行提供必要的上下文:
In this environment you have access to a set of tools you can use to answer the user's question.
{{ FORMATTING INSTRUCTIONS }}
String and scalar parameters should be specified as is, while lists and objects should use JSON format. Note that spaces for string values are not stripped. The output is not expected to be valid XML and is parsed with regular expressions.
Here are the functions available in JSONSchema format:
{{ TOOL DEFINITIONS IN JSON SCHEMA }}
{{ USER SYSTEM PROMPT }}
{{ TOOL CONFIGURATION }}
工具定义的最佳实践
为了在使用工具时获得 Claude 的最佳性能,请遵循以下准则:
- 提供极其详细的描述。 这是工具性能中最重要的因素。你的描述应该解释工具的每个细节,包括:
- 工具的功能
- 何时应该使用它(以及何时不应该)
- 每个参数的含义以及它如何影响工具的行为
- 任何重要的注意事项或限制,例如如果工具名称不清楚,工具不会返回什么信息。你能给 Claude 关于工具的上下文越多,它就越能更好地决定何时以及如何使用它们。每个工具描述至少 3-4 句话,如果工具复杂则更多。
- 优先考虑描述,但对于复杂工具可以考虑使用
input_examples。 清晰的描述最重要,但对于具有复杂输入、嵌套对象或格式敏感参数的工具,你可以使用input_examples字段提供经过 schema 验证的示例。详情请参阅提供工具使用示例。 - 将相关操作合并到更少的工具中。 与其为每个操作创建单独的工具(
create_pr、review_pr、merge_pr),不如将它们分组到一个带有action参数的单一工具中。更少但更强大的工具可以减少选择歧义,使你的工具表面更容易被 Claude 导航。 - 在工具名称中使用有意义的命名空间。 当你的工具跨越多个服务或资源时,用服务作为名称前缀(例如
github_list_prs、slack_send_message)。这使得工具选择在你的库增长时变得明确,在使用工具搜索时尤其重要。 - 设计工具响应只返回高信号信息。 返回语义化的、稳定的标识符(例如 slug 或 UUID)而不是不透明的内部引用,并且只包含 Claude 需要推理下一步的字段。臃肿的响应会浪费上下文,使 Claude 更难提取重要内容。
好的工具描述示例
{
"name": "get_stock_price",
"description": "Retrieves the current stock price for a given ticker symbol. The ticker symbol must be a valid symbol for a publicly traded company on a major US stock exchange like NYSE or NASDAQ. The tool will return the latest trade price in USD. It should be used when the user asks about the current or most recent price of a specific stock. It will not provide any other information about the stock or company.",
"input_schema": {
"type": "object",
"properties": {
"ticker": {
"type": "string",
"description": "The stock ticker symbol, e.g. AAPL for Apple Inc."
}
},
"required": ["ticker"]
}
}
差的工具描述示例
{
"name": "get_stock_price",
"description": "Gets the stock price for a ticker.",
"input_schema": {
"type": "object",
"properties": {
"ticker": {
"type": "string"
}
},
"required": ["ticker"]
}
}
好的描述清楚地解释了工具的功能、何时使用它、它返回什么数据以及 ticker 参数的含义。差的描述太简短,给 Claude 留下了许多关于工具行为和使用的未解问题。
有关工具设计(合并、命名和响应整形)的更深入指导,请参阅为 agent 编写工具。
提供工具使用示例
你可以提供有效工具输入的具体示例,帮助 Claude 更有效地理解如何使用你的工具。这对于具有嵌套对象、可选参数或格式敏感输入的复杂工具特别有用。
基本用法
在工具定义中添加可选的 input_examples 字段,包含示例输入对象数组。每个示例必须根据工具的 input_schema 有效:
curl -sS https://api.anthropic.com/v1/messages \
-H "content-type: application/json" \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-d @- <<'EOF'
{
"model": "claude-opus-4-7",
"max_tokens": 1024,
"tools": [
{
"name": "get_weather",
"description": "Get the current weather in a given location",
"input_schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "The unit of temperature"
}
},
"required": ["location"]
},
"input_examples": [
{"location": "San Francisco, CA", "unit": "fahrenheit"},
{"location": "Tokyo, Japan", "unit": "celsius"},
{"location": "New York, NY"}
]
}
],
"messages": [
{"role": "user", "content": "What's the weather like in San Francisco?"}
]
}
EOF
ant messages create <<'YAML'
model: claude-opus-4-7
max_tokens: 1024
tools:
- name: get_weather
description: Get the current weather in a given location
input_schema:
type: object
properties:
location:
type: string
description: The city and state, e.g. San Francisco, CA
unit:
type: string
enum: [celsius, fahrenheit]
description: The unit of temperature
required: [location]
input_examples:
- location: San Francisco, CA
unit: fahrenheit
- location: Tokyo, Japan
unit: celsius
- location: New York, NY # 'unit' is optional
messages:
- role: user
content: What's the weather like in San Francisco?
YAML
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-4-7",
max_tokens=1024,
tools=[
{
"name": "get_weather",
"description": "Get the current weather in a given location",
"input_schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "The unit of temperature",
},
},
"required": ["location"],
},
"input_examples": [
{"location": "San Francisco, CA", "unit": "fahrenheit"},
{"location": "Tokyo, Japan", "unit": "celsius"},
{
"location": "New York, NY" # 'unit' is optional
},
],
}
],
messages=[{"role": "user", "content": "What's the weather like in San Francisco?"}],
)
print(response)
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
const response = await client.messages.create({
model: "claude-opus-4-7",
max_tokens: 1024,
tools: [
{
name: "get_weather",
description: "Get the current weather in a given location",
input_schema: {
type: "object",
properties: {
location: {
type: "string",
description: "The city and state, e.g. San Francisco, CA"
},
unit: {
type: "string",
enum: ["celsius", "fahrenheit"],
description: "The unit of temperature"
}
},
required: ["location"]
},
input_examples: [
{
location: "San Francisco, CA",
unit: "fahrenheit"
},
{
location: "Tokyo, Japan",
unit: "celsius"
},
{
location: "New York, NY"
// Demonstrates that 'unit' is optional
}
]
}
],
messages: [{ role: "user", content: "What's the weather like in San Francisco?" }]
});
console.log(response);
using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Threading.Tasks;
using Anthropic;
using Anthropic.Models.Messages;
AnthropicClient client = new();
var parameters = new MessageCreateParams
{
Model = Model.ClaudeOpus4_7,
MaxTokens = 1024,
Tools = [
new ToolUnion(new Tool()
{
Name = "get_weather",
Description = "Get the current weather in a given location",
InputSchema = new InputSchema()
{
Properties = new Dictionary<string, JsonElement>
{
["location"] = JsonSerializer.SerializeToElement(new { type = "string", description = "The city and state, e.g. San Francisco, CA" }),
["unit"] = JsonSerializer.SerializeToElement(new { type = "string", @enum = new[] { "celsius", "fahrenheit" }, description = "The unit of temperature" }),
},
Required = ["location"],
},
InputExamples =
[
new Dictionary<string, JsonElement>()
{
{ "location", JsonSerializer.SerializeToElement("San Francisco, CA") },
{ "unit", JsonSerializer.SerializeToElement("fahrenheit") },
},
new Dictionary<string, JsonElement>()
{
{ "location", JsonSerializer.SerializeToElement("Tokyo, Japan") },
{ "unit", JsonSerializer.SerializeToElement("celsius") },
},
new Dictionary<string, JsonElement>()
{
{ "location", JsonSerializer.SerializeToElement("New York, NY") },
},
],
}),
],
Messages = [
new() { Role = Role.User, Content = "What's the weather like in San Francisco?" }
]
};
var message = await client.Messages.Create(parameters);
Console.WriteLine(message);
package main
import (
"context"
"fmt"
"log"
"github.com/anthropics/anthropic-sdk-go"
)
func main() {
client := anthropic.NewClient()
response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
Model: anthropic.ModelClaudeOpus4_7,
MaxTokens: 1024,
Tools: []anthropic.ToolUnionParam{
{OfTool: &anthropic.ToolParam{
Name: "get_weather",
Description: anthropic.String("Get the current weather in a given location"),
InputSchema: anthropic.ToolInputSchemaParam{
Properties: map[string]any{
"location": map[string]any{
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
},
"unit": map[string]any{
"type": "string",
"enum": []string{"celsius", "fahrenheit"},
"description": "The unit of temperature",
},
},
Required: []string{"location"},
},
InputExamples: []map[string]any{
{
"location": "San Francisco, CA",
"unit": "fahrenheit",
},
{
"location": "Tokyo, Japan",
"unit": "celsius",
},
{
"location": "New York, NY",
// Demonstrates that 'unit' is optional
},
},
}},
},
Messages: []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock("What's the weather like in San Francisco?")),
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(response)
}
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.core.JsonValue;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Message;
import com.anthropic.models.messages.Model;
import com.anthropic.models.messages.Tool;
import com.anthropic.models.messages.Tool.InputSchema;
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
MessageCreateParams params = MessageCreateParams.builder()
.model(Model.CLAUDE_OPUS_4_7)
.maxTokens(1024L)
.addTool(Tool.builder()
.name("get_weather")
.description("Get the current weather in a given location")
.inputSchema(InputSchema.builder()
.properties(JsonValue.from(Map.of(
"location", Map.of(
"type", "string",
"description", "The city and state, e.g. San Francisco, CA"
),
"unit", Map.of(
"type", "string",
"enum", List.of("celsius", "fahrenheit"),
"description", "The unit of temperature"
)
)))
.required(List.of("location"))
.build())
.putAdditionalProperty("input_examples", JsonValue.from(List.of(
Map.of(
"location", "San Francisco, CA",
"unit", "fahrenheit"
),
Map.of(
"location", "Tokyo, Japan",
"unit", "celsius"
),
Map.of(
"location", "New York, NY"
)
)))
.build())
.addUserMessage("What's the weather like in San Francisco?")
.build();
Message response = client.messages().create(params);
IO.println(response);
}
<?php
use Anthropic\Client;
$client = new Client(apiKey: getenv("ANTHROPIC_API_KEY"));
$message = $client->messages->create(
maxTokens: 1024,
messages: [
['role' => 'user', 'content' => "What's the weather like in San Francisco?"]
],
model: 'claude-opus-4-7',
tools: [
[
'name' => 'get_weather',
'description' => 'Get the current weather in a given location',
'input_schema' => [
'type' => 'object',
'properties' => [
'location' => [
'type' => 'string',
'description' => 'The city and state, e.g. San Francisco, CA'
],
'unit' => [
'type' => 'string',
'enum' => ['celsius', 'fahrenheit'],
'description' => 'The unit of temperature'
]
],
'required' => ['location']
],
'input_examples' => [
[
'location' => 'San Francisco, CA',
'unit' => 'fahrenheit'
],
[
'location' => 'Tokyo, Japan',
'unit' => 'celsius'
],
[
'location' => 'New York, NY'
]
]
]
],
);
require "anthropic"
client = Anthropic::Client.new
message = client.messages.create(
model: "claude-opus-4-7",
max_tokens: 1024,
tools: [
{
name: "get_weather",
description: "Get the current weather in a given location",
input_schema: {
type: "object",
properties: {
location: {
type: "string",
description: "The city and state, e.g. San Francisco, CA"
},
unit: {
type: "string",
enum: ["celsius", "fahrenheit"],
description: "The unit of temperature"
}
},
required: ["location"]
},
input_examples: [
{
location: "San Francisco, CA",
unit: "fahrenheit"
},
{
location: "Tokyo, Japan",
unit: "celsius"
},
{
location: "New York, NY"
}
]
}
],
messages: [
{ role: "user", content: "What's the weather like in San Francisco?" }
]
)
puts message
示例与你的工具 schema 一起包含在提示中,向 Claude 展示格式良好的工具调用的具体模式。这有助于 Claude 理解何时包含可选参数、使用什么格式以及如何构建复杂输入。
要求和限制
- Schema 验证 - 每个示例必须根据工具的
input_schema有效。无效的示例会返回 400 错误 - 不支持服务器端工具 - 输入示例适用于用户定义和 Anthropic-schema 客户端工具,但不适用于服务器端工具(如网络搜索或代码执行)
- Token 成本 - 示例会增加提示 token:简单示例约 20-50 个 token,复杂嵌套对象约 100-200 个 token
控制 Claude 的输出
强制使用工具
在某些情况下,你可能希望 Claude 使用特定工具来回答用户的问题,即使 Claude otherwise 会直接回答而不调用工具。你可以通过在 tool_choice 字段中指定工具来实现:
tool_choice = {"type": "tool", "name": "get_weather"}
使用 tool_choice 参数时,有四个可能的选项:
auto允许 Claude 决定是否调用任何提供的工具。当提供tools时这是默认值。any告诉 Claude 必须使用提供的工具之一,但不强制使用特定工具。tool强制 Claude 始终使用特定工具。none阻止 Claude 使用任何工具。当没有提供tools时这是默认值。
使用提示缓存时,更改 tool_choice 参数会使缓存的消息块失效。工具定义和系统提示仍保持缓存,但消息内容必须重新处理。
此图说明了每个选项的工作原理:

请注意,当你将 tool_choice 设置为 any 或 tool 时,API 会预填充助手消息以强制使用工具。这意味着模型不会在 tool_use 内容块之前发出自然语言响应或解释,即使明确要求这样做。
将扩展思考与工具使用一起使用时,不支持 tool_choice: {"type": "any"} 和 tool_choice: {"type": "tool", "name": "..."},会导致错误。只有 tool_choice: {"type": "auto"}(默认)和 tool_choice: {"type": "none"} 与扩展思考兼容。
Claude Mythos Preview 不支持强制工具使用。使用 tool_choice: {"type": "any"} 或 tool_choice: {"type": "tool", "name": "..."} 的请求在此模型上会返回 400 错误。使用 tool_choice: {"type": "auto"}(默认)或 tool_choice: {"type": "none"},并依靠提示来影响工具选择。
测试表明这不会降低性能。如果你希望模型在请求使用特定工具的同时提供自然语言上下文或解释,可以使用 {"type": "auto"} 作为 tool_choice(默认),并在 user 消息中添加明确的说明。例如:What's the weather like in London? Use the get_weather tool in your response.
使用严格工具保证工具调用
将 tool_choice: {"type": "any"} 与严格工具使用结合使用,以保证你的工具之一将被调用,并且工具输入严格遵循你的 schema。在工具定义上设置 strict: true 以启用 schema 验证。
使用工具时的模型响应
使用工具时,Claude 通常会在调用工具之前评论它正在做什么或自然地回应用户。
例如,给定提示 "What's the weather like in San Francisco right now, and what time is it there?",Claude 可能会这样回应:
{
"role": "assistant",
"content": [
{
"type": "text",
"text": "I'll help you check the current weather and time in San Francisco."
},
{
"type": "tool_use",
"id": "toolu_01A09q90qw90lq917835lq9",
"name": "get_weather",
"input": { "location": "San Francisco, CA" }
}
]
}
这种自然的响应风格有助于用户理解 Claude 正在做什么,并创造更具对话性的交互。你可以通过系统提示和在提示中提供 <examples> 来引导这些响应的风格和内容。
值得注意的是,Claude 在解释其操作时可能会使用各种措辞和方法。你的代码应该像处理任何其他助手生成的文本一样处理这些响应,而不是依赖特定的格式约定。