Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
mlex
Run your favorite LLMs at blazing-fast speeds on Apple Silicon.
mlex is a safe, idiomatic Rust runtime built directly on Apple MLX (via the official mlx-c C API, vendored and statically linked — no system MLX install, no Python required). It loads MLX-format checkpoints straight off the Hugging Face Hub layout and runs them on the GPU through Metal, with first-class support for every quantization scheme the MLX community actually ships, tool calling, and multi-modal (image/audio/video) input.
This crate is the engine underneath the mlex.js npm package (Node.js bindings), but it's a complete, self-contained Rust library on its own.
Features
- Zero system dependencies at runtime.
mlxandmlx-care vendored, pinned, and built from source viabuild.rs(CMake).cargo buildon a fresh checkout is all it takes. - Broad quantization support. Dense bf16/fp16, affine 2/3/4/5/6/8-bit at any group size,
mxfp4,mxfp8,nvfp4, and mixed per-layer precision checkpoints such as OptiQ or Google QAT exports. - Wide architecture coverage. Qwen2/Qwen3/Qwen3.5 (dense + MoE + vision-capable variants), Gemma4 (text + multi-modal), NemotronH (hybrid Mamba2/attention), DharaAR, and vanilla-Llama-shaped checkpoints (e.g. MiniCPM5) — see the table below.
- Multi-modal. Image input works on vision-capable Qwen3.5 checkpoints, while Gemma4 checkpoints with vision/audio towers additionally accept audio clips and video (uniformly sampled into frames) alongside text.
- System prompts. A leading
role: "system"message is rendered by every supported chat template, exactly like the OpenAI/Anthropic system role. - Reasoning / "thinking". Opt into Qwen3/3.5/3.6, Gemma4, MiniCPM5, and NemotronH's native "thinking" mode, with an optional token budget and the reasoning span automatically split out of the final answer.
- Tool calling. Render OpenAI-style tool/function schemas into the model's native chat template and parse tool calls back out of the reply (Hermes-style JSON and Gemma's native key/value format).
- Stateless, automatic prompt caching. [
Session::generate_cached] takes the full message transcript on every call (mirroring the OpenAI/Anthropic chat APIs) and transparently reuses KV cache state for whatever prefix a previous call already computed — no session handle to manage, no explicit cache invalidation. Pool sizing is configurable via [Session::load_with_cache_config]; a single call can opt out via [GenerateOptions::prompt_cache]. - Streaming. Every generation entry point accepts an
on_tokencallback invoked once per generated token.
Supported architectures
model_type |
Family | Notes |
|---|---|---|
qwen2, llama |
Qwen2 / Llama-shaped | Also covers MiniCPM5 and similar vanilla-GQA checkpoints |
qwen3 |
Qwen3 | Dense, with QK-norm |
qwen3_5, qwen3_5_moe (+ _text variants) |
Qwen3.5 | Dense, Mixture-of-Experts, and vision-capable variants |
gemma4, gemma4_text, gemma4_unified, gemma4_unified_text |
Gemma4 | Text-only, unified, and multi-modal (vision + audio) variants |
nemotron_h |
NemotronH | Hybrid Mamba2 / GatedDelta / attention layers |
dhara_ar |
DharaAR | Canon convolution layers, post-RoPE QK-norm, logit softcap |
Any checkpoint using one of the quantization schemes above works for every architecture where the underlying ops are wired up — this isn't a per-model allowlist, it's a function of config.json's quantization section plus the tensors actually present in the checkpoint.
Installation
Building from source requires:
- A C++17 toolchain (Xcode Command Line Tools on macOS).
- CMake (
brew install cmake). libclangforbindgen(ships with Xcode Command Line Tools).
The vendored mlx/mlx-c C++ sources under vendor/ are built once per target/ via CMake and statically linked; subsequent builds are incremental like any other Rust crate.
mlextargets macOS on Apple Silicon only. MLX's Metal backend doesn't run on Intel Macs, so x86_64 isn't a supported target.
Quickstart
use ;
use ChatMessage;
use Path;
Streaming tokens
let reply = session.generate_cached?;
System prompts
A leading role: "system" message is a first-class part of the chat template contract — every supported family's template special-cases messages[0] being system (or developer), the same convention as the OpenAI/Anthropic APIs, rather than something that only works on one architecture:
let messages = vec!;
let reply = session.generate_cached?;
Multi-turn conversations
There is no session/conversation handle to manage — like the OpenAI and Anthropic chat completion APIs, you grow the message list yourself and pass the full transcript on every call. An internal prompt-cache pool transparently reuses KV state for whatever prefix was already computed (including across independent calls that happen to share a prefix, e.g. a common system prompt):
let mut messages = vec!;
let reply = session.generate_cached?;
messages.push;
messages.push;
let reply2 = session.generate_cached?;
The pool itself (LRU + idle-TTL eviction, keyed by longest exact-prefix match on token ids) is sized once when the model loads — [Session::load] uses [prompt_cache::PromptCacheConfig::default] (16 entries, a 5 minute idle TTL, an 8-token minimum before a prefix is worth caching), and [Session::load_with_cache_config] lets you override it:
use PromptCacheConfig;
use Duration;
let session = load_with_cache_config?;
To opt a single call out of the pool entirely (neither read nor write), set [GenerateOptions::prompt_cache] to Some(false) instead — the two are independent: load_with_cache_config sizes the pool once, GenerateOptions::prompt_cache toggles pool use per call.
Sampling
temperature, top_p, top_k, and seed are all first-class knobs on [sampling::SamplingConfig]:
use GenerateOptions;
use SamplingConfig;
let options = GenerateOptions ;
Reasoning / "thinking"
Qwen3/3.5/3.6, Gemma4, MiniCPM5, and NemotronH checkpoints support an opt-in "thinking" mode via their chat template's enable_thinking variable. Set [GenerateOptions::enable_thinking] to turn it on; any reasoning span the model emits (<think>...</think> or Gemma4's <|channel>thought...<channel|>) is stripped out of reply.text automatically and returned separately as reply.reasoning:
let options = GenerateOptions ;
let reply = session.generate_cached?;
if let Some = &reply.reasoning
println!;
// Round-trip the reasoning back into history on the next turn, matching
// templates that special-case `message.reasoning_content`:
messages.push;
enable_thinking: None (the default) leaves the template's own default in place, which for every family above means reasoning is off — so existing code that doesn't set it keeps behaving exactly as before.
Streaming reasoning and tool calls separately
Every streamed [generate::GeneratedToken] carries a kind (Text, Reasoning, or ToolCall) so a UI can render each live, mirroring OpenAI/Anthropic's typed streaming deltas rather than only being able to split them apart from the resolved [generate::GenerateReply] once generation finishes:
use TokenKind;
session.generate_cached?;
Classification is marker-based and best-effort at token granularity — a marker straddling two tokens is only classified correctly once its second half arrives.
Tool calling
use ;
use json;
let tools = vec!;
let messages = vec!;
let reply = session.generate_cached?;
for call in reply.tool_calls
Feed a tool's result back in as a role: "tool" message (see ChatMessage's tool_call_id field) and call generate_cached again to continue the conversation.
Multi-modal input
use ChatMessage;
let image_bytes = read?;
let messages = vec!;
if session.supports_images
Session::supports_images() is true on image-capable Qwen3.5 and Gemma4 checkpoints. ChatMessage::user_with_audio and ChatMessage::user_with_video are additionally supported on Gemma4 checkpoints with audio/vision towers; Session::supports_audio() gates the audio path, and video is uniformly sampled into frames and processed through the same vision tower as still images.
API surface
- [
generate::Session] — load a model directory, generate/stream completions, all cache-aware viagenerate_cached. - [
prompt_cache::PromptCacheConfig] — override the internal prompt-cache pool's sizing (max entries / idle TTL / minimum-cacheable-tokens) viaSession::load_with_cache_config. - [
tokenizer::ChatMessage] / [tokenizer::ContentPart] — multi-part (text/image/audio/video) chat turns. - [
tools] —Tool,ToolCall,ToolCallFormat, andparse_tool_callsfor tool-calling support. - [
sampling::SamplingConfig] — temperature/top-p/top-k/seed controls. - [
models] — theModelenum and per-architecture implementations, if you need lower-level access (custom caches, raw forward passes). - [
quant] — quantization config parsing, if you're inspecting or building checkpoints.
Run cargo doc --open -p mlex for the full generated API reference.
Testing
Integration tests auto-discover any model checkpoints under MLEX_MODELS_DIR (default <repo>/models, in Hugging Face hub cache layout) and gate on measured peak memory (MLEX_MAX_MODEL_GB, default 5 GB) so the same suite runs unattended in CI against small models and, locally, against anything you've downloaded — set MLEX_INCLUDE_LARGE_MODELS=1 to also exercise larger local-only checkpoints. See the top-level project README for the full test/CI story.
License
MIT