How to give tools to a model whose template reads xml_tools (SmolLM3)
This guide shows how to make a model like SmolLM3 call mm's tools. Its card says it supports tool calling, but through mm it never calls one: it describes the command instead of running it. It assumes you already have an agent file for that model (written by mm init, for example).
Why it does not work by default
mm sends its tools in the OpenAI API's tools field, and llama-server (behind llmman, Ollama, DMR…) hands them to the model's chat template under that name. SmolLM3's template never reads tools: it reads xml_tools (the argument of apply_chat_template(xml_tools=…) in its card's example). The model therefore never sees a tool. Given xml_tools, it answers with the call as text — <tool_call>{"name": "bash", "arguments": {"command": "ls"}}</tool_call> — which the server does not turn into a tool call.
Steps
-
In the agent file, add:
toolFormat: xml_toolsmm then sends the tools in
chat_template_kwargs.xml_tools, writes earlier calls back into the history as<tool_call>text (the template shows a message by its text only), and turns the<tool_call>blocks of the answer into tool calls — streamed or not. They do not appear in the answer's text. -
Turn the reasoning off — SmolLM3's template turns it on by default:
sampling: chat_template_kwargs: enable_thinking: falseWith reasoning on, SmolLM3-3B repeats its call after the tool's answer instead of answering (measured: 3 runs out of 3; with it off, 6 out of 6 answered).
-
Start
mmand ask for something a tool answers:List the files of this directory.A🛠️ bash: lsline, the command's output under it and the⚙ 1 command(s)counter show the call ran.
Variants
- A new agent. For the
smollm3family,mm initdoes both steps: it writestoolFormat: xml_toolswhen the usage has tools, andenable_thinking: falsewhatever the usage, with a note at the end of the file. - A usage without tools (
translator,json): nothing to do,toolFormatchanges nothing without tools. - See what goes over the wire. With
trace: {enabled: true}, the request files showchat_template_kwargs.xml_toolsand notools; the response files show the server's raw<tool_call>text, before mm reads it. See How to see the JSON sent to the model. - A broken call. A
<tool_call>whose JSON is cut (bymax_tokens) or malformed is handed back to the model with a note, as for any model, as long as its tool name can be read; otherwise it stays in the answer's text.
Limits
- Tasks of several steps stay fragile with SmolLM3-3B: in the tests, it sometimes took a tool's output for something the user said (the template shows a tool's answer as a user message). Wrapping the output in
<tool_response>tags made no measured difference. - llama.cpp's
common/chat.cpphad no SmolLM3-specific handling when this was written (2026-11-13), and the llama-server used by llmman did not parse the calls: hence the work on mm's side.
See also
- The key: Configuration reference (
toolFormat) - Turning reasoning off for other servers: How to turn a model's reasoning off
- Where the
smollm3numbers come from:mm initexplanation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
|