Repository navigation
docs(mlx-deploy): fix setup steps that prevent a working install - #242
thijs-hakkenberg wants to merge 2 commits into
Conversation
Testing the MLX guide end-to-end on an M1 Pro surfaced three issues that stop the documented flow from working, plus two stale claims. - Step 3 installed the SDK with a bare `pip install -e .`, which omits torch/torchvision/transformers. The pipeline then fails at startup with `ImportError: Layout detector dependencies are missing or incompatible`. Use `pip install -e '.[layout]'`. - Step 4 presented a four-key `ocr_api` snippet as a usable custom config. A `--config` file replaces the YAML baseline rather than merging with the packaged `glmocr/config.yaml` (see `GlmOcrConfig.from_env`), so that snippet drops `layout.model_dir` and the run dies with `pipeline.layout.model_dir is required for self-hosted layout`. It also empties `layout.id2label`, `layout.label_task_mapping` and `page_loader.task_prompt_mapping`. Document the merge semantics and give two working approaches instead. - Note that `config.yaml` has two `model:` keys (`maas` and `ocr_api`); editing the wrong one leaves `ocr_api.model` as `glm-ocr` and the server returns an opaque HTTP 400. - mlx-vlm ships `glm_ocr` in PyPI 0.7.0, so the git install is no longer required (kept as a fallback). - The transformers conflict behind "Why a Separate Environment?" has converged: mlx-vlm needs >=5.0.0rc3 and the SDK's layout extra needs >=5.3.0. Two environments remain what this guide is tested against. Verified by running the corrected steps end-to-end against mlx-community/GLM-OCR-bf16 on Metal: CLI, Python API, and a scanned invoice PDF all parse successfully. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017e4v9dzir569nZhfSPydRE
The SDK runs up to pipeline.max_workers region requests in parallel (32 in the packaged config). The mlx-vlm server does not handle concurrent vision requests safely: generations are silently truncated and corrupted, dropping table rows and stopping mid-number, with nothing logged. Measured over a 194-file / 228-page invoice corpus on an M1 Pro against mlx-community/GLM-OCR-bf16: - max_workers=4: 91.3% of invoice totals recovered, not reproducible - max_workers=1: ~96.6%, reproducible Concurrency also breaks determinism despite temperature=0.0 / top_k=1. Of 10 byte-identical duplicate PDFs in that corpus, 7 produced different text at max_workers=4 (3 substantially divergent). Re-parsing one file four times diverged on the fourth run; at max_workers=1 three consecutive runs were byte-identical. The mlx-vlm server serves requests sequentially regardless, so max_workers=1 costs little throughput. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017e4v9dzir569nZhfSPydRE
|
Added a fourth issue found while stress-testing this guide on a 194-file / 228-page invoice corpus (Apple M1 Pro,
Same file, same config, only
Measured impact on recovering the invoice total (ground truth from filenames, n=149):
It also breaks determinism despite Since the server serializes requests anyway, I have not filed this upstream with mlx-vlm — happy to, if you agree the fix belongs there rather than in this guide. Documenting it here seems worthwhile either way, since the SDK's default actively triggers it. |
While testing
examples/mlx-deploy/README.mdend-to-end on an Apple M1 Pro (macOS 26.6, 32 GB), I hit three issues that stop the documented flow from working, plus two claims that have gone stale. All fixes are verified by re-running the corrected steps.Blocking issues
1. Step 3 omits the
layoutextra. The guide sayspip install -e ., which does not installtorch,torchvisionortransformers. The pipeline then fails at startup:Changed to
pip install -e '.[layout]'.2. Step 4's config snippet cannot work as shown. It presents a four-key
ocr_apiblock as a usable custom config file. But a--configfile replaces the YAML baseline rather than merging with the packagedglmocr/config.yaml— inGlmOcrConfig.from_env, the custom path becomes the sole YAML layer, with onlyGLMOCR_*env vars and keyword overrides applied on top. Omitted keys fall back to built-in dataclass defaults, not to the packaged values.So that snippet silently produces:
pipeline.layout.model_dir→None(no built-in default), failing withpipeline.layout.model_dir is required for self-hosted layoutlayout.id2label→{}layout.label_task_mapping→{}page_loader.task_prompt_mapping→NoneThe last three are needed to label and route detected regions. The section now documents the merge semantics and gives two approaches that actually work (edit the packaged config in place, or copy it and edit the copy).
3. Two
model:keys are easy to confuse.config.yamlhas one underpipeline.maasand one underpipeline.ocr_api. Editing the wrong one leavesocr_api.modelasglm-ocr, and the mlx-vlm server rejects it with a bareAPI server returned status code: 400. I hit this myself while testing. Added a callout and a troubleshooting entry.Stale claims
4. mlx-vlm no longer needs a git install. The guide says
glm_ocr"is not yet available in the latest PyPI release 0.3.10". PyPI now has stable 0.7.0, and I confirmed its wheel contains theglm_ocrmodel files. Switched topip install 'mlx-vlm>=0.7.0', keeping the git install as a documented fallback.5. The "Why a Separate Environment?" rationale has converged. It describes a conflict between mlx-vlm's
transformers>=5.0.0rc3and the SDK's pin. The SDK'slayoutextra requirestransformers>=5.3.0, so the ranges now overlap and both envs resolved to transformers 5.16.1 here. I kept the two-environment setup (it is what the guide is tested against and keeps server and SDK independently upgradable) but corrected the stated reason.Verification
With the corrected steps, against
mlx-community/GLM-OCR-bf16on Metal:mlx_vlm.serverhealth check — OK (~110 tok/s, 2.3 GB peak)glmocr parseonexamples/source/code.png,seal.png,table.png— OKparse(...)+result.save(...)— OKDocs-only change; no code touched.
🤖 Generated with Claude Code
https://claude.ai/code/session_017e4v9dzir569nZhfSPydRE