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.
As of LFM2.5-VL the family also reads images. The VL model pairs a SigLIP2 encoder with the same hybrid language tower, so it inherits the short KV cache.
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 |
| LFM2.5-VL-3B-OptiQ-4bit | 6.3 GB | 2.83 GB | 2.2× | 37.93 |
| LFM2.5-8B-A1B-OptiQ-4bit | 15.8 GB | 5.46 GB | 2.9× | 28.69 |
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.
Vision
LFM2.5-VL-3B adds a 27-layer SigLIP2 encoder and a two-layer projector on top of the hybrid language tower. OptiQ quantizes the language path to mixed 4/8-bit and keeps the encoder and projector at bf16 in the optiq/ sidecar, so one artifact does text and images.
| Property | Value |
|---|---|
| Vision tower | SigLIP2, 27 layers, hidden 1152, patch 16 |
| Resolution | native aspect ratio, position embeddings resampled per image |
| Token budget | 2×2 pixel unshuffle before the projector, capped at 256 image tokens |
| Language tower | mixed 4/8-bit: 88 layers at 4-bit, 78 at 8-bit |
| On disk | 1.98 GB language + 0.85 GB vision |
Capability Score 37.93. It reads images well and its text scores sit mid-pack for a 3B, but it does not initiate tool calls: BFCL is 0.0% because the model works the answer out itself rather than calling the function. Asked for the area of a triangle it derives the formula, where the text-only 1.2B calls calculate_triangle_area and scores 45.0% through the same harness. It emits correct calls when told to use a tool, so the capability is there and the model simply does not reach for it. For agentic tool use at this size, take the text 1.2B or 2.6B.
The vision tower runs natively in MLX, with no PyTorch and no mlx-vlm at runtime. It was checked against the reference implementation across four patch grids and matches to bf16 round-off, so image answers are the base model's, not an approximation of them.
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