LOCAL AGENTIC AI MASTERCLASS WITH GEMMA 4 & APPLE MLX · MODULE 1

Lab 1: Run Gemma 4 (12B) Locally with Apple MLX & Token Streaming

Build the local inference foundation on Apple Silicon Metal GPU with zero-copy unified memory loading, real-time token streaming, and zero API costs.

Stop paying commercial API bills for agent reasoning loops. Build a high-performance, 100% private local inference layer with Google Gemma 4 (12B) and Apple MLX.

Download notebook to follow along: https://github.com/MysteryBytes-Labs/agentic_ai/tree/main/ai_trading_coach_Gemma4


Why Local LLMs Are Essential for Autonomous Financial Agents

Autonomous agents do not operate like conventional conversational chatbots. A single user inquiry (such as "Scan the market, purge penny stocks, and recommend three breakout opportunities") triggers an intensive chain of internal steps:

  • Task decomposition into sub-goals
  • Multi-turn tool argument synthesis and validation
  • Dynamic web scraping and schema parsing
  • Financial ratio valuation and numerical sanity checks
  • Iterative reflection and critique before final memo synthesis

In an agentic architecture, a single workflow can easily require 30 to 100 round-trip LLM invocations. When routed through proprietary cloud APIs:

  • Token costs compound exponentially: Every step resends conversation history, tool definitions, and system prompts.
  • Latency kills responsiveness: Network round-trips over the public internet introduce 500ms to 2s of latency per loop.
  • Rate limits break pipelines: Cloud provider quotas and sudden throttling disrupt autonomous multi-agent systems.
  • Data privacy is compromised: Sensitive financial watchlists, portfolio balances, and proprietary trading strategies are transmitted to third-party cloud servers.

By hosting Google Gemma 4 (12B) locally with Apple MLX, you transform your Mac into an autonomous agent sandbox with zero per-token API costs, unified memory zero-copy inference, and complete data isolation.


Apple MLX Unified Memory Architecture

Apple MLX is an array framework designed specifically for Apple Silicon. Unlike traditional runtimes (which copy tensor weights back and forth across PCIe buses between host CPU RAM and discrete GPU VRAM), MLX executes computations directly on Apple Silicon's Unified Memory Architecture (UMA) via Apple Metal.

BASH / TERMINAL
┌────────────────────────────────────────────────────────────────┐
│                   APPLE SILICON UNIFIED MEMORY                 │
│                                                                │
│   ┌───────────────────────────┐    ┌───────────────────────┐   │
│   │   CPU Cores (Python Host) │◄──►│  Metal GPU Cores      │   │
│   └───────────────────────────┘    └───────────────────────┘   │
│                 ▲                              ▲               │
│                 │      Zero-Copy Memory Bus    │               │
│                 └──────────────┬───────────────┘               │
│                                ▼                               │
│        ┌──────────────────────────────────────────────┐        │
│        │  Shared Pool (Gemma 4 12B Quantized Weights) │        │
│        └──────────────────────────────────────────────┘        │
└────────────────────────────────────────────────────────────────┘

This zero-copy architecture allows our 12-billion parameter Gemma 4 model to run at peak throughput with a compact ~10 GB local footprint—avoiding duplicate host-to-device memory copies and enabling instantaneous token generation.


Prerequisites & System Requirements

Before running the notebook, verify your machine meets the hardware and software configuration:

Component Minimum Specification Recommended
Operating System macOS 14.0+ (Sonoma) or macOS 15.0+ (Sequoia) macOS 15.0+
Hardware Apple Silicon M1 / M2 / M3 / M4 (Base, Pro, Max, Ultra) Apple Silicon Pro/Max with 16GB+ Unified Memory
Python Environment Python 3.11+ Python 3.12 managed via uv or venv
Frameworks mlx >= 0.22.0, mlx-vlm >= 0.1.18 Latest PyPI releases
Model Weights Gemma 4 12B IT QAT 4-bit (~10 GB safetensors) Cached locally on fast NVMe storage

Step 1: Environment Verification & Apple Metal Acceleration

In your terminal or virtual environment, install the MLX packages:

BASH / TERMINAL
pip install mlx mlx-vlm ipython

In the first cell of lab1_gemma3_setup.ipynb, import mlx.core and verify that Apple Metal acceleration is active:

PYTHON
import os
import mlx.core as mx

# 1. Verify Apple Metal GPU availability
print(f"MLX Version: {mx.__version__}")
print(f"Apple Metal GPU Available: {mx.metal.is_available()}")

# 2. Inspect local model directory
MODEL_PATH = "AIModels/gemma-4-12B-it-qat-4bit"
assert os.path.exists(MODEL_PATH), f"Model directory not found at {MODEL_PATH}"

print(f"Model weights verified at: {MODEL_PATH}")

When run on Apple Silicon, mx.metal.is_available() returns True, confirming that MLX will route all matrix multiplications directly to the Metal execution pipeline.


Step 2: Loading Gemma 4 into Unified Memory with mlx-vlm

Gemma 4 features a unified multimodal architecture. We load both the model weights and the tokenizer/processor via mlx_vlm.load:

PYTHON
from mlx_vlm import load

print("Loading Gemma 4 (12B QAT) into Unified Memory...")
model, processor = load(MODEL_PATH)

print(f"Model Type: {type(model).__name__}")
print("Gemma 4 successfully mapped to Apple Metal GPU device.")

Behind the scenes, MLX memory-maps the 4-bit quantized safetensors weights directly into unified RAM. In under three seconds, the model is initialized with zero memory duplication.


Step 3: Low-Latency Token Streaming via stream_generate

In autonomous agents, waiting for a multi-hundred-token generation to finish before receiving output introduces noticeable latency. By enabling token streaming with MLX's stream_generate generator, the engine emits text chunks the instant each token is decoded:

PYTHON
import sys
from mlx_vlm import stream_generate

prompt = "Write an optimized Python function to reverse a string in-place or using slicing. Explain time complexity."

print("Streaming generation:\n")
for chunk in stream_generate(model, processor, prompt=prompt, max_tokens=256):
    sys.stdout.write(chunk.text)
    sys.stdout.flush()

print("\n\n--- Stream Completed ---")

stream_generate yields decoded text chunks iteratively, allowing you to build real-time visual streaming for user interfaces or stream tokens directly into intermediate parsing routines.


Step 4: Structured Jinja Chat Templates & System Prompts

Instruction-tuned models require exact turn delimiters (<start_of_turn>, <end_of_turn>) to distinguish system instructions from user queries and model outputs. Rather than manually concatenating strings, we use processor.apply_chat_template:

PYTHON
conversation = [
    {
        "role": "system",
        "content": "You are a precise, data-driven financial research analyst. Provide structured tabular outputs."
    },
    {
        "role": "user",
        "content": "Compare New York City and Los Angeles across Population, Area (sq mi), and Top Financial Sector."
    }
]

# Format chat prompt using official Jinja template
formatted_prompt = processor.apply_chat_template(
    conversation,
    tokenize=False,
    add_generation_prompt=True
)

print("Formatted Jinja Prompt Structure:\n")
print(formatted_prompt)

Setting add_generation_prompt=True automatically appends the model turn prefix, cueing Gemma 4 to immediately begin generating the response.


Step 5: Full-Sequence Inference & Rich Display Formatting

To execute non-streaming generation and capture complete outputs, we use MLX's generate function with a low temperature for deterministic consistency:

PYTHON
from mlx_vlm import generate
from IPython.display import display, Markdown

# Generate response with deterministic temperature
response_text = generate(
    model,
    processor,
    prompt=formatted_prompt,
    max_tokens=512,
    temp=0.2
)

# Render clean markdown table in Jupyter notebook
display(Markdown(response_text))

Gemma 4 outputs a clean, well-formed Markdown comparison table complete with column headers and demographic statistics.


Key Takeaways & Series Roadmap

With Lab 1 complete, our high-speed local inference engine is verified and operational on Apple Silicon Metal:

Milestone Status Capability Unlocked
Metal GPU Verification ✅ Complete Zero-copy Apple Silicon UMA acceleration
Gemma 4 (12B) Loading ✅ Complete 4-bit QAT quantization under a ~10 GB RAM footprint
Line-by-Line Streaming ✅ Complete Low-latency token delivery with stream_generate
Jinja Chat Templates ✅ Complete Instruction formatting with system personas

What's Next in Lab 2?

Right now, Gemma 4 is functioning as a static conversational model. In Lab 2, we give our agent hands:

  • Enforcing zero-hallucination outputs using Pydantic v2 schemas
  • Dynamic Temporal Grounding anchored to the live hardware clock
  • Live market telemetry tool calling via the Google Serper API
Next Lab →Lab 2: Type-Safe Pydantic Tool Calling & Live Temporal Grounding