PromptisePromptise
Why PromptiseUse casesRoadmapDocs
GitHubGet started
Promptise - AI Framework LogoPromptise

The foundation layer for agentic intelligence. Build, secure and operate autonomous AI systems with Promptise Foundry.

pip install promptise

[01] Foundry

  • MCPcast
  • The Promptise Agent
  • Reasoning Engine
  • MCP
  • Agent Runtime
  • Prompt Engineering
  • Execution Engine
  • Agent Identity

[02] Resources

  • Documentation
  • GitHub
  • Guides
  • Learning Paths
  • Questions

[03] Company

  • About
  • Terms of Service
  • Privacy Policy
  • Cookie Policy
  • Subprocessors

© 2026 Promptise by Manser Ventures. All rights reserved.

Open source · Python

← Guides> Prompt Engineering

How LLM Tool Calling Works: The Model Never Runs Tools

How LLM tool calling works: the model writes a request, your code runs it. A real two-step refund exchange and design rules for tools, results and gates.

Level
Intermediate
Reading time
4 min
Published
Sep 20, 2025
Last updated
Oct 18, 2026
By
Promptise Team
  • LLM Mental Models
  • Tool Calling
  • Guardrails
Contents · 6 sections↓
  1. 01How does LLM tool calling work?
  2. 02Why it works this way
  3. 03Example: a refund on the user's say-so
  4. 04What it changes in practice
  5. 05Frequently asked questions
  6. 06Next steps

When an LLM "uses a tool", it doesn't run anything. It writes a structured request, a tool name plus JSON arguments, and your code decides whether and how to execute it. That one fact explains most of what goes right and wrong in agents. This essay explains how tool calling works, shows a real two-step exchange where the model asks to issue a refund, and gives the design rules that follow. It's for developers building assistants or agents with tools.

[01]

How does LLM tool calling work?

You send the model a list of tools, each with a name, a description and a JSON Schema for its arguments. When the model decides a tool would help, it replies with a tool call instead of text: get_order_status with {"order_id": "8812"}. Your code runs the function, sends the result back as a message, and the model continues, either with another call or a final answer. The model only ever sees the descriptions you wrote and the results you return.

Key takeaways:

  • The model proposes, your code disposes. Every tool call is a request. Execution, permissions and limits live in your code.

  • Descriptions are prompts. The model chooses tools and fills arguments from the names, descriptions and schemas you write.

  • Results are context. What you return is all the model knows about what happened. Make it short, clear and honest about errors.

  • Irreversible actions need a gate. The model will happily request a refund because a user asked. Your code should check policy or ask a human.


[02]

Why it works this way

Language models output text. Tool calling is a convention on top: models are fine-tuned on examples where the right next output is a structured call, so they learn when a call is appropriate and how to fill the arguments. Toolformer (Schick et al., 2023) showed a model could learn to insert API calls into text; ReAct (Yao et al., 2022) showed that alternating reasoning with actions and observations helps on multi-step tasks. Today's APIs (OpenAI function calling, Anthropic tool use) and the Model Context Protocol standardize the format, and constrained decoding can guarantee the arguments match your schema.

The orchestrator is your loop: call the model, execute what it asks, append the result, repeat until it answers or a limit hits. The model is the planner inside that loop, not the runtime.


[03]

Example: a refund on the user's say-so

Two tools, one of them irreversible. Run on gpt-5-mini; results vary by model.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
tools = [
  {"type": "function", "function": {
    "name": "get_order_status",
    "description": "Look up the shipping status of an order by its ID.",
    "parameters": {"type": "object", "properties": {"order_id": {"type": "string"}},
                   "required": ["order_id"], "additionalProperties": False}}},
  {"type": "function", "function": {
    "name": "refund_order",
    "description": "Refund an order in full. Irreversible.",
    "parameters": {"type": "object",
                   "properties": {"order_id": {"type": "string"}, "reason": {"type": "string"}},
                   "required": ["order_id", "reason"], "additionalProperties": False}}},
]
# user: "Where is my order 8812? If it's lost, just refund it."

The first reply has no text, only a call:

Output
tool_calls: [get_order_status {"order_id":"8812"}]

The code returns {"order_id": "8812", "status": "lost_in_transit", "carrier": "DHL", "last_scan": "2026-10-09"}. The second reply:

Output
tool_calls: [refund_order {"order_id":"8812","reason":"Order marked lost in transit; customer requested refund"}]

That's reasonable behavior, and it's still a request. Nothing has been refunded. Before running it, your code can check what the model can't: whether the user owns order 8812, whether the carrier claim window has passed, whether the amount is under the auto-approve limit. Above the limit, it can pause for a human. The description said "Irreversible", and the model called it anyway, because the user asked. Descriptions inform the model; they don't enforce anything.

The refund example as a sequence: the model requests get_order_status for order 8812, your code returns lost_in_transit, and the model requests refund_order. Before running it, your code checks ownership, the carrier claim window and the auto-approve limit, then runs the refund or pauses for a human.
FigureThe model proposes tool calls and your code decides: the refund example step by step

[04]

What it changes in practice

  • Put every rule that matters in code. Ownership checks, amount limits, rate limits, allowed values. Validate arguments against the schema and against your business rules before executing. The model's judgment is a first filter, not the control.

  • Write tools for the model as a reader. Clear names, one job per tool, descriptions that say when to use it and when not, argument descriptions with formats ("ISO 8601 date"). Fewer, well-separated tools beat many overlapping ones.

  • Return results the model can act on. Short JSON with the fields it needs. Errors should say what went wrong and what to try ("order not found; ask the user to check the ID"), not a stack trace or an empty string.

  • Bound the loop. Cap the number of steps and the cost per task, and stop on repeated identical calls.


[05]

Frequently asked questions

Does the model execute the function?

No. It returns the function name and arguments. Your application executes it, or doesn't, and sends the result back. Hosted tools such as a provider's built-in web search are executed by the provider, but the same principle applies: the model only requests.

How does the model choose which tool to call?

From the conversation plus the tool names, descriptions and schemas. Vague or overlapping descriptions cause wrong choices. With many tools, selection gets worse; see too many MCP tools.

Can tool calls be trusted?

Treat them like input from a user: the arguments may be wrong, and a prompt injection in a tool result can steer the next call. Validate and authorize every call in code.

What's the difference between tool calling and MCP?

Tool calling is the model-level mechanism: the model emits a structured call. MCP is a protocol for exposing tools, resources and prompts from separate servers to any compatible client, so tools don't have to be hard-coded into each app. See what is MCP?


[06]

Next steps

  • Plan multi-step calls and validate them first: LLM tool call planning.

  • Write the loop yourself: ReAct agent from scratch.

  • Gate risky actions: human-in-the-loop approval for AI agents.

  • Patterns for coordinating agents: LLM agent orchestration patterns.

  • Why tool results are an attack surface: treat LLM output as untrusted.

Contents

  1. 01How does LLM tool calling work?
  2. 02Why it works this way
  3. 03Example: a refund on the user's say-so
  4. 04What it changes in practice
  5. 05Frequently asked questions
  6. 06Next steps

Learning paths

Want more structure? Paths put guides in order, like a short course.

See the paths →

> Read next

Related guides

  • // 01Intermediate · 5 minWhy LLM Output Is Untrusted Input: Design for InjectionWhy to treat LLM output as untrusted: indirect prompt injection, OWASP LLM risks, a real injected support ticket, and design rules that contain the damage.
  • // 02Beginner · 4 minWhy Can't LLMs Count Letters? Tokens and ProbabilityWhy LLMs miscount letters, reverse strings wrong and miss word limits: tokenization, sampling, real failures, and why exact work belongs in your code.
  • // 03Intermediate · 18 minStop Secrets Leaking Into LLM Logs and TracesHow API keys and tokens end up in LLM logs and traces, and how to redact them from tool results, observability and log lines before anything is stored.
  • // 04Advanced · 20 minPolicy as Code for AI Agent Tool Calls: OPA vs ApprovalPolicy as code for AI agent tool calls: when deterministic rules beat human approval or model judgment, and how to check each call with OPA before it runs.
  • // 05Intermediate · 20 minAI-Based PII Detection and Redaction Tools for LLM AppsAI-based PII detection and redaction for LLMs: regex, NER, Presidio, cloud DLP and LLM detectors compared, with code to mask prompts, tool output and logs.
  • // 06Intermediate · 18 minHidden Text Prompt Injection: Sanitize Pages for AI AgentsStop hidden text prompt injection: strip CSS-hidden text, comments and invisible characters from web pages, scan what is left, and limit agent tools.

Keep going.

Browse every guide by topic and level, or follow a learning path that puts them in order.

All guidesLearning paths