Instructions to use peculiar-ragdoll/Sharp-LFM2.5-Chat-Templates with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- MLX
How to use peculiar-ragdoll/Sharp-LFM2.5-Chat-Templates with MLX:
# Download the model from the Hub pip install huggingface_hub[hf_xet] hf download peculiar-ragdoll/Sharp-LFM2.5-Chat-Templates --local-dir Sharp-LFM2.5-Chat-Templates
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- LM Studio
- Atomic Chat
Sharp LFM2.5 Chat Templates
A drop-in chat template for LFM2.5-24B-A2B: Liquid AI's own template with four rendering bugs fixed and the Sharp terseness prompt added.
It is the same idea as Qwen-Sharp-Chat-Templates,
applied to Liquid's template rather than ported from Qwen's. LFM2.5 has its own control tokens, its
own Pythonic tool-call encoding and a generation prompt that always opens <think>; all of that is
kept exactly as Liquid wrote it.
Status: v1.0.0, compatibility-verified, effect not yet benchmarked. Everything under Verified was measured on the vendor Q4_K_M GGUF. What the terseness prompt does to answer length and quality on this model has not been measured yet — a Claw-Eval terse on/off run is set up and will be published here when it completes. Until then this card makes no token-savings or accuracy claim for LFM2.5. (On Qwen the same prompt measured +7.4 answer score and −59% answer tokens on Claw-Eval, but that is a different model family.)
What it fixes
Each fix is checked in both directions by check_template.py: the stock template really has the
bug, and this one really doesn't.
1. developer messages become system messages. OpenAI's newer clients — Codex, anything on the
Responses API — send the system prompt as role developer. Stock renders it as a role the model
was never trained on, and when tools are present the tool list ends up in a separate system turn.
stock: <|im_start|>developer\nBe brief.<|im_end|>
sharp: <|im_start|>system\nBe brief.<|im_end|>
llama.cpp already remaps this role before rendering; transformers, vLLM and the MLX servers don't.
2. Past answers that mention </think> are no longer truncated. Stock cuts every past assistant
turn at the last </think> it contains — including one the answer merely talks about:
user: How do I end a think block?
assistant: Close the block with </think>, then write the answer.
stock replays: , then write the answer.
sharp replays: Close the block with </think>, then write the answer.
A raw reasoning trace left inline in content is now cut at its first </think>, so a mention
later in the answer survives too, and a trace supplied both inline and in reasoning_content is no
longer rendered twice.
3. Raw reasoning replays with its opening tag. The generation prompt opens <think> itself, so
raw model output never contains it. A client that replays raw output — --reasoning-format none,
or anything that stores content verbatim — got an orphan closing tag in the current turn:
stock: <|im_start|>assistant\nUse get_weather.</think><|tool_call_start|>[get_weather(city='Oslo')]…
sharp: <|im_start|>assistant\n<think>Use get_weather.</think><|tool_call_start|>[get_weather(city='Oslo')]…
4. Attachments no longer leak into the prompt. LFM2.5-24B-A2B is text-only. Stock pasted an
OpenAI image_url part into the prompt as raw JSON — base64 payload and all — and rendered a bare
{"type": "image"} part as <image>, which in this tokenizer is a special token left over from
Liquid's vision models (an image slot with no image behind it). Responses-API input_text /
output_text parts were also dumped as JSON.
stock: {"type": "image_url", "image_url": {"url": "data:image/png;base64,iVBORw0KGgo..."}}What is this?
sharp: [image omitted]What is this?
Audio, video and file parts render as [attachment omitted]; Responses-API text parts render as text.
What it adds
The Sharp terseness prompt, appended after your own system prompt and before the tool list. Your system prompt is kept; nothing you pass in is replaced.
<|im_start|>system
You are a support agent.
Answer directly, after thinking. Lead with the answer, then only what it needs to be correct and usable.
Never: open with preamble or pleasantries; restate the question; add filler transitions; hedge with niceties; or repeat a point you've already made.
Always: keep essential steps, caveats, uncertainties, and specifics — never drop correctness or a needed warning for brevity. Keep the final answer lean. Use the least structure that conveys it (plain prose when short; lists or code only when they earn their place). If genuinely uncertain, say so and explain why — never omit uncertainty for the sake of brevity.
If a user request is genuinely ambiguous, ask a sharp question, don't guess.
List of tools: [{"type": "function", "function": {"name": "get_weather", ...}}]<|im_end|>
The text is word-for-word the one in the Qwen Sharp template (v22.5.0), so results stay comparable across families. Only the "after thinking" lead is used, because LFM2.5 always thinks.
What it deliberately doesn't change
Control tokens, the Pythonic tool-call encoding, the pre-opened <think>, Liquid's
preserve_thinking kwarg, the transformers {% generation %} and continue-final-message hooks, and
the error on JSON-string tool arguments are all untouched.
That includes three things that look like quirks. The model card's example shows double-quoted arguments with the call before the text; the template renders single quotes, text first, and JSON literals inside nested arguments. We checked what the model actually generates — see below — and the template is right; the card's example predates LFM2.5.
With no system prompt, no tools and terseness off, the render is byte-identical to stock across 18 conversation shapes. Every difference from Liquid's template is one of the changes above.
Verified
On the vendor LFM2.5-24B-A2B-Q4_K_M.gguf, llama.cpp build 9890:
- llama.cpp still uses its dedicated LFM2.5 parser. The server logs
Using specialized template: LFM2.5with this template loaded (see the warning under Use). - llama.cpp and transformers render it identically — 13 of 13 test conversations, byte for byte, once llama.cpp's handling of the leading BOS is accounted for (it strips it from the text and adds exactly one back when tokenizing; checked).
- The model's own output matches the template's encoding. In 12 raw generations it wrote
…</think><|tool_call_start|>[get_weather(city='Oslo')]<|tool_call_end|>— single-quoted strings,\'escapes,{"remind": true, "room": null}inside nested arguments, nothing between</think>and the call. - Tool loops keep the prompt cache. Through
/v1/chat/completions, with the client sendingreasoning_contentback, turn 2 re-processed only the 16 new tokens in 3 of 3 conversations: the replayed history matched the generation token for token. A client that dropsreasoning_contentstill works, but re-processes the previous assistant turn (31–63 tokens in our test).
Use
Do not edit the
List of tools: [line. llama.cpp chooses its LFM2.5 parser by finding that exact text in the template. Without it, llama.cpp falls back to a generic parser that can't handle a reply that starts inside<think>, and the reasoning leaks into the answer. For the same reason, don't add LFM2's older tool-list tokens anywhere in the file, comments included — they select a different parser.
llama.cpp, per run (replaces whatever template the GGUF embeds):
hf download peculiar-ragdoll/Sharp-LFM2.5-Chat-Templates chat_template.jinja --local-dir .
llama-server -m LFM2.5-24B-A2B-Q4_K_M.gguf --chat-template-file chat_template.jinja -ngl 99
Check it took: curl localhost:8080/props | jq -r .chat_template | head -3 should show
LFM2.5 Sharp chat template v1.0.0.
llama.cpp, permanently — rewrite the GGUF's embedded template without requantizing:
pip install gguf
gguf-new-metadata --chat-template-file chat_template.jinja input.gguf output.gguf
transformers / vLLM / MLX — put chat_template.jinja in the model directory, replacing
Liquid's. LFM2.5's tokenizer_config.json carries no embedded template, so the .jinja file is the
only source and there is nothing else to patch. These render through transformers' engine, which is
what the test suite uses; vLLM, MLX and LM Studio have not been run live with this template yet.
Keep reasoning in its own field. Leave llama.cpp's --reasoning-format at its default; none
leaves the trace inline in content. For agent loops, send each assistant turn's
reasoning_content back with the history — that is what keeps the prompt cache valid between tool
calls.
Turning terseness off
Per request, through chat_template_kwargs:
{"messages": [...], "chat_template_kwargs": {"terse": false}}
In Python, apply_chat_template(..., terse=False). A top-level terse field in the request body is
not passed to the template and has no effect. Turning it off keeps all four fixes; it removes only
the appended prompt.
suppress_tool_instructions. Some runtimes — LM Studio's MLX backend is the known case — have
no native tool-call parser and inject their own [TOOL_REQUEST] protocol into the system prompt.
When that marker is present the template leaves out its own tool list, so the model isn't given two
contradictory formats. {"suppress_tool_instructions": true} or false overrides the automatic
detection either way.
Tests
pip install transformers jinja2
python3 check_template.py
57 checks, rendered through transformers' own template compiler. They cover:
- No unintended drift: byte-identical to
chat_template_stock.jinja(Liquid's original, unmodified) on 18 conversation shapes that trigger none of the fixes. - Every fix, both ways: the stock template has the bug, this one doesn't.
- The additions: terseness on by default,
terse=Falsehonoured, the caller's system prompt kept, the[TOOL_REQUEST]stand-down and its override. - The wire format: call encoding, generation prompt and error paths unchanged.
- The llama.cpp parser guard:
List of tools: [present, LFM2's tool-list tokens absent.
The suite was itself tested by running it with the stock template in place of this one: exactly the 18 assertions about this template's behaviour fail, and nothing else.
Known limitations
- One
</think>case is still ambiguous. If a past answer mentions</think>and is sent without itsreasoning_content, it is treated as a raw trace and cut, exactly as stock does.</think>is one token whether it ends a trace or is quoted, and the model ends about half its traces with no newline before the tag (6 of 12 in our sample), so the two can't be told apart. Sendreasoning_contentback and the case doesn't arise. - Terseness unmeasured on LFM2.5 — see the status note at the top.
- Tested on Q4_K_M only. The template is the same for every quant, but live checks ran on one.
- Placeholders have no separator.
[image omitted]sits directly against the following text, in the same position stock put<image>.
What it isn't
- Not a fine-tune, despite the
base_model_relation: finetunetag — that is the closest vocabulary Hugging Face offers for "derived from", and it links this repo from Liquid's. No weights are involved. - Not an official Liquid AI release. This is an independent modification of their template.
Credits and license
The template is Liquid AI's work — the format, the tool-call encoding, the thinking conventions —
modified here as described above. chat_template_stock.jinja is their original, unmodified, kept for
the differential tests. The terseness prompt comes from
Qwen-Sharp-Chat-Templates.
Both templates are distributed under the LFM Open License v1.0, the license of the
original. Note its commercial-use condition (section 5): rights for commercial use are conditioned on your
entity staying under a US$10 million annual-revenue threshold. Read the license for the exact terms. chat_template.jinja carries a notice that it is
a modified file, as the license requires.
Citation
@misc{Sharp-LFM2.5-Chat-Templates,
title = {Sharp LFM2.5 Chat Templates},
author = {Saga Ishtardottir},
year = {2026},
url = {https://huggingface.co/peculiar-ragdoll/Sharp-LFM2.5-Chat-Templates},
note = {Liquid AI's LFM2.5-24B-A2B chat template with four rendering fixes and a default-on, switchable terseness system prompt (v1.0.0)}
}