🎯 什麼情境該想到我
當 agent 要對很多筆資料重複呼叫同一個工具,每次回傳又是一大包,而真正需要的只是篩選、加總後的幾行結論。這時讓模型寫一段程式,在沙盒裡自己跑迴圈呼叫工具、自己算,只把結果交回來。
⚙️ 怎麼用(步驟 / 公式)
1. 機制:工具結果改由程式碼接收
- 傳統工具呼叫:模型每要一次工具,就停下來(
stop_reason == "tool_use")。你執行工具,把tool_result放回對話,再呼叫模型。每一筆原始結果都進模型的上下文。 - PTC:模型先用 code execution 工具寫一段 Python。程式裡把你的工具當成 async 函式呼叫,例如:
程式跑到工具呼叫時,API 回應裡會出現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 ])tool_use區塊,上面的caller標明是程式發起的。你照樣執行工具、照樣用tool_result回傳,但這份結果只交給沙盒裡的程式,模型看不到。程式篩選、加總完,只print出結論,模型讀到的只有這段輸出。 - notebook 原文:「只有
direct呼叫會被模型『看到』;code_execution_20250825類型只有 code execution 容器看得到。」
2. 設定(照 notebook 原文)
- 每個要開放給程式呼叫的工具,加上
allowed_callers欄位:tool["allowed_callers"] = ["code_execution_20250825"]- 沒有
allowed_callers的工具,預設只能由模型直接呼叫。 - 兩種都允許就寫
["direct", "code_execution_20250825"]。 - 只開放可以安全重複執行的工具。
- 沒有
- 在 tools 陣列加上 code execution 工具:
{"type": "code_execution_20250825", "name": "code_execution"} - 用 beta 版 messages API:
client.beta.messages.create(..., betas=["advanced-tool-use-2025-11-20"])。 - 有狀態的流程要帶容器 ID:從
response.container.id取得,下一次請求用extra_body={"container": container_id}傳回去。notebook 說單輪流程不需要。 - 處理工具呼叫時讀
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-betaheader,官方範例直接用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 呼叫 | 4 | 4 |
| 總 token | 110,473 | 15,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,只算最後的程式執行結果和模型回覆。
- 回覆等待中的程式呼叫時,那則 user 訊息只能有
- 工具只回一小段結果、或只呼叫一兩次時,多一層程式反而增加成本與複雜度(推論)。
🔗 相關工具
- 工具集設計:工具回傳要精簡、截斷要明示——改得動工具時先從這裡下手
- Function Calling 與結構化輸出:傳統工具呼叫的基本流程
- ReAct 與 Agent Loop:上下文隨輪數超線性成長,PTC 是其中一種解法
- 工具-agent工作流的基本模式:固定流程的模式,和讓模型寫程式編排是兩條路