DEV Community

AgentChip
AgentChip

Posted on

I Run a 465GB LLM on a Mac Studio — Here's the Entire Tooling Stack

The short version

I run a Mac Studio M3 Ultra with 512GB of unified memory as my daily LLM inference machine. The biggest model I serve locally is a 465GB quant of DeepSeek V4 Pro. It boots, it streams tokens, and it costs me $0/month in API fees.

Getting here took more than brew install llama.cpp. This post is the full tooling stack: how the models get onto the machine, how the server stays alive, how memory actually behaves on Apple Silicon, and the network plumbing that makes 100GB+ downloads survivable.

Why a Mac instead of GPUs

One sentence of math: 512GB of unified memory costs less than two used A100s with 80GB each, and my workload is batch generation (content pipelines, agents), not latency-critical chat. Tokens/second is modest — but when a job runs 24/7 in the background, throughput-per-dollar is the only metric that matters.

The catch is that Apple Silicon inference has its own operational rules. Here's what actually matters.

1. Memory is the whole game

On a discrete-GPU box, VRAM is a hard wall. On Apple Silicon, "GPU memory" is a budget negotiation with the OS. Practical lessons:

  • Raise the GPU allocation limit. macOS by default caps Metal's working set well below your physical RAM. sudo sysctl iogpu.wired_limit_mb=<N> lets the model actually use what you paid for. For a 465GB model on a 512GB machine you need this — the default ceiling will evict you straight into swap hell.
  • Leave headroom for the KV cache. Model weights are only the entry fee. A 128K-context session on a big MoE model wants gigabytes of KV cache. I budget model_size + 15-20% as the real footprint and keep context windows on a leash in production.
  • Never let it swap. Once a 400GB+ model starts swapping, you're not running inference anymore, you're running a disk benchmark. If the machine is shared (mine doubles as a desktop during the day), the inference window and the human window need to be scheduled, or the model needs to fit with real slack.

2. The server layer: boring on purpose

My serving stack is llama.cpp's server mode behind a dead-simple management layer:

  • One script per model profile. start-flash.sh (153GB daily driver) and start-pro.sh (465GB heavy hitter). Each script pins the flags that took me days to tune: Metal layers, context size, flash attention, KV cache quantization, thread counts.
  • A graceful shutdown script. Killing a llama.cpp server mid-write is how you corrupt a long session's cache. SIGTERM, wait for the port to release, done.
  • A watchdog. If the health endpoint stops answering, the watchdog restarts the profile. LLM servers are long-running processes; treat them like any other production service — auto-restart or it didn't happen.

The point isn't the scripts themselves (they're trivial). The point is that the tuning lives in versioned files, not in my memory. Six months from now, the flags that made V4 Pro stable will still be there.

3. Downloading 465GB without losing your mind

This is the part nobody warns you about. A 465GB model is not a download, it's a project:

  • Resume or die. Plain curl on a multi-day transfer is a coin flip. Everything goes through a downloader with real resume (Range requests verified against actual bytes on disk, not "it stopped at 99% so close enough").
  • Chunked storage formats need chunked strategies. Some HF repos now use deduplicated chunk storage (Xet). Those chunks don't behave like plain S3 files — the tooling that works for .safetensors blobs can fail silently on Xet chunks. Test your pipeline on a small file from the same repo before committing to the big one.
  • Mirrors and relays are a first-class concern. If you're on a network where HF is slow or unreachable, the reliable pattern is: download on a relay VPS with good peering, then pull over your own tunnel. I run a SOCKS5 relay on a small HK box; a one-command script brings the tunnel up and the downloader uses it transparently. WireGuard templates handle the "I want the whole machine tunneled" case.

4. The proxy/tunnel kit

Everything network-related is also packaged as scripts, not wiki pages:

  • One command brings up the SOCKS5 relay tunnel (autossh, auto-reconnect, local port fixed).
  • WireGuard configs are templates with the keys stripped — fill in three fields and it works.
  • A proxy profile switcher lets the download scripts and the inference box use different exits without touching system settings.

5. What I'd tell someone starting today

  1. Buy memory, not compute. For local inference on Apple Silicon, every GB of unified memory is a GB of model you can serve.
  2. Quantize aggressively, measure honestly. A 2-bit quant of a frontier MoE beats an 8-bit quant of a model one tier down, most days. But verify on your workload — perplexity benchmarks don't write your prompts.
  3. Automate the boring 20% early. Download resume, server watchdog, graceful shutdown. None of it is hard; all of it is miserable to retrofit after a 3-day download dies at 91%.
  4. Keep the human and the machine from fighting. If the box is also a workstation, schedule the heavy profiles for off-hours or pick a model size that leaves real room.

The toolkit

I've packaged my actual scripts — the model server profiles with tuned flags, the resumable downloader with mirror/relay support, the tunnel one-liners, and the memory/sysctl tuning notes — into a single zip: AI Dev Kit for Mac ($9.99, one-time). It's the exact set I run on my M3 Ultra, tested on macOS 14+ on Apple Silicon. If this post saved you a weekend, the kit saves you the other three.

If you've got your own Apple Silicon inference war stories — especially KV cache tuning on the big MoEs — I'd genuinely like to hear them in the comments.

Top comments (0)