LFM2.5 on Apple Silicon
LFM2.5 is Liquid AI's on-device series, from 230M up to an 8B sparse MoE. It is a hybrid: short convolutional blocks alternate with full-attention blocks, and only the attention blocks carry a KV cache. On the 1.2B that means six layers hold cache out of the whole stack, so memory grows slowly as context does. That is the property that makes the family interesting on a laptop or a phone, and it is why the bundled KV config is short.
The quants
Every row is a six-metric Capability Score, not a perplexity number. Sizes are the artifact on disk.
| Model | bf16 size | OptiQ size | Compression | Capability Score |
|---|---|---|---|---|
| LFM2.5-230M-OptiQ-4bit | 443 MB | 180 MB | 2.5× | 24.83 |
| LFM2.5-350M-OptiQ-4bit | 681 MB | 269 MB | 2.5× | 26.60 |
| LFM2.5-1.2B-Instruct-OptiQ-4bit | 2.34 GB | 825 MB | 2.8× | 47.82 |
| LFM2.5-1.2B-Thinking-OptiQ-4bit | 2.34 GB | 820 MB | 2.9× | 54.14 |
| LFM2.5-1.2B-JP-202606-OptiQ-4bit | 2.34 GB | 838 MB | 2.8× | 47.83 |
| LFM2.5-2.6B-OptiQ-4bit | 5.2 GB | 1.93 GB | 2.7× | 35.19 |
Which one to reach for
The Thinking variant is the one to use if you can spare the tokens. It scores 64.7% on MMLU against the Instruct model's 43.3%, and 82.8% on GSM8K against 69.7%. Reasoning is doing real work at this size, not decorating the answer.
The Japanese variant is the interesting one. Its overall score lands at 47.83 against the Instruct model's 47.82, near enough to call identical, but the capability sits in different places: seven points more on MMLU, nearly ten more on HumanEval, and roughly eight less on both GSM8K and IFEval. Same total, redistributed.
Below a gigabyte the 230M and 350M are useful for classification, routing and extraction rather than open-ended chat. Both score at chance on long-context retrieval.
Hello world
from mlx_lm import load, generate model, tok = load("mlx-community/LFM2.5-1.2B-Thinking-OptiQ-4bit") prompt = tok.apply_chat_template( [{"role": "user", "content": "What is 17 * 23? Think briefly then answer."}], tokenize=False, add_generation_prompt=True, ) print(generate(model, tok, prompt=prompt, max_tokens=2048))
max_tokens. Set the cap too low and the entire allowance is consumed before the answer starts, so you get an empty string back rather than a short reply. 2048 is a sensible floor.
Tool calling
LFM2.5 does not emit JSON tool calls. It writes Python, between two special tokens:
<|tool_call_start|>[get_weather(city="Paris")]<|tool_call_end|>
Pass tools= to apply_chat_template and the catalog is rendered into the system prompt. OptiQ parses this form in both the evaluator and the agent loop, so a model that calls tools correctly scores as though it does.
Serving
Each quant ships a kv_config.json sized for its handful of attention layers. On the 1.2B that is six layers at roughly four bits.
optiq serve --model mlx-community/LFM2.5-1.2B-Thinking-OptiQ-4bit \ --kv-config kv_config.json