Agno v2.3: Nano Banana, Claude Structured Outputs, and More

Nancy Chauhan
November 28, 2025
5 min read

What's new in v2.3?

This might be our longest changelog yet! At the core, it's the same blazing-fast, truly agnostic framework you know and love. But v2.3 brings some seriously exciting features that make building multi-agent systems even more powerful.

What's changed?

With Agno v2.3, you'll find: ‍

Nano Banana image generation

Key improvement: Generate images with Google's Gemini 2.5 Flash Image model. And yes, Google actually named it Nano Banana.

We couldn't resist adding support for this one. The name alone is worth the upgrade.

Setup:

# Install dependencies
pip install agno google-genai Pillow

# Set your Google API key
export GOOGLE_API_KEY="your_api_key"
from agno.agent import Agent
from agno.tools.nano_banana import NanoBananaTools

agent = Agent(
    tools=[NanoBananaTools()], 
    name="NanoBanana Image Generator"
)

agent.run(
    "Generate an image of a futuristic city with flying cars",
    markdown=True,
)


Watch your images come to life

Images appear in real-time in the AgentOS chat interface. No more waiting around wondering if your generation worked, you'll see it streaming in.

# Want a specific aspect ratio? We've got you covered
portrait_agent = Agent(
    tools=[NanoBananaTools(aspect_ratio="2:3")],  # Portrait
    name="Portrait Generator",
)

widescreen_agent = Agent(
    tools=[NanoBananaTools(aspect_ratio="16:9")],  # Cinematic
    name="Widescreen Generator",
)

Supported aspect ratios: 1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9. Pick your canvas.

See it in action

Claude structured outputs

Key improvement: Get guaranteed structured responses from Claude. No more JSON parsing headaches. Remember the days of writing 47 lines of parsing code for every Claude response? Yeah, those days are over.

from typing import List
from agno.agent import Agent
from agno.models.anthropic import Claude
from pydantic import BaseModel, Field


class MovieScript(BaseModel):
    setting: str = Field(..., description="Provide a nice setting for a blockbuster movie.")
    ending: str = Field(..., description="Ending of the movie. If not available, provide a happy ending.")
    genre: str = Field(..., description="Genre of the movie. If not available, select action, thriller or romantic comedy.")
    name: str = Field(..., description="Give a name to this movie")
    characters: List[str] = Field(..., description="Name of characters for this movie.")
    storyline: str = Field(..., description="3 sentence storyline for the movie. Make it exciting!")


movie_agent = Agent(
    model=Claude(id="claude-sonnet-4-5"),
    description="You help people write movie scripts.",
    output_schema=MovieScript,  # Guaranteed structured output
)

movie_agent.print_response("New York")

Type-safe responses every time

# Get the response in a variable
run = movie_agent.run("New York")
# Returns validated MovieScript object
print(run.content.name)       # Movie title
print(run.content.genre)      # "Action Thriller"
print(run.content.characters) # ["John McClane", "Hans Gruber", ...]

Works with any Pydantic model. Define your schema once, get clean data every time.

Check out the full example

RedisCluster support for production scale

Key improvement: Scale your agent infrastructure with Redis Cluster for high-availability deployments. Your agents can now handle millions of sessions.

Single Redis getting crushed by your agent's popularity? RedisCluster gives you automatic sharding, failover, and the kind of reliability that lets you sleep at night

from redis import RedisCluster
from agno.agent import Agent
from agno.db.redis import RedisDb
from agno.models.openai import OpenAIChat
from agno.tools.duckduckgo import DuckDuckGoTools

# Connect to Redis Cluster with startup nodes
redis_client = RedisCluster(
    startup_nodes=[
        {"host": "node1.redis.example.com", "port": 6379},
        {"host": "node2.redis.example.com", "port": 6379},
        {"host": "node3.redis.example.com", "port": 6379},
    ],
    decode_responses=True,
    skip_full_coverage_check=True,
)

# Use RedisCluster with Agno
db = RedisDb(redis_client=redis_client)

agent = Agent(
    model=OpenAIChat(id="gpt-4"),
    db=db,                          # Automatic sharding and failover
    tools=[DuckDuckGoTools()],
    add_history_to_context=True,    # Auto-loads chat history
)

agent.print_response("How many people live in Canada?")
agent.print_response("What is their national anthem called?")

Perfect for production deployments requiring high availability, multi-region systems, and applications with millions of sessions.

Check out the Redis database documentation  →

Seamless database migrations

Key improvement: MigrationManager handles schema updates automatically. No more manual database changes.

from agno.db.migrations.manager import MigrationManager
from agno.db.postgres import PostgresDb

db = PostgresDb(db_url="postgresql://localhost/agno")
migration_manager = MigrationManager(db=db)

# Your database is now future-proof
await migration_manager.up()

Migrate specific tables or versions

# Update just one table
await migration_manager.up(table_type="session")

# Or target a specific version
await migration_manager.up(target_version="2.3.0")

Check out the migrations documentation  →

Context compression (Beta)

Key improvement: Keep your agents running smoothly within their context window. Context compression automatically compresses tool call results in a running context, helping you avoid rate limits and maintain response quality during long conversations.

This is especially useful for agents that make many tool calls or work with large responses.

from agno.agent import Agent
from agno.models.openai import OpenAIChat
from agno.tools.duckduckgo import DuckDuckGoTools

agent = Agent(
    model=OpenAIChat(id="gpt-4o"),
    tools=[DuckDuckGoTools()],
    compress_tool_results=True,
)

agent.print_response("Research each of the following topics: AI, Crypto, Web3, and Blockchain")

Check out the context compression docs

Memory optimization (Beta)

Key improvement: Smarter memory management with automatic summarization. The new optimize_memories and aoptimize_memories methods on MemoryManager let you summarize user memories outside of agent runs.

from agno.db.sqlite import SqliteDb
from agno.memory import MemoryManager
from agno.memory.strategies.types import MemoryOptimizationStrategyType
from agno.models.openai import OpenAIChat

db = SqliteDb(db_file="tmp/agno.db")

memory_manager = MemoryManager(
    model=OpenAIChat(id="gpt-4o-mini"),
    db=db,
)

# Optimize memories for a user
memory_manager.optimize_memories(
    user_id="user_123",
    strategy=MemoryOptimizationStrategyType.SUMMARIZE,
    apply=True,  # Apply changes to database
)

Currently supports one summarization strategy, with more coming soon.

Check out the memory optimization docs

Gemini file search support

Key improvement: Full-featured document search powered by Gemini. Build RAG pipelines with native Google infrastructure.

What's included:

  • File Search Store Management: Create, list, get, and delete document stores
  • File Upload & Import: Direct upload with custom chunking configuration and metadata
  • Document Management: List, get, delete, and update documents with metadata filtering
  • Citation Extraction: Helper methods to extract and format source citations from responses
  • Async Support: Full async/await support for production workloads

Check out these cookbooks to get started:

And a whole lot more...

Beyond the headline features, v2.3 includes:

  • Enhanced error handling across all model providers
  • Optimized memory management for multi-turn conversations
  • Better async support throughout the framework
  • Expanded toolkit integrations

We're already working on v2.4 with even more exciting features. Stay tuned! 🚀

See the Changelog for more details on v2.3. Or check out this guide for help upgrading your Agno applications.

🧡 Team Agno


Install the latest version:

pip install -U agno