Tool Calling with Local LLMs: A Practical Guide (2026)

Published: August 8, 2026 — Tool calling is the difference between a model that talks and a model that does. The model emits a structured request — "call search_kb(query='leave policy')" — your code runs it, and the model continues with the result. In 2026, local models handle this natively and reliably, which unlocks fully private agents. This guide covers the mechanics, the models that support it, a working Ollama loop, and the failure modes you'll actually hit.

⚡ Quick Takeaways

How Tool Calling Works

  1. You declare tools. Each tool is a name, a description, and a JSON Schema for its arguments.
  2. The model decides. When a tool would help, the model returns a tool_calls message instead of a plain answer — e.g. search_kb(query="leave policy", limit=3).
  3. You execute. Your code dispatches to the real function, with validation.
  4. You feed back the result. The tool output is appended as a tool message, and the model answers (or calls again).

The key mental model: the model proposes; your code disposes. Everything that actually happens — file writes, API calls, DB queries — runs through code you control. That's the safety property that makes local tool calling safe.

Which Local Models Support It

Model Tool calling Notes
Qwen3-8B / Qwen3.5-9B Excellent The 2026 default — multi-call, parallel calls, reliable JSON
GLM-4-9B Very good Strong schema adherence, good on CPU
Gemma 4 12B Very good Multimodal + tools; needs ~10GB VRAM
Llama 3.1/3.2 8B Good Reliable single calls; parallel calls weaker
Qwen3.5-4B Decent Tiny-hardware option; keep tool count low
Phi-4-mini Weak Great at math/code, not tool orchestration

Full rankings with downloads: sub-12B by power and sub-12B for coding.

The Minimal Ollama Tool Loop

import json, requests

# 1. Declare tools (JSON Schema)
tools = [{
    "type": "function",
    "function": {
        "name": "search_kb",
        "description": "Search the internal knowledge base for documents about a topic.",
        "parameters": {
            "type": "object",
            "properties": {
                "query": {"type": "string", "description": "Search phrase"},
                "limit": {"type": "integer", "minimum": 1, "maximum": 10}
            },
            "required": ["query"]
        }
    }
}]

# 2. The real function behind the tool
def search_kb(query: str, limit: int = 3) -> str:
    # In production: query ChromaDB (see the 30-min RAG guide)
    return f"[KB] Top {limit} results for '{query}'"

messages = [{"role": "user", "content": "What's our leave policy?"}]

for _ in range(5):  # iteration guard
    r = requests.post("http://localhost:11434/api/chat", json={
        "model": "qwen3:8b",
        "messages": messages,
        "tools": tools,
    })
    msg = r.json()["message"]
    messages.append({"role": "assistant", "content": msg.get("content") or ""})

    if msg.get("tool_calls"):
        for call in msg["tool_calls"]:
            fn = call["function"]
            if fn["name"] == "search_kb":
                result = search_kb(**fn["arguments"])
                messages.append({"role": "tool",
                                 "name": fn["name"],
                                 "content": result})
        continue

    print(msg["content"])   # final grounded answer
    break

That's the entire loop: declare tools → send → execute → feed back → repeat. requests and the Ollama API — no framework required. For graph control (loops, interrupts, persistence), layer LangGraph on top — see Build an AI Agent with LangGraph + Ollama.

Failure Modes and Fixes

Symptom Cause Fix
Model never calls tools Descriptions too vague; task doesn't need tools Write descriptions as triggers ("Call when the user asks about...")
Wrong arguments (string for number) Schema unclear; context leak Add examples to descriptions; enforce types in code
Calls wrong tool among many Tool count too high Keep ≤10 tools; merge related ones; use a router tool
Loops forever Tool result doesn't satisfy the task Iteration guard (see for _ in range(5)); improve tool output quality
Malformed JSON Model without native support Switch model or use prompt-based JSON protocol

The Safety Boundary

Where Tool Calling Takes You

🚀 In production

Lawyer Assistant uses exactly this pattern: the local model calls a retrieval tool over a ChromaDB index of legal documents, and every answer is grounded in what the tool returned. No cloud, no prompt leakage — just a model, a tool, and a loop.

Frequently Asked Questions (FAQ)

What is tool calling (function calling)?

Tool calling is when an LLM, instead of answering directly, emits a structured request to call a function you defined — with arguments in JSON. Your code runs the function and returns the result, and the model continues from there. It's the mechanism behind agents, RAG lookups, and API integrations.

Which local models support tool calling well?

The reliable 2026 picks: Qwen3 and Qwen3.5 (excellent), GLM-4-9B, Gemma 4, and Llama 3.1+ derivatives. Check each model card for tool-calling support — some small models only handle single-call, not multi-call parallel invocations.

How do I implement tool calling with Ollama?

Ollama's API accepts a tools array of JSON schemas alongside the model name. The response contains a message with tool_calls, which your code executes and appends as tool messages before calling again. The example in this post is a complete minimal loop.

Why does my local model call the wrong tool or wrong arguments?

Usually one of: tool descriptions too vague (the model doesn't know when to use them), too many tools in one call (models degrade past ~10), arguments colliding with context, or a model without proper function-calling fine-tuning. Fix the schema and descriptions before blaming the model.

Do I need a special model for tool calling?

Native tool calling needs a model trained for it — a JSON output in a specific format. Models without it can be coerced with prompt-based protocols (asking for JSON output), which is more fragile. Prefer natively supported models; they're common in 2026.

Is tool calling safe with local models?

The model is a request generator — your code decides what actually runs. That's the safety boundary: validate arguments, whitelist operations, require confirmation for destructive tools, and log every call. Local execution also means no data leaves the machine for any tool call.

Sources & Further Reading