Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions backend_service/mlx_worker_diagnostics.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,30 @@
_UNSUPPORTED_QUANT_ALGOS = {"NVFP4", "NVINT4"}


_FLINT_USE_GGUF = (
"Use the Flint INT4 GGUF (RecursiveSI/flint-int4-gguf) with the llama.cpp backend instead."
)


def _reject_unloadable_flint(model_dir: Path) -> None:
"""Say why a Flint checkpoint cannot load on MLX, instead of 'Model type flint not supported'."""
if (model_dir / "flint-int4.json").exists():
raise RuntimeError(
"Recursive's MLX INT4 build of Flint stores its embeddings in a layout only their own "
"rec engine reads, so MLX cannot load it. " + _FLINT_USE_GGUF
)
shipped = [
name
for name in ("mlx_lm", "mlx_vlm")
if importlib.util.find_spec(f"{name}.models.flint") is not None
]
if not shipped:
raise RuntimeError(
"The installed MLX packages do not include the Flint architecture "
"(mlx-vlm 0.7.10 or newer does). " + _FLINT_USE_GGUF
)


def _reject_unsupported_quant(model_path: str) -> None:
"""Raise early if the model uses a quantisation format MLX cannot handle."""
cfg_path = Path(model_path) / "config.json"
Expand All @@ -40,6 +64,8 @@ def _reject_unsupported_quant(model_path: str) -> None:
try:
with open(cfg_path) as f:
cfg = json.load(f)
if cfg.get("model_type") == "flint":
_reject_unloadable_flint(Path(model_path))
qcfg = cfg.get("quantization_config") or {}
algo = qcfg.get("quant_algo", "")
method = qcfg.get("quant_method", "")
Expand Down
33 changes: 33 additions & 0 deletions tests/test_mlx_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,3 +366,36 @@ def apply_chat_template(self, messages, **kwargs):

if __name__ == "__main__":
unittest.main()


class FlintOnMlxTests(unittest.TestCase):
"""A Flint checkpoint MLX cannot load fails with a reason and the way out."""

def _dir(self, *, marker: bool) -> str:
directory = Path(tempfile.mkdtemp())
self.addCleanup(lambda: __import__("shutil").rmtree(directory, ignore_errors=True))
(directory / "config.json").write_text(json.dumps({"model_type": "flint"}), encoding="utf-8")
if marker:
(directory / "flint-int4.json").write_text("{}", encoding="utf-8")
return str(directory)

def test_recursives_int4_export_points_at_the_gguf(self) -> None:
from backend_service.mlx_worker_diagnostics import _reject_unsupported_quant

with self.assertRaises(RuntimeError) as ctx:
_reject_unsupported_quant(self._dir(marker=True))
self.assertIn("RecursiveSI/flint-int4-gguf", str(ctx.exception))

def test_a_stack_without_the_architecture_says_so(self) -> None:
from backend_service.mlx_worker_diagnostics import _reject_unsupported_quant

with mock.patch("importlib.util.find_spec", return_value=None):
with self.assertRaises(RuntimeError) as ctx:
_reject_unsupported_quant(self._dir(marker=False))
self.assertIn("do not include the Flint architecture", str(ctx.exception))

def test_a_stack_that_ships_it_is_left_alone(self) -> None:
from backend_service.mlx_worker_diagnostics import _reject_unsupported_quant

with mock.patch("importlib.util.find_spec", return_value=object()):
_reject_unsupported_quant(self._dir(marker=False))
Loading