Claude工具调用深度指南:Tool Choice策略与JSON输出定制
一、工具调用核心机制(Python SDK实现)
import anthropic
from anthropic.types import ToolParam
# 初始化客户端
client = anthropic.Anthropic(api_key="YOUR_API_KEY")
# 1. 工具箱定义(Tools参数)
tools = [
ToolParam( # 使用SDK提供的类型安全定义
name="get_weather",
description="获取指定城市的当前天气",
input_schema={
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "城市名称,如'北京'或'New York'"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "温度单位"
}
},
"required": ["location"]
}
),
ToolParam(
name="calculate",
description="执行数学计算",
input_schema={
"type": "object",
"properties": {
"expression": {
"type": "string",
"description": "数学表达式,如'(12+5)*3'"
}
},
"required": ["expression"]
}
)
]
# 2. 工具选择策略(Tool Choice参数)
# 自动模式(默认)
tool_choice_auto = {"type": "auto"}
# 强制指定工具
tool_choice_forced = {
"type": "tool",
"name": "get_weather" # 指定具体工具名
}
# 强制使用任一工具
tool_choice_any = {"type": "any"}
# API调用示例
response = client.messages.create(
model="claude-3-opus-20240229",
max_tokens=1024,
system="你是一个有帮助的助手,仅在必要时使用工具。",
messages=[
{"role": "user", "content": "纽约现在的温度是多少?"}
],
tools=tools,
tool_choice=tool_choice_auto # 可替换为其他策略
)
二、工具调用响应处理
def handle_tool_call(response):
# 1. 检查是否调用了工具
if response.stop_reason == "tool_use":
tool_use = next(
(block for block in response.content if block.type == "tool_use"),
None
)
if tool_use:
print(f"工具调用: {tool_use.name}")
print(f"输入参数: {tool_use.input}")
# 2. 执行本地工具函数
if tool_use.name == "get_weather":
result = fetch_weather(
tool_use.input["location"],
tool_use.input.get("unit", "celsius")
)
elif tool_use.name == "calculate":
result = eval_expression(tool_use.input["expression"])
# 3. 构造工具响应
tool_response = {
"type": "tool_result",
"tool_use_id": tool_use.id,
"content": str(result)
}
# 4. 继续对话
next_response = client.messages.create(
model=response.model,
messages=[
*response.messages,
{
"role": "assistant",
"content": response.content
},
{
"role": "user",
"content": [tool_response]
}
],
tools=tools
)
return next_response
return response
# 示例工具实现
def fetch_weather(location: str, unit: str) -> dict:
"""模拟天气API调用"""
return {
"location": location,
"temperature": 22.5,
"unit": unit,
"conditions": "晴天"
}
def eval_expression(expr: str) -> float:
"""安全计算表达式"""
import ast
return ast.literal_eval(expr)
三、JSON结构化输出最佳实践
# 方法1:通过提示工程实现
def get_structured_output_prompt():
response = client.messages.create(
model="claude-3-sonnet-20240229",
messages=[
{
"role": "user",
"content": "分析文本情感: '我非常喜欢这款新产品,但价格太高了'"
},
{
"role": "assistant",
"content": "{"
}
],
max_tokens=300,
stop_sequences=["}"], #当出现json的结束字符,就终止回答
system="""你是一个情感分析API,返回JSON格式:
{
"positive": <0-1的浮点数>,
"negative": <0-1的浮点数>,
"neutral": <0-1的浮点数>,
"summary": "<10字总结>"
}"""
)
return response.content[0].text
# 方法2:伪工具调用(官方推荐)
def get_structured_output_tool():
# 定义伪工具
json_tool = ToolParam(
name="capture_data",
description="捕获结构化数据",
input_schema={
"type": "object",
"properties": {
"positive": {"type": "number"},
"negative": {"type": "number"},
"neutral": {"type": "number"},
"summary": {"type": "string"}
},
"required": ["positive", "negative", "neutral", "summary"]
}
)
response = client.messages.create(
model="claude-3-haiku-20240307",
messages=[
{
"role": "user",
"content": "分析文本情感: '这个服务太棒了,解决了我所有问题'"
}
],
tools=[json_tool],
tool_choice={"type": "tool", "name": "capture_data"}
)
# 提取结构化数据
if response.stop_reason == "tool_use":
tool_block = next(b for b in response.content if b.type == "tool_use")
return tool_block.input
return {}
四、企业级客服系统完整实现
class CustomerServiceAgent:
def __init__(self):
self.client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
self.tools = self._init_tools()
self.conversation_history = []
def _init_tools(self):
return [
ToolParam(
name="get_customer_info",
description="通过客户ID查询客户信息",
input_schema={
"type": "object",
"properties": {
"customer_id": {"type": "string", "pattern": "^C\\d{3}$"}
},
"required": ["customer_id"]
}
),
ToolParam(
name="get_order_details",
description="查询订单详情",
input_schema={
"type": "object",
"properties": {
"order_id": {"type": "string", "pattern": "^O\\d{4}$"}
},
"required": ["order_id"]
}
),
ToolParam(
name="cancel_order",
description="取消指定订单",
input_schema={
"type": "object",
"properties": {
"order_id": {"type": "string", "pattern": "^O\\d{4}$"}
},
"required": ["order_id"]
}
)
]
def _call_tool(self, tool_name: str, input_params: dict):
"""连接真实业务系统"""
if tool_name == "get_customer_info":
return db.query(Customer).filter_by(id=input_params["customer_id"]).first()
elif tool_name == "get_order_details":
return order_service.get_order(input_params["order_id"])
elif tool_name == "cancel_order":
return order_service.cancel_order(input_params["order_id"])
return {"error": "未知工具"}
def process_message(self, user_input: str):
# 1. 添加用户消息到历史
self.conversation_history.append({"role": "user", "content": user_input})
while True:
# 2. 调用Claude
response = self.client.messages.create(
model="claude-3-opus-20240229",
messages=self.conversation_history,
tools=self.tools,
max_tokens=1024,
system="你是一个客户服务助手,严格遵守以下规则:\n1. 仅使用提供工具查询信息\n2. 不要虚构数据\n3. 用中文回复"
)
# 3. 处理响应
if response.stop_reason == "end_turn":
assistant_msg = "".join(
block.text for block in response.content if block.type == "text"
)
self.conversation_history.append({
"role": "assistant",
"content": assistant_msg
})
return assistant_msg
elif response.stop_reason == "tool_use":
tool_use = next(
block for block in response.content if block.type == "tool_use"
)
# 执行工具调用
tool_result = self._call_tool(tool_use.name, tool_use.input)
# 添加工具结果到对话历史
self.conversation_history.append({
"role": "assistant",
"content": response.content
})
self.conversation_history.append({
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": tool_use.id,
"content": json.dumps(tool_result, ensure_ascii=False)
}
]
})
else:
return "系统处理异常,请稍后再试"
# 使用示例
agent = CustomerServiceAgent()
print(agent.process_message("我想取消订单O1234"))
print(agent.process_message("客户C567的信息呢?"))
五、高级技巧与最佳实践
- 工具选择策略优化
# 动态切换策略示例
def smart_tool_choice(user_input):
if "天气" in user_input:
return {"type": "tool", "name": "get_weather"}
elif "计算" in user_input or any(char in user_input for char in "+-*/()"):
return {"type": "tool", "name": "calculate"}
return {"type": "auto"} # 其他情况自动选择
- 错误处理增强
# 在工具调用函数中添加
def _call_tool(tool_name, input_params):
try:
# ...原有逻辑...
except DatabaseError as e:
return {"error": "数据库错误", "details": str(e)}
except Exception as e:
return {"error": "系统异常", "code": "SYS500"}
- 性能优化:enable_prompt_cache
在 Claude 的 Python SDK(如
anthropic
包)中,enable_prompt_cache
是用于启用提示词缓存(Prompt Cache)的参数,它的作用是为了加快重复请求的响应速度,尤其是在提示词内容不变的情况下,避免每次都重新发送和处理相同的 prompt。
# 启用提示缓存(Claude企业版功能)
response = client.messages.create(
# ...其他参数...
enable_prompt_cache=True, # 减少重复提示处理
stream=True # 流式传输大响应
)
# 处理流式响应
with client.messages.stream(
model="claude-3-sonnet-20240229",
messages=[...],
tools=tools,
max_tokens=1024
) as stream:
for event in stream:
if isinstance(event, TextDelta):
print(event.text, end="", flush=True)
elif isinstance(event, ToolUseBlock):
print(f"\n[调用工具: {event.name}]")
- 输入验证增强
# 在工具定义中使用JSON Schema高级特性
input_schema={
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email", # 使用内置格式验证
"pattern": "^.+@mycompany\\.com$" # 自定义正则
}
},
"errorMessage": {
"properties": {
"email": "必须是公司邮箱地址"
}
}
}
六、调试与监控
# 启用详细日志
import logging
anthropic_logger = logging.getLogger("anthropic")
anthropic_logger.setLevel(logging.DEBUG)
# 检查token使用
print(f"输入token: {response.usage.input_tokens}")
print(f"输出token: {response.usage.output_tokens}")
# 使用Anthropic的监控仪表板
"""
1. 访问 https://console.anthropic.com/
2. 查看API使用分析
3. 监控延迟和错误率
4. 设置使用警报
"""
最佳实践总结:
- 优先使用
ToolParam
类型定义工具- 复杂场景采用伪工具技术实现结构化输出
- 生产环境添加完备的错误处理
- 使用流式传输处理大响应
- 启用提示缓存减少延迟
- 监控API使用和性能指标
本文所有代码兼容Anthropic Python SDK v0.20+,请使用最新版SDK获取完整功能支持。完整示例可在Anthropic官方GitHub仓库查看:github.com/anthropics/…