載入中

建立一個具有工具的對話系統需要實作一個迴圈,持續呼叫 Claude,直到它不再要求使用工具為止。當 Claude 不再要求使用工具時,這表示它已經準備好向使用者提供最終回應。

偵測工具請求

要知道 Claude 是否想要使用工具,關鍵在於回應訊息中的 stop_reason 欄位。當 Claude 決定需要呼叫工具時,此欄位會被設為 "tool_use"。這讓我們有一個簡潔的方式來檢查是否需要繼續對話迴圈:

python
if response.stop_reason != "tool_use":
    break  # Claude is done, no more tools needed

對話迴圈

主要的對話函式遵循一個簡單的模式:

python
def run_conversation(messages):
    while True:
        response = chat(messages, tools=[get_current_datetime_schema])
        add_assistant_message(messages, response)
        print(text_from_message(response))
        
        if response.stop_reason != "tool_use":
            break
            
        tool_results = run_tools(response)
        add_user_message(messages, tool_results)
    
    return messages

這個迴圈會持續進行,直到 Claude 提供最終答案而不再要求任何工具為止。

處理多個工具呼叫

Claude 可以在單一回應中請求多個工具。訊息內容包含一個區塊列表,我們需要分別處理每個工具使用區塊:

run_tools 函式透過篩選出工具使用區塊並逐一處理來處理這個情況:

python
def run_tools(message):
    tool_requests = [
        block for block in message.content if block.type == "tool_use"
    ]
    tool_result_blocks = []
    
    for tool_request in tool_requests:
        # 處理每個工具請求...

工具結果區塊

對於每個工具使用區塊,我們需要建立一個對應的工具結果區塊。這些區塊有特定的必填欄位:

工具結果區塊必須包含與原始工具使用區塊相同的 ID,但放在 tool_use_id 欄位中:

python
tool_result_block = {
    "type": "tool_result",
    "tool_use_id": tool_request.id,
    "content": json.dumps(tool_output),
    "is_error": False
}

錯誤處理

穩健的工具執行需要處理潛在的錯誤。當工具失敗時,我們仍然需要回傳一個工具結果區塊,但附帶錯誤資訊:

python
try:
    tool_output = run_tool(tool_request.name, tool_request.input)
    tool_result_block = {
        "type": "tool_result",
        "tool_use_id": tool_request.id,
        "content": json.dumps(tool_output),
        "is_error": False
    }
except Exception as e:
    tool_result_block = {
        "type": "tool_result", 
        "tool_use_id": tool_request.id,
        "content": f"Error: {e}",
        "is_error": True
    }

可擴展的工具路由

為了支援多個工具,請建立一個獨立的路由函式,而不是將工具名稱寫死在程式碼中:

python
def run_tool(tool_name, tool_input):
    if tool_name == "get_current_datetime":
        return get_current_datetime(**tool_input)
    elif tool_name == "other_tool":
        return other_tool_function(**tool_input)
    # 依需求新增更多工具

這種方法讓新增工具變得容易,而不需要修改核心對話邏輯。

完整工作流程

完整的多輪對話運作方式如下:

  • 將使用者訊息連同可用工具傳送給 Claude
  • Claude 以文字和/或工具使用區塊回應
  • 執行任何被請求的工具並建立工具結果區塊
  • 將工具結果以使用者訊息的形式傳回給 Claude
  • 重複此過程,直到 Claude 提供不含工具請求的最終回應

這創造了一種無縫的體驗,讓 Claude 能夠在多個對話輪次中進行多次工具呼叫,以收集所有必要的資訊,然後再向使用者提供全面的最終答案。