refusal rate
Subscribe

Ollama tool calling explained: the tools field, the tool_calls loop in Python, streaming, how to find tool-capable models, and why calls fail in practice.

[ fig. 01 — how-to ]48×5
[ fig. 01 — how-to ]16×5

Short answer

Ollama tool calling works through the tools field on /api/chat (or /v1/chat/completions). The model returns message.tool_calls instead of text, your code runs the function, appends a role: tool message, and calls the model again until no tool_calls come back. Only models tagged tools on ollama.com support it, and most failures trace to chat templates, small context windows or client parsing.

Native endpoint
POST /api/chat with tools[]
OpenAI-compatible
/v1 supports tools, not tool_choice
Streaming tool calls
Since May 28, 2025
Default context (<24 GiB)
4k tokens

Key takeaways

  1. Ollama never executes your functions. It parses the model's output into tool_calls; your code runs them and sends results back as role: tool messages.
  2. Only models whose template supports tools work. Check the tools tag on ollama.com or the capabilities array from /api/show.
  3. Streaming tool calls has worked since May 2025: accumulate content, thinking and tool_calls across chunks, then send them back together.
  4. Most failures in GitHub issues are template or parser mismatches (tool calls printed as text), not the model being dumb.
  5. Raise the context window. Ollama defaults to 4k tokens under 24 GiB VRAM, and its docs recommend at least 64k for agents and coding tools.

Ollama tool calling is a request/response loop that your code drives: you describe functions in a tools array, the model answers with structured tool_calls instead of prose, and you run them. Ollama has supported it since July 2024 (Ollama blog), on the native API and on the OpenAI-compatible /v1 endpoint. The hard part in 2026 is not the API. It is picking a model and Ollama version whose template and parser agree, which is where most of the GitHub issues below come from.

How does Ollama tool calling work?

The model never runs anything: Ollama turns its output into message.tool_calls, and your application executes the function and sends the result back. The Ollama docs describe four steps:

  1. Send model, messages and a tools array to /api/chat. Each tool is type: "function" with a name, description and a JSON Schema parameters object.
  2. The model’s chat template renders the tool definitions into the prompt. When the model decides to call one, Ollama’s parser returns message.tool_calls, each with function.name and function.arguments.
  3. You append the assistant message (with its tool_calls), run each function, and append one {"role": "tool", "tool_name": ..., "content": ...} message per result.
  4. You send the whole history back. Repeat until a response contains no tool_calls; that response’s content is the final answer.
[ fig. 01 — The tool-calling loop, from the Ollama tool calling docs. ]
Ollama tool calling is a loop run by your code: send messages and tools, receive tool_calls, execute the function, append a role tool message, and call the model again until no tool_calls come back.

The docs also cover parallel calls (several tool_calls in one response, all results returned in one follow-up) and a multi-turn agent loop, where they suggest telling the model in the system prompt that it can call tools several times. Cap the loop in your own code anyway. Docker’s evaluation harness failed any test that still wanted tools after five rounds (Docker), which is a sane default.

How do you call a tool from Python or JS?

Install the official SDK and pass either Python functions or JSON schemas in tools; the SDK builds the schema from type hints and the docstring. This is the pattern from the official ollama-python example, trimmed:

bash
pip install -U ollama
ollama pull qwen3
python
from ollama import chat

def add_two_numbers(a: int, b: int) -> int:
    """Add two numbers.

    Args:
      a (int): The first number
      b (int): The second number
    """
    return int(a) + int(b)  # arguments don't always match the schema exactly

tools = {"add_two_numbers": add_two_numbers}
messages = [{"role": "user", "content": "What is three plus one?"}]

response = chat("qwen3", messages=messages, tools=list(tools.values()))
if response.message.tool_calls:
    messages.append(response.message)
    for call in response.message.tool_calls:
        fn = tools.get(call.function.name)
        output = fn(**call.function.arguments) if fn else "Function not found"
        messages.append({"role": "tool", "tool_name": call.function.name, "content": str(output)})
    response = chat("qwen3", messages=messages)
print(response.message.content)

Two details from that official example are worth keeping. The int() casts exist because returned arguments “don’t always conform exactly to schema”, so validate before you execute. And on the native API, arguments arrives as a parsed object, so you can unpack it directly.

JavaScript is the same shape: npm i ollama, then ollama.chat({ model, messages, tools }) and push role: 'tool' messages with tool_name (docs).

If your code already uses the OpenAI SDK, point it at http://localhost:11434/v1 with any API key and pass tools as usual. The OpenAI compatibility page marks tools as supported on /v1/chat/completions and function calling on /v1/responses, but tool_choice is not supported, so you cannot force a specific tool. See our Ollama OpenAI-compatible API guide for base URLs and the context-length catch on /v1.

Which models support tool calling in Ollama?

A model supports tool calling in Ollama only if its template handles tools, and Ollama labels those models with a tools tag. Three ways to check:

  • Browse ollama.com/search?c=tools, which filters the library to tool-capable models.
  • Look for the tools tag on a model page. For example, qwen3-coder carries it, in 30B (19 GB, 3.3B active parameters) and 480B variants with a 256K context.
  • Query /api/show, whose response includes a capabilities array (API reference):
bash
curl -s http://localhost:11434/api/show -d '{"model":"qwen3-coder"}' | jq .capabilities

If you send tools to a model without that capability, the request fails with a 400 instead of silently ignoring the tools; Zed had to stop sending tools to such models for that reason (Zed #37221). Third-party GGUFs pulled from Hugging Face are the usual surprise: their bundled template decides whether tools work, not the weights.

Which one to pick depends on your hardware, and the only systematic public comparison is dated. Docker’s June 2025 run of 3,570 test cases across 21 models found:

Model (Ollama tag)Tool selection F1Note
qwen3:14B Q4_K_M0.971Best local model, close to hosted GPT-4 (0.974)
qwen3:8B F160.933Best under 10B, about half the 14B latency
qwen3:8B Q4_K_M0.919Quantization cost little
llama3.1:8B F160.835
qwen2.5:7B Q4_K_M0.753
gemma3:4B0.733
llama3.3:70B Q4_K_M0.607Size did not help

Source: Docker, June 30, 2025. Those models are a generation old, but the pattern still matches community reports: the Qwen family is the default choice for tool use. In April 2026 the author of an MLX server reported on HN that Qwen models hit 100% tool-calling success across five agent frameworks, while Llama and DeepSeek-R1 ranged from 40% to 100% depending on the framework (HN). For coding agents specifically, see local LLM coding agent.

Does streaming work with tool calls?

Yes, since May 28, 2025. Before that, Ollama waited for the full output and parsed it as JSON, which blocked streaming (Ollama blog). The newer parser reads each model’s template to learn its tool-call prefix, so it can separate tool calls from normal text as tokens arrive. It also falls back to JSON parsing when a model emits a call without the prefix, and the prefix matching fixed duplicate tool calls caused by models repeating an earlier call.

With stream: true, the docs say to accumulate thinking, content and tool_calls across chunks, append them together as one assistant message with the tool results, and loop until a turn ends with no tool calls. The same post notes that a context window of 32k or more appears to improve tool-calling performance.

Streaming through the OpenAI-compatible layer is where clients break. In an OpenCode issue, users found that Gemma 4 streams a non-standard reasoning field in its deltas; the client saw empty content and missed the tool_calls in the final chunk, even though direct Ollama calls returned them correctly. The reported workaround was sending reasoning_effort: "none".

Why is Ollama tool calling not working?

When Ollama tool calling fails, the cause is usually a template, parser or context problem rather than the API call. The table maps symptoms in public issues to their likely cause:

SymptomLikely causeWhat to tryEvidence
400 error as soon as tools is sentModel template has no tool supportPick a model with the tools tag; re-pull for an updated templateZed #37221
Tool call printed as text (<tool_call> or raw JSON in content)Parser/renderer mismatch or a version regressionUpdate Ollama; if a release broke it, pin the previous one#14745
Model announces an action but never calls it, or loopsRenderer uses a different format from the one the model was trained onTry another tag or model; watch the issue for a fix#14493
First call works, the turn after the tool result fails with a 400Client sends message order or fields the model’s template rejectsUpdate the client; test the same model on /api/chat directlyContinue #9249
Works early, degrades as the session growsContext window too small, tool schemas truncatedSet OLLAMA_CONTEXT_LENGTH; docs recommend 64k+ for agentsContext docs
tool_calls present in the API, agent does nothingClient fails to parse streamed callsDisable thinking or switch clientsOpenCode #20995

Two of these deserve detail. Issue #14745 (March 2026) reported qwen3.5:9b writing its tool call as plain text on Ollama 0.17.7, which halts any agent. Several users said downgrading to 0.17.5 fixed it; it was closed via a fix PR on March 27, 2026, though one user later reported a similar regression on a different model. Issue #14493 argues that Ollama routes Qwen 3.5 through a Hermes-style JSON renderer while the model was trained on the Qwen3-Coder XML format, and that the Go runner accepts repeat_penalty and similar options but ignores them. A maintainer disputed the “completely non-functional” framing, partial fixes shipped in March, and users were still reporting problems in September 2026.

The context default matters more than most guides admit. Ollama gives 4k tokens on machines with under 24 GiB of VRAM (docs), and an agent with a dozen tool schemas can fill that before the user prompt. Raise it and confirm with ollama ps:

bash
OLLAMA_CONTEXT_LENGTH=64000 ollama serve
ollama ps   # check the CONTEXT column

Tool calling also does not compose with everything. A September 2026 HN comment noted that on Ollama, structured outputs are still incompatible with tool calling and reasoning (HN); for schema-constrained output on its own, see Ollama structured output.

What do developers report in practice?

The recurring theme in practitioner reports is that the model, the template and the client all have to agree, and you often cannot tell which one broke.

  • Templates are the usual suspect. A June 2026 HN commenter listed the possible causes on a mixed AMD setup: some models ship with broken templates, some are not trained for tool calling, and some agent harnesses don’t support the format (HN). Another April 2026 thread noted that many quantized GGUFs don’t support tool calling, so you have to check each one (HN).
  • Same model, different result locally. An r/LocalLLM poster found Qwen3.6 tool calls worked through a cloud router but failed every time on local Ollama with about 96 tool schemas. Replies suspected the template; the poster later attributed it to long-context attention problems on their AMD ROCm backend, fixed by moving tools to the end of the request or shrinking the payload (thread). That is one user’s diagnosis, not a confirmed bug.
  • Reasoning models without tool support print JSON. In an r/LocalLLM thread about OpenCode, the models returned JSON describing file reads but nothing ran; a reply pointed out that DeepSeek R1 8B can’t do tool calling and suggested a Qwen model with a tools template plus an Ollama update (thread). An HN user made the same point about DeepSeek on Ollama back in September 2025 (HN).
  • Client-side formatting breaks the second turn. The Continue report found Mistral and Gemma models failed after the tool result came back, while Qwen3 Coder, GLM and Kimi models completed the same flow (Continue #9249).
  • Ollama is actively changing here. An engineer who works on Ollama’s tool calling said on HN in September 2025 that there had been “a big push” over the previous year to improve parsing (HN). The practical upshot: an upgrade can fix your problem or cause it, so pin versions in anything you depend on.

If you are wiring tools from an MCP server rather than hand-written functions, the loop is the same but the setup differs; that is covered in Ollama MCP.

FAQ

Does Ollama support function calling?

Yes. Ollama calls it tool calling. Pass a tools array to /api/chat or to the OpenAI-compatible /v1/chat/completions, and tool-capable models return tool_calls that your code executes.

Which Ollama models support tool calling?

Models with the tools tag on ollama.com, listed at ollama.com/search?c=tools, or any model whose /api/show capabilities include tools. Qwen-family models (qwen3, qwen3-coder) are the most consistently reported to work.

Can I force Ollama to call a specific tool?

Not through tool_choice, which the OpenAI-compatible endpoint does not support. You can narrow the tools list to the one function you want and say so in the system prompt.

Why does my model print the tool call instead of running it?

Usually a parser or template mismatch between Ollama and that model, or a model not trained for tools. Update Ollama, check the model’s tools tag, and test with /api/chat directly to rule out your client.

Does tool calling work with streaming in Ollama?

Yes, since May 2025. Accumulate content, thinking and tool_calls from the chunks, then send the assistant message and tool results back for the next turn.

Sources (10)
  1. Ollama docs: Tool calling
  2. Ollama blog: Tool support (July 25, 2024)
  3. Ollama blog: Streaming responses with tool calling (May 28, 2025)
  4. Ollama docs: OpenAI compatibility
  5. Ollama docs: Context length
  6. ollama-python: examples/tools.py
  7. Ollama models with tool support (ollama.com search, c=tools)
  8. ollama/ollama issue #14745: qwen3.5:9b prints tool call instead of executing it
  9. ollama/ollama issue #14493: Qwen 3.5 27B tool calling and renderer/parser mismatch
  10. Docker: Local LLM tool calling, a practical evaluation (June 30, 2025)

Keep reading