AI agents and automation Assemble manually

How to build an agent with tool-calling

Tool-calling is the heart of a modern AI agent. In this guide, you’ll build a working agent from scratch, walking through the journey from concept to debugging and evaluation.

What is tool-calling, and why is it needed?

Tool-calling is a mechanism where an LLM doesn’t just generate text but instead forms a structured request to an external tool (API, function, script). This transforms the LLM from a “conversational interface” into an autonomous executor. Without tool-calling, an agent cannot interact with real-world systems: databases, CRMs, payment gateways, etc.

Agent’s thinking loop with tool-calling

flowchart TD  
    A[User] -->|Request| B[Context + Instruction]  
    B --> C[LLM: Planning]  
    C --> D{Tool needed?}  
    D -->|Yes| E[Generate tool_call]  
    D -->|No| F[Generate response]  
    E --> G[Execute tool]  
    G --> H[Tool result]  
    H --> I[LLM: Synthesize response]  
    I --> J[Response to user]  
    F --> J

Minimal example: Python + OpenAI

Example of an agent that can retrieve the current time via a tool:

import openai

# 1. Tool (actual function)
def get_current_time():
    from datetime import datetime
    return datetime.now().isoformat()

# 2. Tool description for the LLM
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_current_time",
            "description": "Returns the current time in ISO format",
            "parameters": {"type": "object", "properties": {}}
        }
    }
]

# 3. Agent loop
messages = [{"role": "user", "content": "What time is it now?"}]

response = openai.chat.completions.create(
    model="gpt-4o-mini",
    messages=messages,
    tools=tools,
    tool_choice="auto"
)

choice = response.choices[0]
if choice.message.tool_calls:
    # 4. Execute the tool
    tool_call = choice.message.tool_calls[0]
    if tool_call.function.name == "get_current_time":
        result = get_current_time()
        messages.append(choice.message)
        messages.append({
            "role": "tool",
            "tool_call_id": tool_call.id,
            "content": result
        })
        # 5. Final response
        final = openai.chat.completions.create(
            model="gpt-4o-mini",
            messages=messages
        )
        print(final.choices[0].message.content)
else:
    print(choice.message.content)

Typical Errors During Assembly

  • No validation for tool_call — The agent calls a non-existent tool or one with incorrect parameters. Solution: Always verify `tool_call.function.name` and `arguments` before execution.
  • Cyclic calls — The agent keeps calling the same tool infinitely. Solution: Limit the number of tool calls per session (e.g., `max_steps=5`).
  • Context leak — Tool results end up in the public log. Solution: Filter `tool_call` and `tool` messages before saving.
  • Missing fallback — When the tool encounters an error, the agent “hangs.” Solution: Return a structured error (e.g., `{"error": "DB_TIMEOUT", "retry_after": 30}`).

Example: CRM assistant agent

Scenario: User requests “find client by email and show the last deal.”

  • Tools: `find_customer(email)`, `get_last_deal(customer_id)`
  • Context: Instruction + Dialogue History + Tool Descriptions
  • Agent log:
    Find the client ivan@company.com and show the last deal.  
    → tool_call: find_customer(email="ivan@company.com")  
    → {"id": "c123", "name": "Ivan Petrov"}  
    → tool_call: get_last_deal(customer_id="c123")  
    → {"deal": "SaaS Pro", "amount": 15000, "date": "2025-04-10"}  
    → Ivan Petrov’s last deal: SaaS Pro (15,000 ₽, April 10).

Pre-launch checklist

  • [ ] All `tool_call`s are handled in `try/except` with a fallback message
  • [ ] Step limit (max_steps) is set and logged
  • [ ] Tools do not return sensitive data (passwords, tokens)
  • [ ] Audit: saves `tool_call.id`, `name`, `status`, `duration_ms`
  • [ ] Tests: there are evals with mocked tools
  • [ ] Human review: manual approval enabled for critical tools (e.g., fund debits)

Next step

After mastering basic tool-calling—move on to agent testing and orchestration of stepsIn a real project, you’ll combine tool-calling with memory, retries, and fallback logic—this creates resilient agent systems.