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.
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.
- POST /api/chat with tools[]
- /v1 supports tools, not tool_choice
- Since May 28, 2025
- 4k tokens
Key takeaways
- 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.
- Only models whose template supports tools work. Check the tools tag on ollama.com or the capabilities array from /api/show.
- Streaming tool calls has worked since May 2025: accumulate content, thinking and tool_calls across chunks, then send them back together.
- Most failures in GitHub issues are template or parser mismatches (tool calls printed as text), not the model being dumb.
- 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:
- Send
model,messagesand atoolsarray to/api/chat. Each tool istype: "function"with aname,descriptionand a JSON Schemaparametersobject. - 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 withfunction.nameandfunction.arguments. - You append the assistant message (with its
tool_calls), run each function, and append one{"role": "tool", "tool_name": ..., "content": ...}message per result. - You send the whole history back. Repeat until a response contains no
tool_calls; that response’scontentis the final answer.
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:
pip install -U ollama
ollama pull qwen3from 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
toolstag 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 acapabilitiesarray (API reference):
curl -s http://localhost:11434/api/show -d '{"model":"qwen3-coder"}' | jq .capabilitiesIf 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 F1 | Note |
|---|---|---|
| qwen3:14B Q4_K_M | 0.971 | Best local model, close to hosted GPT-4 (0.974) |
| qwen3:8B F16 | 0.933 | Best under 10B, about half the 14B latency |
| qwen3:8B Q4_K_M | 0.919 | Quantization cost little |
| llama3.1:8B F16 | 0.835 | |
| qwen2.5:7B Q4_K_M | 0.753 | |
| gemma3:4B | 0.733 | |
| llama3.3:70B Q4_K_M | 0.607 | Size 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.
We build CandorNo GPU? Use a hosted model
Uncensored AI, right in your browser.
Candor runs open models with refusals removed, so it answers the questions other assistants deflect. New accounts get free credits, no card needed.
Try Candor freeDoes 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:
| Symptom | Likely cause | What to try | Evidence |
|---|---|---|---|
400 error as soon as tools is sent | Model template has no tool support | Pick a model with the tools tag; re-pull for an updated template | Zed #37221 |
Tool call printed as text (<tool_call> or raw JSON in content) | Parser/renderer mismatch or a version regression | Update Ollama; if a release broke it, pin the previous one | #14745 |
| Model announces an action but never calls it, or loops | Renderer uses a different format from the one the model was trained on | Try another tag or model; watch the issue for a fix | #14493 |
| First call works, the turn after the tool result fails with a 400 | Client sends message order or fields the model’s template rejects | Update the client; test the same model on /api/chat directly | Continue #9249 |
| Works early, degrades as the session grows | Context window too small, tool schemas truncated | Set OLLAMA_CONTEXT_LENGTH; docs recommend 64k+ for agents | Context docs |
tool_calls present in the API, agent does nothing | Client fails to parse streamed calls | Disable thinking or switch clients | OpenCode #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:
OLLAMA_CONTEXT_LENGTH=64000 ollama serve
ollama ps # check the CONTEXT columnTool 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.
We build CandorSkip the setup
Want an uncensored model without hosting one?
Candor (candorai.dev) is an uncensored AI chat app that runs in your browser: it answers the questions mainstream assistants dodge, on health, money, law and work, without the lecture. New accounts get free credits, no card needed.
Facts from candorai.dev, checked Nov 10, 2026. Candor never changes how we rank or review models. Disclosure.
Sources (10)
- Ollama docs: Tool calling
- Ollama blog: Tool support (July 25, 2024)
- Ollama blog: Streaming responses with tool calling (May 28, 2025)
- Ollama docs: OpenAI compatibility
- Ollama docs: Context length
- ollama-python: examples/tools.py
- Ollama models with tool support (ollama.com search, c=tools)
- ollama/ollama issue #14745: qwen3.5:9b prints tool call instead of executing it
- ollama/ollama issue #14493: Qwen 3.5 27B tool calling and renderer/parser mismatch
- Docker: Local LLM tool calling, a practical evaluation (June 30, 2025)
Written by Refusal Rate editors from papers, model cards, official docs and pricing pages. Anything we ran ourselves is labeled as our own test, with the hardware and settings. Our method.