Home / Articles

A Zero-API-Cost Multi-Agent Blogger on a Mac: Gemma 4, Ollama and Google ADK

Build a local planner, writer and validator agent system on Apple Silicon using Gemma 4 through Ollama, LiteLLM and Google ADK, with no per-request model fees.

Publisher: REACTAPP.TOP8 min read1919 words

This article is published in English.

Sources: No API Costs: Building a Local Multi-Agent AI System with Gemma 4, Ollama, and Google ADK

A planning-and-writing agent can run entirely on a laptop. Everything below happens on an Apple Silicon Mac with no per-request fees: Gemma 4 served by Ollama, Google's Agent Development Kit (ADK) managing the agents, and LiteLLM bridging the two.

Language models are moving past question-and-answer. Applications built on them interpret a goal, draft a plan, call tools, judge results and hand work to specialist agents. Many tutorials for such systems depend on paid cloud APIs, which is convenient but brings usage charges, API-key handling, rate limits and questions about where data goes. Going local removes the token-based billing. It does not make computing free, since memory, processor time, storage and electricity are still spent.

The system being built

The project plans, writes and reviews a technical blog article. Given a topic, it works out the steps, produces a structured outline, writes the piece and evaluates the draft. That exercises two basic parts of agentic AI, reasoning and acting. Five components do the work:

  • A planner agent that drafts the article outline.
  • An outline validator that checks whether the plan meets the requirements.
  • A writer agent that turns the approved outline into a full article.
  • An article validator that reviews structure and technical clarity.
  • A root agent that orchestrates the whole flow.

The design follows Google's own Build an AI Agent with Google ADK codelab, with one change: the hosted Gemini model is replaced by Gemma 4 running locally through Ollama.

Choosing the model

Gemma 4 is a newer family of open models from Google DeepMind with multimodal input, reasoning, tool use and coding support. This setup uses:

gemma4:e4b

The E4B label refers to the effective number of parameters active at a time, meant to give stronger capability without engaging every parameter on every input. The Ollama build is about 9.6 GB and should run on a Mac with 16 GB of unified memory, though little will be left for other applications. On a machine that struggles, a smaller variant exists:

gemma4:e2b

It gives up some reasoning quality in exchange for speed and a smaller memory footprint.

The reference machine was an Apple M1 Pro with a 10-core processor, 16 GB of unified memory, macOS, Python 3.13, Homebrew and Ollama. Other systems that Ollama supports should work too, although install commands and speed will differ.

Step 1: install Ollama

Ollama is a simple way to download and run open models locally. With Homebrew:

brew install ollama

If it is already installed, update it:

brew update
brew upgrade ollama

Confirm the install:

ollama --version

The macOS app from the official Ollama site is an alternative.

Step 2: pull the model

Download the E4B model. Expect several minutes, since the file runs to a few gigabytes:

ollama pull gemma4:e4b

Then check that it is listed:

ollama list

The entry should look roughly like this:

NAME            ID              SIZE
gemma4:e4b      ...             9.6 GB

Step 3: talk to the model directly

Before adding ADK, check that Gemma works through Ollama by itself:

ollama run gemma4:e4b

Try a simple prompt:

Create an outline for an article explaining AI agents to beginners.

Any sensible answer shows that the local model is working. Leave the interactive session with:

/bye

This test isolates problems. If the model fails here, debugging the agent framework is pointless.

Step 4: see whether Ollama is already running

By default Ollama listens on:

http://127.0.0.1:11434

Starting the server by hand may produce an error:

ollama serve
Error: listen tcp 127.0.0.1:11434: bind: address already in use

That error does not necessarily mean trouble. It usually means Ollama is already up. Test it with a request to the tags endpoint:

curl http://127.0.0.1:11434/api/tags

A running server answers with JSON listing the installed models. To see which models are currently loaded:

ollama ps

A second server should never be started on the same port.

Step 5: create the ADK project

Make a project folder wherever suits:

cd /Users/yourusername
mkdir bloggeragent
cd bloggeragent

Create the files the project needs:

touch requirements.txt .env .gitignore __init__.py agent.py

The layout should end up like this:

bloggeragent/
├── .env
├── .gitignore
├── __init__.py
├── agent.py
└── requirements.txt

Step 6: a virtual environment

A Python virtual environment keeps the project's dependencies apart from the rest of the system. Create one:

python3 -m venv .venv

Activate it:

source .venv/bin/activate

The terminal prompt should now begin with:

(.venv)

Check that the right interpreter is in use:

which python

The path returned should point inside the project's environment, something like:

/Users/philipobiorah/bloggeragent/.venv/bin/python

Step 7: install ADK with local-model support

Put the dependencies in requirements.txt:

google-adk[extensions]==2.2.0
python-dotenv
litellm>=1.84

Then install them:

python -m pip install --upgrade pip
python -m pip install -r requirements.txt

The [extensions] part matters. A basic ADK install may lack the optional packages that the LiteLlm wrapper needs, and the app can then fail with an import error:

ImportError: LiteLLM support requires:
pip install google-adk[extensions]

If that appears, install the extras explicitly:

python -m pip install --upgrade "google-adk[extensions]==2.2.0"
python -m pip install --upgrade "litellm>=1.84"

Quotation marks stop shells such as Zsh from treating the square brackets as a pattern. To verify the integration:

python -c "from google.adk.models.lite_llm import LiteLlm; print('LiteLLM connection ready')"

The expected output is:

LiteLLM connection ready

Step 8: point the project at Ollama

Add the local address to .env:

OLLAMA_API_BASE=http://127.0.0.1:11434

Unlike the hosted Gemini version, the local setup needs no Google API key, so this variable is absent:

GOOGLE_API_KEY

Local configuration is still worth protecting, so add these entries to .gitignore:

.env
.venv/
__pycache__/
*.pyc

Keeping .env out of version control is good practice even when the file holds no secrets today.

Step 9: make the folder a package

Add one line to __init__.py so that ADK can import the agent definition from the package:

from . import agent

Step 10: define the local model

Open agent.py and start with the imports:

import datetime
from dotenv import load_dotenv
from google.adk.agents import Agent, LoopAgent
from google.adk.models.lite_llm import LiteLlm
from google.adk.tools import agent_tool

Load the environment configuration:

load_dotenv()

Create the connector to the local model:

MODEL = LiteLlm(
    model="ollama_chat/gemma4:e4b"
)

Google recommends the ollama_chat provider over plain ollama. The chat-specific interface keeps conversational context better and lowers the chance of inappropriate repeated tool calls. With the smaller model, only the model string changes:

MODEL = LiteLlm(
    model="ollama_chat/gemma4:e2b"
)

Step 11: the multi-agent workflow

The full multi-agent code comes from Google's codelab, in its step on building the multi-agent blog writer. The supplied code goes into agent.py. It defines these pieces:

  • BlogPlanner produces the outline.
  • OutlineValidationChecker reviews it.
  • RobustBlogPlanner runs planning and that review inside a loop with a fixed limit.
  • BlogWriter expands the outline into the article.
  • BlogPostValidationChecker examines the finished text.
  • RobustBlogWriter ties writing to that examination.
  • planner_tool and writer_tool present the two workflows as callable tools.
  • root_agent drives the process from start to end.

In the original, these agents talk to a hosted Gemini model. The architecture stays, and only the model configuration changes.

As in the codelab, __init__.py contains:

from . import agent

That exposes the agent workflow to the ADK runner. Next, adjust the imports in the codelab's agent.py. Add the LiteLlm import:

from google.adk.models.lite_llm import LiteLlm

These two imports are unused in the supplied code and can be removed:

import sys
from pathlib import Path

These stay:

import datetime
from dotenv import load_dotenv
from google.adk.agents import Agent, LoopAgent
from google.adk.tools import agent_tool

The codelab defines its model with an environment lookup:

MODEL = os.getenv("MODEL", "gemini-flash-latest")

Replace that line with the local connector:

MODEL = LiteLlm(
    model="ollama_chat/gemma4:e4b"
)

The top of agent.py should then read:

import datetime
from dotenv import load_dotenv
from google.adk.agents import Agent, LoopAgent
from google.adk.models.lite_llm import LiteLlm
from google.adk.tools import agent_toolload_dotenv()MODEL = LiteLlm(
    model="ollama_chat/gemma4:e4b"
)

The planner, writer, validators, LoopAgent, AgentTool and root_agent definitions stay exactly as the codelab presents them. Every agent already carries:

model=MODEL

So changing the one shared MODEL variable redirects the entire system from the hosted Gemini API to Gemma 4 running through Ollama.

What this exercises

Several agent concepts meet in this small project:

  • Reasoning: Gemma interprets the goal and decides on an approach.
  • Planning: the planner agent drafts the outline.
  • Acting: the root agent invokes the specialist workflows.
  • Tool use: planning and writing are exposed as agent tools.
  • Shared state: results are passed along from the planner to the writer and the checkers.
  • Validation: dedicated checker agents look over each intermediate output.
  • Orchestration: one root agent decides what runs when.
  • Iteration: bounded loops allow revision.
  • Local inference: Ollama runs Gemma 4 on the Mac.

Together they show a locally hosted language model acting as the reasoning engine inside a larger agentic system.

Running the finished version

A complete implementation, with planner, writer, validators, the local Gemma 4 configuration and the root agent, is published in a GitHub repository called bloggeragent. To use it, clone it:

git clone https://github.com/philipobiorah/bloggeragent.git
cd bloggeragent

Create and activate a virtual environment:

python3 -m venv .venv
source .venv/bin/activate

Install the dependencies:

python -m pip install -r requirements.txt

This is the full local adaptation of Google's blog-writing example, set up for Gemma 4 through Ollama and LiteLLM instead of the hosted Gemini API.

The takeaway

An AI agent does not always need a paid model API. With Gemma 4, Ollama, LiteLLM and Google ADK, a multi-agent application can plan an article, validate the plan, write a draft, review it and return the result on an Apple Silicon Mac without per-request charges. Running locally also makes it easier to see how agent systems work beneath the chat interface.

The main lesson is that an agent is more than its language model. A capable one emerges from the combination of model, instructions, tools, state, orchestration, validation and safeguards. Running the model locally gives more control over the infrastructure, and the design of the system around it decides whether that control produces something useful, reliable and responsible.