经 AI Skill Hub 精选评估,MLX-VLM 获评「强烈推荐」。已获得 4.8k 颗 GitHub Star,这款AI工具在功能完整性、社区活跃度和易用性方面表现出色,AI 评分 8.5 分,适合有一定技术背景的用户使用。
MLX-VLM 是一款基于 Python 开发的开源工具,专注于 AI、视觉语言模型、Python 等核心功能。作为 GitHub 开源项目,它拥有活跃的社区支持和持续的版本迭代,代码完全透明可审计,支持本地部署以保护数据隐私。无论是个人使用还是集成到企业工作流,都能提供稳定可靠的解决方案。
MLX-VLM 是一款基于 Python 开发的开源工具,专注于 AI、视觉语言模型、Python 等核心功能。作为 GitHub 开源项目,它拥有活跃的社区支持和持续的版本迭代,代码完全透明可审计,支持本地部署以保护数据隐私。无论是个人使用还是集成到企业工作流,都能提供稳定可靠的解决方案。
# 方式一:pip 安装(推荐)
pip install mlx-vlm
# 方式二:虚拟环境安装(推荐生产环境)
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install mlx-vlm
# 方式三:从源码安装(获取最新功能)
git clone https://github.com/Blaizzy/mlx-vlm
cd mlx-vlm
pip install -e .
# 验证安装
python -c "import mlx_vlm; print('安装成功')"
# 命令行使用
mlx-vlm --help
# 基本用法
mlx-vlm input_file -o output_file
# Python 代码中调用
import mlx_vlm
# 示例
result = mlx_vlm.process("input")
print(result)
# mlx-vlm 配置文件示例(config.yml) app: name: "mlx-vlm" debug: false log_level: "INFO" # 运行时指定配置文件 mlx-vlm --config config.yml # 或通过环境变量配置 export MLX_VLM_API_KEY="your-key" export MLX_VLM_OUTPUT_DIR="./output"
mlx_vlm.server --trust-remote-code
mlx_vlm.server --api-key <secret-token>
The easiest way to get started is to install the mlx-vlm package using pip:
pip install -U mlx-vlm
The Gradio chat UI needs an extra dependency that is not part of the base install:
pip install -U 'mlx-vlm[ui]'
Quote the package name so that shells which expand square brackets, such as zsh, do not treat [ui] as a glob pattern.
mlx_vlm.server --model Qwen/Qwen3.5-4B \ --enable-thinking \ --thinking-budget 512 \ --thinking-start-token "<think>" \ --thinking-end-token "</think>"
print(apc.coordinator(model).plan.describe())
document = Path("long_document.txt").read_text()
try: # First request computes the full prefix and stores reusable K/V blocks. prompt1 = apply_chat_template( processor, model.config, prompt=f"{document}\n\nSummarize the key decisions.", num_images=0, ) for _ in stream_generate( model, processor, prompt1, max_tokens=128, temperature=0.0, apc_manager=apc ): pass
# Second request shares the same document prefix and only prefills the suffix. prompt2 = apply_chat_template( processor, model.config, prompt=f"{document}\n\nList the open engineering risks.", num_images=0, ) for chunk in stream_generate( model, processor, prompt2, max_tokens=128, temperature=0.0, apc_manager=apc ): print(chunk.text, end="", flush=True)
print(apc.stats_snapshot()) finally: apc.close()
To compare cold, warm-memory, warm-disk, and disk-eviction behavior with a
model, use the same direct API path:
python import os import tempfile import time from pathlib import Path
from mlx_vlm import load, stream_generate from mlx_vlm.apc import APCManager, DiskBlockStore from mlx_vlm.prompt_utils import apply_chat_template
model_id = "Qwen/Qwen3-VL-4B-Instruct" contexts = [8000, 20000, 50000, 100000] disk_cap_gb = 0 # 0 means uncapped shard_max_blocks = 256 context_sweep_max_tokens = 1 # one token is enough to measure prefill reuse
test_prompt_tokens = 8000 fill_prompts = 80 eviction_disk_cap_gb = 3.0
os.environ["APC_DISK_SHARD_MAX_BLOCKS"] = str(shard_max_blocks)
model, processor = load(model_id) tokenizer = processor.tokenizer if hasattr(processor, "tokenizer") else processor
def disk_cap_bytes(gb: float): return None if gb <= 0 else int(gb * (1 << 30))
def make_context(target_tokens: int, seed: int = 0) -> str: line = ( f"Document {seed}: APC benchmark content with deterministic facts, " "dates, identifiers, and repeated technical notes.\n" ) line_tokens = max(1, len(tokenizer.encode(line, add_special_tokens=False))) text = line * max(1, target_tokens // line_tokens) while len(tokenizer.encode(text, add_special_tokens=False)) < target_tokens: text += line return text
def make_prompt(context: str, question: str) -> str: return apply_chat_template( processor, model.config, prompt=f"{context}\n\n{question}", num_images=0, )
def run_once(apc: APCManager, context: str, question: str, max_tokens: int = 32): prompt = make_prompt(context, question) apc.reset_stats()
last = None output = [] start = time.perf_counter() for chunk in stream_generate( model, processor, prompt, max_tokens=max_tokens, temperature=0.0, apc_manager=apc, ): output.append(chunk.text) last = chunk
if last is None: raise RuntimeError("generation returned no chunks")
return { "wall_s": time.perf_counter() - start, "prompt_tokens": last.prompt_tokens, "prompt_tps": last.prompt_tps, "generation_tps": last.generation_tps, "apc": apc.stats_snapshot(), "text": "".join(output).strip(), }
def print_result(label: str, result: dict) -> None: stats = result["apc"] print( f"{label:<12} " f"prompt_tokens={result['prompt_tokens']:>7} " f"prompt_tps={result['prompt_tps']:>8.1f} " f"gen_tps={result['generation_tps']:>7.1f} " f"matched={stats.get('matched_tokens', 0):>7} " f"disk_hits={stats.get('disk_hits', 0):>5} " f"disk_evictions={stats.get('disk_evictions', 0):>5}" )
def open_apc(cache_root: Path, namespace: str, disk_gb: float) -> APCManager: disk = DiskBlockStore( cache_root, namespace=namespace, max_bytes=disk_cap_bytes(disk_gb), ) return APCManager(num_blocks=4096, block_size=16, disk=disk)
def run_context_sweep() -> None: print("cold / warm-memory / warm-disk") with tempfile.TemporaryDirectory() as tmp: cache_root = Path(tmp) for target_tokens in contexts: context = make_context(target_tokens) namespace = f"{model_id}-context-{target_tokens}" apc = open_apc(cache_root, namespace, disk_cap_gb) try: print(f"\ncontext ~= {target_tokens} text tokens") print_result( "cold", run_once( apc, context, "Summarize the key decisions.", max_tokens=context_sweep_max_tokens, ), ) print_result( "warm-memory", run_once( apc, context, "List the open engineering risks.", max_tokens=context_sweep_max_tokens, ), ) finally: # Closing waits for queued disk writes before reopening the disk tier. apc.close()
apc = open_apc(cache_root, namespace, disk_cap_gb) try: print_result( "warm-disk", run_once( apc, context, "Extract the implementation timeline.", max_tokens=context_sweep_max_tokens, ), ) finally: apc.close()
def run_disk_eviction_workload() -> None: print("\ndisk eviction workload") with tempfile.TemporaryDirectory() as tmp: cache_root = Path(tmp) namespace = f"{model_id}-eviction" test_context = make_context(test_prompt_tokens, seed=0)
apc = open_apc(cache_root, namespace, eviction_disk_cap_gb) try: print_result( "seed", run_once(apc, test_context, "Summarize the retained test prefix."), ) finally: apc.close()
apc = open_apc(cache_root, namespace, eviction_disk_cap_gb) try: for i in range(fill_prompts): fill_context = make_context(test_prompt_tokens, seed=i + 1) run_once( apc, fill_context, f"Summarize filler document {i + 1}.", max_tokens=1, ) if (i + 1) % 10 == 0: stats = apc.stats_snapshot() print( f"filled={i + 1:>3} " f"disk_gb={stats.get('disk_bytes', 0) / (1 << 30):.2f} " f"disk_evictions={stats.get('disk_evictions', 0)}" ) finally: apc.close()
apc = open_apc(cache_root, namespace, eviction_disk_cap_gb) try: print_result( "post-fill", run_once( apc, test_context, "Check whether the retained test prefix still restores.", ), ) finally: apc.close()
run_context_sweep() run_disk_eviction_workload()
#### Server
Enable in-memory APC for the server with environment variables:
sh APC_ENABLED=1 \ APC_NUM_BLOCKS=4096 \ mlx_vlm.server --model Qwen/Qwen3-VL-4B-Instruct --port 8080
APC works with KV-cache quantization (`--kv-bits`):
sh APC_ENABLED=1 \ APC_NUM_BLOCKS=4096 \ mlx_vlm.server --model Qwen/Qwen3-VL-4B-Instruct --kv-bits 8 --port 8080
APC persists caches to disk by default when enabled, under
`$MLX_VLM_CACHE_HOME/apc` (or `~/.cache/mlx-vlm/apc`), with a 20 GiB cap per
model namespace. Customize the location and cap:
sh APC_ENABLED=1 \ APC_NUM_BLOCKS=4096 \ APC_DISK_PATH=~/.cache/mlx-vlm/caching \ APC_DISK_MAX_GB=3 \ APC_DISK_SHARD_MAX_BLOCKS=256 \ mlx_vlm.server --model Qwen/Qwen3-VL-4B-Instruct --port 8080
Repeated requests with the same long prefix will hit APC automatically:
sh curl -X POST "http://localhost:8080/v1/chat/completions" \ -H "Content-Type: application/json" \ -H "X-APC-Tenant: demo" \ -d '{ "model": "Qwen/Qwen3-VL-4B-Instruct", "messages": [{ "role": "user", "content": "Paste a long shared document here.\n\nNow answer question A." }], "max_tokens": 128 }'
Use the same `X-APC-Tenant` value for requests that may share cached prefixes. Use different tenant values to isolate cache entries between users or workspaces.
Inspect and reset APC state:
sh curl http://localhost:8080/v1/cache/stats curl -X POST http://localhost:8080/v1/cache/reset
`restored_tokens` counts prefix tokens successfully materialized for generation
across block and exact caches, in memory or on disk. A lookup alone does not
increase it, nor does a failed batch restore. A successful restore remains counted
if the request later fails or is cancelled.
The previous `served_tokens` block-storage count is now `stored_tokens`;
`token_hit_rate` retains its existing calculation,
`matched_tokens / (matched_tokens + stored_tokens)`.
Configure APC on a running server with `PATCH /v1/settings`. Use
`GET /v1/settings` to discover supported settings and read their current values:
sh curl http://localhost:8080/v1/settings
curl -X PATCH http://localhost:8080/v1/settings \ -H 'Content-Type: application/json' \ -d '{ "apc_enabled": true, "apc_disk_enabled": true, "apc_memory_max_gb": 2, "apc_disk_max_gb": 20, "apc_checkpoint_interval_tokens": 1024 }'
The endpoint also accepts `apc_memory_reserve_gb`, `apc_disk_queue_max_gb`,
`apc_disk_path`, `apc_disk_shard_max_blocks`, `apc_block_size`, `apc_num_blocks`,
`apc_checkpoint_entries`, and `apc_checkpoint_guard_tokens`. When
`MLX_VLM_SERVER_API_KEY` is configured, include `Authorization: Bearer <key>`.
Settings apply on the next text-generation request through the existing model
reload path; the server process stays running. Reloading clears resident caches
and retires the previous disk writer after its generation worker finishes.
Existing disk files remain available. Updating APC options while APC is disabled
stages them for the next enable. The response reports `applied`, `rejected`,
`reload_kinds`, and the resulting settings; invalid sizes are rejected without
changing those values. Unchanged settings do not trigger a reload.
Use `null` for automatic memory budgets or the default disk path/cap. Zero has
specific meanings: `apc_memory_max_gb: 0` retains caches only on disk,
`apc_disk_max_gb: 0` removes the disk cap, and `apc_disk_queue_max_gb: 0` writes
synchronously. An empty `apc_disk_path` or `apc_disk_enabled: false` disables
persistence. PATCH merges with current settings; the optional
`{"op": "replace", "values": {...}}` form first restores startup environment
defaults. `/v1/cache/stats` shows the active manager after the next request.
Common APC environment variables:
| Variable | Default | Description |
|----------|---------|-------------|
| `APC_ENABLED` | `0` | Set to `1` to enable APC |
| `APC_NUM_BLOCKS` | `2048` | Number of in-memory APC blocks |
| `APC_BLOCK_SIZE` | `16` | Tokens per APC block |
| `APC_CHECKPOINT_ENTRIES` | `2` | In-memory checkpoint entries; also bounds snapshots captured per hybrid prompt (disk-only mode captures two) |
| `APC_CHECKPOINT_GUARD_TOKENS` | `1` | Tokens retained after a reusable hybrid checkpoint boundary; the default preserves the normal final-token prefill boundary |
| `APC_CHECKPOINT_INTERVAL_TOKENS` | `2048` | Spacing of intermediate hybrid checkpoints, rounded up to a multiple of `APC_BLOCK_SIZE`; `0` keeps only the final checkpoint |
| `APC_MEMORY_MAX_GB` | auto | Resident block and checkpoint budget in GiB: 10% of Metal's recommended working set, capped at 8 GiB; `0` retains caches only on disk |
| `APC_MEMORY_RESERVE_GB` | auto | Additional memory headroom in GiB: 10% of Metal's recommended working set, at least 1 GiB |
| `APC_DISK_ENABLED` | `1` | Set to `0` to disable disk persistence |
| `MLX_VLM_CACHE_HOME` | `~/.cache/mlx-vlm` | Base cache directory; APC uses its `apc` subdirectory unless `APC_DISK_PATH` is set |
| `APC_DISK_PATH` | cache directory above | Directory for persistent disk shards; an empty value disables persistence |
| `APC_DISK_MAX_GB` | `20` | Disk cap per model namespace in GiB; `0` means uncapped |
| `APC_DISK_QUEUE_MAX_GB` | `1` | Maximum tensor bytes held by queued disk writes in GiB; larger writes run synchronously; `0` makes all writes synchronous |
| `APC_DISK_SHARD_MAX_BLOCKS` | `256` | Max blocks per disk segment shard |
| `APC_MAX_POOL_TENSORS` | `450000` | Stops adding memory blocks before the Metal resource limit; disk writes continue |
| `APC_LAYER_MAJOR_MEMORY_MIN_TOKENS` | `50000` | Store long warm-memory prefixes as compact layer-major snapshots instead of per-block tensors |
| `APC_HASH` | `fast` | Set to `sha256` for a stable cryptographic hash |
| `APC_TRACE` | unset | Set to `1` for greppable store/reject/self-check log lines |
Custom cache layouts can opt in without APC model-name checks by implementing `prefix_cache_snapshot()` and `prefix_cache_restore(snapshot)`. In-tree dense, sliding-window, recurrent, composite, VLM, and Omni cache layouts are detected automatically. APC works with `--kv-bits` (including TurboQuant): the live KV cache stays quantized; pageable APC K/V blocks are stored as dequantized float K/V, so block-pool size does not shrink with quant.
When APC is enabled on the server, a non-fatal layout self-check runs at model load.
Requests with a shared document and different questions can reuse their common
prefix. Dense K/V caches, including compact layer-major memory snapshots, match
complete blocks before the first differing token. Hybrid, recurrent and sliding
window caches must restore a state captured before that divergence: their final
state cannot be rolled back by slicing K/V tensors.
Hybrid prefill now captures intermediate checkpoints as well as the final guard
checkpoint, in streaming, continuous batching and DiffusionGemma generation.
With the defaults, each prompt stores its latest 2,048-token boundary before the
final checkpoint and the final checkpoint itself. For example, a 30,000-token
document followed by 20 instruction tokens can reuse 28,672 tokens when the
instructions change. The same checkpoints persist across server restarts when
the disk tier is enabled.
Captures are bounded by `APC_CHECKPOINT_ENTRIES` to avoid copying the growing
hybrid cache at every prefill chunk. More entries retain more earlier boundaries;
a smaller interval gives finer reuse near the end. Reuse still requires a
retained boundary before the divergence. Short prompts below the interval,
divergence before the earliest retained checkpoint, and evicted checkpoints can
miss. Media checkpoints include all media tokens so the remaining suffix is text.
Changing checkpoint boundaries can change floating-point execution shapes, as
with other chunked or cached prefill paths.
The resident byte budget includes exact snapshots as well as pageable blocks.
Before embeddings and prefill, APC drains pending disk writes and evicts idle
checkpoints and blocks in LRU order within each tier. Admission uses current
Metal allocations, available system RAM, and the incoming prompt's estimated
cache growth, based on observed bytes per token. Leased blocks remain valid for
active requests. Snapshots that exceed the budget are written directly to disk
without making another resident copy, and disk restores stay out of the memory
LRU when promotion would exceed the budget. Disk pressure may therefore trade
latency for lower memory use.
These controls limit APC's memory overhead; model weights and an individual
request must still fit in memory. Tune the reserve for models with larger
prefill or vision temporaries. `/v1/cache/stats` reports resident bytes,
the memory budget, prefill reserve, memory evictions, and pending disk bytes.
#### KV Cache Quantization
Reduce KV cache memory during continuous batching with `--kv-bits`. Both uniform quantization and TurboQuant are supported. Compatible with Automatic Prefix Caching (`APC_ENABLED=1`).
sh
Generate output from a model using the CLI:
```sh
Start the server: ```sh mlx_vlm.server --port 8080
mlx-vlm 是一个专为 Apple Silicon 优化的视觉语言模型库,旨在通过 MLX 框架实现高效的视觉推理任务。该项目支持多种先进的视觉模型,能够处理图像与视频输入,为开发者提供高性能、低延迟的视觉理解能力。
项目引入了 Vision Feature Caching 机制,专门优化了多轮对话场景。在处理涉及同一张图片的连续对话时,系统会通过 LRU cache 缓存已投影的视觉特征,避免在每一轮对话中重复调用高能耗的 vision encoder,从而显著提升推理效率并降低计算开销。
在使用某些特定模型时,需要确保在启动时启用 `--trust-remote-code` 参数,以允许执行远程代码。这对于加载部分非标准架构的模型至关重要,请根据实际需求在命令行中进行配置。
安装 mlx-vlm 非常简单,推荐使用 pip 进行快速部署。您可以通过运行命令 `pip install -U mlx-vlm` 来安装或更新至最新版本,确保您的开发环境已配置好 Python 包管理工具。
项目提供了灵活的使用方式,支持 Python Script 和 Command Line 两种模式。开发者可以通过 Python 调用 `load` 和 `generate` 函数进行复杂的视觉推理任务(如对比多张图片);同时,也可以直接使用命令行工具 `mlx_vlm.video_generate` 来实现对视频内容的描述与分析。
mlx-vlm 提供了完善的接口支持。通过 Command Line Interface (CLI),用户可以直接在终端生成模型输出;此外,项目还内置了基于 FastAPI 的 Server 模式,支持通过指定端口启动服务;对于开发者,还提供了 Python API,可以通过在 `load` 函数中传递 `quantize_activations=True` 等参数来优化性能。
目前 mlx-vlm 已支持多种主流视觉模型的视频对话功能,包括 Qwen2-VL、Qwen2.5-VL、Idefics3 以及 LLaVA 等。随着项目的持续迭代,未来将支持更多类型的视觉模型,为开发者提供更丰富的模型生态选择。
高质量的开源AI工具,实现视觉语言模型的推理和微调
AI Skill Hub 为第三方内容聚合平台,本页面信息基于公开数据整理,不对工具功能和质量作任何法律背书。
建议在沙箱或测试环境中充分验证后,再部署至生产环境,并做好必要的安全评估。
✅ MIT 协议 — 最宽松的开源协议之一,可自由商用、修改、分发,仅需保留版权声明。
AI Skill Hub 点评:MLX-VLM 的核心功能完整,质量优秀。对于AI 技术爱好者来说,这是一个值得纳入个人工具库的选择。建议先在非生产环境试用,再逐步推广。
| 原始名称 | mlx-vlm |
| 原始描述 | 开源AI工具:MLX-VLM is a package for inference and fine-tuning of Vision Language Models (VL。⭐4.8k · Python |
| Topics | AI视觉语言模型Python |
| GitHub | https://github.com/Blaizzy/mlx-vlm |
| License | MIT |
| 语言 | Python |
收录时间:2026-05-30 · 更新时间:2026-05-30 · License:MIT · AI Skill Hub 不对第三方内容的准确性作法律背书。