Skip to main content

Introduction

This playbook demonstrates building a multi-modal agent by composing image generation and vision capabilities into a single agent class. You’ll use Python’s multiple inheritance to combine SDToolsMixin (Stable Diffusion image generation) and VLMToolsMixin (Vision Language Model analysis) with GAIA’s base Agent class. The architecture is straightforward: your agent runs an LLM as its reasoning engine, which has access to tools from both mixins. When a user asks to generate an image and create a story, the LLM decides the sequence—call generate_image(), then call create_story_from_image() to analyze the result. Behind the scenes, Lemonade Server hosts the model endpoints locally, providing LLM inference for the agent’s reasoning, VLM inference for image analysis, and Stable Diffusion for image generation. Everything runs on your machine with no external API calls. The key pattern you’ll learn is tool composition through mixins. Each mixin registers its tools via the @tool decorator during initialization. You’ll see how domain-specific tools can wrap generic capabilities, creating specialized workflows while keeping the underlying components reusable. By the end, you’ll have a working multi-modal agent in ~60 lines of code and understand how to compose tool capabilities using GAIA’s mixin architecture.

Quick Test

First time? See Setup Guide to install prerequisites (uv, Python, AMD drivers).
Want to try it first before building? Install GAIA with the built-in SD agent (gaia sd ships in the standalone gaia-agent-sd package):
Install models and start Lemonade Server:
Generate one image + story with the built-in agent:

What You’ll Build

An ImageStoryAgent that generates images and creates stories about them. ~60 lines of code total. When you run agent.process_query("create a robot exploring ancient ruins"), here’s what happens:
  1. LLM decides the plan: Gemma-4-E4B-it analyzes your query and returns {plan: [{tool: "generate_image", tool_args: {prompt: "..."}}, {tool: "create_story_from_image", tool_args: {...}}]}
  2. Executes generate_image(): Sends prompt to SDXL-Turbo (4-step diffusion model), receives PNG bytes, saves to disk (~17s)
  3. Executes create_story_from_image(): Calls your custom tool → sends image bytes to the Gemma-4-E4B-it vision model → receives 2-3 paragraph narrative (~15s)
  4. Returns result: {"status": "success", "result": "Here's your image and story...", "conversation": [...], "steps_taken": 3}
You’ll create the create_story_from_image tool yourself using VLM capabilities. Two models, one agent:
  • Gemma-4-E4B-it-GGUF (~3GB): Multimodal model — serves as both the reasoning engine (decides which tools to call and when) and the vision-language model (analyzes images and generates text)
  • SDXL-Turbo (6.5GB): Diffusion model - generates images from text prompts
All run locally via Lemonade Server. The GGUF model uses AMD Radeon iGPU (Vulkan); SDXL runs on CPU.

Prerequisites

1

Complete setup

If you haven’t already, follow the Setup guide to install prerequisites (uv, Lemonade Server, etc.).
2

Create project folder

3

Create virtual environment

uv will automatically download Python 3.12 if not already installed.
Activate the environment:
4

Install GAIA

The custom agent you build below only needs the gaia.sd and gaia.vlm mixins from core amd-gaia. The agent-sd extra additionally installs the standalone gaia-agent-sd package so the built-in gaia sd command (used in the Quick Test and Troubleshooting) is available too.
5

Initialize SD profile

This command:
  1. Installs Lemonade Server (if not already installed)
  2. Starts Lemonade Server automatically
  3. Configures Lemonade Server with 16K context (required for SD agent multi-step planning)
  4. Downloads two models (~10GB):
    • SDXL-Turbo (6.5GB) - Diffusion model in safetensors format
    • Gemma-4-E4B-it-GGUF (~3GB) - Multimodal GGUF model used for both agentic reasoning and vision (loaded with 16K context)
  5. Verifies models and context size
Hardware acceleration:
  • GGUF models run on iGPU (Radeon integrated graphics) via Vulkan
  • SDXL-Turbo currently runs on CPU (GPU acceleration planned)
Video: Running gaia init --profile sd and watching models download

Building the Agent

Create a new file image_story_agent.py and add this code:

Step 1: Initialize the Agent

What this does:
  • Agent, SDToolsMixin, VLMToolsMixin: Inherits three capabilities - reasoning, image generation, vision analysis
  • super().__init__(model_id="Gemma-4-E4B-it-GGUF"): Sets up the multimodal reasoning LLM (downloaded by gaia init --profile sd)
  • init_sd(): Registers image generation tools (generate_image, list_sd_models, get_generation_history)
  • init_vlm(): Registers vision tools (analyze_image, answer_question_about_image)
The agent now has 5 tools from mixins. You’ll add a 6th custom tool next.
From SDToolsMixin:
  • Sends prompt to SDXL-Turbo diffusion model
  • Returns: {"status": "success", "image_path": "...", "generation_time_s": 17.2, "seed": 123456}
  • Saves PNG to output_dir
  • Returns available models with speed/quality characteristics
  • Returns recent generations from this session
From VLMToolsMixin:
  • Sends image bytes to the Gemma-4-E4B-it vision model
  • Returns: {"status": "success", "description": "...", "focus_analysis": "..."}
  • Sends image + question to VLM
  • Returns: {"status": "success", "answer": "...", "confidence": "high"}
You can change default_model in init_sd():

Step 2: Add Custom Tool

Add _register_tools() to create create_story_from_image:
What this does:
  • @tool(atomic=True): Registers create_story_from_image as an atomic tool
    • atomic=True: Tool is self-contained - executes completely without multi-step planning
    • Most tools are atomic (generate image, analyze image, query database)
    • Non-atomic: multi-step tasks like “research a topic”
  • Reads image bytes from file path
  • Builds a storytelling prompt based on the style parameter
  • Calls self.vlm_client.extract_from_image() - sends image + prompt to the Gemma-4-E4B-it vision model
  • Returns structured dict with story text and metadata
  • Decorator auto-generates JSON schema from function signature and docstring

Step 3: Add System Prompt (Optional)

Add _get_system_prompt() to customize instructions:
What this does:
  • Documents your custom create_story_from_image tool (parameters, return value, purpose)
  • Provides explicit workflow: generate image → create story using the image_path → include full text in answer
  • Sets critical rules: use image_path from results, include complete story text, default to one image
  • Gives example showing proper parameter passing between tool calls
Why this is important:
  • Mixins only describe their own tools (SD guidelines don’t know about VLM or custom tools)
  • Your custom tool needs explicit documentation and usage instructions
  • Clear workflow prevents errors like missing image_path or incomplete responses
  • Examples help the LLM understand expected behavior
Tool schemas (parameters, types) are auto-added by the @tool decorator. Your system prompt provides usage guidelines and workflow that schemas can’t express.

Step 4: Add CLI and Run

Add the CLI loop to test your agent:
Quick summary:
  • Creates output directory and initializes agent (loads Gemma-4-E4B-it, registers 6 tools)
  • Loops: reads input → calls process_query(input) → prints result
  • process_query() handles LLM planning and tool execution automatically
When you call agent.process_query("create a robot exploring ruins"):Step 1 - LLM Planning:
Step 2 - LLM Response:
Step 3 - Tool Execution:
  • Calls generate_image("robot exploring ancient ruins") → Saves PNG to disk (~17s)
  • Calls create_story_from_image("path/to/image.png") → Gets story from VLM (~15s)
Step 4 - Final Synthesis:
  • Agent sends tool results back to LLM
  • LLM creates final answer combining both results
Step 5 - Return Value:
Agent limits: Max 20 steps (configurable). Stops when LLM returns answer field instead of requesting more tools.
Run it:
Or skip the typing and run the complete example from the GAIA repository:
Try:
🎉 Congratulations! You’ve built a fully functional multi-modal agent in ~60 lines of code. The agent can generate images with Stable Diffusion, analyze them with vision models, and create stories—all running locally on AMD hardware.

Troubleshooting

Error: LemonadeClientError: Cannot connect to http://localhost:13305Solution: Lemonade Server isn’t running. Check status:
If not running, gaia init --profile sd should have started it. Try restarting:
Error: Model 'SDXL-Turbo' not foundSolution: Download missing models:
Or re-run init:
Error: ModuleNotFoundError: No module named 'gaia.sd'Solution: Upgrade GAIA:
Verify installation:
Question: How do I generate the same image twice?Solution: Use a fixed seed:CLI:
Python:
By default, images use random seeds for variety. Specify a seed for reproducibility.

Still Having Issues?

If you’re experiencing a problem not listed above, we’re here to help: Report an Issue:
  • 🐛 Create a GitHub Issue - Best for bugs, feature requests, and technical issues
  • Include your GAIA version (gaia --version), OS, and error messages
Get Help: Before Reporting:
  1. Check the FAQ and Troubleshooting Guide
  2. Search existing issues to avoid duplicates
  3. Include reproduction steps, error messages, and environment details

What’s Next?

Try the CLI

Use gaia sd for quick image generation with stories

Agent System Deep Dive

Complete guide to GAIA’s Agent architecture

VLM Tools Reference

Learn more about VLMToolsMixin capabilities

Other Playbooks

Build Chat agents, Code agents, Jira agents, and more