加载中

当Claude决定使用工具时,它会返回一个需要仔细处理的特殊响应结构。理解这种响应格式并实现适当的对话管理,对于构建健壮的工具启用型应用程序至关重要。

工具选择配置

在深入了解响应之前,有必要先了解如何控制Claude何时使用工具。toolChoice 参数为您提供了三个选项:

  • auto - Claude自行决定是否使用工具(默认行为)
  • any - Claude必须使用工具,但可以选择使用哪一个
  • specific tool - 强制Claude按名称使用特定工具

第三个选项在测试时特别有用,当您想确保Claude调用特定函数时。

多部分消息结构

当Claude想要使用工具时,它会返回一个包含多个内容部分的助手消息,而不仅仅是文本:

该响应包含两个部分:

  • 文本部分 - 人类可读的解释,例如"我可以帮您查找当前时间。让我为您查找该信息"
  • ToolUse部分 - 结构化数据,告知您应运行哪个工具以及使用什么参数

理解ToolUse部分

ToolUse部分包含三个关键信息:

  • toolUseId - 一个唯一标识符,您在发送回工具结果时需要用到它
  • name - Claude想要调用的工具的确切名称,来自您的JSON schema
  • input - Claude想要传递给您的工具函数的参数字典

带工具的对话流程

工具使用遵循一种特定的对话模式,需要维护完整的消息历史:

当您收到工具使用请求时,您需要:

  1. 从ToolUse部分提取工具信息
  2. 运行您的实际工具函数
  3. 连同完整的对话历史一起发送回ToolResult消息
  4. 在下一次请求中包含原始用户消息和助手的工具使用消息

更新辅助函数

为了正确处理多部分消息,您需要更新消息处理函数。以下是如何使您的函数足够灵活,以处理简单文本和复杂的多部分内容:

python
def add_user_message(messages, content):
    if isinstance(content, str):
        user_message = {"role": "user", "content": [{"text": content}]}
    else:
        user_message = {"role": "user", "content": content}
    messages.append(user_message)

def add_assistant_message(messages, content):
    if isinstance(content, str):
        assistant_message = {"role": "assistant", "content": [{"text": content}]}
    else:
        assistant_message = {"role": "assistant", "content": content}
    messages.append(assistant_message)

您还需要更新聊天函数,使其同时返回文本和完整的部分列表:

python
def chat(messages, system=None, temperature=1.0, stop_sequences=[], tools=None):
    # ……现有的设置代码……
    
    response = client.converse(**params)
    
    text = response["output"]["message"]["content"][0]["text"]
    parts = response["output"]["message"]["content"]
    
    return text, parts

检查停止原因

Claude的响应还包含一个顶层的 stopReason 字段。当它等于 "tool_use" 时,表示Claude想要调用工具,而不仅仅是提供文本响应——这就是您提取工具信息并执行所请求函数的信号。上面的 chat() 辅助函数尚未暴露此字段,因此目前您可以通过检查返回的部分列表中是否存在带有 toolUse 键的条目来检测工具使用。您将在后续课程中扩展 chat(),使其直接返回 stopReason。

有了这些模式,您就可以处理Claude的工具使用请求,并在多轮工具交互过程中保持适当的对话流程。