Claude Platform Docs
Messages工具

工具运行器(SDK)

使用 SDK 的工具运行器自动处理智能体循环、错误包装和类型安全。

"Tool runner"(工具运行器)会为您处理 "agentic loop"(智能体循环)、错误包装和类型安全,让您无需亲自处理。当您需要人工参与审批、自定义日志记录或条件执行时,请改用手动循环

工具运行器无需您手动处理工具调用、工具结果和对话管理,而是自动:

  • 在 Claude 调用工具时运行工具
  • 处理请求/响应周期
  • 管理对话状态
  • 提供类型安全和验证

基本用法

使用 SDK 辅助工具定义工具,然后使用工具运行器运行它们。

根据 SDK 的工具签名,工具以字符串或内容块(文本、图像或文档块)的形式返回结果,因此工具可以返回多模态结果。返回的字符串会成为单个文本内容块。要返回结构化数据(例如 JSON 对象或数字),请先将其编码为字符串。

使用 @beta_tool 装饰器通过类型提示和文档字符串定义工具。

import json
from anthropic import Anthropic, beta_tool

client = Anthropic()


@beta_tool
def get_weather(location: str, unit: str = "fahrenheit") -> str:
    """Get the current weather in a given location.

    Args:
        location: The city and state, e.g. San Francisco, CA
        unit: Temperature unit, either 'celsius' or 'fahrenheit'
    """
    return json.dumps({"temperature": "20°C", "condition": "Sunny"})


@beta_tool
def calculate_sum(a: int, b: int) -> str:
    """Add two numbers together.

    Args:
        a: First number
        b: Second number
    """
    return str(a + b)


runner = client.beta.messages.tool_runner(
    model="claude-opus-5",
    max_tokens=1024,
    tools=[get_weather, calculate_sum],
    messages=[
        {
            "role": "user",
            "content": "What's the weather like in Paris? Also, what's 15 + 27?",
        }
    ],
)
for message in runner:
    print(message)

@beta_tool 装饰器会检查函数参数和文档字符串,为您推导出 JSON schema。

迭代工具运行器

工具运行器是一个可迭代对象,会产出来自 Claude 的消息。在每次迭代中,运行器会检查 Claude 是否请求了工具使用。如果是,它会运行该工具并自动将结果发送回 Claude,然后产出来自 Claude 的下一条消息以继续您的循环。

您可以在任意一次迭代中使用 break 语句结束循环。运行器会一直循环,直到 Claude 返回一条不含工具使用的消息,或者(如果您设置了 max_iterations)直到达到 max_iterations

如果您不需要中间消息,可以直接获取最终消息:

使用 runner.until_done() 获取最终消息。

client = anthropic.Anthropic()

runner = client.beta.messages.tool_runner(
    model="claude-opus-5",
    max_tokens=1024,
    tools=[get_weather, calculate_sum],
    messages=[
        {
            "role": "user",
            "content": "What's the weather like in Paris? Also, what's 15 + 27?",
        }
    ],
)
final_message = runner.until_done()
for block in final_message.content:
    if block.type == "text":
        print(block.text)

高级用法

在循环内部,您可以读取每条响应消息,并在下一次 API 调用之前修改运行器的状态。每次迭代遵循以下生命周期:

  1. 运行器使用其当前状态向 Messages API 发送请求。
  2. 运行器将响应消息产出给您的循环体。
  3. 您的循环体运行。您可以读取消息,并可选择修改运行器的状态。
  4. 当您的循环体返回时,运行器会检查您是否修改了其消息历史。
    • 如果您未修改消息历史: 如果消息包含工具调用,运行器会追加助手消息和工具结果,然后继续。如果没有工具调用,循环退出。
    • 如果您修改了消息历史: 运行器会跳过自动追加,并原样使用您的状态。请参阅接管消息历史

接管消息历史

默认情况下,运行器会为您管理对话状态:在每个工具调用轮次之后,它会将助手消息和所有工具结果追加到自己的消息历史中。当您想要重试某个轮次(丢弃响应并重新发送)、注入后续消息或自行构建工具结果时,您可以接管消息历史。

您可以通过在循环体内部修改运行器的消息来接管。具体方法取决于 SDK。请参阅下面各语言的标签页。

当您在某次迭代中接管时,运行器不会追加该轮次的助手消息或工具结果。您需要负责保持对话有效:自行追加助手消息和工具结果(如果您希望该轮次计入),有条件地修改状态以便在没有工具调用时循环仍能退出,并传入 max_iterations 以限制循环次数。全部七个 SDK 都支持 max_iterations

使用 generate_tool_call_response() 检查或计算工具结果。在循环内部调用 append_messages() 会告知运行器您正在自行管理历史,因此请在您追加的内容中包含助手消息和工具结果。

runner = client.beta.messages.tool_runner(
    model="claude-opus-5",
    max_tokens=1024,
    max_iterations=10,
    tools=[get_weather],
    messages=[{"role": "user", "content": "What's the weather in San Francisco?"}],
)

for message in runner:
    tool_response = runner.generate_tool_call_response()
    if tool_response is not None:
        # append_messages() 会将状态标记为已修改,因此 runner 会跳过
        # 本次迭代的自动追加。您需要自行追加助手消息和
        # 工具结果,以及任何后续内容。
        runner.append_messages(
            message,
            tool_response,
            {"role": "user", "content": "Please be concise."},
        )
    # 当没有工具调用时,保持状态不变,以便循环退出。

要在不接管消息历史的情况下更改 max_tokens 等请求参数,请使用 set_messages_params()。运行器仍会自动追加助手消息和工具结果。

for message in runner:
    runner.set_messages_params(lambda params: {**params, "max_tokens": 2048})

自动上下文管理

对于长时间运行的智能体任务,TypeScript 和 Ruby 工具运行器支持自动压缩,当令牌使用量超过阈值时会生成摘要,使对话能够超越 "context window"(上下文窗口)限制继续进行。这两个 SDK 都已弃用此客户端选项,转而推荐服务端压缩,后者通过 context_management 请求参数适用于每个 SDK 的工具运行器。Python SDK(v1.0 及更高版本)以及 Go、Java、C# 和 PHP 工具运行器不包含客户端压缩。

调试工具执行

当工具抛出异常时,工具运行器会捕获它,并将错误作为带有 is_error: true 的工具结果返回给 Claude。工具结果携带异常的消息(在 Python 中为其类型和消息),而非完整的堆栈跟踪。

SDK 记录的日志内容因语言而异。每当工具引发未处理的异常时,Python SDK 会通过标准 logging 模块记录完整的异常,包括其堆栈跟踪。Python、TypeScript 和 Java SDK 会读取 ANTHROPIC_LOG 环境变量以开启 SDK 的日志记录,其中包括请求和响应详情:

# 以 info 级别记录日志
export ANTHROPIC_LOG=info

# 以 debug 级别记录日志以获得更详细的输出
export ANTHROPIC_LOG=debug

Go、Ruby、C# 和 PHP SDK 不读取 ANTHROPIC_LOG。除 Python 外,没有 SDK 会记录失败的工具:要查看工具失败的原因,请在工具函数内部捕获并记录异常,然后再返回或重新抛出。

拦截工具错误

默认情况下,工具错误会传回给 Claude,Claude 随后可以做出适当响应。但是,您可能希望检测错误并以不同方式处理,例如提前停止执行或实现自定义错误处理。

在 Python 和 TypeScript SDK 中,使用工具响应方法(Python 中为 generate_tool_call_response(),TypeScript 中为 generateToolResponse())拦截工具结果,并在发送给 Claude 之前检查错误。其他 SDK 不公开该钩子。它们的标签页描述了最接近的替代方案:

client = anthropic.Anthropic()

runner = client.beta.messages.tool_runner(
    model="claude-opus-5",
    max_tokens=1024,
    tools=[my_tool],
    messages=[{"role": "user", "content": "Run my_tool with the query 'hello'."}],
)

for message in runner:
    tool_response = runner.generate_tool_call_response()

    if tool_response is not None:
        # tool_response 是一个 dict:{"role": "user", "content": [...]}
        # 检查是否有任何工具结果包含错误
        for block in tool_response["content"]:
            if block.get("is_error"):
                # 选项 1:抛出异常以停止循环
                raise RuntimeError(f"Tool failed: {json.dumps(block['content'])}")

                # 选项 2:记录日志并继续(交由 Claude 处理)
                # logger.error(f"Tool error: {json.dumps(block['content'])}")

    # 正常处理消息
    print(message.content)

修改工具结果

您可以在工具结果发送回 Claude 之前修改它们。这对于添加 cache_control 等元数据以在工具结果上启用 "prompt caching"(提示缓存),或转换工具输出非常有用。请参阅提示缓存

在 Python 和 TypeScript SDK 中,使用工具响应方法获取工具结果,然后在运行器继续之前修改它。是显式追加修改后的结果还是就地变更,取决于 SDK。请参阅每个标签页中的代码注释。

client = anthropic.Anthropic()

runner = client.beta.messages.tool_runner(
    model="claude-opus-5",
    max_tokens=1024,
    tools=[search_documents],
    messages=[
        {
            "role": "user",
            "content": "Search for information about the climate of San Francisco",
        }
    ],
)

for message in runner:
    tool_response = runner.generate_tool_call_response()

    if tool_response is not None:
        # tool_response 是一个 dict:{"role": "user", "content": [...]}
        # 修改工具结果以添加缓存控制
        for block in tool_response["content"]:
            if block["type"] == "tool_result":
                # 添加 cache_control 以缓存此工具结果
                block["cache_control"] = {"type": "ephemeral"}

        # 追加修改后的响应(这会阻止自动追加原始响应)
        runner.append_messages(message, tool_response)

    print(message.content)

流式传输

启用 "streaming"(流式传输)以增量处理每个轮次的响应。每次迭代会产出一个流对象,您可以迭代它以获取事件。

设置 stream=True 并使用 get_final_message() 获取累积的消息。

client = anthropic.Anthropic()

runner = client.beta.messages.tool_runner(
    model="claude-opus-5",
    max_tokens=1024,
    tools=[calculate_sum],
    messages=[{"role": "user", "content": "What is 15 + 27?"}],
    stream=True,
)

# 流式传输时,runner 返回 BetaMessageStream
for message_stream in runner:
    for event in message_stream:
        print("event:", event)
    print("message:", message_stream.get_final_message())

print(runner.until_done())

后续步骤

通过语法约束采样强制 Claude 的工具输入符合 JSON Schema。

解析 tool_use 块、格式化 tool_result 响应,并使用 is_error 处理错误。

启用、格式化和禁用并行工具调用,并提供消息历史指导和故障排除。

指定工具 schema、编写有效的描述,并控制 Claude 何时调用您的工具。

Was this page helpful?