Claude Platform Docs
Messages工具

工具執行器(SDK)

使用 SDK 的工具執行器自動處理代理迴圈、錯誤包裝與型別安全。

「Tool runner」(工具執行器)會替您處理「agentic loop」(代理迴圈)、錯誤包裝與型別安全,讓您不必親自處理。當您需要人工介入審核、自訂日誌記錄或條件式執行時,請改用手動迴圈

工具執行器不需要您手動處理工具呼叫、工具結果與對話管理,而是會自動:

  • 在 Claude 呼叫工具時執行工具
  • 處理請求/回應循環
  • 管理對話狀態
  • 提供型別安全與驗證

基本用法

使用 SDK 輔助工具定義工具,然後使用工具執行器來執行它們。

依據 SDK 的工具簽章不同,工具會以字串或內容區塊(文字、圖片或文件區塊)的形式回傳結果,因此工具可以回傳多模態結果。回傳的字串會成為單一文字內容區塊。若要回傳結構化資料(例如 JSON 物件或數字),請先將其編碼為字串。

使用 @beta_tool 裝飾器,透過型別提示與 docstring 來定義工具。

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 裝飾器會檢查函式引數與 docstring,為您推導出 JSON schema。

迭代工具執行器

工具執行器是一個可迭代物件,會產出來自 Claude 的訊息。在每次迭代中,執行器會檢查 Claude 是否請求了工具使用。若是,它會執行該工具並自動將結果傳回給 Claude,然後產出 Claude 的下一則訊息以繼續您的迴圈。

您可以在任何一次迭代中使用 break 陳述式結束迴圈。執行器會持續迴圈,直到 Claude 回傳不含工具使用的訊息,或直到達到您所設定的 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 會跳過
        # 本次迭代的自動附加。請自行附加 assistant 訊息與
        # tool result,以及任何後續內容。
        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 工具執行器支援自動壓縮,當 token 用量超過閾值時會產生摘要,讓對話能夠超越「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": [...]}
        # 修改工具結果以加入 cache control
        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?