Claude tool use 教學:四步流程
從 API 角度看 tool use 的四步流程——initial、tool_use、tool_result、final,中間是兩個 request、不是 callback。
TL;DR
- Tool use = 你給 Claude 一張「能做什麼」的菜單,它告訴你「我要呼叫哪個」,你執行完再餵回去
- 整個來回是兩個 API request——中間是你的 server 在跑東西,不是 Claude 自己連你的 DB
- 不是 callback、不是 webhook——是分段對話,每段都要把完整歷史重傳
想看 agent 角度的 tool use 心智模型?看 Claude Code 系列。本章是 API hands-on——JSON 結構、content blocks、agent loop 怎麼寫都會走過。
一個情境:使用者問「SF 現在的天氣」
你在做 chatbot,使用者敲:「舊金山現在的天氣?」
直接餵給 Claude 不開 tool use,會拿到很客氣的拒答:
抱歉,我沒辦法存取即時天氣資訊。我的訓練資料有 cutoff date,無法查詢當下情況。
問題很直白:Claude 沒有網路、沒有 DB、沒有檔案系統。它只會吃 text、吐 text。真的去打 weather API 的人是你的 server。Tool use 就是把「Claude 想要什麼資料」跟「你的 server 怎麼拿」串起來的協定。
四步流程
關鍵:圖中第 2 步跟第 6 步是兩個獨立的 messages.create 呼叫。中間沒有 long-polling、webhook 或 streaming callback。就是你正常 send 完一個 request 看 response,發現它要 tool,自己跑完,再 send 下一個。
像櫃檯的便利貼,不是廚房的快遞
比喻一下:tool use 像餐廳櫃檯。
- 客人(user)跟櫃檯(你的 server)下單
- 櫃檯把單子(tool_use 請求)寫在便利貼遞給廚房(外部 API / DB)
- 廚房做完菜端回櫃檯(tool_result)
- 櫃檯再把菜送到客人桌上(final response)
廚房不會直接跟客人講話。Claude 也不會自己連你的 DB。每一段都是櫃檯(你的 code)在轉手。
一個 happy path 的 JSON
第一個 request——附上 tools 參數:
import anthropic
client = anthropic.Anthropic()
tools = [{
"name": "get_weather",
"description": "查詢指定城市的即時天氣",
"input_schema": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "城市名"}
},
"required": ["city"],
},
}]
messages = [{"role": "user", "content": "舊金山現在的天氣?"}]
res = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
tools=tools,
messages=messages,
)
Claude 回的 response 會是這個結構:
{
"stop_reason": "tool_use",
"content": [
{ "type": "text", "text": "我來查一下舊金山的天氣。" },
{
"type": "tool_use",
"id": "toolu_01A09q90qw90lq917835lq9",
"name": "get_weather",
"input": { "city": "San Francisco" }
}
]
}
兩個 block:一段給 user 看的 text、一個 tool_use block 告訴你它要哪個 tool、傳什麼 input。stop_reason: "tool_use" 是「我要 tool、不要忘了餵我結果」的訊號。
第二個 request——把 tool_result 塞回去
你的 server 拿 input 真的去打 weather API(或假資料),然後再呼叫一次 API:
weather_data = "18°C, partly cloudy" # 假裝你打完 weather API
messages.append({"role": "assistant", "content": res.content}) # 整段塞回去
messages.append({
"role": "user",
"content": [{
"type": "tool_result",
"tool_use_id": "toolu_01A09q90qw90lq917835lq9",
"content": weather_data,
}],
})
final = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
tools=tools, # 後續 request 也要帶
messages=messages,
)
print(final.content[0].text)
# "舊金山現在 18°C,多雲。"
兩個重點:
tool_use_id必須對應前一個 response 的tool_use.id,不然 API 直接報錯- 第二個 request 也要帶
tools參數——Claude 需要 schema 才能解讀對話歷史裡的 tool block
為什麼不直接讓 Claude 連 DB?
幾個務實的原因:
- 權限管理:你的 DB 連線、API key、business logic 在你 server 才管得住
- 安全:model 不該直接拿到 production credentials
- 可觀測:tool 怎麼跑、跑多久、傳什麼參數,全部走你的 code,log / audit / rate limit 都好做
- stateless:Anthropic 的 API 設計成可以負載到任意機器;幫 user 連他們的 DB 不可能 scale
「分段對話」聽起來繞,但這個繞是必要的。
接下來
下一篇進到第一步的關鍵——tool schema 怎麼寫。name 動詞化、description 是 tool 的 system prompt、input_schema 怎麼讓 Claude 不亂傳參數,schema 寫得好決定了它選不選對 tool。

