Skip to main content

Galileo observability integration for Google ADK

Project description

galileo-adk

PyPI version Python versions License

Galileo observability for Google ADK agents. Automatic tracing of agent runs, LLM calls, and tool executions.

Installation

pip install galileo-adk

Requirements: Python 3.10+, a Galileo API key, and a Google AI API key

Quick Start

import asyncio
from galileo_adk import GalileoADKPlugin
from google.adk.runners import Runner
from google.adk.agents import LlmAgent
from google.genai import types

async def main():
    plugin = GalileoADKPlugin(project="my-project", log_stream="production")
    agent = LlmAgent(name="assistant", model="gemini-2.0-flash", instruction="You are helpful.")
    runner = Runner(agent=agent, plugins=[plugin])

    message = types.Content(parts=[types.Part(text="Hello! What can you help me with?")])
    async for event in runner.run_async(user_id="user-123", session_id="session-456", new_message=message):
        if event.is_final_response():
            print(event.content.parts[0].text)

if __name__ == "__main__":
    # Set environment variables: GALILEO_API_KEY, GOOGLE_API_KEY
    asyncio.run(main())

Configuration

Parameter Environment Variable Description
project GALILEO_PROJECT Project name (required unless ingestion_hook provided)
log_stream GALILEO_LOG_STREAM Log stream name (required unless ingestion_hook provided)
ingestion_hook - Custom callback for trace data (bypasses Galileo backend)

Features

Session Tracking

All traces with the same session_id are automatically grouped into a Galileo session, enabling conversation-level tracking:

import asyncio
from galileo_adk import GalileoADKPlugin
from google.adk.runners import Runner
from google.adk.agents import LlmAgent
from google.genai import types

async def main():
    plugin = GalileoADKPlugin(project="my-project", log_stream="production")
    agent = LlmAgent(name="assistant", model="gemini-2.0-flash", instruction="You are helpful.")
    runner = Runner(agent=agent, plugins=[plugin])

    # All traces in this conversation are grouped together
    session_id = "conversation-abc"

    # First message
    message1 = types.Content(parts=[types.Part(text="Hello! What's the capital of France?")])
    async for event in runner.run_async(user_id="user-123", session_id=session_id, new_message=message1):
        if event.is_final_response():
            print(f"Response 1: {event.content.parts[0].text}")

    # Follow-up in same session
    message2 = types.Content(parts=[types.Part(text="What about Germany?")])
    async for event in runner.run_async(user_id="user-123", session_id=session_id, new_message=message2):
        if event.is_final_response():
            print(f"Response 2: {event.content.parts[0].text}")

if __name__ == "__main__":
    # Set environment variables: GALILEO_API_KEY, GOOGLE_API_KEY
    asyncio.run(main())

Custom Metadata

Attach custom metadata to traces using ADK's RunConfig. Metadata is propagated to all spans (agent, LLM, tool) within the invocation:

import asyncio
from galileo_adk import GalileoADKPlugin
from google.adk.runners import Runner
from google.adk.agents import LlmAgent
from google.adk.agents.run_config import RunConfig
from google.genai import types

async def main():
    plugin = GalileoADKPlugin(project="my-project", log_stream="production")
    agent = LlmAgent(name="assistant", model="gemini-2.0-flash", instruction="You are helpful.")
    runner = Runner(agent=agent, plugins=[plugin])

    run_config = RunConfig(
        custom_metadata={
            "user_tier": "premium",
            "conversation_id": "conv-abc",
            "turn": 1,
            "experiment_group": "A",
        }
    )

    message = types.Content(parts=[types.Part(text="Hello! Tell me a fun fact.")])
    async for event in runner.run_async(
        user_id="user-123",
        session_id="session-456",
        new_message=message,
        run_config=run_config,
    ):
        if event.is_final_response():
            print(event.content.parts[0].text)

if __name__ == "__main__":
    # Set environment variables: GALILEO_API_KEY, GOOGLE_API_KEY
    asyncio.run(main())

Callback Mode

For granular control over which callbacks to use, attach them directly to your agent instead of using the plugin:

import asyncio
from galileo_adk import GalileoADKCallback
from google.adk.runners import Runner
from google.adk.agents import LlmAgent
from google.genai import types

async def main():
    callback = GalileoADKCallback(project="my-project", log_stream="production")

    agent = LlmAgent(
        name="assistant",
        model="gemini-2.0-flash",
        instruction="You are helpful.",
        before_agent_callback=callback.before_agent_callback,
        after_agent_callback=callback.after_agent_callback,
        before_model_callback=callback.before_model_callback,
        after_model_callback=callback.after_model_callback,
        before_tool_callback=callback.before_tool_callback,
        after_tool_callback=callback.after_tool_callback,
    )
    runner = Runner(agent=agent)

    message = types.Content(parts=[types.Part(text="Hello! How are you?")])
    async for event in runner.run_async(user_id="user-123", session_id="session-456", new_message=message):
        if event.is_final_response():
            print(event.content.parts[0].text)

if __name__ == "__main__":
    # Set environment variables: GALILEO_API_KEY, GOOGLE_API_KEY
    asyncio.run(main())

Retriever Spans

By default, all FunctionTool calls are logged as tool spans. To log a retriever function as a retriever span (enabling RAG quality metrics in Galileo), decorate it with @galileo_retriever:

from galileo_adk import galileo_retriever
from google.adk.tools import FunctionTool

@galileo_retriever
def search_docs(query: str) -> str:
    """Search the knowledge base."""
    results = my_vector_db.search(query)
    return "\n".join(r["content"] for r in results)

tool = FunctionTool(search_docs)

Ingestion Hook

Intercept traces for custom processing before forwarding to Galileo:

import asyncio
import os
from galileo import GalileoLogger
from galileo_adk import GalileoADKPlugin
from google.adk.runners import Runner
from google.adk.agents import LlmAgent
from google.genai import types

logger = GalileoLogger(
    project=os.getenv("GALILEO_PROJECT", "my-project"),
    log_stream=os.getenv("GALILEO_LOG_STREAM", "dev"),
)

def my_ingestion_hook(request):
    """Hook that captures traces locally and forwards to Galileo with session management."""
    if hasattr(request, "traces") and request.traces:
        print(f"\n[Ingestion Hook] Intercepted {len(request.traces)} trace(s)")
        for trace in request.traces:
            spans = getattr(trace, "spans", []) or []
            span_types = [getattr(s, "type", "unknown") for s in spans]
            print(f"  - Trace with {len(spans)} span(s): {span_types}")

    # Session management: same external_id returns the same Galileo session
    galileo_session_id = logger.start_session(external_id=request.session_external_id)
    request.session_id = galileo_session_id

    # Forward traces to Galileo
    logger.ingest_traces(request)

async def main():
    plugin = GalileoADKPlugin(ingestion_hook=my_ingestion_hook)
    agent = LlmAgent(name="assistant", model="gemini-2.0-flash", instruction="You are helpful.")
    runner = Runner(agent=agent, plugins=[plugin])

    message = types.Content(parts=[types.Part(text="Hello!")])
    async for event in runner.run_async(user_id="user-123", session_id="session-456", new_message=message):
        if event.is_final_response():
            print(event.content.parts[0].text)

if __name__ == "__main__":
    # Set environment variables: GALILEO_API_KEY, GOOGLE_API_KEY
    asyncio.run(main())

Resources

License

Apache-2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

galileo_adk-1.0.0.tar.gz (49.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

galileo_adk-1.0.0-py3-none-any.whl (25.6 kB view details)

Uploaded Python 3

File details

Details for the file galileo_adk-1.0.0.tar.gz.

File metadata

  • Download URL: galileo_adk-1.0.0.tar.gz
  • Upload date:
  • Size: 49.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for galileo_adk-1.0.0.tar.gz
Algorithm Hash digest
SHA256 c42201c35c582e01457c163bbcd18774dad0cb2e6541790c618890b02097bc69
MD5 b3d88b76acf428fb9200f4a2d4c444fd
BLAKE2b-256 ccca2285a68e955764bc4ef561eb7f318db1c64d7114d8959ddbab8eeb620c5b

See more details on using hashes here.

Provenance

The following attestation bundles were made for galileo_adk-1.0.0.tar.gz:

Publisher: release-adk.yaml on rungalileo/galileo-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file galileo_adk-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: galileo_adk-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 25.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for galileo_adk-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d9dad415d96eec610f813b4b2fbb0f3781ef44333e8b5b1142e00da908915f18
MD5 fdc6c83806250664e52176da9b5ca5b1
BLAKE2b-256 a19e7f832c0d4340572125be4c290331e375ef08f63040b22f3510d4cb346f64

See more details on using hashes here.

Provenance

The following attestation bundles were made for galileo_adk-1.0.0-py3-none-any.whl:

Publisher: release-adk.yaml on rungalileo/galileo-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page