服务器工具
使用 Anthropic 执行的工具:server_tool_use 块、pause_turn 续接和域名过滤。
本页介绍服务器执行工具的共享机制:server_tool_use 块、pause_turn 续接、ZDR 注意事项和域名过滤。有关各个工具,请参见工具参考。
server_tool_use 块
server_tool_use 块在服务器执行的工具运行时出现在 Claude 的响应中。其 id 字段使用 srvtoolu_ 前缀,以区别于客户端工具调用:
{
"type": "server_tool_use",
"id": "srvtoolu_01A2B3C4D5E6F7G8H9",
"name": "web_search",
"input": { "query": "latest quantum computing breakthroughs" }
}
API 在内部执行工具。你可以在响应中看到调用及其结果,但你不需要处理执行。与客户端 tool_use 块不同,你不需要用 tool_result 响应。结果块在同一个助手轮次中紧跟 server_tool_use 块之后出现。
服务端循环和 pause_turn
使用 web search 等服务器工具时,API 可能返回 pause_turn 停止原因,表示 API 已暂停一个长时间运行的轮次。
以下是处理 pause_turn 停止原因的方法:
import anthropic
client = anthropic.Anthropic()
# 使用 web search 的初始请求
response = client.messages.create(
model="claude-opus-4-7",
max_tokens=1024,
messages=[
{
"role": "user",
"content": "Search for comprehensive information about quantum computing breakthroughs in 2025",
}
],
tools=[{"type": "web_search_20250305", "name": "web_search", "max_uses": 10}],
)
# 检查响应是否有 pause_turn 停止原因
if response.stop_reason == "pause_turn":
# 使用暂停的内容继续对话
messages = [
{
"role": "user",
"content": "Search for comprehensive information about quantum computing breakthroughs in 2025",
},
{"role": "assistant", "content": response.content},
]
# 发送续接请求
continuation = client.messages.create(
model="claude-opus-4-7",
max_tokens=1024,
messages=messages,
tools=[{"type": "web_search_20250305", "name": "web_search", "max_uses": 10}],
)
print(continuation)
else:
print(response)
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
async function main() {
// 使用 web search 的初始请求
const response = await client.messages.create({
model: "claude-opus-4-7",
max_tokens: 1024,
messages: [
{
role: "user",
content:
"Search for comprehensive information about quantum computing breakthroughs in 2025"
}
],
tools: [
{
type: "web_search_20250305",
name: "web_search",
max_uses: 10
}
]
});
// 检查响应是否有 pause_turn 停止原因
if (response.stop_reason === "pause_turn") {
// 使用暂停的内容继续对话
const messages: Anthropic.MessageParam[] = [
{
role: "user",
content:
"Search for comprehensive information about quantum computing breakthroughs in 2025"
},
{ role: "assistant", content: response.content }
];
// 发送续接请求
const continuation = await client.messages.create({
model: "claude-opus-4-7",
max_tokens: 1024,
messages: messages,
tools: [
{
type: "web_search_20250305",
name: "web_search",
max_uses: 10
}
]
});
console.log(continuation);
} else {
console.log(response);
}
}
main().catch(console.error);
using Anthropic;
using Anthropic.Models.Messages;
using System;
using System.Linq;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
AnthropicClient client = new();
var parameters = new MessageCreateParams
{
Model = "claude-opus-4-7",
MaxTokens = 1024,
Messages = [
new() {
Role = Role.User,
Content = "Search for comprehensive information about quantum computing breakthroughs in 2025"
}
],
Tools = [new ToolUnion(new WebSearchTool20250305() { MaxUses = 10 })]
};
var response = await client.Messages.Create(parameters);
if (response.StopReason == "pause_turn")
{
var continuationParams = new MessageCreateParams
{
Model = "claude-opus-4-7",
MaxTokens = 1024,
Messages = [
new() {
Role = Role.User,
Content = "Search for comprehensive information about quantum computing breakthroughs in 2025"
},
new() {
Role = Role.Assistant,
Content = response.Content.Select(block => new ContentBlockParam(block.Json)).ToList()
}
],
Tools = [new ToolUnion(new WebSearchTool20250305() { MaxUses = 10 })]
};
var continuation = await client.Messages.Create(continuationParams);
Console.WriteLine(continuation);
}
else
{
Console.WriteLine(response);
}
}
}
package main
import (
"context"
"fmt"
"log"
"github.com/anthropics/anthropic-sdk-go"
)
func main() {
client := anthropic.NewClient()
webSearchTool := []anthropic.ToolUnionParam{
{OfWebSearchTool20250305: &anthropic.WebSearchTool20250305Param{
MaxUses: anthropic.Int(10),
}},
}
response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
Model: anthropic.ModelClaudeOpus4_7,
MaxTokens: 1024,
Messages: []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock("Search for comprehensive information about quantum computing breakthroughs in 2025")),
},
Tools: webSearchTool,
})
if err != nil {
log.Fatal(err)
}
if response.StopReason == "pause_turn" {
// 将响应内容转换为助手消息的参数类型
var contentParams []anthropic.ContentBlockParamUnion
for _, block := range response.Content {
contentParams = append(contentParams, block.ToParam())
}
continuation, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
Model: anthropic.ModelClaudeOpus4_7,
MaxTokens: 1024,
Messages: []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock("Search for comprehensive information about quantum computing breakthroughs in 2025")),
anthropic.NewAssistantMessage(contentParams...),
},
Tools: webSearchTool,
})
if err != nil {
log.Fatal(err)
}
fmt.Println(continuation)
} else {
fmt.Println(response)
}
}
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Message;
import com.anthropic.models.messages.StopReason;
import com.anthropic.models.messages.WebSearchTool20250305;
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
MessageCreateParams params = MessageCreateParams.builder()
.model("claude-opus-4-7")
.maxTokens(1024L)
.addUserMessage("Search for comprehensive information about quantum computing breakthroughs in 2025")
.addTool(WebSearchTool20250305.builder()
.maxUses(10L)
.build())
.build();
Message response = client.messages().create(params);
if (response.stopReason().isPresent()
&& response.stopReason().get().equals(StopReason.PAUSE_TURN)) {
MessageCreateParams continuationParams = MessageCreateParams.builder()
.model("claude-opus-4-7")
.maxTokens(1024L)
.addUserMessage("Search for comprehensive information about quantum computing breakthroughs in 2025")
.addMessage(response)
.addTool(WebSearchTool20250305.builder()
.maxUses(10L)
.build())
.build();
Message continuation = client.messages().create(continuationParams);
IO.println(continuation);
} else {
IO.println(response);
}
}
<?php
use Anthropic\Client;
$client = new Client(apiKey: getenv("ANTHROPIC_API_KEY"));
$response = $client->messages->create(
maxTokens: 1024,
messages: [
[
'role' => 'user',
'content' => 'Search for comprehensive information about quantum computing breakthroughs in 2025'
]
],
model: 'claude-opus-4-7',
tools: [
[
'type' => 'web_search_20250305',
'name' => 'web_search',
'max_uses' => 10
]
],
);
if ($response->stopReason === 'pause_turn') {
$messages = [
[
'role' => 'user',
'content' => 'Search for comprehensive information about quantum computing breakthroughs in 2025'
],
[
'role' => 'assistant',
'content' => $response->content
]
];
$continuation = $client->messages->create(
maxTokens: 1024,
messages: $messages,
model: 'claude-opus-4-7',
tools: [
[
'type' => 'web_search_20250305',
'name' => 'web_search',
'max_uses' => 10
]
],
);
echo $continuation;
} else {
echo $response;
}
require "anthropic"
client = Anthropic::Client.new
response = client.messages.create(
model: "claude-opus-4-7",
max_tokens: 1024,
messages: [
{
role: "user",
content:
"Search for comprehensive information about quantum computing breakthroughs in 2025"
}
],
tools: [
{
type: "web_search_20250305",
name: "web_search",
max_uses: 10
}
]
)
if response.stop_reason == :pause_turn
messages = [
{
role: "user",
content: "Search for comprehensive information about quantum computing breakthroughs in 2025"
},
{
role: "assistant",
content: response.content
}
]
continuation = client.messages.create(
model: "claude-opus-4-7",
max_tokens: 1024,
messages: messages,
tools: [
{
type: "web_search_20250305",
name: "web_search",
max_uses: 10
}
]
)
puts continuation
else
puts response
end
处理 pause_turn 时:
- 继续对话: 在后续请求中原样传回暂停的响应,让 Claude 继续其轮次
- 按需修改: 你可以选择在继续之前修改内容,以中断或重定向对话
- 保留工具状态: 在续接请求中包含相同的工具以维持功能
ZDR 和 allowed_callers
Web search(web_search_20250305)和 web fetch(web_fetch_20250910)的基本版本符合零数据留存 (ZDR) 条件。
带动态过滤的 _20260209 版本默认不符合 ZDR 条件,因为动态过滤内部依赖代码执行。
要在 ZDR 下使用 _20260209 服务器工具,请通过在工具上设置 "allowed_callers": ["direct"] 来禁用动态过滤:
{
"type": "web_search_20260209",
"name": "web_search",
"allowed_callers": ["direct"]
}
这将工具限制为仅直接调用,绕过内部代码执行步骤。
即使 web fetch 在符合 ZDR 的配置中使用,网站发布者仍可能保留 Claude 从其网站获取内容时传递给 URL 的任何参数。
域名过滤
访问网络的服务器工具接受 allowed_domains 和 blocked_domains 参数来控制 Claude 可以访问哪些域名。
使用域名过滤器时:
- 域名不应包含 HTTP/HTTPS 协议(使用
example.com而非https://example.com) - 子域名会自动包含(
example.com覆盖docs.example.com) - 特定子域名将结果限制为仅该子域名(
docs.example.com仅返回该子域名的结果,不返回example.com或api.example.com的结果) - 支持子路径,匹配路径后的任何内容(
example.com/blog匹配example.com/blog/post-1) - 你可以使用
allowed_domains或blocked_domains,但不能在同一请求中同时使用
通配符支持:
- 每个域名条目只允许一个通配符(
*),且必须出现在域名部分之后(在路径中) - 有效:
example.com/*、example.com/*/articles - 无效:
*.example.com、ex*.com、example.com/*/news/*
无效的域名格式会返回 invalid_tool_input 工具错误。
请求级域名限制必须与 Claude Console 中配置的组织级域名限制兼容。请求级域名只能进一步限制域名,不能覆盖或扩展超出组织级列表。如果你的请求包含与组织设置冲突的域名,API 会返回验证错误。
请注意,域名中的 Unicode 字符可能通过同形攻击创建安全漏洞,其中来自不同脚本的视觉相似字符可以绕过域名过滤器。例如,аmazon.com(使用西里尔字母 'а')可能看起来与 amazon.com 完全相同,但代表不同的域名。
配置域名允许/阻止列表时:
- 尽可能使用纯 ASCII 域名
- 考虑 URL 解析器可能以不同方式处理 Unicode 规范化
- 用潜在的同形变体测试你的域名过滤器
- 定期审计你的域名配置以查找可疑的 Unicode 字符
使用代码执行进行动态过滤
Web search 和 web fetch 的 _20260209 版本内部使用代码执行来对搜索结果应用动态过滤器。
将独立的 code_execution 工具与 _20260209 版本的 web 工具一起使用会创建两个执行环境,这可能会使模型困惑。使用其中一种,或将两者都固定到同一版本。
流式传输服务器工具事件
服务器工具事件作为正常 SSE 流的一部分进行流式传输。server_tool_use 块及其结果以 content_block_start 和 content_block_delta 事件到达,与文本和客户端工具调用的流式传输方式相同。
完整的事件参考参见流式传输。各个工具页面记录了不同的工具特定事件名称。
批量请求
所有服务器工具都支持批处理。参见批处理。