Claude에서의 도구 사용
Claude에서의 도구 사용 (Tool use with Claude)
도구 사용(함수 호출이라고도 해요)은 Claude가 우리가 정의한 함수나 Anthropic이 제공하는 함수를 호출할 수 있게 해 줘요. Claude는 사용자 요청과 도구 설명을 보고 언제 도구를 호출할지 결정한 뒤, 우리 애플리케이션이 실행하는 구조화된 호출(클라이언트 도구)이나 Anthropic이 실행하는 호출(서버 도구)을 반환해요. 도구가 어디서 실행되는지, 언제 호출되는지, 어떤 도구가 내 작업에 맞는지부터 차근차근 알아가 보아요.
출처: 문서
본문
도구 사용(함수 호출이라고도 함)은 우리가 정의한 함수나 Anthropic이 제공하는 함수를 Claude가 호출할 수 있게 해 줘요. Claude는 사용자 요청과 도구의 설명을 바탕으로 언제 도구를 호출할지 결정해요. 그런 다음 우리 애플리케이션이 실행하는 구조화된 호출(클라이언트 도구)이나 Anthropic이 실행하는 호출(서버 도구)을 반환해요.
여기 Anthropic이 대신 실행해 주는 서버 도구인 웹 검색 도구를 쓰는 최소 예시가 있어요:
ant messages create --transform content --format yaml \
--model claude-opus-5-5 \
--max-tokens 1024 \
--tool '{type: web_search_20260209, name: web_search}' \
--message '{role: user, content: "What is the latest on the Mars rover?"}'
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-5-5",
max_tokens=1024,
tools=[{"type": "web_search_20260209", "name": "web_search"}],
messages=[{"role": "user", "content": "What's the latest on the Mars rover?"}],
)
print(response.content)
const client = new Anthropic();
const response = await client.messages.create({
model: "claude-opus-5-5",
max_tokens: 1024,
tools: [{ type: "web_search_20260209", name: "web_search" }],
messages: [{ role: "user", content: "What's the latest on the Mars rover?" }]
});
console.log(response.content);
AnthropicClient client = new();
var parameters = new MessageCreateParams
{
Model = Model.ClaudeOpus5_5,
MaxTokens = 1024,
Tools = [new ToolUnion(new WebSearchTool20260209())],
Messages = [new() { Role = Role.User, Content = "What's the latest on the Mars rover?" }]
};
var message = await client.Messages.Create(parameters);
Console.WriteLine(message.Content);
client := anthropic.NewClient()
response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
Model: anthropic.ModelClaudeOpus5_5,
MaxTokens: 1024,
Tools: []anthropic.ToolUnionParam{
{OfWebSearchTool20260209: &anthropic.WebSearchTool20260209Param{}},
},
Messages: []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock("What's the latest on the Mars rover?")),
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(response.Content)
import com.anthropic.models.messages.WebSearchTool20260209;
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
MessageCreateParams params = MessageCreateParams.builder()
.model(Model.CLAUDE_OPUS_5_5)
.maxTokens(1024L)
.addTool(WebSearchTool20260209.builder().build())
.addUserMessage("What's the latest on the Mars rover?")
.build();
Message response = client.messages().create(params);
IO.println(response.content());
}
$client = new Client();
$message = $client->messages->create(
model: 'claude-opus-5-5',
maxTokens: 1024,
tools: [
['type' => 'web_search_20260209', 'name' => 'web_search'],
],
messages: [
['role' => 'user', 'content' => "What's the latest on the Mars rover?"],
],
);
echo $message;
client = Anthropic::Client.new
message = client.messages.create(
model: "claude-opus-5-5",
max_tokens: 1024,
tools: [{ type: "web_search_20260209", name: "web_search" }],
messages: [{ role: "user", content: "What's the latest on the Mars rover?" }]
)
puts message.content
Claude는 Anthropic의 인프라에서 검색을 실행하고 인용된 결과를 같은 응답에 담아 돌려줘요. 우리가 정의한 함수를 Claude가 호출하게 하려면 input_schema가 있는 도구를 전달하고, Claude가 tool_use 블록을 반환하면 그 호출을 실행하면 돼요. 도구 사용의 동작 방식에서 그 왕복 과정을 처음부터 끝까지 보여줘요. 도구 정의하기와 도구 호출 처리하기에 대해 더 알아보세요.
도구 사용의 동작 방식 (How tool use works)
도구는 주로 코드가 어디서 실행되는지에 따라 달라져요. 클라이언트 도구(사용자 정의 도구와 bash, text_editor 같은 Anthropic 정의 스키마를 가진 도구 포함)는 우리 애플리케이션에서 실행돼요. Claude는 stop_reason: "tool_use"와 하나 이상의 tool_use 블록으로 응답해요. 우리 코드가 그 작업을 실행하고 tool_result를 다시 보내 주는 구조예요. 서버 도구(web_search, web_fetch, code_execution, tool_search 등)는 Anthropic의 인프라에서 실행돼요. Claude가 클라이언트 도구와 같은 병렬 도구 호출 그룹 안에서 호출하지 않는 한, 실행을 처리할 필요 없이 결과를 바로 볼 수 있어요(정지 이유와 폴백 참고).
클라이언트 도구에 대한 전체 왕복 과정을 보여 드릴게요. 첫 요청이 get_weather 도구를 정의하고, Claude가 그 도구를 호출해 질문에 답해요. 응답이 tool_use 블록을 싣고 오면 우리 코드가 조회를 실행하고, 두 번째 요청이 tool_result 블록에 그 결과를 보내서 Claude가 답변할 수 있게 해 줘요.
Run the tool, then send the result back in a tool_result block.
Claude uses the result to answer the original question.
WEATHER="15 degrees Celsius, partly cloudy"
curl -s https://api.anthropic.com/v1/messages
-H "x-api-key: $ANTHR...KEY"
-H "anthropic-version: 2023-06-01"
-H "content-type: application/json"
-d "$(jq -n
--argjson tools "$TOOLS"
--arg msg "$USER_MSG"
--argjson assistant "$(echo "$RESPONSE" | jq '.content')"
--arg tool_use_id "$(echo "$TOOL_USE" | jq -r '.id')"
--arg weather "$WEATHER"
'{
model: "claude-opus-5-5",
max_tokens: 1024,
tools: $tools,
tool_choice: {type: "auto", disable_parallel_tool_use: true},
messages: [
{role: "user", content: $msg},
{role: "assistant", content: $assistant},
{role: "user", content: [
{type: "tool_result", tool_use_id: $tool_use_id, content: $weather}
]}
]
}')"
```bash CLI
# ant reads the request body as YAML on stdin; jq carries the conversation
# state into the second request.
USER_MSG="What's the weather in San Francisco?"
MESSAGES=$(jq -n --arg msg "$USER_MSG" '[{role: "user", content: $msg}]')
call_api() {
{
cat <<'YAML'
model: claude-opus-5-5
max_tokens: 1024
# Ask for at most one tool call per turn.
tool_choice: {type: auto, disable_parallel_tool_use: true}
tools:
- name: get_weather
description: Get the current weather for a given location.
input_schema:
type: object
properties:
location: {type: string, description: "City and state, e.g. San Francisco, CA"}
required: [location]
YAML
printf 'messages: %s\n' "$MESSAGES"
} | ant messages create --format json
}
# Claude replies with a tool_use block naming the tool and its arguments.
RESPONSE=$(call_api)
TOOL_USE=$(jq '.content[] | select(.type == "tool_use")' <<<"$RESPONSE")
echo "Claude called $(jq -r '.name' <<<"$TOOL_USE") with $(jq -c '.input' <<<"$TOOL_USE")"
# Run the tool, then send the result back in a tool_result block.
WEATHER="15 degrees Celsius, partly cloudy"
MESSAGES=$(jq \
--argjson assistant "$(jq '.content' <<<"$RESPONSE")" \
--arg tool_use_id "$(jq -r '.id' <<<"$TOOL_USE")" \
--arg weather "$WEATHER" \
'. + [
{role: "assistant", content: $assistant},
{role: "user", content: [
{type: "tool_result", tool_use_id: $tool_use_id, content: $weather}
]}
]' <<<"$MESSAGES")
# Claude uses the result to answer the original question.
call_api
client = anthropic.Anthropic()
tools = [
{
"name": "get_weather",
"description": "Get the current weather for a given location.",
"input_schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City and state, e.g. San Francisco, CA",
}
},
"required": ["location"],
},
}
]
messages = [{"role": "user", "content": "What's the weather in San Francisco?"}]
# Claude replies with a tool_use block naming the tool and its arguments.
response = client.messages.create(
model="claude-opus-5-5",
max_tokens=1024,
tools=tools,
# Ask for at most one tool call per turn.
tool_choice={"type": "auto", "disable_parallel_tool_use": True},
messages=messages,
)
tool_use = next(block for block in response.content if block.type == "tool_use")
print(f"Claude called {tool_use.name} with {json.dumps(tool_use.input)}")
# Run the tool, then send the result back in a tool_result block.
weather = "15 degrees Celsius, partly cloudy" # your weather lookup goes here
messages += [
{"role": "assistant", "content": response.content},
{
"role": "user",
"content": [
{"type": "tool_result", "tool_use_id": tool_use.id, "content": weather}
],
},
]
followup = client.messages.create(
model="claude-opus-5-5",
max_tokens=1024,
tools=tools,
tool_choice={"type": "auto", "disable_parallel_tool_use": True},
messages=messages,
)
# Claude uses the result to answer the original question.
final_text = next(block for block in followup.content if block.type == "text")
print(final_text.text)
const client = new Anthropic();
const tools: Anthropic.Tool[] = [
{
name: "get_weather",
description: "Get the current weather for a given location.",
input_schema: {
type: "object",
properties: {
location: { type: "string", description: "City and state, e.g. San Francisco, CA" }
},
required: ["location"]
}
}
];
const messages: Anthropic.MessageParam[] = [
{ role: "user", content: "What's the weather in San Francisco?" }
];
// Claude replies with a tool_use block naming the tool and its arguments.
const response = await client.messages.create({
model: "claude-opus-5-5",
max_tokens: 1024,
tools,
// Ask for at most one tool call per turn.
tool_choice: { type: "auto", disable_parallel_tool_use: true },
messages
});
const toolUse = response.content.find(
(block): block is Anthropic.ToolUseBlock => block.type === "tool_use"
)!;
console.log(`Claude called ${toolUse.name} with ${JSON.stringify(toolUse.input)}`);
// Run the tool, then send the result back in a tool_result block.
const weather = "15 degrees Celsius, partly cloudy"; // your weather lookup goes here
messages.push(
{ role: "assistant", content: response.content },
{
role: "user",
content: [{ type: "tool_result", tool_use_id: toolUse.id, content: weather }]
}
);
const followup = await client.messages.create({
model: "claude-opus-5-5",
max_tokens: 1024,
tools,
tool_choice: { type: "auto", disable_parallel_tool_use: true },
messages
});
// Claude uses the result to answer the original question.
const finalText = followup.content.find(
(block): block is Anthropic.TextBlock => block.type === "text"
)!;
console.log(finalText.text);
AnthropicClient client = new();
List<ToolUnion> tools =
[
new ToolUnion(new Tool()
{
Name = "get_weather",
Description = "Get the current weather for a given location.",
InputSchema = new InputSchema()
{
Properties = new Dictionary<string, JsonElement>
{
["location"] = JsonSerializer.SerializeToElement(new
{
type = "string",
description = "City and state, e.g. San Francisco, CA",
}),
},
Required = ["location"],
},
}),
];
// Ask for at most one tool call per turn.
var toolChoice = new ToolChoice(new ToolChoiceAuto { DisableParallelToolUse = true });
const string userPrompt = "What's the weather in San Francisco?";
// Claude replies with a tool_use block naming the tool and its arguments.
var response = await client.Messages.Create(new MessageCreateParams
{
Model = Model.ClaudeOpus5_5,
MaxTokens = 1024,
Tools = tools,
ToolChoice = toolChoice,
Messages = [new() { Role = Role.User, Content = userPrompt }],
});
ToolUseBlock? toolUse = null;
foreach (var block in response.Content)
{
if (block.TryPickToolUse(out var picked))
{
toolUse = picked;
break;
}
}
Console.WriteLine($"Claude called {toolUse!.Name} with {JsonSerializer.Serialize(toolUse.Input)}");
// Run the tool, then send the result back in a tool_result block.
var weather = "15 degrees Celsius, partly cloudy";
List<ContentBlockParam> toolResults =
[
new ContentBlockParam(new ToolResultBlockParam()
{
ToolUseID = toolUse.ID,
Content = weather,
}),
];
var followup = await client.Messages.Create(new MessageCreateParams
{
Model = Model.ClaudeOpus5_5,
MaxTokens = 1024,
Tools = tools,
ToolChoice = toolChoice,
Messages =
[
new() { Role = Role.User, Content = userPrompt },
new() { Role = Role.Assistant, Content = response.Content.Select(block => new ContentBlockParam(block.Json)).ToList() },
new() { Role = Role.User, Content = new MessageParamContent(toolResults) },
],
});
// Claude uses the result to answer the original question.
foreach (var block in followup.Content)
{
if (block.TryPickText(out var text))
{
Console.WriteLine(text.Text);
}
}
client := anthropic.NewClient()
ctx := context.Background()
tools := []anthropic.ToolUnionParam{
{OfTool: &anthropic.ToolParam{
Name: "get_weather",
Description: anthropic.String("Get the current weather for a given location."),
InputSchema: anthropic.ToolInputSchemaParam{
Properties: map[string]any{
"location": map[string]any{
"type": "string",
"description": "City and state, e.g. San Francisco, CA",
},
},
Required: []string{"location"},
},
}},
}
// Ask for at most one tool call per turn.
toolChoice := anthropic.ToolChoiceUnionParam{
OfAuto: &anthropic.ToolChoiceAutoParam{DisableParallelToolUse: anthropic.Bool(true)},
}
messages := []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock("What's the weather in San Francisco?")),
}
// Claude replies with a tool_use block naming the tool and its arguments.
response, err := client.Messages.New(ctx, anthropic.MessageNewParams{
Model: anthropic.ModelClaudeOpus5_5,
MaxTokens: 1024,
Tools: tools,
ToolChoice: toolChoice,
Messages: messages,
})
if err != nil {
log.Fatal(err)
}
var toolUse anthropic.ContentBlockUnion
for _, block := range response.Content {
if block.Type == "tool_use" {
toolUse = block
break
}
}
fmt.Printf("Claude called %s with %s\n", toolUse.Name, string(toolUse.Input))
// Run the tool, then send the result back in a tool_result block.
weather := "15 degrees Celsius, partly cloudy"
var assistantContent []anthropic.ContentBlockParamUnion
for _, block := range response.Content {
assistantContent = append(assistantContent, block.ToParam())
}
messages = append(messages,
anthropic.NewAssistantMessage(assistantContent...),
anthropic.NewUserMessage(anthropic.NewToolResultBlock(toolUse.ID, weather, false)),
)
followup, err := client.Messages.New(ctx, anthropic.MessageNewParams{
Model: anthropic.ModelClaudeOpus5_5,
MaxTokens: 1024,
Tools: tools,
ToolChoice: toolChoice,
Messages: messages,
})
if err != nil {
log.Fatal(err)
}
// Claude uses the result to answer the original question.
for _, block := range followup.Content {
if block.Type == "text" {
fmt.Println(block.Text)
}
}
import com.anthropic.core.JsonValue;
import com.anthropic.models.messages.ContentBlockParam;
// ...
import com.anthropic.models.messages.Tool;
import com.anthropic.models.messages.Tool.InputSchema;
import com.anthropic.models.messages.ToolChoiceAuto;
import com.anthropic.models.messages.ToolResultBlockParam;
import com.anthropic.models.messages.ToolUseBlock;
// ...
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
Tool weatherTool = Tool.builder()
.name("get_weather")
.description("Get the current weather for a given location.")
.inputSchema(InputSchema.builder()
.properties(JsonValue.from(Map.of(
"location", Map.of(
"type", "string",
"description", "City and state, e.g. San Francisco, CA"
)
)))
.required(List.of("location"))
.build())
.build();
// Ask for at most one tool call per turn.
ToolChoiceAuto toolChoice = ToolChoiceAuto.builder()
.disableParallelToolUse(true)
.build();
String userPrompt = "What's the weather in San Francisco?";
// Claude replies with a tool_use block naming the tool and its arguments.
Message response = client.messages().create(MessageCreateParams.builder()
.model(Model.CLAUDE_OPUS_5_5)
.maxTokens(1024L)
.addTool(weatherTool)
.toolChoice(toolChoice)
.addUserMessage(userPrompt)
.build());
ToolUseBlock toolUse = response.content().stream()
.flatMap(block -> block.toolUse().stream())
.findFirst()
.orElseThrow();
IO.println("Claude called " + toolUse.name() + " with " + toolUse._input());
// Run the tool, then send the result back in a tool_result block.
String weather = "15 degrees Celsius, partly cloudy";
Message followup = client.messages().create(MessageCreateParams.builder()
.model(Model.CLAUDE_OPUS_5_5)
.maxTokens(1024L)
.addTool(weatherTool)
.toolChoice(toolChoice)
.addUserMessage(userPrompt)
.addMessage(response)
.addUserMessageOfBlockParams(List.of(ContentBlockParam.ofToolResult(
ToolResultBlockParam.builder()
.toolUseId(toolUse.id())
.content(weather)
.build())))
.build());
// Claude uses the result to answer the original question.
followup.content().stream()
.flatMap(block -> block.text().stream())
.forEach(textBlock -> IO.println(textBlock.text()));
}
use Anthropic\Messages\ToolChoiceAuto;
$client = new Client();
$tools = [
[
'name' => 'get_weather',
'description' => 'Get the current weather for a given location.',
'input_schema' => [
'type' => 'object',
'properties' => [
'location' => [
'type' => 'string',
'description' => 'City and state, e.g. San Francisco, CA',
],
],
'required' => ['location'],
],
],
];
$userMessage = ['role' => 'user', 'content' => "What's the weather in San Francisco?"];
// Ask for at most one tool call per turn.
$toolChoice = ToolChoiceAuto::with(disableParallelToolUse: true);
// Claude replies with a tool_use block naming the tool and its arguments.
$response = $client->messages->create(
model: 'claude-opus-5-5',
maxTokens: 1024,
tools: $tools,
toolChoice: $toolChoice,
messages: [$userMessage],
);
$toolUse = null;
foreach ($response->content as $block) {
if ($block->type === 'tool_use') {
$toolUse = $block;
break;
}
}
printf("Claude called %s with %s\n", $toolUse->name, json_encode($toolUse->input));
// Run the tool, then send the result back in a tool_result block.
$weather = '15 degrees Celsius, partly cloudy';
$followup = $client->messages->create(
model: 'claude-opus-5-5',
maxTokens: 1024,
tools: $tools,
toolChoice: $toolChoice,
messages: [
$userMessage,
['role' => 'assistant', 'content' => $response->content],
[
'role' => 'user',
'content' => [
[
'type' => 'tool_result',
'tool_use_id' => $toolUse->id,
'content' => $weather,
],
],
],
],
);
// Claude uses the result to answer the original question.
foreach ($followup->content as $block) {
if ($block->type === 'text') {
echo $block->text, "\n";
}
}
client = Anthropic::Client.new
tools = [
{
name: "get_weather",
description: "Get the current weather for a given location.",
input_schema: {
type: "object",
properties: {
location: {type: "string", description: "City and state, e.g. San Francisco, CA"}
},
required: ["location"]
}
}
]
messages = [{role: "user", content: "What's the weather in San Francisco?"}]
# Claude replies with a tool_use block naming the tool and its arguments.
response = client.messages.create(
model: "claude-opus-5-5",
max_tokens: 1024,
tools: tools,
# Ask for at most one tool call per turn.
tool_choice: {type: "auto", disable_parallel_tool_use: true},
messages: messages
)
tool_use = response.content.find { |block| block.type == :tool_use }
puts "Claude called #{tool_use.name} with #{JSON.generate(tool_use.input)}"
# Run the tool, then send the result back in a tool_result block.
weather = "15 degrees Celsius, partly cloudy"
messages += [
{role: "assistant", content: response.content},
{
role: "user",
content: [
{type: "tool_result", tool_use_id: tool_use.id, content: weather}
]
}
]
followup = client.messages.create(
model: "claude-opus-5-5",
max_tokens: 1024,
tools: tools,
tool_choice: {type: "auto", disable_parallel_tool_use: true},
messages: messages
)
# Claude uses the result to answer the original question.
final_text = followup.content.find { |block| block.type == :text }
puts final_text.text
Claude called get_weather with {"location": "San Francisco, CA"}
The current weather in San Francisco is 15 degrees Celsius with partly cloudy skies.
도구 호출 처리하기는 결과 형식과 오류 신호를 포함해 각 단계를 자세히 다뤄요. 병렬 도구 사용은 한꺼번에 여러 도구를 호출하는 응답을 다루고요. 이 왕복 과정을 직접 작성하지 않으려면 도구 러너를 쓰세요. SDK가 도구를 실행하고 결과를 자동으로 다시 보내 줘요.
에이전틱 루프와 각 접근 방식을 언제 고를지 포함한 전체 개념 모델은 도구 사용의 동작 방식을 보세요.
Model Context Protocol(MCP) 서버에 연결하려면 MCP 커넥터를 보세요. 직접 MCP 클라이언트를 만들려면 Model Context Protocol 안내의 MCP 클라이언트 만들기를 참고하세요.
Claude가 도구를 사용할 때 (When Claude uses tools)
기본 tool_choice인 {"type": "auto"}에서는 Claude가 매 턴 도구를 호출할지 직접 응답할지를 결정해요. 요청이 그 도구가 설명된 능력과 일치하고 답이 이미 컨텍스트에 없으면 도구를 호출하고, 안정적인 지식, 창의적 작업, 대화형 턴에는 직접 응답해요.
이 경계는 시스템 프롬프트로 조정할 수 있어요. 예상했는데 Claude가 도구를 호출하지 않으면 "Use the tools to investigate before responding." 같은 가벼운 지침이 도구 사용을 늘려 줘요. 더 강한 형태인 "Always call a tool first before responding."는 더 밀어붙이고요. 반대로 "Use your judgment about whether to call a tool or respond directly."는 트리거 동작을 보수적으로 유지해요.
프롬프트에 의존하지 않고 도구 호출을 강제하려면 tool_choice를 설정하세요.
커스텀 도구 정의에 strict: true를 추가하면 Claude의 도구 호출이 항상 우리 스키마와 정확히 일치하게 할 수 있어요. 엄격한 도구 사용을 참고하세요.
각 서버 도구의 페이지는 자체 트리거 경계를 더 자세히 설명해요.
예를 들어 location 매개변수가 필수인 get_weather 도구가 있을 때 위치를 지정하지 않고 "What's the weather?"라고 묻으면 Claude(특히 Claude Sonnet)는 우리가 주지 않은 값을 추측할 수 있어요:
{
"type": "tool_use",
"id": "toolu_01A09q90qw90lq917835lq9",
"name": "get_weather",
"input": { "location": "New York, NY", "unit": "fahrenheit" }
}
이 동작은 보장되지 않아요. 특히 더 모호한 프롬프트와 덜 강력한 모델에서는 그럴 수 있어요.
도구 고르기 (Choose a tool)
type 문자열, 버전, beta 헤더는 도구 레퍼런스를 참고하세요.
우리의 도구 (Your own tools)
우리가 정의하는 도구는 스키마를 직접 쓰고 애플리케이션이 각 호출을 실행해요.
Anthropic 스키마 클라이언트 도구 (Anthropic-schema client tools)
Anthropic이 스키마를 공개하고 Claude가 그걸 학습시켜요. 그래도 각 호출을 실행하고 tool_result를 반환하는 건 우리 애플리케이션 몫이에요.
서버 도구 (Server tools)
서버 도구는 Anthropic의 인프라에서 실행되고 우리 애플리케이션에는 핸들러 코드가 필요 없어요. 공통으로 적용되는 동작 방식은 서버 도구를 보세요.
가격 (Pricing)
도구 사용 요청의 가격은 다음에 따라 책정돼요:
- 모델에 보낸 입력 토큰 총수(
tools매개변수에 포함된 것 포함) - 생성된 출력 토큰 수
- 서버 측 도구의 경우, 추가 사용량 기반 가격(예: 웹 검색은 검색 1회당 요금)
클라이언트 측 도구는 다른 Claude API 요청과 같은 가격이지만, 서버 측 도구는 그 특정 사용량에 따라 추가 요금이 발생할 수 있어요.
도구 사용에서 오는 추가 토큰은 다음에서 나와요:
- API 요청의
tools매개변수(도구 이름, 설명, 스키마) - API 요청과 응답의
tool_use콘텐츠 블록 - API 요청의
tool_result콘텐츠 블록
tools를 쓰면 API가 도구 사용을 가능하게 하는 특별한 시스템 프롬프트도 모델에 자동으로 포함시켜요. 각 모델에 필요한 도구 사용 토큰 수는 다음 표에 나와 있어요(앞서 언급한 추가 토큰 제외). 이 표는 도구가 최소 1개 제공된다고 가정한다는 점에 주의하세요. tools를 제공하지 않으면 none 도구 선택은 시스템 프롬프트 토큰을 0개만 사용해요.
| Model | Tool use system prompt tokens: auto, none | Tool use system prompt tokens: any, tool |
|---|---|---|
| Claude Opus 5.5 | 286 tokens | |
| Claude Opus 5 | 286 tokens | 406 tokens |
| Claude Opus 4.8 | 290 tokens | 410 tokens |
| Claude Opus 4.7 | 675 tokens | 804 tokens |
| Claude Opus 4.6 | 497 tokens | 589 tokens |
| Claude Opus 4.5 | 496 tokens | 588 tokens |
| Claude Opus 4.1 (retired, except on Bedrock and Google Cloud) | 313 tokens | 315 tokens |
| Claude Opus 4 (retired, except on Google Cloud) | 313 tokens | 315 tokens |
| Claude Sonnet 5 | 354 tokens | 474 tokens |
| Claude Sonnet 4.6 | 497 tokens | 589 tokens |
| Claude Sonnet 4.5 | 496 tokens | 588 tokens |
| Claude Sonnet 4 (retired, except on Bedrock and Google Cloud) | 313 tokens | 315 tokens |
| Claude Haiku 4.5 | 496 tokens | 588 tokens |
| Claude Haiku 3.5 (retired, except on Bedrock and Google Cloud) | 264 tokens | 355 tokens |
- auto, none:
tool_choice가 auto나 none일 때의 수치예요. - any, tool:
tool_choice가 any나 tool일 때의 수치예요. - Retired: 다른 클라우드 플랫폼에서는 여전히 사용 가능할 수 있어요. 자세한 내용은 모델 폐기를 보세요.
이 토큰 수치들은 정상 입력·출력 토큰에 더해져 요청의 총 비용을 계산해요.
현재 모델별 가격은 모델 개요 표를 보세요.
도구 사용 프롬프트를 보내면 다른 API 요청과 마찬가지로 응답의 usage 메트릭에 입력·출력 토큰 수가 모두 포함돼요.
일부 서버 도구는 토큰 위에 사용량 기반 요금을 추가해요. 요율은 웹 검색 도구와 코드 실행 도구를 보세요.