> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Lab Walkthrough Build a Tool Calling App

> Guide to building a Python app where an LLM suggests tool calls, dispatches local handlers, and returns tool outputs for final responses.

Time to put this into practice.

In this hands-on lesson you'll build a small Python application where the language model decides when to call tools on your behalf. You'll:

* Define tool schemas the model can inspect
* Implement local handler functions that perform the requested work
* Wire a tool-call loop that executes model-suggested tool calls and returns results for the model to finalize a reply

This same pattern—model suggests a tool call, your app runs the tool, and the model composes the final answer—powers many AI agents.

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/z7NmHsFQN9LCEiD0/images/AI-Agents-for-Beginners-OpenClaw-Case-Study/Tools-and-Workflows/Lab-Walkthrough-Build-a-Tool-Calling-App/retro-tool-calling-app-poster.jpg?fit=max&auto=format&n=z7NmHsFQN9LCEiD0&q=85&s=11af2337d4334ab2c8685f337529393d" alt="A retro-style poster with large yellow pixel text reading &#x22;BUILD A TOOL-CALLING APP&#x22; and a small teal label &#x22;HANDS-ON LAB&#x22; with a key icon. It also shows the lines &#x22;Define tools · Write handlers · Wire the loop,&#x22; a green &#x22;TOOL-CALL LOOP&#x22; button, and the tagline &#x22;The same pattern that powers every AI agent&#x22; on a dark grid background." width="1920" height="1080" data-path="images/AI-Agents-for-Beginners-OpenClaw-Case-Study/Tools-and-Workflows/Lab-Walkthrough-Build-a-Tool-Calling-App/retro-tool-calling-app-poster.jpg" />
</Frame>

Prerequisites

* Python 3.11 (virtual environment recommended)
* OpenAI SDK installed in the environment
* Working directory: `/root/code`

Step 1 — Create the app file
Create a file named `tool_app.py` in `/root/code`:

```bash theme={null}
vi /root/code/tool_app.py
```

Step 2 — Full example: tool-call loop
Below is a concise, complete script that demonstrates the pattern end-to-end: define tool schemas (JSON-schema style), implement local handler functions, dispatch tool calls from the model response, and provide tool outputs back to the model for a final answer.

```python theme={null}
# tool_app.py
import os
import json
from openai import OpenAI

# Instantiate the client using environment variables:
# OPENAI_API_KEY and (optional) OPENAI_API_BASE
client = OpenAI(
    api_key=os.environ.get("OPENAI_API_KEY"),
    api_base=os.environ.get("OPENAI_API_BASE"),
)

# System-level instruction
system_message = "You are an assistant that can call local tools to answer user questions."

# Tool schema (JSON Schema-like)
tools = [
    {
        "name": "get_calendar",
        "description": "Retrieve calendar events for a given date. Returns a JSON array of events.",
        "parameters": {
            "type": "object",
            "properties": {
                "date": {"type": "string", "description": "Date in YYYY-MM-DD format"}
            },
            "required": ["date"]
        }
    }
]

# Local implementation of the tool. In a real app this would query a calendar API or DB.
def get_calendar(date: str) -> str:
    # Mocked calendar events for demonstration.
    events = [
        {"time": "10:00 AM", "title": "Team standup"},
        {"time": "02:00 PM", "title": "Dentist appointment"}
    ]
    # Return as JSON string so the model can parse it if needed.
    return json.dumps({"date": date, "events": events})

# Dispatcher maps tool name to the Python function
def execute_tool(tool_name: str, args: dict) -> str:
    if tool_name == "get_calendar":
        return get_calendar(args.get("date"))
    raise ValueError(f"Unknown tool: {tool_name}")

def main():
    messages = [
        {"role": "system", "content": system_message},
        {"role": "user", "content": "What's on my calendar today?"}
    ]

    # First request: the model may decide to call a tool
    response = client.chat.completions.create(
        model="openai/gpt-4.1-mini",
        messages=messages,
        tools=tools,
    )

    print("Finish reason:", response.choices[0].finish_reason)

    # If the model requested tool calls, process them
    if response.choices[0].finish_reason == "tool_calls":
        msg = response.choices[0].message
        # Append the model's tool call message to the conversation history
        messages.append({"role": msg.role, "content": msg.content})

        # Iterate over tool calls the model requested
        for tc in getattr(msg, "tool_calls", []):
            tool_name = tc.function.name
            # tc.function.arguments is usually a JSON string
            args = json.loads(tc.function.arguments)
            result = execute_tool(tool_name, args)

            # Provide the tool output back to the model as a tool message
            messages.append({
                "role": "tool",
                "tool_call_id": tc.id,
                "content": result
            })

        # Second request: with the tool outputs available, model composes the final answer
        final = client.chat.completions.create(
            model="openai/gpt-4.1-mini",
            messages=messages,
            tools=tools,
        )
        print(final.choices[0].message.content)
    else:
        # If the model answered directly (no tools), print the response
        print(response.choices[0].message.content)

if __name__ == "__main__":
    main()
```

Step 3 — Set environment variables
Before running the script, ensure your API key (and optional base URL) are exported:

```bash theme={null}
export OPENAI_API_KEY="sk-..."
# Optional if using a hosted or proxy endpoint:
# export OPENAI_API_BASE="https://api.your-hosted-openai.example"
```

Step 4 — Run the script

```bash theme={null}
python3 tool_app.py
```

Example output

```text theme={null}
Finish reason: tool_calls
You have a team standup at 10:00 AM and a dentist appointment at 02:00 PM today.
```

Why this works — quick summary

* You supply the model with a `tools` list. Each tool includes:
  * `name` — unique tool identifier
  * `description` — natural-language description of the tool's purpose
  * `parameters` — a JSON Schema-like object describing expected arguments
* The model may respond with a message whose finish reason is `tool_calls`. That response can include one or more tool call objects.
* Your app:
  1. Extracts the tool name and arguments from the model's tool call
  2. Executes the corresponding local function
  3. Appends a `role: "tool"` message containing the tool output (and `tool_call_id` for correlation)
  4. Calls the model again so it can compose a natural-language final answer using the tool output

Reference table — message roles and purpose

| Role | Purpose | Example |
| - | - | - |
| `system` | Global instructions for assistant behavior | `{"role":"system","content":"You are an assistant..."}` |
| `user` | End-user question or prompt | `{"role":"user","content":"What's on my calendar today?"}` |
| `assistant` | Assistant reply (may include tool calls) | Assistant-generated text or tool-call directives |
| `tool` | Tool outputs supplied back to the model | `{"role":"tool","tool_call_id":"...","content":"{...}"}` |

Links and further reading

* [OpenAI API reference](https://platform.openai.com/docs/api-reference)
* [JSON Schema](https://json-schema.org/understanding-json-schema/)
* For building production agents, consider robust validation, authentication, retries, and logging.

<Callout icon="lightbulb" color="#1CB2FE">
  Make sure your tool outputs are in a format the model can parse (for example, JSON strings or clear natural language). Also ensure `OPENAI_API_KEY` is set in your environment before running the script.
</Callout>

<CardGroup>
  <Card title="Watch Video" icon="video" cta="Learn more" href="https://learn.kodekloud.com/user/courses/ai-agents-for-beginner-openclaw-case-study/module/5063e430-2631-48f3-b37f-4b3dd0d5c166/lesson/7a21ce89-e784-49f0-8a2b-056b41fa5f0f" />
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.