Skip to main content
This quickstart will guide you through building a Google ADK agent with automatic memory, tool tracking, and query augmentation - all with just a few lines of code.

Prerequisites

1

Set Up Ryumem Server

First, you need a running Ryumem server. See Setup Guide for Docker Compose or local installation.Quick start with Docker:
git clone https://github.com/predictable-labs/ryumem.git
cd ryumem
cp server/.env.example server/.env
# Add your GOOGLE_API_KEY to server/.env
docker-compose up -d
2

Get Your API Key

Register to get your Ryumem API key:
curl -X POST "http://localhost:8000/register" \
  -H "Content-Type: application/json" \
  -d '{"customer_id": "my_project"}'
Save the API key from the response (starts with ryu_).
3

Install Dependencies for Google ADK

pip install ryumem google-adk python-dotenv
4

Set Environment Variables

Create a .env file in your project:
GOOGLE_API_KEY=your_google_api_key

Building Your First Agent With Google ADK

Let’s build a weather assistant that remembers conversations and automatically tracks what it does.

1. Create the Agent Tools

First, define some simple tools for our agent:
from google.adk.tools import FunctionTool

def get_weather_report(city: str) -> dict:
    """Get the current weather for a specified city."""
    if city.lower() == "london":
        return {
            "status": "success",
            "report": "Cloudy with 18°C and chance of rain."
        }
    elif city.lower() == "paris":
        return {
            "status": "success",
            "report": "Sunny with 25°C."
        }
    else:
        return {
            "status": "error",
            "error_message": f"Weather info for '{city}' not available."
        }

def analyze_sentiment(text: str) -> dict:
    """Analyze the sentiment of text."""
    if "good" in text.lower() or "sunny" in text.lower():
        return {"sentiment": "positive", "confidence": 0.8}
    elif "rain" in text.lower() or "bad" in text.lower():
        return {"sentiment": "negative", "confidence": 0.7}
    else:
        return {"sentiment": "neutral", "confidence": 0.6}

# Wrap as ADK tools
weather_tool = FunctionTool(func=get_weather_report)
sentiment_tool = FunctionTool(func=analyze_sentiment)

2. Create the Agent with Memory

Now create your agent and add memory with ONE line:
import os
from dotenv import load_dotenv
from google.adk.agents import Agent
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
from ryumem import Ryumem
from ryumem.integrations import add_memory_to_agent, wrap_runner_with_tracking

# Load environment variables
load_dotenv()

# Create the agent
agent = Agent(
    model="gemini-2.0-flash-exp",
    name="weather_assistant",
    instruction="""You are a helpful assistant that provides weather information
    and analyzes sentiment. Use get_weather_report for weather queries and
    analyze_sentiment for feedback.""",
    tools=[weather_tool, sentiment_tool]
)

# ⭐ Add memory in ONE line!
ryumem = Ryumem(
    api_url="http://localhost:8000",
    api_key="ryu_your_api_key_here"
)

memory = add_memory_to_agent(
    agent,
    ryumem_instance=ryumem,
    track_tools=True,  # Automatically track all tool calls
)
The agent now has 3 additional memory tools that it can use automatically: search_memory(), save_memory(), and get_entity_context().

3. Enable Query Tracking & Augmentation

Wrap your runner to automatically track queries and augment them with history:
import asyncio
from google.genai import types

async def main():
    # Setup session
    session_service = InMemorySessionService()
    await session_service.create_session(
        app_name="weather_app",
        user_id="user_123",
        session_id="session_456"
    )

    # Create runner
    runner = Runner(
        agent=agent,
        app_name="weather_app",
        session_service=session_service
    )

    # ⭐ Wrap for automatic query tracking and augmentation!
    runner = wrap_runner_with_tracking(
        runner,
        memory,
        augment_queries=True,      # Enable query augmentation
        similarity_threshold=0.3,  # Match queries with 30%+ similarity
        top_k_similar=5            # Use top 5 similar queries for context
    )

    # Run queries
    queries = [
        "What's the weather in London?",
        "That sounds nice!",
        "How about Paris?"
    ]

    for query in queries:
        print(f"\n👤 User: {query}")

        content = types.Content(
            role='user',
            parts=[types.Part(text=query)]
        )

        # Run the agent - everything tracked automatically!
        events = runner.run(
            user_id="user_123",
            session_id="session_456",
            new_message=content
        )

        # Get response
        for event in events:
            if event.is_final_response():
                response = event.content.parts[0].text
                print(f"🤖 Agent: {response}")

# Run it!
if __name__ == "__main__":
    asyncio.run(main())

4. Run Your Agent

Save the code as my_first_agent.py and run:
python my_first_agent.py
You should see output like:
👤 User: What's the weather in London?
🤖 Agent: The weather in London is currently cloudy with a temperature
of 18 degrees Celsius and there's a chance of rain.

👤 User: That sounds nice!
🤖 Agent: I'm glad you think so! The weather seems pleasant despite the
chance of rain.

👤 User: How about Paris?
🤖 Agent: The weather in Paris is sunny with a temperature of 25 degrees
Celsius. Much warmer and sunnier than London!

What Just Happened?

Behind the scenes, Ryumem:
  1. Tracked all tool executions - Every call to get_weather_report() and analyze_sentiment() was logged
  2. Stored user queries - All three questions were saved as episodes
  3. Augmented queries - Later queries got context from earlier similar ones
  4. Linked everything hierarchically - Queries are linked to their tool executions

What’s Next?

Full Code

Here’s the complete working example:
import os
import asyncio
from dotenv import load_dotenv
from google.adk.agents import Agent
from google.adk.tools import FunctionTool
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
from google.genai import types
from ryumem import Ryumem
from ryumem.integrations import add_memory_to_agent, wrap_runner_with_tracking

load_dotenv()

# Define tools
def get_weather_report(city: str) -> dict:
    if city.lower() == "london":
        return {"status": "success", "report": "Cloudy with 18°C"}
    elif city.lower() == "paris":
        return {"status": "success", "report": "Sunny with 25°C"}
    return {"status": "error", "error_message": f"No data for {city}"}

def analyze_sentiment(text: str) -> dict:
    if "good" in text.lower() or "sunny" in text.lower():
        return {"sentiment": "positive", "confidence": 0.8}
    elif "rain" in text.lower():
        return {"sentiment": "negative", "confidence": 0.7}
    return {"sentiment": "neutral", "confidence": 0.6}

weather_tool = FunctionTool(func=get_weather_report)
sentiment_tool = FunctionTool(func=analyze_sentiment)

# Create agent
agent = Agent(
    model="gemini-2.0-flash-exp",
    name="weather_assistant",
    instruction="You provide weather info and analyze sentiment.",
    tools=[weather_tool, sentiment_tool]
)

# Add memory
ryumem = Ryumem(
    api_url="http://localhost:8000",
    api_key="ryu_your_api_key_here"
)
memory = add_memory_to_agent(
    agent,
    ryumem_instance=ryumem,
    track_tools=True,
)

async def main():
    session_service = InMemorySessionService()
    await session_service.create_session(
        app_name="weather_app",
        user_id="user_123",
        session_id="session_456"
    )

    runner = Runner(
        agent=agent,
        app_name="weather_app",
        session_service=session_service
    )

    runner = wrap_runner_with_tracking(
        runner,
        memory,
        augment_queries=True,
        similarity_threshold=0.3,
        top_k_similar=5
    )

    queries = [
        "What's the weather in London?",
        "That sounds nice!",
        "How about Paris?"
    ]

    for query in queries:
        print(f"\n👤 User: {query}")
        content = types.Content(role='user', parts=[types.Part(text=query)])
        events = runner.run(user_id="user_123", session_id="session_456", new_message=content)

        for event in events:
            if event.is_final_response():
                print(f"🤖 Agent: {event.content.parts[0].text}")

if __name__ == "__main__":
    asyncio.run(main())
This complete example is available in the repository as examples/simple_tool_tracking_demo.py.

Visualizing Results in Dashboard

All the queries, tool executions, and memories from your agent are automatically visible in the Ryumem dashboard:
  • Chat & Query: Search and explore the knowledge graph
  • Episodes: View all stored memories and conversations
  • Tool Analytics: See tool execution statistics and patterns
  • Queries: Track query history and augmentation

Dashboard Guide

Learn how to navigate and use all dashboard features