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
17 changes: 17 additions & 0 deletions tests/test_text_model_dispatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,20 @@ class _Vlm:
with caplog.at_level(logging.ERROR, logger="vllm_mlx.text_model_from_vlm"):
assert build_text_model(_Vlm(), tmp_path) is None
assert not caplog.records


@pytest.mark.parametrize("model_type", ["qwen4_exp", "qwen4_exp_text"])
def test_qwen4_exp_stays_on_mlx_vlm_text_path(tmp_path, caplog, model_type):
"""Qwen4-Exp is not compatible with the generic Qwen3.5 TextModel."""
(tmp_path / "config.json").write_text(
'{"text_config": {"model_type": "' + model_type + '"}}'
)

class _Vlm:
language_model = object()

with caplog.at_level(logging.INFO, logger="vllm_mlx.text_model_from_vlm"):
assert build_text_model(_Vlm(), tmp_path) is None

assert "mlx-vlm text path" in caplog.records[-1].getMessage()
assert not [record for record in caplog.records if record.levelno >= logging.ERROR]
13 changes: 13 additions & 0 deletions vllm_mlx/text_model_from_vlm.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@
# that names neither the model nor the class. Hence the logging either side.
_DEFAULT_TEXT_MODEL = ("mlx_lm.models.qwen3_5", ("TextModel", "TextModelArgs"))

# These architectures are not compatible with the generic Qwen3.5 text
# skeleton. Returning no extracted TextModel keeps SimpleEngine on the loaded
# mlx-vlm path for text as well as media instead of silently serving incorrect
# logits from a mechanically compatible but architecturally different model.
_VLM_ONLY_TEXT_MODEL_PREFIXES = ("qwen4_exp",)


def _import_text_model_classes(model_type: str):
"""Return ``(Model, ModelArgs)`` for a text config's ``model_type``."""
Expand Down Expand Up @@ -92,6 +98,13 @@ def build_text_model(
config = json.loads((model_path / "config.json").read_text())
text_config = config.get("text_config", config)
model_type = text_config.get("model_type") or config.get("model_type", "")
if model_type.startswith(_VLM_ONLY_TEXT_MODEL_PREFIXES):
logger.info(
"Keeping model_type=%r on the mlx-vlm text path; no compatible "
"mlx-lm TextModel is registered",
model_type,
)
return None
TextModel, TextModelArgs = _import_text_model_classes(model_type)
text_model_cls = f"{TextModel.__module__}.{TextModel.__qualname__}"
logger.debug(
Expand Down
Loading