19. Artifacts

This blog is part of the ADK Masterclass - Hands-On Series. Artifacts provide a way for agents to store and manage files, images, and other binary data produced during execution. This is essential for agents that generate reports, images, or need to persist data between sessions.

View Code on GitHub

Table of Contents

1. What are Artifacts?

graph LR Agent[Agent] --> |"Creates"| Artifact[Artifact] Artifact --> |"Stores"| Service[Artifact Service] subgraph Types["Artifact Types"] Image[Images] File[Files] Data[Binary Data] end Artifact --> Types Service --> |"Retrieves"| User[User/App] style Agent fill:#e3f2fd,stroke:#1565c0 style Artifact fill:#f3e5f5,stroke:#7b1fa2 style Service fill:#e8f5e9,stroke:#2e7d32

Think of artifacts as files your agent can save and retrieve. When an agent generates a chart, creates a report, or processes an image, it needs somewhere to store that output. Artifacts provide that storage.

Key characteristics:

  • Named: Each artifact has a filename like "report.pdf" or "chart.png"
  • Versioned: Saving the same filename creates a new version (v1, v2, v3...)
  • Scoped: Can be tied to a single session or persist across all user sessions

2. Why Use Artifacts?

Text responses are great, but agents often need to produce richer outputs. Without artifacts, we'd have to:

  • Encode binary data as base64 in responses (inefficient and ugly)
  • Manage file storage ourselves (complex and error-prone)
  • Lose track of what files were generated in which session

Artifacts solve this by providing a structured way to store, version, and retrieve non-text outputs with proper metadata.

Common Use Cases

  • Document Generation: Reports, summaries, transcripts
  • Data Export: CSV files, JSON data, analysis results
  • Image Handling: Charts, diagrams, AI-generated images
  • User Content: Uploaded files, processed media
  • Persistent State: User preferences, configuration files

3. Core Concepts

3.1. How Artifacts are Stored

Under the hood, artifacts are wrapped in a types.Part object. This object holds the raw bytes plus a MIME type that tells the system what kind of data it is:

from google.genai import types

# Create an artifact from bytes
report_bytes = json.dumps({"title": "Q4 Report"}).encode('utf-8')

# Wrap it in a Part object
artifact = types.Part.from_bytes(
    data=report_bytes,
    mime_type="application/json"
)

3.2. Versioning

Every time you save an artifact with the same filename, ADK creates a new version. This lets you track changes over time:

  • First save: version 1
  • Second save (same filename): version 2
  • Loading without specifying version gets the latest
  • You can request a specific version if needed

3.3. Session vs. User Scope

By default, artifacts are tied to the current session. But sometimes you want data to persist across sessions—like user preferences. Use the user: prefix for that:

Scope Example When to Use
Session "report.json" Temporary files for this conversation
User "user:settings.json" Data that should survive across sessions

4. Tutorial

Prerequisites

Setup Environment

# Create and activate virtual environment
python3 -m venv .venv
source .venv/bin/activate

# Install dependencies
pip install google-adk python-dotenv

# Set our API key
export GOOGLE_API_KEY=our_api_key_here

4.1. Enable Artifact Storage

To use artifacts, pass an artifact service to your Runner. For local development, use InMemoryArtifactService:

from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
from google.adk.artifacts import InMemoryArtifactService

runner = Runner(
    agent=my_agent,
    app_name="my_app",
    session_service=InMemorySessionService(),
    artifact_service=InMemoryArtifactService(),  # Add this line
)

4.2. Saving Artifacts from Tools

Inside a tool function, use tool_context.save_artifact() to store files. Here's a practical example that saves a JSON report:

from google.adk.agents import Agent
from google.adk.tools import ToolContext
from google.genai import types
import json

def save_report(title: str, content: str, tool_context: ToolContext) -> dict:
    """Save a report as an artifact."""
    
    # Prepare the data
    report = {"title": title, "content": content}
    report_bytes = json.dumps(report).encode('utf-8')
    
    # Wrap in types.Part
    artifact = types.Part.from_bytes(
        data=report_bytes,
        mime_type="application/json"
    )
    
    # Save it
    version = tool_context.save_artifact(
        filename="report.json",
        artifact=artifact
    )
    
    return {"saved": True, "version": version}

root_agent = Agent(
    model="gemini-2.5-flash",
    name="report_agent",
    instruction="Help users create and save reports.",
    tools=[save_report],
)

4.3. Loading Artifacts

To retrieve a saved artifact, use load_artifact(). It returns the data wrapped in a types.Part:

def get_report(filename: str, tool_context: ToolContext) -> dict:
    """Load a previously saved report."""
    
    artifact = tool_context.load_artifact(filename)
    
    if artifact is None:
        return {"error": f"'{filename}' not found"}
    
    # Extract the data
    data = artifact.inline_data.data
    content = json.loads(data.decode('utf-8'))
    
    return {"found": True, "content": content}

4.4. Listing All Artifacts

You can get a list of all artifact filenames in the current scope:

def list_saved_files(tool_context: ToolContext) -> dict:
    """List all saved artifacts."""
    
    filenames = tool_context.list_artifacts()
    
    return {
        "count": len(filenames),
        "files": filenames
    }

5. Artifact Services

ADK provides two storage backends. Choose based on your needs:

Service Best For Data Persists?
InMemoryArtifactService Development & testing No - gone when app restarts
GcsArtifactService Production apps Yes - stored in Google Cloud Storage

Using GCS for Production

For production, store artifacts in Google Cloud Storage. Your data persists across app restarts and can be shared between instances.

Prerequisites

# 1. Create a GCS bucket
gsutil mb gs://my-adk-artifacts-bucket

# 2. Configure Application Default Credentials
gcloud auth application-default login

Setup Code

from google.adk.artifacts import GcsArtifactService

# Create GCS-backed artifact storage
artifact_service = GcsArtifactService(
    bucket_name="my-adk-artifacts-bucket"
)

runner = Runner(
    agent=my_agent,
    app_name="my_app",
    session_service=session_service,
    artifact_service=artifact_service,
)

GCS Benefits

  • Persistent: Data survives app restarts and deployments
  • Scalable: Handles large files and high traffic
  • Secure: IAM-based access control
  • Shareable: Multiple app instances can access the same bucket

6. Best Practices

  • Use descriptive filenames: Include extensions like .json, .png, .pdf so it's clear what the file contains
  • Set correct MIME types: This helps when the artifact is retrieved and needs to be interpreted
  • Check for null: load_artifact() returns None if the file doesn't exist—always handle this case
  • Use user: prefix wisely: Only use it for data that truly needs to persist across sessions
  • Consider file size: For very large files, consider streaming or external storage instead
  • Clean up: In production, implement a cleanup strategy for old artifacts to manage storage costs

Next Steps

With artifacts covered, the final module in Core Components explores Events—the underlying event system that powers agent execution and enables real-time streaming.

Resources

Comments