Cybersecurity

The Complete Loop

NLP LLMs GPT MCP AI Agents SQL Injection Cloud Databases SQL Rust
1,376 words Includes Code
🎯 Key Takeaway
Function calling lets an LLM decide which external tool to use and what arguments to pass — but the application code controls which tools exist, which are allowed, and what happens with the result. The LLM never executes code directly. It produces a structured request; your code validates and executes it.

You ask a chatbot: "What's the weather in London and what is 15 times 7 plus 3?"

The LLM doesn't know the weather. It can't reliably do arithmetic. But it knows which tool to call and what arguments to pass. That's function calling.

This tutorial explains the complete function calling loop — from user request through tool selection, validation, execution, and back to a final answer. You'll learn with safe calculator and weather examples, then understand the security model that makes this practical.

This tutorial builds on the How AI Coding Agents Work article and connects to MCP vs APIs and Structured AI Outputs.

1. The Complete Loop

Function calling follows a strict cycle. The LLM never breaks the loop by executing code directly.

User LLM (decides tool) Validate Execute Tool Result LLM (generates answer) User

Each step has a clear owner:

Step Owner What Happens
1. User asks User Natural language request
2. LLM decides LLM Selects tool + generates arguments as JSON
3. Validate Your code Permission check + argument validation
4. Execute Your code Runs the actual function
5. Return result Your code Sends result back to LLM as context
6. LLM answers LLM Generates natural language answer using tool result
Critical insight: The LLM produces a request to call a tool. It does not execute the tool itself. Your code decides whether to honor that request. This is the security boundary.

2. Tool Definitions

Before the LLM can call a tool, you define what tools exist. Each definition includes:

// Tool definition sent to the LLM
{
  "name": "calculator",
  "description": "Perform mathematical calculations",
  "parameters": {
    "type": "object",
    "properties": {
      "expression": {
        "type": "string",
        "description": "Math expression to evaluate"
      }
    },
    "required": ["expression"]
  }
}

The tool definition is essentially a JSON schema. The LLM reads this definition and generates arguments matching the schema when it decides to call the tool.

What the LLM Sees

You send the LLM a system message listing all available tools. The LLM doesn't execute them — it just knows they exist and what arguments they accept.

# System message (simplified)
You have access to the following tools:

calculator(expression) — Evaluate math
weather(city, units) — Get current weather

When you need a tool, respond with:
{"tool_calls": [{"name": "...", "arguments": {...}}]}

3. What the LLM Outputs

When the LLM decides to use a tool, it produces structured JSON — not executable code:

// LLM output when deciding to call a tool
{
  "tool_calls": [
    {
      "name": "calculator",
      "arguments": {
        "expression": "25 * 17 + 3"
      }
    }
  ]
}

Your code receives this JSON, validates it, and executes the calculator function with the argument "25 * 17 + 3". The LLM never touches the calculator code.

Multiple Tool Calls

The LLM can request multiple tools in a single response:

"tool_calls": [
  {"name": "weather", "arguments": {"city": "London"}},
  {"name": "calculator", "arguments": {"expression": "100 / 7"}}
]

Your code executes both tools and returns both results. The LLM then combines them into a natural language answer.

4. Validation and Security

Never trust the LLM's tool call output blindly. Always validate before execution.

Layer 1: Tool Allowlist

Which tools exist in your system? The LLM can only call tools you've defined.

Layer 2: Permission Check

Which tools is this request allowed to use? A customer-facing app might only allow calculator and weather — not file_reader or database_query.

def can_use_tool(tool_name, policy):
  if tool_name not in policy.allowed_tools:
    return False, "Tool not allowed"
  if tool_name in policy.blocked_tools:
    return False, "Tool explicitly blocked"
  return True, "Allowed"

Layer 3: Argument Validation

Even allowed tools can receive dangerous arguments. Validate before executing:

Tool Dangerous Argument Blocked By
calculator __import__('os').system('rm -rf /') Forbidden pattern blocklist
database_query DROP TABLE users SQL write-operation blocklist
file_reader /etc/passwd Sensitive path blocklist

Layer 4: Human Confirmation

For high-risk operations, require human approval before execution. The tool call pauses until a human clicks "Approve."

The principle: The LLM suggests. Your code decides. A human confirms (when needed). This triple-layer approach keeps the LLM from causing harm.

5. Calculator Example: Complete Walkthrough

Let's trace a complete function call for "What is 25 times 17 plus 3?"

# Step 1: User message
user: "What is 25 * 17 + 3?"

# Step 2: LLM responds with tool call
assistant: {
  "tool_calls": [{
    "name": "calculator",
    "arguments": {"expression": "25 * 17 + 3"}
  }]
}

# Step 3: Your code validates
Permission check: calculator → ✅ Allowed
Argument check: expression="25 * 17 + 3" → ✅ Safe

# Step 4: Your code executes
result = calculator(expression="25 * 17 + 3")
result = {"result": 428, "expression": "25 * 17 + 3"}

# Step 5: Result sent back to LLM
tool_result: {"result": 428}

# Step 6: LLM generates answer
assistant: "25 × 17 + 3 = 428"

The LLM chose the tool and arguments. Your code validated, executed, and returned the result. The LLM then wrote the final answer.

6. Weather Example

The same loop works for API calls:

user: "What's the weather in London?"

assistant: {
  "tool_calls": [{
    "name": "weather",
    "arguments": {"city": "London", "units": "celsius"}
  }]
}

result: {"city": "London", "temp": 15, "condition": "Cloudy"}

assistant: "It's currently 15°C and Cloudy in London."

In production, the weather function would call a real weather API. The pattern is identical — the LLM provides the arguments, your code makes the API call.

7. Function Calling vs MCP

Function calling and MCP (Model Context Protocol) solve related but different problems:

Aspect Function Calling MCP
What it is API-level feature from LLM providers Open protocol for tool integration
Tool definition JSON schema per request Server advertises tools dynamically
Execution Your code handles each call MCP server handles execution
Discovery Static (you define tools) Dynamic (server publishes tools)
Multi-tool Per-provider format Standardized across providers
Best for Simple, provider-specific tools Portable, multi-server integrations
They're complementary: Function calling is the mechanism. MCP is the ecosystem. MCP servers often expose tools through function calling. For a full comparison, see MCP vs APIs. For the MCP security model, see MCP Security Checklist.

8. Common Mistakes

Mistake Risk Fix
Executing tool calls without validation Malicious or malformed arguments Always validate before execution
No tool allowlist LLM invents tools that don't exist Define explicit tool list
Giving LLM all tools always Unnecessary access to sensitive tools Least-privilege per request
Trusting LLM arguments blindly SQL injection, path traversal Validate every argument
No retry on malformed output Single bad output = failure Retry with error feedback

9. FAQ

Can the LLM execute code directly?
No. In function calling, the LLM produces a JSON request describing which function to call with which arguments. Your application code receives this request, validates it, and executes the function. The LLM never has direct access to your system.
Which providers support function calling?
OpenAI (GPT-4, GPT-3.5), Anthropic (Claude via tool use), Google (Gemini), and Mistral all support function calling. The syntax varies slightly between providers, but the concept is identical: you define tools, the LLM generates structured calls, and your code executes them.
How many tools can I give the LLM?
Practically, 10-20 tools per request works well. Beyond that, the LLM may struggle to select the right tool, and the tool definitions consume context-window tokens. For many tools, consider MCP's dynamic tool discovery or hierarchical tool organization.
What if the LLM calls the wrong tool?
The LLM can make mistakes. That's why validation matters — if the LLM calls the wrong tool, your validation layer catches inappropriate arguments. If it calls a tool you didn't intend, the permission system blocks it. For critical applications, add a confirmation step before execution.

Continue Learning

Try the JSON Formatter

Put what you've learned into practice with this free BestWordz tool.

Open Tool →

Continue Learning: MCP & AI Agents

Build connected AI agent systems

  1. What Is LM Studio?
  2. The 15 AI Security Domains
  3. The Complete Loop (this article)
  4. Free-Form vs Structured Output
  5. Why RAG Exists: The Hallucination Problem