Applied AI School
v0 · 規劃中
Anthropic

Multi-turn 與多 tool

一輪不夠用——寫一個會 loop 的 agent loop,加 max_iterations 防無窮自呼,多 tool 一輪可能多個 tool_use 要全部跑完再回。

TL;DR

  • 一輪 tool use 通常不夠——要寫一個 while loop 直到 stop_reason != "tool_use"
  • 多 tool 場景:model 一輪可能回多個 tool_use block,要全部跑完再 batch 回
  • max_iterations 不然 model 跑歪可能無限自呼,燒錢又當機

一個情境:「177 天後是星期幾?幫我設提醒」

User 給你這句。你的 server 上有三個 tool:

  • get_current_datetime() → 拿今天
  • add_duration_to_datetime(start, days) → 加日期
  • set_reminder(date, text) → 寫到 reminder DB

要把這個 task 完成,Claude 得做三件事連在一起:

  1. 先呼叫 get_current_datetime 拿今天
  2. 拿到結果後,呼叫 add_duration_to_datetime 加 177 天
  3. 再呼叫 set_reminder 寫進去
  4. 最後回 user:「已設定 6 月 27 日的提醒」

這要四個 API request。每次 Claude 看到上一輪 tool result 才能決定下一步。寫死「一個 request = 一個 tool call」遠遠不夠。

Agent loop 的骨架

把它變一個 while loop。Pseudo-code:

while True:
    response = call_claude(messages, tools)
    messages.append(assistant=response.content)

    if response.stop_reason != "tool_use":
        break                          # ← 結束,回 final text 給 user

    tool_results = run_all_tools(response)
    messages.append(user=tool_results)

return messages

每次 loop 三件事:

  1. 問 Claude 下一步是什麼(call API)
  2. 把 assistant message 寫回 history(包含 text + tool_use block)
  3. 是 tool_use 就跑、不是就停

跑 tool 的部分要小心一個細節:一輪可能有多個 tool_use block,要全部跑完再一次回。

跑多 tool:filter content blocks

import json

def run_tool(name, tool_input):
    if name == "get_current_datetime":
        return get_current_datetime(**tool_input)
    elif name == "add_duration_to_datetime":
        return add_duration_to_datetime(**tool_input)
    elif name == "set_reminder":
        return set_reminder(**tool_input)
    raise ValueError(f"Unknown tool: {name}")

def run_tools(message):
    tool_use_blocks = [b for b in message.content if b.type == "tool_use"]
    results = []
    for block in tool_use_blocks:
        try:
            output = run_tool(block.name, block.input)
            results.append({
                "type": "tool_result",
                "tool_use_id": block.id,
                "content": json.dumps(output),
                "is_error": False,
            })
        except Exception as e:
            results.append({
                "type": "tool_result",
                "tool_use_id": block.id,
                "content": f"Error: {e}",
                "is_error": True,
            })
    return results

幾個關鍵:

  • block.type == "tool_use" 篩出 tool 請求(也可能混 text block,要忽略)
  • 一個 tool 失敗不要 crash 整個 loop——包 try/except 把 error 餵回 model
  • 全部結果放在同一個 user message 裡,不要分多個

包進 run_conversation

def run_conversation(messages, tools, max_iterations=10):
    for _ in range(max_iterations):
        res = client.messages.create(
            model="claude-sonnet-4-6",
            max_tokens=2048,
            tools=tools,
            messages=messages,
        )
        messages.append({"role": "assistant", "content": res.content})

        if res.stop_reason != "tool_use":
            return messages                          # 結束

        tool_results = run_tools(res)
        messages.append({"role": "user", "content": tool_results})

    raise RuntimeError("Hit max_iterations without final answer")

一個 user query 進來呼叫一次 run_conversation,內部跑幾輪 model 不知道,對你的 caller 來說就是「問一次拿一次答案」。這個包裝就是 mini agent。

結束條件三選一

實務上 loop 會在三個地方退出:

條件怎麼觸發建議
stop_reason == "end_turn"model 覺得任務完成正常退出
stop_reason == "stop_sequence"撞到你設的 stop_sequences(少見)視為正常退出
max_iterations你的硬上限看成 anomaly,log 起來分析

max_iterations 不只是保險,更是你的成本防線。每輪都是一個完整 API call、token 線性累加,一輪掉到無窮迴圈帳單會很有感。

REPL 心智模型

把這個 loop 想成 model 跟 tool 的 REPL——每輪 model 看到上一輪的 tool result 才決定下一步:

一個 user query 可能跑 4 個 API request 才結束。每次 model 看完 tool result 才決定下一步

LLM 是一邊執行一邊規劃的。它不會預先規劃完一次說完,而是看到上一輪的 result 才決定下一步。所以 schema 寫得清楚比想多步驟順序重要。

Agent loop 跟「真正的 agent」差在哪

到這裡你已經寫了一個會 loop、會用多 tool、會處理 error 的小型 agent。

但「真正的 agents」還會做更多事:planning、memory、subagent、long-horizon execution、自動 compaction。這些變數一拉開,loop 結構會更複雜——這個系列的 agents 章節 會專門講 workflow vs agent 的取捨、Anthropic 的 best practice、什麼時候自己刻什麼時候用內建 agent harness。

這篇的 run_conversation 是 agent 的最小骨架,80% 的 production 場景用這個就夠。

接下來

下一篇換個角度——不是所有 tool 都要自己寫。Anthropic 直營了一些 server-side 跑的 tool,像 web_searchtext_editorcode_execution。怎麼用、跟自寫 tool 的差別是什麼,下一篇收尾整個 Tool Use section。