~/TechPurAI
~/tutorials/building-ai-agents/ai-agent-tools-and-function-calling-explained
intermediate·part 5 of 22·3 min read

AI Agent Tools and Function Calling Explained

Updated Aug 16, 2026AI

Part 4 covered one function schema in isolation. A real agent needs a genuine toolkit — several real, well-designed functions it can choose between and chain together. This part covers designing that toolkit correctly.

A real, complete toolkit for an inventory agent

python
tools = [
    {
        "name": "check_inventory",
        "description": "Check the current real stock level for a product SKU",
        "input_schema": {
            "type": "object",
            "properties": {"product_id": {"type": "string"}},
            "required": ["product_id"],
        },
    },
    {
        "name": "get_supplier_lead_time",
        "description": "Get the real, current lead time in days for a supplier",
        "input_schema": {
            "type": "object",
            "properties": {"supplier_id": {"type": "string"}},
            "required": ["supplier_id"],
        },
    },
    {
        "name": "create_reorder_request",
        "description": "Create a real reorder request for a product at a specific quantity",
        "input_schema": {
            "type": "object",
            "properties": {
                "product_id": {"type": "string"},
                "quantity": {"type": "integer"},
            },
            "required": ["product_id", "quantity"],
        },
    },
]

This is a real, complete, working toolkit — every tool from part 1's illustrative loop example, now as an actual, valid schema. Notice each one has one real, genuinely narrow, single responsibility.

The real, single-responsibility principle for tools

text
Too broad: a single manage_inventory tool that both checks stock
  AND creates reorders, distinguished by some real, internal
  "action" parameter — genuinely harder for the model to use
  correctly, since it has to also decide the right internal mode
Correctly scoped: check_inventory and create_reorder_request as two
  real, separate, narrow tools — the model's job is simply choosing
  the right ONE, not choosing a tool AND a mode within it
Why it matters

This directly parallels good real software design generally — a function that does one real thing is easier to reason about, test, and combine with others than one that does several real things behind a mode flag. The same real principle applies to designing tools for a model to choose between; narrower, more numerous real tools are genuinely easier for a model to select correctly than fewer, broader ones.

Why tool COUNT genuinely matters too

text
Too few, overly broad tools: the model struggles to express a
  precise real intent
Too many, narrowly overlapping tools: the model can genuinely
  confuse which of several, similar real tools is the correct choice
  for a given situation

A real, practical range for a single, well-scoped agent (per this series' own builds) is typically somewhere in the single digits to low double digits — genuinely fewer, more differentiated real tools tend to produce more reliable tool selection than a large, overlapping set.

The real, complete multi-tool loop, executing correctly

python
tool_functions = {
    "check_inventory": check_inventory,
    "get_supplier_lead_time": get_supplier_lead_time,
    "create_reorder_request": create_reorder_request,
}

def run_inventory_agent(request: str) -> str:
    messages = [{"role": "user", "content": request}]

    for _ in range(5):  # part 18 of the LLM & Advanced AI series' own iteration limit
        response = client.messages.create(
            model="claude-sonnet-5", max_tokens=1024, tools=tools, messages=messages,
        )
        messages.append({"role": "assistant", "content": response.content})

        if response.stop_reason != "tool_use":
            return response.content[0].text

        tool_call = next(b for b in response.content if b.type == "tool_use")
        result = tool_functions[tool_call.name](**tool_call.input)
        messages.append({
            "role": "user",
            "content": [{"type": "tool_result", "tool_use_id": tool_call.id, "content": str(result)}],
        })

This tool_functions dictionary — mapping each real tool's name to its actual, real Python function — is the genuine, direct link between the schemas the model sees and the real code that actually executes; every tool named in the schema needs a real, matching entry here, or the loop breaks the moment the model requests it.

Designing real tool descriptions the model can act on correctly

text
Weak: "gets inventory"
Strong: "Check the current real stock level for a product SKU —
  use this BEFORE deciding whether a reorder is needed"

Including real, explicit guidance about when to use a tool — not just what it does — genuinely improves the model's real decision-making at each loop iteration, directly extending part 4's point about description quality.

Next: building your first AI agent with Python — the complete, real, working inventory-monitoring agent, assembled end to end.

VK

Vijay Kumar

Founder of TechPurAI — writing hands-on tutorials and honest tool breakdowns.

LinkedIn ↗
← previous4. What Is Function Calling in LLMs?next →6. Build Your First AI Agent with Python