Tool schemas — JSON mô tả tool cho Claude

5 — Tool UseTrung cấp20 phút

Khi bạn viết function Python, bạn thêm docstring cho dev khác đọc:

Bạn sẽ học được
  • Viết tool schema đầy đủ với name, description, input_schema
  • Hiểu JSON Schema spec — types, required, defaults
  • Viết description chất lượng giúp Claude biết khi nào call tool
  • Generate schema bằng Claude (self-generate) để tiết kiệm thời gian
  • Dùng ToolParam type cho type safety

3 thành phần của schema

1. name

Examples: get_weather, search_emails, create_calendar_event.

2. description

Quan trọng nhất. Claude dựa vào đây quyết định khi nào call tool.

Best practices:

Bad: "Gets data"

Good: "Get current weather conditions for a specified location. Use this when user asks about weather, temperature, or wind. Returns a formatted string with temperature, conditions, and wind speed."

3. input_schema

Follows JSON Schema spec — standard cho validate JSON data.

  • Snake_case
  • Descriptive verb
  • Match Python function name (convention)
  • 3-4 sentences
  • Describe what tool does
  • When Claude nên dùng
  • What tool returns
{
  "name": "get_weather",
  "description": "Get current weather conditions for a specified location. Use this when user asks about current weather, temperature, or atmospheric conditions. Returns text with temperature, conditions, and wind.",
  "input_schema": {
    "type": "object",
    "properties": {
      "location": {
        "type": "string",
        "description": "City name or airport code, e.g., 'San Francisco' or 'SFO'"
      },
      "unit": {
        "type": "string",
        "enum": ["F", "C"],
        "description": "Temperature unit: F for Fahrenheit, C for Celsius",
        "default": "F"
      }
    },
    "required": ["location"]
  }
}

JSON Schema basics

Types

Example object schema

Additional constraints

  • string — text
  • integer — số nguyên
  • number — float / int
  • boolean — true/false
  • array — list
  • object — dict (nested)
  • null — null value
  • enum: restrict to list of values
  • default: default value if not provided
  • minimum / maximum: numeric range
  • minLength / maxLength: string length
  • pattern: regex for string
  • description: per-field docs
{
  "type": "object",
  "properties": {
    "name": {"type": "string"},
    "age": {"type": "integer"},
    "is_admin": {"type": "boolean"},
    "tags": {
      "type": "array",
      "items": {"type": "string"}
    },
    "address": {
      "type": "object",
      "properties": {
        "street": {"type": "string"},
        "city": {"type": "string"}
      }
    }
  },
  "required": ["name", "age"]
}

Viết schema đầy đủ — Ví dụ get_current_datetime

Naming convention: function_name + function_name_schema. Dễ pair.

from datetime import datetime

def get_current_datetime(date_format="%Y-%m-%d %H:%M:%S"):
    if not date_format:
        raise ValueError("date_format cannot be empty")
    return datetime.now().strftime(date_format)


get_current_datetime_schema = {
    "name": "get_current_datetime",
    "description": "Returns the current date and time formatted according to the specified format. Use when user asks for current time, today's date, or to timestamp an event.",
    "input_schema": {
        "type": "object",
        "properties": {
            "date_format": {
                "type": "string",
                "description": "Python strftime format string. Examples: '%Y-%m-%d' for date only, '%H:%M' for hour:minute, '%Y-%m-%d %H:%M:%S' for full datetime.",
                "default": "%Y-%m-%d %H:%M:%S"
            }
        },
        "required": []
    }
}

Ví dụ phức tạp hơn — search_emails

Phân tích

  • query là required
  • from_sender, date_from, date_to optional — Claude sẽ pass nếu user mention
  • max_results có default + min/max để tránh abuse
  • pattern cho date validate format
search_emails_schema = {
    "name": "search_emails",
    "description": "Search user's email inbox by keywords, sender, or date range. Use when user asks to find emails, check inbox, or recall past conversations. Returns list of emails matching criteria.",
    "input_schema": {
        "type": "object",
        "properties": {
            "query": {
                "type": "string",
                "description": "Search keywords to match in email subject or body"
            },
            "from_sender": {
                "type": "string",
                "description": "Filter by sender email address (optional)"
            },
            "date_from": {
                "type": "string",
                "description": "Start date in YYYY-MM-DD format (optional)",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
            },
            "date_to": {
                "type": "string",
                "description": "End date in YYYY-MM-DD format (optional)",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
            },
            "max_results": {
                "type": "integer",
                "description": "Max number of emails to return",
                "minimum": 1,
                "maximum": 50,
                "default": 10
            }
        },
        "required": ["query"]
    }
}

Tự generate schema bằng Claude

Thay vì viết schema thủ công, dùng Claude:

Prompt

Output (Claude generate)

Generate a JSON schema for tool calling for this Python function.
Follow Anthropic best practices.

Function:
def create_calendar_event(title, start_time, duration_minutes=60, attendees=None):
    """Create calendar event. Returns event ID."""
    ...

Reference: https://docs.anthropic.com/en/docs/build-with-claude/tool-use

Output (Claude generate)

Bạn chỉ cần review + adjust. Tiết kiệm 10 phút/schema.

{
  "name": "create_calendar_event",
  "description": "Create a new calendar event and return the event ID. Use when user asks to schedule meetings, appointments, or reminders.",
  "input_schema": {
    "type": "object",
    "properties": {
      "title": {
        "type": "string",
        "description": "Event title/subject"
      },
      "start_time": {
        "type": "string",
        "description": "Event start time in ISO 8601 format (e.g., '2026-04-20T14:00:00')"
      },
      "duration_minutes": {
        "type": "integer",
        "description": "Event duration in minutes",
        "default": 60,
        "minimum": 15
      },
      "attendees": {
        "type": "array",
        "items": {"type": "string"},
        "description": "List of attendee email addresses (optional)"
      }
    },
    "required": ["title", "start_time"]
  }
}

Type safety với ToolParam

Thay vì raw dict, dùng ToolParam type từ SDK:

Benefits

  • IDE autocomplete
  • Mypy type checking
  • Catch schema typo trước runtime
from anthropic.types import ToolParam

get_weather_schema: ToolParam = {
    "name": "get_weather",
    "description": "...",
    "input_schema": {
        ...
    }
}

Pass schema trong API call

Claude sẽ thấy tất cả schema và decide dùng cái nào (hoặc không dùng).

response = client.messages.create(
    model=model,
    max_tokens=1000,
    messages=messages,
    tools=[
        get_weather_schema,
        get_current_datetime_schema,
        search_emails_schema,
    ],  # ← List of schemas
)

Organize schemas

Cho app nhiều tool, tách file:

Usage:

# tools/weather.py
def get_weather(location, unit="F"):
    ...

get_weather_schema = {...}


# tools/email.py
def search_emails(query, ...):
    ...

search_emails_schema = {...}


# tools/__init__.py
from .weather import get_weather, get_weather_schema
from .email import search_emails, search_emails_schema

ALL_TOOLS = [
    {"schema": get_weather_schema, "function": get_weather},
    {"schema": search_emails_schema, "function": search_emails},
]

ALL_SCHEMAS = [t["schema"] for t in ALL_TOOLS]
TOOL_FUNCTIONS = {t["schema"]["name"]: t["function"] for t in ALL_TOOLS}

Organize schemas (tiếp)

response = client.messages.create(
    tools=ALL_SCHEMAS,
    ...
)

# Sau này dispatch
if response.stop_reason == "tool_use":
    tool_call = response.content[-1]
    func = TOOL_FUNCTIONS[tool_call.name]
    result = func(**tool_call.input)

Anti-patterns

❌ Description quá ngắn

Claude không biết khi nào dùng. Fix: 3-4 sentences.

❌ Param name không rõ

"description": "Weather tool"

❌ Param name không rõ

Fix: location, query, order_id — tên có ý nghĩa.

❌ Quên required

"properties": {"x": {"type": "string"}}

❌ Quên required

Claude có thể pass incomplete, tool crash.

Fix: List required properly.

❌ Dùng any type

Không có any trong JSON Schema. Nếu cần flexible:

❌ Schema quá dài

15 nested levels → Claude overwhelm.

Fix: Flatten. Nếu nested cần → bẻ thành nhiều tool.

  • oneOf cho multi type
  • string rồi parse trong function
"required": []  // mọi field optional

Áp dụng ngay

Bài tập 1: Generate schema tool đầu tiên (15 phút)

Chọn 1 function cho app của bạn. Dùng Claude generate schema. Review + adjust.

Bài tập 2: Review schema quality (10 phút)

Cho schema bạn viết, check:

  • [ ] Name snake_case, descriptive?
  • [ ] Description 3-4 sentences?
  • [ ] Mỗi property có description?
  • [ ] required đúng?
  • [ ] Có default cho optional params?

Tóm tắt

🎯 Schema = docstring cho Claude. Rõ ràng → Claude dùng tool đúng.

🎯 3 phần: name, description, input_schema. Description là quan trọng nhất.

🎯 Tự generate schema bằng Claude tiết kiệm 10 phút.

🎯 ToolParam type cho IDE autocomplete + type check.

🎯 Organize multi-tool qua ALL_SCHEMAS và TOOL_FUNCTIONS dict.

Nội dung này có hữu ích không?