Deploying Autonomous AI Agents on an M2 MacBook
A hands-on guide to AI agent M2 deployment: run a local LLM on 8GB Apple Silicon, wire up a CrewAI agent, and keep memory under control.
Yes, you can run a real autonomous agent on an M2 MacBook, including the 8GB model, but you are going to live inside a memory budget the whole time. The trick to AI agent M2 deployment is not a bigger model. It is picking a small quantized model that leaves room for the agent loop, the tool calls, and everything else macOS is already holding in RAM. Get that budget right and an M2 handles a genuinely useful agent offline, with no API bill and no data leaving the machine. Get it wrong and the model gets swapped to disk, tokens crawl, and the agent times out mid-task.
This guide walks the working setup end to end: why Apple Silicon changed the local math, how to size a model against your RAM, and how to point a CrewAI agent at a locally served model so the reasoning loop never touches the network.
Why the M2 changes the local math
The reason a laptop can run an LLM at all is unified memory. On a traditional PC the GPU has its own VRAM, and model weights have to be copied across the PCIe bus before the GPU can touch them. Apple Silicon puts the CPU, GPU, and Neural Engine on one high-bandwidth memory pool, so the GPU reads weights in place with no transfer step. That is why an M2 with 16GB can serve a 7B model that would need a discrete GPU with dedicated VRAM on a comparable PC.
Apple leaned into this with MLX, a machine learning framework built specifically for the unified memory architecture on M-series chips. The practical upshot for agent builders: the same physical RAM that runs your editor, your browser, and the agent process is also your model’s working memory. There is no separate pool to fall back on. On an 8GB machine that shared pool is the entire story.
The memory budget on 8GB
Start with the honest accounting. macOS and a couple of everyday apps will hold 3 to 4GB before you launch anything. That leaves roughly 4 to 5GB for the model plus its runtime context. A model’s memory footprint is driven by its parameter count and its quantization level. Four-bit quantization is the sweet spot in 2026: it cuts the memory cost to roughly half a gigabyte per billion parameters with a barely measurable drop in quality.
Here is the rough budget for common sizes at 4-bit:
| Model size | Weights (4-bit) | Fits 8GB? | Fits 16GB? |
|---|---|---|---|
| 1B | ~0.7 GB | Yes, easily | Yes |
| 3B | ~2.0 GB | Yes, with care | Yes |
| 7B | ~4.5 GB | Tight, single task only | Yes, comfortably |
| 13B | ~8.0 GB | No | Tight |
| 30B+ | ~18 GB and up | No | No |
On 8GB you are realistically looking at a 3B model for anything with an agent loop on top, or a 7B model if the agent is the only thing running and you keep the context window short. Do not fight this. A disciplined 3B agent that stays in RAM beats a 7B agent that swaps to SSD and stalls. If your work genuinely needs a bigger model than the hardware holds, that is a serving problem, and choosing an LLM serving engine like vLLM or TGI on a machine with real GPU memory is the honest answer rather than forcing it onto a laptop.
Install the runtime and pull a model
Ollama is the fastest way to serve a model locally. It handles the download, the quantization variants, and a local HTTP endpoint that agent frameworks already speak to. Install it and pull a small model:
$ brew install ollama
$ ollama serve &
$ ollama pull llama3.2:3b
The 3b tag pulls a 4-bit quantized build by default, which is what you want on constrained hardware. Confirm it responds before you put an agent in front of it:
$ ollama run llama3.2:3b "Reply with OK if you can read this."
Watch memory while that runs. In a second terminal:
$ ollama ps
That prints the loaded model and its resident size. If the size is close to your free RAM, drop to a smaller model or a shorter context before you add the agent, because the agent loop needs headroom for its own prompt assembly and tool output. If you want a fuller walkthrough of running models locally for real work, the pattern in local LLM for log analysis covers the same runtime from a debugging angle.
Wire up the agent
An autonomous agent is a model plus a loop that lets it call tools, read the result, and decide the next step. CrewAI is a compact framework for this, and it talks to Ollama with two lines of config. The key detail for local deployment is pointing the LLM class at your Ollama endpoint instead of a hosted API:
from crewai import Agent, Task, Crew, LLM
# Point the model at the local Ollama server, not a cloud API.
local_llm = LLM(
model="ollama/llama3.2:3b",
base_url="http://localhost:11434",
temperature=0.2,
)
researcher = Agent(
role="Release notes summarizer",
goal="Extract the breaking changes from a changelog",
backstory="You read changelogs and flag what will break a deploy.",
llm=local_llm,
max_iter=4,
verbose=True,
)
task = Task(
description="Summarize the breaking changes in the pasted changelog.",
expected_output="A bulleted list of breaking changes, one line each.",
agent=researcher,
)
crew = Crew(agents=[researcher], tasks=[task])
result = crew.kickoff()
print(result)
Two settings matter more than the rest on constrained hardware. max_iter caps how many times the agent loops before it must return, which stops a confused 3B model from burning memory on an endless tool-calling spiral. A low temperature keeps the output deterministic enough that a small model does not wander off task. Both are guardrails against the failure mode that hits small local models hardest: the agent that never decides it is done.
Pin the context size with a Modelfile
The num_ctx advice above is worth making concrete, because the default context on many models is larger than an 8GB machine can afford. Ollama lets you bake a smaller context into a derived model with a Modelfile, so every call the agent makes inherits the cap without you passing options each time:
FROM llama3.2:3b
PARAMETER num_ctx 2048
PARAMETER temperature 0.2
Build it once and point the agent at the derived name:
$ ollama create agent-3b -f ./Modelfile
$ ollama run agent-3b "ready?"
Then set model="ollama/agent-3b" in the CrewAI config. Now the context ceiling is a property of the model, not something a stray call can blow past. On 8GB this one change is often the difference between a run that stays resident and one that spills to disk halfway through a long tool chain.
Keep the agent alive under memory pressure
Once the agent runs, most of your effort goes into keeping the model resident in RAM rather than swapped to SSD. Swapping is where local agents die. It does not crash, it just slows every token by an order of magnitude until the task times out. These steps keep an M2 8GB honest, in priority order:
- Cap the context window. The KV cache grows with context length and eats RAM fast. Set a modest
num_ctx(2048 or 4096) in the Ollama model options rather than the default. A shorter context is the single biggest memory lever on the runtime side. - Run one model at a time. Ollama keeps a model loaded for five minutes after the last call by default. If your agent switches between two models, both stay resident and you double the footprint. Use one model for the whole crew, or set a short
keep_aliveso idle models unload. - Trim the toolset. Every tool the agent can call adds its schema and description to the system prompt, which grows the context on every single step. Give the agent only the tools the task needs.
- Close the memory hogs. A browser with forty tabs can hold more RAM than your model. Free the pool before a run. On 8GB this is not optional.
- Watch resident size, not activity monitor guesses. Keep
ollama psvisible during a run so you see the moment the model would spill.
What breaks, and how to catch it
The common failure on small local agents is not a crash. It is a quiet quality drop when the model is too small for the reasoning the task demands. A 3B model will happily produce a confident, wrong answer and an agent will act on it. Treat any autonomous local agent as untrusted output until you have checked it, the same way you would treat a remote one. The failure modes catalogued in AI agent risks from Snyk’s audit apply just as much to a model running on your own laptop; a local model is private, not automatically safe.
Three concrete checks catch most of the trouble:
- Log every tool call and its result. When an agent goes wrong, the transcript of what it called and what came back tells you whether the model reasoned badly or a tool returned garbage.
- Set a hard iteration cap (the
max_iterabove) so a stuck agent fails fast instead of thrashing memory for minutes. - Validate the final output against a schema your code can check, rather than trusting free text. A small model earns trust one verified output at a time.
When to stop fighting 8GB
There is a real ceiling here, and knowing where it sits saves hours. If your agent needs a 7B or larger model to reason well, and it also needs to run tools and hold a real context at the same time, 8GB is the wrong tool. The clean options are to move up to a 16GB or 24GB M-series machine, where a 7B model runs with headroom, or to keep the agent orchestration local while offloading only the heavy reasoning step to a hosted model over the network. The local-first instinct is worth keeping, but not at the cost of an agent that times out on every third task.
A middle path is worth calling out, because it keeps most of the benefit. Run the agent orchestration, the tool calls, the file access, and the memory locally on the M2, and route only the single hardest reasoning step to a hosted model when the local one is clearly out of its depth. The agent stays private for everything except the one call that needs more capability, and you keep the offline behavior for the routine 90 percent. If you go that route, treat the boundary carefully: anything you send to a hosted model has left the machine, and the same governance you would apply to a cloud agent applies to that hop.
For an 8GB M2 the sweet spot is narrow and genuinely useful: a 3B model, a short context, a tight toolset, and a single well-scoped task per run. Summarizing changelogs, drafting commit messages, triaging logs, classifying tickets. Give it that and it earns its keep offline, on hardware you already own, with nothing leaving the laptop.
Related articles
Get the next article in your inbox
Practical DevOps tips, tutorials, and guides. No spam, unsubscribe anytime.