mcpField
T
tool-use

tool-use

github.com/thelobbiAgent 工作流2154 次安装1 天前更新
代码仓库

关于 tool-use

tool-use 是面向使用 Claude 构建工具型 Agent 和工作流的开发者指南,涵盖模式设计、工具选择、编排、错误处理和严格模式验证。

主要功能

  1. 01设计 JSON Schema 工具输入
  2. 02说明工具选择模式
  3. 03介绍多轮及并行调用
  4. 04讲解工具结果与错误处理
  5. 05说明严格模式验证

适用场景

  1. 01为 Claude 应用定义工具
  2. 02编排顺序或并行工具调用
  3. 03处理无效输入和工具故障

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/thelobbi/claude --skill tool-use

安装后在 Claude Code 中输入/tool-use确认已加载。

附带文件QUICK-REFERENCE.md

详细介绍

工具使用技能

使用 Claude 实现工具的综合指南,涵盖架构设计、工具选择模式、多轮对话、错误处理模式,以及扩展思考和严格架构符合性等高级功能。

何时使用此技能

在以下情况启用此技能:

  • 使用 JSON 架构定义自定义工具
  • 构建使用工具的 Agent 工作流
  • 实现工具结果处理
  • 构建并行或顺序工具编排
  • 需要确保符合架构
  • 实现错误恢复模式
  • 将工具与扩展思考结合使用

核心概念

工具定义架构

每个工具都需要一个 JSON 架构输入定义,其中包含:

  • name:工具标识符(正则表达式:^[a-zA-Z0-9_-]{1,64}$)
  • description:对用途、使用时机和行为的详细说明(至少 3-4 句)
  • input_schema:用于定义参数的 JSON 架构
  • input_examples(可选,测试版):有效输入的具体示例
工具定义最佳实践
{
  "name": "get_stock_price",
  "description": "Retrieves the current stock price for a given ticker symbol. The ticker symbol must be a valid symbol for a publicly traded company on a major US stock exchange like NYSE or NASDAQ. The tool will return the latest trade price in USD. Use this when the user asks about the current or most recent price of a specific stock. It will not provide any other information about the stock or company beyond the price.",
  "input_schema": {
    "type": "object",
    "properties": {
      "ticker": {
        "type": "string",
        "description": "The stock ticker symbol, e.g. AAPL for Apple Inc. Must be uppercase."
      },
      "include_historical": {
        "type": "boolean",
        "description": "Optional. Whether to include 52-week high/low prices.",
        "default": false
      }
    },
    "required": ["ticker"],
    "additionalProperties": false
  },
  "input_examples": [
    {"ticker": "AAPL"},
    {"ticker": "MSFT", "include_historical": true},
    {"ticker": "GOOGL"}
  ]
}

关键指南:

  • 描述至少应包含 3-4 句
  • 说明工具的功能、使用时机、返回内容和限制
  • 对于复杂的嵌套对象或对格式敏感的参数,请使用 input_examples
  • 设置 additionalProperties: false 以进行严格验证
  • 对受约束的参数使用枚举
工具选择模式

控制 Claude 是否以及如何决定使用工具:

模式行为使用场景
"auto"Claude 自行决定是否使用工具(默认)一般工具使用,让 Claude 自行决定
"any"Claude 必须使用一个工具,但可自行选择强制使用工具,但不指定具体工具
"tool"强制使用指定工具(例如,{"type": "tool", "name": "get_weather"})结构化 JSON 输出,需要指定工具
"none"禁止使用所有工具仅使用普通文本回复
# Allow Claude to decide
# tool_choice="auto" (default)

# Force any tool to be used
tool_choice={"type": "any"}

# Force specific tool (useful for JSON output)
tool_choice={"type": "tool", "name": "record_summary"}

# Prevent tool use
tool_choice={"type": "none"}

扩展思考的重要限制:

  • 扩展思考仅支持 tool_choice: {"type": "auto"} 或 {"type": "none"}
  • 使用扩展思考时,不能使用 {"type": "any"} 或 {"type": "tool"}
  • 若要在使用工具时进行复杂推理,请改用单独的“think”工具
严格架构符合性(测试版)

使用 strict: true 启用有保障的架构验证:

tools=[{
    "name": "search_flights",
    "strict": True,  # Enable strict mode
    "input_schema": {
        "type": "object",
        "properties": {
            "destination": {"type": "string"},
            "departure_date": {"type": "string", "format": "date"},
            "passengers": {"type": "integer"}
        },
        "required": ["destination", "departure_date"],
        "additionalProperties": False
    }
}]

优点:

  • 保证参数类型安全(绝不会出现用 "2" 代替 2 的情况)
  • 不会缺少必填字段
  • 无需在运行时验证架构
  • 可靠性达到生产就绪水平

限制:

  • 拒绝响应优先于架构(安全性优先)
  • Token 上限导致的截断可能破坏架构
  • 不支持某些递归架构
  • 需要 structured-outputs-2025-11-13 测试版标头

单工具使用模式

基本模式:定义工具 → Claude 调用工具 → 返回结果 → Claude 回复

import anthropic

client = anthropic.Anthropic()

response = client.messages.create(
    model="claude-sonnet-5",
    max_tokens=1024,
    tools=[{
        "name": "get_weather",
        "description": "Get current weather in a location",
        "input_schema": {
            "type": "object",
            "properties": {
                "location": {
                    "type": "string",
                    "description": "City and state, e.g. San Francisco, CA"
                }
            },
            "required": ["location"]
        }
    }],
    messages=[{"role": "user", "content": "What's the weather in SF?"}]
)

# Check if Claude wants to use tool
if response.stop_reason == "tool_use":
    tool_use = next(b for b in response.content if b.type == "tool_use")
    print(f"Tool: {tool_use.name}")
    print(f"Input: {tool_use.input}")

    # Execute tool (simulate)
    tool_result = "68°F, partly cloudy"

    # Return result to Claude
    response = client.messages.create(
        model="claude-sonnet-5",
        max_tokens=1024,
        tools=[...],  # Same tools
        messages=[
            {"role": "user", "content": "What's the weather in SF?"},
            {"role": "assistant", "content": response.content},
            {"role": "user", "content": [{
                "type": "tool_result",
                "tool_use_id": tool_use.id,
                "content": tool_result
            }]}
        ]
    )

    print(response.content[0].text)

多轮工具对话

工具通常需要按顺序调用,其中一个工具的输出会作为另一个工具的输入:

# User asks: "What's the weather where I am?"
# Flow: get_location() → get_weather(location)

response = client.messages.create(
    model="claude-sonnet-5",
    max_tokens=1024,
    tools=[
        {
            "name": "get_location",
            "description": "Get user's location from IP address",
            "input_schema": {"type": "object", "properties": {}}
        },
        {
            "name": "get_weather",
            "description": "Get weather for location",
            "input_schema": {
                "type": "object",
                "properties": {
                    "location": {"type": "string"}
                },
                "required": ["location"]
            }
        }
    ],
    messages=[{"role": "user", "content": "What's the weather where I am?"}]
)

# Claude calls get_location first
tool_use = next(b for b in response.content if b.type == "tool_use")
location_result = "San Francisco, CA"

# Send location result back
response = client.messages.create(
    model="claude-sonnet-5",
    max_tokens=1024,
    tools=[...],
    messages=[
        {"role": "user", "content": "What's the weather where I am?"},
        {"role": "assistant", "content": response.content},
        {"role": "user", "content": [{
            "type": "tool_result",
            "tool_use_id": tool_use.id,
            "content": location_result
        }]}
    ]
)

# Claude now calls get_weather with the location
tool_use2 = next(b for b in response.content if b.type == "tool_use")
weather_result = "68°F, sunny"

# Final result
response = client.messages.create(
    model="claude-sonnet-5",
    max_tokens=1024,
    tools=[...],
    messages=[
        {"role": "user", "content": "What's the weather where I am?"},
        {"role": "assistant", "content": response.content},
        {"role": "user", "content": [{
            "type": "tool_result",
            "tool_use_id": tool_use.id,
            "content": location_result
        }]},
        {"role": "assistant", "content": response.content},
        {"role": "user", "content": [{
            "type": "tool_result",
            "tool_use_id": tool_use2.id,
            "content": weather_result
        }]}
    ]
)

print(response.content[0].text)

并行工具使用模式

Claude 可以同时调用多个互不依赖的工具:

response = client.messages.create(
    model="claude-sonnet-5",
    max_tokens=1024,
    tools=[...],
    messages=[{
        "role": "user",
        "content": "What's the weather in SF and NYC? What time is it there?"
    }]
)

# Claude makes 4 parallel tool calls (2 weather + 2 time)
tool_uses = [b for b in response.content if b.type == "tool_use"]
print(f"Parallel calls: {len(tool_uses)}")  # 4

# Execute all tools and collect results
tool_results = []
for tool_use in tool_uses:
    if tool_use.name == "get_weather":
        if "San Francisco" in str(tool_use.input):
            result = "68°F, partly cloudy"
        else:
            result = "45°F, clear"
    else:  # get_time
        if "Los_Angeles" in str(tool_use.input):
            result = "2:30 PM PST"
        else:
            result = "5:30 PM EST"

    tool_results.append({
        "type": "tool_result",
        "tool_use_id": tool_use.id,
        "content": result
    })

# IMPORTANT: Return all results in ONE user message
response = client.messages.create(
    model="claude-sonnet-5",
    max_tokens=1024,
    tools=[...],
    messages=[
        {"role": "user", "content": "What's the weather in SF and NYC? What time is it there?"},
        {"role": "assistant", "content": response.content},
        {"role": "user", "content": tool_results}  # All results together!
    ]
)

print(response.content[0].text)

并行工具的关键格式规则:

  • 所有工具结果必须放在一条用户消息中
  • 工具结果块必须排在内容数组最前面
  • 如有需要,可在工具结果之后添加文本
  • 格式错误会让 Claude 学会避免并行调用

工具结果处理

基本工具结果格式
{
    "type": "tool_result",
    "tool_use_id": "toolu_01A09q90qw90lq917835lq9",
    "content": "15 degrees"
}
带图像的工具结果
{
    "type": "tool_result",
    "tool_use_id": "toolu_01A09q90qw90lq917835lq9",
    "content": [
        {"type": "text", "text": "Current weather screenshot:"},
        {
            "type": "image",
            "source": {
                "type": "base64",
                "media_type": "image/jpeg",
                "data": "/9j/4AAQSkZJRg..."
            }
        }
    ]
}
带文档的工具结果
{
    "type": "tool_result",
    "tool_use_id": "toolu_01A09q90qw90lq917835lq9",
    "content": [
        {"type": "text", "text": "Document content:"},
        {
            "type": "document",
            "source": {
                "type": "text",
                "media_type": "text/plain",
                "data": "Full document content here"
            }
        }
    ]
}
工具结果中的错误处理
# Tool execution error
{
    "type": "tool_result",
    "tool_use_id": "toolu_01A09q90qw90lq917835lq9",
    "content": "ConnectionError: Weather API is unavailable (HTTP 500)",
    "is_error": True
}

# Missing parameter error
{
    "type": "tool_result",
    "tool_use_id": "toolu_01A09q90qw90lq917835lq9",
    "content": "Error: Missing required 'location' parameter",
    "is_error": True
}

错误恢复模式

模式 1:妥善报告错误

工具执行失败时,报告错误,由 Claude 修正后重试:

if tool_execution_failed:
    tool_result = {
        "type": "tool_result",
        "tool_use_id": tool_use.id,
        "content": f"Error: {error_message}",
        "is_error": True
    }

Claude 通常会重试 2-3 次,然后向用户致歉。

模式 2:严格架构强制

使用 strict: true 时,会在执行前阻止无效参数:

# With strict: true, Claude CANNOT send invalid parameters
# Invalid type: "passengers": "two" → prevented by schema
# Missing required field → prevented by schema
# Type mismatch: int vs string → prevented by schema
模式 3:最大 Token 数处理

如果工具使用过程中响应被截断,请提高上限后重试:

if response.stop_reason == "max_tokens":
    last_block = response.content[-1]
    if last_block.type == "tool_use":
        # Incomplete tool use, retry with more tokens
        response = client.messages.create(
            model="claude-sonnet-5",
            max_tokens=4096,  # Increased
            messages=messages,
            tools=tools
        )

用工具生成结构化 JSON 输出

使用工具确保输出为结构化 JSON,而不执行工具:

response = client.beta.messages.create(
    model="claude-sonnet-5",
    max_tokens=1024,
    betas=["structured-outputs-2025-11-13"],
    tools=[{
        "name": "record_summary",
        "description": "Record structured image summary",
        "input_schema": {
            "type": "object",
            "properties": {
                "key_colors": {
                    "type": "array",
                    "items": {
                        "type": "object",
                        "properties": {
                            "r": {"type": "number"},
                            "g": {"type": "number"},
                            "b": {"type": "number"},
                            "name": {"type": "string"}
                        },
                        "required": ["r", "g", "b", "name"]
                    }
                },
                "description": {"type": "string"},
                "estimated_year": {"type": "integer"}
            },
            "required": ["key_colors", "description"]
        }
    }],
    tool_choice={"type": "tool", "name": "record_summary"},
    messages=[{
        "role": "user",
        "content": [
            {"type": "image", "source": {"type": "url", "url": "https://..."}},
            {"type": "text", "text": "Describe this image"}
        ]
    }]
)

# Extract structured output from tool use input
tool_use = next(b for b in response.content if b.type == "tool_use")
structured_data = tool_use.input

并行使用工具的最佳实践

鼓励并行执行

在系统提示词中添加以下内容,以增强并行使用工具的效果:

<use_parallel_tool_calls>
For maximum efficiency, whenever you perform multiple independent operations,
invoke all relevant tools simultaneously rather than sequentially. Prioritize
calling tools in parallel whenever possible. When reading 3 files, run 3 tool
calls in parallel. When running multiple commands like 'ls' or 'list_dir',
always run all commands in parallel.
</use_parallel_tool_calls>
衡量并行使用工具的效果
def measure_parallel_efficiency(messages):
    # Find assistant messages with tool use
    tool_call_messages = [
        msg for msg in messages
        if msg.get("role") == "assistant"
        and any(b.get("type") == "tool_use" for b in msg.get("content", []))
    ]

    total_tools = sum(
        len([b for b in msg.get("content", []) if b.get("type") == "tool_use"])
        for msg in tool_call_messages
    )

    if not tool_call_messages:
        return 0

    avg_per_message = total_tools / len(tool_call_messages)
    print(f"Average tools per message: {avg_per_message}")
    # > 1.0 indicates parallel tool use working

集成扩展思考

扩展思考的限制
# ✅ ALLOWED with extended thinking
response = client.messages.create(
    model="claude-opus-4-8",
    thinking={"type": "adaptive"},
    tools=[...],
    tool_choice={"type": "auto"},  # Default
    messages=[...]
)

# ✅ ALLOWED with extended thinking
tool_choice={"type": "none"}  # No tools

# ❌ NOT ALLOWED with extended thinking
# tool_choice={"type": "any"}  → Error
# tool_choice={"type": "tool", "name": "..."}  → Error
用于复杂推理的“Think”工具

需要结合工具进行扩展推理时,请使用“think”工具:

tools=[{
    "name": "think",
    "description": "Pause and think carefully before proceeding",
    "input_schema": {
        "type": "object",
        "properties": {
            "reasoning": {
                "type": "string",
                "description": "Your detailed reasoning"
            }
        },
        "required": ["reasoning"]
    }
}, {
    "name": "get_weather",
    "description": "Get weather information",
    "input_schema": {...}
}]

SDK 工具运行器(简化实现)

Python 和 TypeScript SDK 提供了可自动执行工具的工具运行器:

import anthropic
from anthropic import beta_tool

client = anthropic.Anthropic()

@beta_tool
def get_weather(location: str, unit: str = "fahrenheit") -> str:
    """Get current weather in a location.

    Args:
        location: City and state, e.g. San Francisco, CA
        unit: Temperature unit, either 'celsius' or 'fahrenheit'
    """
    # Tool implementation
    return '{"temperature": "20°C", "condition": "Sunny"}'

# Tool runner automatically handles tool execution loop
runner = client.beta.messages.tool_runner(
    model="claude-sonnet-5",
    max_tokens=1024,
    tools=[get_weather],
    messages=[{"role": "user", "content": "What's the weather in Paris?"}]
)

# Iterate through responses
for message in runner:
    print(message.content[0].text)

# Or get final message directly
final_message = runner.until_done()

JSON Schema 支持与限制

支持的功能
  • 所有基本类型:object、array、string、integer、number、boolean、null
  • 使用 enum 限定取值
  • 使用 const 指定固定值
  • 使用 anyOf、allOf 表示复杂类型
  • 使用 $ref、$def、definitions 组合 Schema
  • 字符串格式:date-time、time、date、duration、email、hostname、uri、ipv4、ipv6、uuid
  • 数组 minItems(仅支持 0 和 1)
不支持的功能
  • 递归 Schema(限制嵌套深度)
  • 枚举中的复杂类型
  • 外部 $ref(例如 HTTP URL)
  • 数值限制(minimum、maximum、multipleOf)
  • 字符串限制(minLength、maxLength)
  • 高级数组限制
  • additionalProperties 的值只能是 false
  • 正则表达式模式中的反向引用

常见用例

数据提取
tools=[{
    "name": "extract_info",
    "description": "Extract structured data from text",
    "input_schema": {
        "type": "object",
        "properties": {
            "name": {"type": "string"},
            "email": {"type": "string"},
            "company": {"type": "string"}
        },
        "required": ["name", "email"]
    }
}]
API 集成
tools=[{
    "name": "search_api",
    "description": "Search external API",
    "input_schema": {
        "type": "object",
        "properties": {
            "query": {"type": "string"},
            "limit": {"type": "integer", "minimum": 1, "maximum": 100}
        },
        "required": ["query"]
    }
}]
多步骤编排
tools=[
    {"name": "validate_input", ...},
    {"name": "process_data", ...},
    {"name": "save_result", ...}
]
# Claude orchestrates the workflow

性能注意事项

工具的 Token 成本
  • 工具定义会增加输入 Token
  • 请求和响应中的工具使用块计为 Token
  • 工具结果块计为 Token
  • 工具使用的系统提示词:根据 tool_choice 不同,为 313–346 个 Token
文法编译
  • 首次使用 Schema:文法编译会增加额外延迟
  • 后续使用:文法会缓存 24 小时
  • Schema 或工具集发生变化时,缓存会失效
  • 名称或描述发生变化时,缓存不会失效
上下文窗口管理

在较长的对话中,使用工具可能会迅速占用上下文。可采用以下策略:

  1. 压缩:总结工具结果
  2. 分块:将大型操作拆分为较小的请求
  3. 工具运行器:在需要时自动压缩上下文
  4. 检查点:在不同阶段之间保存对话状态

强制使用工具(结构化输出)

使用 tool_choice 强制指定行为:

# Force use of a tool (for JSON output)
response = client.messages.create(
    model="claude-sonnet-5",
    max_tokens=1024,
    tools=[sentiment_tool],
    tool_choice={"type": "tool", "name": "sentiment_tool"},
    messages=[{"role": "user", "content": "Analyze this text..."}]
)

# No prefilled explanations with forced tool_choice
# Claude goes straight to tool use

# For explanations WITH tool use, use tool_choice="auto" (default)
# and add instruction: "Use the sentiment_tool in your response"

处理停止原因

tool_use

Claude 想要使用工具。提取工具使用块并执行工具。

end_turn

Claude 已完成响应生成。不会再调用工具。

max_tokens

响应被截断。如果最后一个块是未完成的 tool_use,请使用更高的 max_tokens 重试。

pause_turn(使用服务端工具时)

长时间运行的操作已暂停。继续对话以恢复操作。


资源

评论

支持 Markdown