Dùng nhiều tools cùng lúc — Adding tools to your system

5 — Tool UseTrung cấp15 phút

Bài 6.36 đã có 3 tools. Adding thêm tools = làm thế nào?

Bạn sẽ học được
  • Thêm tool mới vào existing system mà không refactor
  • Hiểu pattern scalable cho 5-20 tools
  • Test scenarios yêu cầu Claude combine nhiều tool
  • Optimize tool selection qua description quality

4-step để thêm tool

Bước 1: Viết function

Bước 2: Define schema

@register_tool("search_web")
def search_web(query: str, max_results: int = 5) -> str:
    # ... call search API
    return formatted_results

Bước 2: Define schema

Bước 3: Add vào schemas list

search_web_schema = {
    "name": "search_web",
    "description": "Search the web for current information. Use when user asks about recent events, facts, or information not in your training data.",
    "input_schema": {
        "type": "object",
        "properties": {
            "query": {"type": "string", "description": "Search query"},
            "max_results": {"type": "integer", "default": 5}
        },
        "required": ["query"]
    }
}

Bước 3: Add vào schemas list

Bước 4: Test

ALL_TOOLS = [
    get_current_datetime_schema,
    add_duration_to_datetime_schema,
    set_reminder_schema,
    search_web_schema,  # ← thêm
]

Bước 4: Test

Xong. Không refactor code chính.

final, _ = run_conversation(
    "What's the latest news about Anthropic?",
    tools=ALL_TOOLS
)

Test scenarios — force Claude dùng nhiều tool

Scenario 1: Sequential (output tool 1 → input tool 2)

Claude flow:

Scenario 2: Parallel

  • add_duration_to_datetime(2050-01-01, 177, days) → 2050-06-27
  • set_reminder("doctor's appointment", "2050-06-27T...") → confirmation
"Set a reminder for my doctor's appointment. It's 177 days after Jan 1st, 2050."

Scenario 2: Parallel

Claude có thể request 2 tool trong 1 turn:

Bạn execute cả 2, send back results cùng lúc.

Scenario 3: Mixed (text + tool + text)

  • add(10, 10)
  • add(30, 30)
"What's 10+10 and 30+30?"

Scenario 3: Mixed (text + tool + text)

Claude có thể:

  • Turn 1: Output joke (text only)
  • Turn 2: Call get_weather(SF)
  • Turn 3: Translate joke (text only)
"Tell me a joke, then check current weather in SF, then translate joke to Vietnamese."

Quality tool description = Claude dùng đúng tool

Tool description giúp Claude decide khi nào dùng tool nào. Bad description → Claude pick sai.

Bad

Cùng 1 function conceptually, Claude confused.

Good

tool1_schema = {"name": "search", "description": "Search things"}
tool2_schema = {"name": "query", "description": "Query information"}

Good

Explicit về when NOT to use → Claude pick đúng.

search_emails_schema = {
    "name": "search_emails",
    "description": "Search user's email inbox. Use ONLY for finding emails. For web search use search_web. For internal knowledge base use search_docs."
}

search_web_schema = {
    "name": "search_web",
    "description": "Search the public web. Use for current events, facts from external sources. DO NOT use for emails or internal docs."
}

search_docs_schema = {
    "name": "search_docs",
    "description": "Search internal company knowledge base. Use for company policies, internal documentation. DO NOT use for email or web."
}

Tool organization: 5+ tools

File tools/ với các module:

tools/__init__.py:

App imports:

tools/
├── __init__.py      # Export ALL_TOOLS
├── datetime.py      # Date/time tools
├── email.py         # Email tools
├── search.py        # Search tools
├── calendar.py      # Calendar tools
└── file.py          # File ops tools
from .datetime import (
    get_current_datetime, get_current_datetime_schema,
    add_duration_to_datetime, add_duration_to_datetime_schema,
)
from .email import search_emails, search_emails_schema
# ... etc

ALL_TOOLS = [
    get_current_datetime_schema,
    add_duration_to_datetime_schema,
    search_emails_schema,
    # ... etc
]

Tool organization: 5+ tools (tiếp)

from tools import ALL_TOOLS
from tools import TOOL_FUNCTIONS  # registered via decorator

run_conversation(user_msg, tools=ALL_TOOLS)

Selective tool exposure

Không phải conversation nào cần tất cả tool. Expose theo context:

Giảm tool count → Claude pick chính xác hơn + cost thấp hơn (schemas tốn token).

# Customer service agent
CUSTOMER_SERVICE_TOOLS = [
    get_order_status_schema,
    create_refund_request_schema,
    search_kb_schema
]

# Sales agent
SALES_TOOLS = [
    lookup_customer_schema,
    create_quote_schema,
    schedule_meeting_schema
]


def run_agent(user_msg: str, agent_type: str):
    tools_map = {
        "customer_service": CUSTOMER_SERVICE_TOOLS,
        "sales": SALES_TOOLS
    }
    return run_conversation(user_msg, tools=tools_map[agent_type])

Parallel tool execution

Khi Claude request nhiều tool independent (không phụ thuộc nhau), execute parallel:

Nếu Claude call 5 API parallel, mỗi mất 1s → async tổng 1s (vs 5s sync).

import asyncio

async def run_tools_parallel(tool_uses):
    async def _run_one(tu):
        try:
            output = await asyncio.to_thread(run_tool, tu.name, tu.input)
            return {
                "type": "tool_result",
                "tool_use_id": tu.id,
                "content": str(output),
                "is_error": False
            }
        except Exception as e:
            return {
                "type": "tool_result",
                "tool_use_id": tu.id,
                "content": str(e),
                "is_error": True
            }
    
    results = await asyncio.gather(*(_run_one(tu) for tu in tool_uses))
    return results

Tool performance metrics

Track mỗi tool:

Insight:

  • Tool nào dùng nhiều → optimize first
  • Tool nào error rate cao → debug
  • Tool nào slow → cache hoặc async
from collections import defaultdict
import time

tool_metrics = defaultdict(lambda: {"calls": 0, "errors": 0, "total_time": 0})


def run_tool_tracked(name, input_data):
    start = time.time()
    try:
        result = run_tool(name, input_data)
        tool_metrics[name]["calls"] += 1
        return result
    except Exception as e:
        tool_metrics[name]["errors"] += 1
        raise
    finally:
        tool_metrics[name]["total_time"] += time.time() - start


# Report
for name, m in tool_metrics.items():
    avg_time = m["total_time"] / m["calls"] if m["calls"] > 0 else 0
    error_rate = m["errors"] / m["calls"] if m["calls"] > 0 else 0
    print(f"{name}: {m['calls']} calls, {error_rate:.1%} error, {avg_time:.2f}s avg")

Anti-patterns

❌ 20 tools, không organization

Flat list → messy, hard to maintain.

Fix: Tách module theo domain.

❌ Expose all tools cho mọi context

Tool "admin_delete_user" exposed cho chatbot public.

Fix: Scoped tools theo role/context.

❌ Tool description giống nhau

Claude confused pick.

Fix: Description rõ + "don't use for X" để guide.

❌ Sequential execution khi parallel có thể

5 independent tool, chạy sync → 5x slower.

Fix: asyncio.gather parallel.

Áp dụng ngay

Bài tập 1: Add 3 tools mới (30 phút)

Cho reminder app, add:

Test scenario: "Show my reminders, delete the one about dentist, update the work meeting to 'team standup'."

Bài tập 2: Parallel execution (20 phút)

Scenario: "Get weather in SF, NYC, Tokyo."

Claude request 3 get_weather calls. Implement parallel với asyncio. Đo thời gian sync vs async.

  • list_reminders() — list upcoming reminders
  • delete_reminder(id) — delete by ID
  • update_reminder(id, new_text) — update

Tóm tắt

🎯 Adding tool = 4 bước: function + schema + add to list + test. Không refactor.

🎯 Scale 10+ tools: organize modules, selective exposure, metrics.

🎯 Tool description quality quyết định Claude pick đúng.

🎯 Parallel execution cho independent tools → speedup 5-10x.

🎯 Track metrics per tool cho observability production.

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