<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Mlx on vishctl</title><link>https://vishctl.dev/tags/mlx/</link><description>Recent content in Mlx on vishctl</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Tue, 15 Sep 2026 15:00:00 +0800</lastBuildDate><atom:link href="https://vishctl.dev/tags/mlx/index.xml" rel="self" type="application/rss+xml"/><item><title>oMLX vs Ollama vs vMLX vs MLX-LM: Local LLMs on Apple Silicon</title><link>https://vishctl.dev/posts/omlx-vs-vmlx-vs-mlx-32gb-macbook-air/</link><pubDate>Tue, 15 Sep 2026 15:00:00 +0800</pubDate><guid>https://vishctl.dev/posts/omlx-vs-vmlx-vs-mlx-32gb-macbook-air/</guid><category>ai</category><category>local-llm</category><category>mlx</category><category>omlx</category><category>vmlx</category><category>ollama</category><category>apple-silicon</category><description>My local LLM picks for Apple Silicon: oMLX first, Ollama second, vMLX third, and official MLX-LM fourth. Setup commands and the benefits of each.</description><content:encoded><![CDATA[<p>I&rsquo;ve been playing with local LLMs on my <strong>32 GB MacBook Air</strong>. Three names kept coming up: <strong>MLX, vMLX, and oMLX</strong>. Then there is <strong>Ollama&rsquo;s own MLX engine</strong>.</p>
<p>The names sound similar. The real difference is how much help each gives you around running the model.</p>
<p><strong>My preference: oMLX first, Ollama second, vMLX third, and official MLX-LM fourth.</strong> That order reflects what I want from an everyday local AI setup.</p>
<p>For MLX-LM, vMLX, and oMLX, I used the same <a href="https://huggingface.co/mlx-community/Qwen3-8B-4bit">4-bit Qwen3 model</a>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">mlx-community/Qwen3-8B-4bit
</span></span></code></pre></div><h2 id="mlx--mlx-lm-simple-direct-flexible">MLX / MLX-LM: simple, direct, flexible</h2>
<p><a href="https://ml-explore.github.io/mlx/build/html/index.html">MLX</a> is Apple&rsquo;s machine learning framework. It uses unified memory so CPU and GPU operations can share the same data.</p>
<p><a href="https://github.com/ml-explore/mlx-lm">MLX-LM</a> supplies the LLM tools: load models, chat, generate text, and fine-tune.</p>
<p><strong>Main benefit: a straightforward way to run a model and experiment with it.</strong></p>
<p>Install <code>uv</code> once through Homebrew, then MLX-LM:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">brew install uv
</span></span><span class="line"><span class="cl">uv tool install mlx-lm
</span></span></code></pre></div><p>Start chatting:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">mlx_lm.chat --model mlx-community/Qwen3-8B-4bit
</span></span></code></pre></div><p>Or expose an OpenAI-compatible API:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">mlx_lm.server <span class="se">\
</span></span></span><span class="line"><span class="cl">  --model mlx-community/Qwen3-8B-4bit <span class="se">\
</span></span></span><span class="line"><span class="cl">  --host 127.0.0.1 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --port <span class="m">8080</span>
</span></span></code></pre></div><p>API base: <code>http://localhost:8080/v1</code>. The model downloads from Hugging Face if needed.</p>
<p>MLX-LM already supports <strong>in-memory prompt caching and concurrent batching</strong> for eligible requests. Repeated prompts can reuse work instead of starting from scratch. <a href="https://github.com/ml-explore/mlx-lm/blob/main/mlx_lm/server.py">Server implementation</a></p>
<p>It also supports saving prompt caches to files. That gives scripts explicit cache reuse, while automated SSD-cache management is a separate serving feature.</p>
<p><strong>My pick for:</strong> terminal chat, Python experiments, fine-tuning, and learning how inference works.</p>
<h2 id="vmlx-more-control-over-serving">vMLX: more control over serving</h2>
<p><a href="https://github.com/jjang-ai/vmlx">vMLX</a> adds serving controls around MLX: continuous batching, paged KV caching, prefix reuse, cache quantization, and SSD persistence.</p>
<p><strong>Main benefit: more control when an application sends multiple requests.</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">uv tool install vmlx
</span></span><span class="line"><span class="cl">vmlx serve mlx-community/Qwen3-8B-4bit <span class="se">\
</span></span></span><span class="line"><span class="cl">  --host 127.0.0.1 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --port <span class="m">8000</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  --continuous-batching <span class="se">\
</span></span></span><span class="line"><span class="cl">  --use-paged-cache
</span></span></code></pre></div><p>API base: <code>http://localhost:8000/v1</code>. The command explicitly enables continuous batching and paged caching.</p>
<p>Batching lets requests share GPU work. Paged caching organizes attention state into reusable blocks. These features become useful as conversations and concurrent requests grow.</p>
<p>The <a href="https://github.com/jjang-ai/vmlx#configuration">configuration options</a> also include disk caching and KV-cache quantization. Enable and tune these for the workload; the basic command does not enable every feature.</p>
<p>vMLX supports <strong>OpenAI and Anthropic API formats</strong>. Its <strong>MLX Studio desktop app</strong> adds a UI and a gateway for multiple loaded models.</p>
<p><strong>My pick for:</strong> local apps, multiple clients, and tuning how requests are served.</p>
<h2 id="omlx-easier-everyday-management">oMLX: easier everyday management</h2>
<p><a href="https://github.com/jundot/omlx">oMLX</a> combines inference with model management and a cache that spans RAM and SSD.</p>
<p><strong>Main benefit: less manual work keeping a local AI server useful.</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">brew tap jundot/omlx https://github.com/jundot/omlx
</span></span><span class="line"><span class="cl">brew install jundot/omlx/omlx
</span></span><span class="line"><span class="cl">omlx start
</span></span></code></pre></div><p>Open <code>http://localhost:8000/admin</code>. Search for <code>mlx-community/Qwen3-8B-4bit</code>, download it into the configured model directory, and select it for chat.</p>
<p>API base: <code>http://localhost:8000/v1</code>.</p>
<p>The dashboard lets me manage models and settings without doing everything in the terminal. Pin frequently used models, unload others, or let automatic eviction free memory.</p>
<p>The <strong>admin dashboard is a web UI</strong>. The separately available <strong>macOS app</strong> provides the native menu-bar experience.</p>
<p>Persistent caching is another useful benefit. Supported cached context can be restored from SSD after a restart or eviction, reducing repeated prompt processing.</p>
<p><strong>My pick for:</strong> an everyday local AI service, switching models, and long-running coding assistants.</p>
<p><strong>Port note:</strong> vMLX and oMLX both use port 8000 above. Run one at a time. Stop the managed oMLX service with <code>omlx stop</code>; use Ctrl-C for foreground servers.</p>
<h2 id="where-the-performance-benefits-come-from">Where the performance benefits come from</h2>
<p><strong>Repeated prompts:</strong> MLX-LM already caches context in memory. Adding a serving layer does not automatically make every follow-up faster.</p>
<p><strong>After a restart:</strong> persistent SSD caching gives vMLX and oMLX another way to recover reusable context. Restoring that work can be cheaper than processing the whole prompt again.</p>
<p><strong>Several requests at once:</strong> batching targets total throughput. Completing more requests together does not necessarily mean one chat generates tokens faster.</p>
<p><strong>Long conversations:</strong> cache size and memory pressure become increasingly important. On my 32 GB Air, I would leave room for macOS, other apps, and temporary inference buffers.</p>
<p><strong>First request:</strong> downloading, loading weights, and processing a fresh prompt are separate costs. A fast cached response says little about a completely fresh start.</p>
<p>The distinction I care about is simple: <strong>how soon the answer starts, how quickly it continues, and how much memory the server needs</strong>. Those are three different things to optimize.</p>
<h2 id="ollama-mlx-keep-a-familiar-workflow">Ollama MLX: keep a familiar workflow</h2>
<p>Ollama has its own <a href="https://ollama.com/blog/mlx-performance">MLX-based inference engine</a>, with optimized kernels and sampling for supported models.</p>
<p><strong>Main benefit: MLX inference through familiar Ollama commands and integrations.</strong></p>
<p>With a current Ollama installation, one supported example is:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ollama run gemma4:12b-mlx
</span></span></code></pre></div><p>This uses a different model from the Qwen3 example above. Different 4-bit formats also have different tradeoffs, so I would keep the weights and quantization consistent for a speed comparison.</p>
<p>Ollama MLX may work better for some people, especially when their apps already integrate with Ollama. It deserves a place alongside the dedicated MLX servers.</p>
<p><strong>My pick for:</strong> keeping an existing Ollama setup with supported MLX models.</p>
<h2 id="which-would-i-choose">Which would I choose?</h2>
<table>
	<thead>
			<tr>
					<th>My ranking</th>
					<th>Tool</th>
					<th>Why I would choose it</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td><strong>1</strong></td>
					<td><strong>oMLX</strong></td>
					<td>Model management and persistent caching for everyday local AI</td>
			</tr>
			<tr>
					<td><strong>2</strong></td>
					<td><strong>Ollama</strong></td>
					<td>Familiar commands and integrations, with MLX for supported models</td>
			</tr>
			<tr>
					<td><strong>3</strong></td>
					<td><strong>vMLX</strong></td>
					<td>Serving and cache controls for local apps and concurrent requests</td>
			</tr>
			<tr>
					<td><strong>4</strong></td>
					<td><strong>Official MLX-LM</strong></td>
					<td>Direct tools for learning, scripting, and fine-tuning</td>
			</tr>
	</tbody>
</table>
<p><strong>oMLX is my first choice. Ollama is my next choice</strong> for its familiar workflow and integrations.</p>
<p>vMLX comes third when I want more serving controls. Official MLX-LM comes fourth for my everyday setup, while remaining useful for direct experiments and learning.</p>
<p>On a 32 GB Air, I would start with one loaded model and a modest context limit. Then increase context and concurrency while watching memory pressure and response time.</p>
]]></content:encoded></item></channel></rss>