🎯 什麼情境該想到我

當 agent 要對很多筆資料重複呼叫同一個工具,每次回傳又是一大包,而真正需要的只是篩選、加總後的幾行結論。這時讓模型寫一段程式,在沙盒裡自己跑迴圈呼叫工具、自己算,只把結果交回來。

⚙️ 怎麼用(步驟 / 公式)

1. 機制:工具結果改由程式碼接收

  • 傳統工具呼叫:模型每要一次工具,就停下來(stop_reason == "tool_use")。你執行工具,把 tool_result 放回對話,再呼叫模型。每一筆原始結果都進模型的上下文。
  • PTC:模型先用 code execution 工具寫一段 Python。程式裡把你的工具當成 async 函式呼叫,例如:
    team = json.loads(await get_team_members({'department': 'engineering'}))
    results = await asyncio.gather(*[
        get_expenses({'employee_id': m['id'], 'quarter': 'Q3'}) for m in team
    ])
    程式跑到工具呼叫時,API 回應裡會出現 tool_use 區塊,上面的 caller 標明是程式發起的。你照樣執行工具、照樣用 tool_result 回傳,但這份結果只交給沙盒裡的程式,模型看不到。程式篩選、加總完,只 print 出結論,模型讀到的只有這段輸出。
  • notebook 原文:「只有 direct 呼叫會被模型『看到』;code_execution_20250825 類型只有 code execution 容器看得到。」

2. 設定(照 notebook 原文)

  1. 每個要開放給程式呼叫的工具,加上 allowed_callers 欄位:
    tool["allowed_callers"] = ["code_execution_20250825"]
    • 沒有 allowed_callers 的工具,預設只能由模型直接呼叫。
    • 兩種都允許就寫 ["direct", "code_execution_20250825"]。
    • 只開放可以安全重複執行的工具。
  2. 在 tools 陣列加上 code execution 工具:
    {"type": "code_execution_20250825", "name": "code_execution"}
  3. 用 beta 版 messages API:client.beta.messages.create(..., betas=["advanced-tool-use-2025-11-20"])。
  4. 有狀態的流程要帶容器 ID:從 response.container.id 取得,下一次請求用 extra_body={"container": container_id} 傳回去。notebook 說單輪流程不需要。
  5. 處理工具呼叫時讀 block.caller["type"]:"direct" 是模型直接叫的,"code_execution_20250825" 是程式叫的。兩種都要回 tool_result。

⚠️ 官方文件已改版(查證 2026-11-02,Claude 官方文件 programmatic-tool-calling、code-execution-tool 頁):

  • PTC 現在需要 code_execution_20260120 或更新版(另有 code_execution_20260521)。code_execution_20250825 只支援 Bash 與檔案操作,不支援 PTC。
  • allowed_callers 改寫 ["code_execution_20260120"]。20260120 與 20260521 可互通,回應裡的 caller 一律標 code_execution_20260120。
  • 三個 code execution 版本都不需要 anthropic-beta header,官方範例直接用 client.messages.create,容器用 container= 參數傳。舊 beta header 仍可用。
  • Claude Haiku 4.5 接受新版工具型別,但不支援 PTC。可從 Models API 的 capabilities.code_execution.supported 確認模型是否支援。
  • notebook 工具定義裡的 input_examples(給模型看的輸入範例),官方仍標為 beta。

3. 工具描述要寫清楚回傳格式

notebook 每個工具的 description 都多一段 RETURN FORMAT,例如「回傳 JSON 字串,是陣列不是包在物件裡,用 json.loads() 解析」。推論:程式碼看不到結果長相就得先寫好解析邏輯,回傳格式講不清楚,程式會解析錯。

4. 划算多少(notebook 單次實驗結果)

任務:找出 8 位工程師中誰超過 Q3 差旅預算(標準 $5,000,超過的人再查有沒有自訂預算)。每人有 20–50 筆帶大量欄位的費用紀錄。

指標傳統PTC
API 呼叫44
總 token110,47315,919
耗時35.38 秒34.88 秒
減少—token −85.6%、時間 −1.4%
  • token 省在哪:傳統做法第 3 輪光輸入就 51,744 token,全是原始費用紀錄。PTC 各輪輸入約 4–6 千。
  • 推論:時間幾乎沒省,可能因為 mock API 的模擬延遲 DELAY_MULTIPLIER = 0,工具本身不花時間,往返省下的延遲顯不出來。
  • 兩邊算出的數字不一樣:傳統做法讓模型心算,Alice 的差旅合計是 9,177.88。同一個 kernel 裡 mock 資料相同,推論是模型心算漏了項目。這正是 notebook 說的第三個好處:算術交給程式,結果精確。

5. 什麼時候用

notebook 列的五個條件:

  • 資料量大、欄位多,需要篩選、解析、彙總。
  • 有前後相依:下一個工具要看前一個結果才決定要不要叫。
  • 同一種呼叫要對很多個對象跑迴圈。
  • 用運算邏輯可以縮減要進上下文的內容。
  • 工具可以安全地重複執行,不需要人盯著。

特別適合你改不動的第三方 API:回傳太肥也沒辦法改,就讓程式先過濾。

🧪 我實際套用的紀錄

  • 2026-11-02:(待填)

⚠️ 注意 / 什麼時候不適用

  • 呼叫次數不一定變少:notebook 文字說 PTC 在這例子需要更多次 API 呼叫,但表格是 4 比 4,另一格又印出 3。省的是 token,不是往返次數。
  • 會被重複呼叫、會改資料的工具要慎開:程式可以在迴圈裡連打很多次,模型和人都不會逐筆看到。
  • 以下限制出自官方文件(查證 2026-11-02),notebook 沒提:
    • 回覆等待中的程式呼叫時,那則 user 訊息只能有 tool_result,不能夾文字;內容只能是字串或 text,不能是圖片、文件。
    • 程式在等工具結果時約 4 分鐘逾時,程式內會拋 TimeoutError。容器閒置約 5 分鐘會被收;等待中的請求一定要帶容器 ID,否則 API 拒絕。
    • code_execution_20260521 每個 Python cell 有 90 秒上限。
    • 不能用:strict: true 的工具、用 tool_choice 強制程式呼叫某工具、disable_parallel_tool_use: true。MCP connector 提供的工具、computer use/browser use 工具集不能被程式呼叫。
    • 計費:程式呼叫的工具結果不算輸入/輸出 token,只算最後的程式執行結果和模型回覆。
  • 工具只回一小段結果、或只呼叫一兩次時,多一層程式反而增加成本與複雜度(推論)。

🔗 相關工具