加载中

构建使用工具的多轮对话需要处理来自Claude的不同响应类型。当Claude响应时,它可能需要使用工具,也可能直接提供答案。您的代码需要优雅地处理这两种情况。

简单工具集成的问题

如果您只是将工具结果添加到每次对话中,就会遇到问题。当Claude回答像"1+1等于多少?"这样的简单问题时,它不需要任何工具。但如果您的代码总是尝试处理工具结果,最终会在对话历史中添加空消息。

解决方案是检查每次Claude响应返回的stop_reason。这会告诉您Claude为什么停止生成——是自然完成,还是因为它想使用工具。

停止原因

Claude可能因以下几种原因停止:

  • "tool_use" - 模型想要调用工具
  • "end_turn" - 模型已完成生成其响应
  • "max_tokens" - 达到输出限制
  • "stop_sequence" - 遇到了您提供的停止序列

改进聊天函数

首先,更新您的聊天函数以返回更多信息。不要只是分别返回文本和各个部分,而是返回一个包含您所需一切内容的字典:

python
def chat(messages, tools=None, system=None, **kwargs):
    # ……现有代码……
    
    return {
        "parts": parts,
        "stop_reason": response["stopReason"],
        "text": "\n".join([p["text"] for p in parts if "text" in p])
    }

这种方法从响应部分中提取所有文本内容,这比假设第一部分始终是文本更加稳健。

构建对话循环

创建一个处理完整对话流程的函数:

python
def run_conversation(messages):
    while True:
        result = chat(messages, tools=[get_current_datetime_schema])
        
        add_assistant_message(messages, result["parts"])
        print(result["text"])
        
        if result["stop_reason"] != "tool_use":
            break
            
        tool_result_parts = run_tools(result["parts"])
        add_user_message(messages, tool_result_parts)
    
    return messages

这个循环会持续进行,直到Claude因工具使用以外的原因停止。每次迭代:

  1. 将当前消息发送给Claude
  2. 将Claude的响应添加到消息历史中
  3. 检查Claude是否想要使用工具
  4. 如果是,运行工具并将结果添加回对话中
  5. 如果不是,退出循环

测试实现

这种方法可以处理需要工具的问题和简单问题:

python
# 需要工具的问题
messages = []
add_user_message(messages, "What time is it?")
run_conversation(messages)

# 简单问题
messages = []
add_user_message(messages, "What is 1+1?")
run_conversation(messages)

对于时间相关的问题,Claude会使用datetime工具。对于数学问题,它会直接响应,不进行任何工具调用。对话循环会根据Claude的停止原因自动调整。

当您添加更多工具时,这种模式可以很好地扩展——同一个循环可以处理工具使用和直接响应的任何组合,使您的对话式AI更加稳健和自然。