> ## Documentation Index
> Fetch the complete documentation index at: https://arize-ax.mintlify.site/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Instrument Google ADK agents

> Trace agents built with Google ADK in Arize AX using OpenInference: capture agent runs, model calls, and tool calls without changing your agent code.

[Google ADK](https://adk.dev/) is an open-source framework for building, debugging, and deploying AI agents. Learn how to instrument Google ADK agents to capture every agent run, model call, and tool call so you can observe, evaluate, and improve quality. This guide wires the OpenInference Google ADK instrumentor into a Google ADK app to send traces to Arize AX.

## Overview

In this guide, you will instrument an existing Google ADK application, run it, and read the resulting traces in Arize AX. The steps apply to any app built on ADK, whether it runs as a script, a worker, or behind a web framework such as FastAPI.

This guide assumes you have familiarity with:

* Python
* The ADK building blocks: agents, runners, tools, sessions, and the `adk` command-line interface
* Environment variables and package installation

By the end of this guide, you will be able to:

* Initialize Arize AX tracing so ADK is instrumented before it runs
* Capture agent runs, model calls, and tool calls as traces with no changes to your agent logic
* Group traces by conversation using ADK sessions
* Verify and read the trace tree in Arize AX

## Before you start

You need:

* An existing agent built with Google ADK
* Python 3.10 or later
* An Arize AX account ([sign up](https://arize.com/sign-up/))
* Credentials for the model your agent uses. For Gemini, get a `GOOGLE_API_KEY` from [Google AI Studio](https://aistudio.google.com/app/apikey). ADK also runs other providers, including Anthropic and OpenAI through LiteLlm; see the [ADK models guide](https://adk.dev/agents/models/) for what your agent supports.

### Get your Arize AX credentials

Sign in to your [Arize AX account](https://app.arize.com/) and create a tracing project from **Projects → New Tracing Project**. The setup page shows the credentials you need: copy your **Space ID**, then click **Create API Key** to generate a key and save it somewhere safe. You reference them as `ARIZE_SPACE_ID` and `ARIZE_API_KEY` when you configure your environment below, and they route your traces to the correct space.

<Frame>
  <img src="https://storage.googleapis.com/arize-assets/doc-images/quickstarts/new-tracing-project-page.png" alt="New Tracing Project setup page in Arize AX showing the Space ID and the Create API Key button" />
</Frame>

The steps below instrument a small example agent, a health coach with a single tool, so the trace shows the AGENT → LLM → TOOL shape end to end. Attach the instrumentor once inside your agent package, before the agent loads. From there, ADK captures every agent run, model call, and tool call automatically, with no manual spans and no changes to your agent code.

<Steps>
  <Step title="Install the instrumentor">
    Install the OpenInference instrumentor for Google ADK alongside the SDK and Arize tracing dependencies.

    ```bash theme={null}
    pip install arize-otel \
      openinference-instrumentation-google-adk \
      google-adk
    ```
  </Step>

  <Step title="Add tracing to your agent package">
    ADK loads an agent as a package: a folder with an `agent.py` that defines `root_agent` and an `__init__.py`. Add a tracing module to that package and import it before the agent, so tracing is configured before ADK builds and runs the agent.

    ```text theme={null}
    health_coach/
    ├── __init__.py          # imports tracing first, then the agent
    ├── agent.py             # your existing agent (unchanged)
    └── instrumentation.py   # new: Arize AX tracing setup
    ```

    The tracing module is where all the instrumentation lives. `register()` builds a tracer provider from your Arize credentials, and `GoogleADKInstrumentor().instrument(...)` patches ADK to emit spans.

    ```python instrumentation.py theme={null}
    import os

    from arize.otel import register
    from openinference.instrumentation.google_adk import GoogleADKInstrumentor

    tracer_provider = register(
        space_id=os.environ["ARIZE_SPACE_ID"],
        api_key=os.environ["ARIZE_API_KEY"],
        project_name=os.environ.get("ARIZE_PROJECT_NAME", "google-adk-app"),
    )

    # Patch Google ADK so every run, model call, and tool call is traced.
    GoogleADKInstrumentor().instrument(tracer_provider=tracer_provider)
    ```

    Import the tracing module before the agent module in the package's `__init__.py`. ADK runs this file when it loads the package, so tracing is in place before the agent handles a request.

    ```python __init__.py theme={null}
    from . import instrumentation  # noqa: F401 - configure tracing first
    from . import agent  # noqa: F401
    ```

    Your `agent.py` needs no tracing code. For reference, the example this guide traces is a health coach with a single tool:

    ```python agent.py theme={null}
    from google.adk.agents import Agent


    def get_daily_calories(age: int, activity_level: str) -> dict:
        """Recommend a daily calorie target for an age and activity level.

        Args:
            age: The person's age in years.
            activity_level: One of "low", "moderate", or "high".
        """
        base = {"low": 1800, "moderate": 2200, "high": 2600}.get(activity_level, 2000)
        # Metabolism eases with age, so trim the target slightly for older adults.
        if age >= 50:
            base -= 200
        return {"status": "success", "recommended_calories": base}


    root_agent = Agent(
        name="health_coach",
        model="gemini-2.5-flash",
        description="A friendly health coach that gives nutrition guidance.",
        instruction=(
            "You are a friendly health coach. Use get_daily_calories to answer "
            "questions about calorie targets. Reply in two concise sentences."
        ),
        tools=[get_daily_calories],
    )
    ```
  </Step>

  <Step title="Provide credentials">
    ADK loads a `.env` file from the agent folder before importing it, so place your Arize AX and model credentials there. The tracing module reads them at startup, which keeps secrets out of your source.

    ```bash health_coach/.env theme={null}
    ARIZE_SPACE_ID=<your-space-id>
    ARIZE_API_KEY=<your-api-key>
    ARIZE_PROJECT_NAME=google-adk-app
    GOOGLE_API_KEY=<your-gemini-api-key>
    ```

    `ARIZE_PROJECT_NAME` is the project your traces land in. Name it for the app so runs stay grouped where you expect them. Keep the `.env` out of version control; `adk create` adds it to `.gitignore` for you.
  </Step>

  <Step title="Run your agent">
    Run your agent. `adk web` opens a browser interface for chatting with the agent, and `adk run` chats in the terminal. Both discover the package, load its `.env`, and trace every run.

    ```bash theme={null}
    # Browser interface, served from the folder containing your agent package.
    adk web

    # Or run in the terminal, pointed at the agent package.
    adk run health_coach
    ```

    Send the agent a message that needs its tools, and each run produces a trace. Multi-agent systems are traced the same way: when an agent hands off to a sub-agent, the sub-agent's run and its tool calls nest under the parent in the trace tree.

    <Note>
      The example uses Gemini through a model string. ADK also runs other providers through [LiteLlm](https://adk.dev/agents/models/) (for example, `model=LiteLlm(model="anthropic/claude-sonnet-4-6")`). The instrumentor traces every model backend the same way, so nothing in the tracing setup changes when you switch models.
    </Note>
  </Step>

  <Step title="Group traces by conversation">
    ADK assigns each conversation a session and tags every span with its `session.id`, so traces are already grouped by conversation. `adk web` and `adk run` create a session per chat and keep the same `session.id` across the turns in it, so Arize AX threads those turns together and you can replay the full conversation. When you drive the agent from your own code, you set the `session_id` yourself; reuse a stable identifier such as the user or thread ID across turns.
  </Step>

  <Step title="Verify in Arize AX">
    Open your Arize AX space and select the project you set in `ARIZE_PROJECT_NAME`. Within about 30 seconds of a run, a new trace appears with this shape:

    * An **`invocation`** root span (CHAIN) for the run.
    * An **`agent_run`** span (AGENT) carrying the agent name, input, and final output.
    * One or more **`call_llm`** child spans (LLM) with the prompt, response, model name, and token counts. A tool-using turn produces two: the first emits the tool call, the second consumes the tool result.
    * An **`execute_tool`** child span (TOOL) for each tool the agent ran, with the tool inputs and outputs.

    Each span name is suffixed with the app, agent, or tool identifier, so the example run appears as `invocation [health_coach]`, `agent_run [health_coach]`, and `execute_tool get_daily_calories`.

    If no traces appear, see [Troubleshooting](#troubleshooting).
  </Step>
</Steps>

## Run programmatically

To run an ADK agent outside the CLI, in a batch job, a test, or a web service, drive it with a `Runner` in your own script. Import the tracing module first so ADK is instrumented before the agent runs, and flush spans before a short-lived process exits.

```python run.py theme={null}
from health_coach import instrumentation  # noqa: F401 - configure tracing first
from health_coach.agent import root_agent

import asyncio

from google.adk.runners import InMemoryRunner
from google.genai import types


async def main() -> None:
    runner = InMemoryRunner(agent=root_agent, app_name="health_coach")
    await runner.session_service.create_session(
        app_name="health_coach", user_id="u1", session_id="s1"
    )
    async for event in runner.run_async(
        user_id="u1",
        session_id="s1",
        new_message=types.Content(
            role="user",
            parts=[types.Part(text="I'm 34 and moderately active. What's my daily calorie target?")],
        ),
    ):
        if event.is_final_response():
            print(event.content.parts[0].text.strip())

    # Short-lived script: flush batched spans before the process exits.
    instrumentation.tracer_provider.force_flush()


asyncio.run(main())
```

Set the model credentials in the environment before you run the script, the same way ADK loads them from `.env` for the CLI. Long-running apps and servers flush spans on their own, so `force_flush()` is only needed for scripts that exit right after a run.

## What gets captured

The Google ADK instrumentor records the shape of each agent run:

* **Invocation and agent spans.** An `invocation` CHAIN span wraps each run, and an `agent_run` AGENT span carries the agent name, input, and final output. Sub-agents nest under the parent agent.
* **Model spans.** One `call_llm` LLM span per model call, with the prompt, response, model name, and token counts.
* **Tool spans.** One `execute_tool` TOOL span per tool invocation, with the tool name, inputs, and outputs, so you can see what the agent decided to do and what each tool returned.
* **Session grouping.** The ADK session id, emitted as `session.id`, which threads related runs into one conversation.

Because the instrumentor hooks ADK's own runner, model, and tool layers, the full tree is captured automatically regardless of which model provider the agent uses.

## Troubleshooting

* **No traces in Arize AX.** Confirm `ARIZE_SPACE_ID` and `ARIZE_API_KEY` are available to the agent, either in the agent folder's `.env` or in the shell that runs it. Enable OpenTelemetry debug logs with `export OTEL_LOG_LEVEL=debug` and rerun.
* **ADK spans missing.** The tracing module must be imported before the agent module in the package's `__init__.py`, so `GoogleADKInstrumentor().instrument(...)` runs before ADK executes the agent.
* **A short-lived script exports nothing.** Spans are batched by default, so a script that exits right after the run can quit before they flush. Call `tracer_provider.force_flush()` before the process exits. `adk web` and `adk run` handle this for you.
* **`401` or `403` from the model.** Verify the credentials for your model provider are set and valid, and that the key has access to the model your agent requests.
* **`404` or model-not-found from the model.** Providers occasionally rename or retire model aliases. Swap the model set in your agent for one your key can call.
* **No traces from a remote runtime** Local instrumentation does not propagate to a remote runtime. Run `register(...)` and `GoogleADKInstrumentor().instrument(...)` inside the deployed agent module, not the local driver, and confirm the remote environment has your Arize credentials.

## Next steps

<CardGroup cols={2}>
  <Card title="Set up sessions" icon="layer-group" href="/docs/ax/instrument/set-up-sessions">
    Group multi-turn runs into conversations with session and user IDs.
  </Card>

  <Card title="Customize your traces" icon="sliders" href="/docs/ax/instrument/customize-your-traces">
    Attach metadata, tags, and custom attributes to your spans.
  </Card>

  <Card title="Evaluate agents" icon="clipboard-check" href="/docs/ax/concepts/evaluators/evaluating-agents">
    Score tool selection, tool results, and goal completion.
  </Card>

  <Card title="Google ADK integration" icon="book-open" href="/docs/ax/integrations/python-agent-frameworks/google-adk/google-adk-tracing">
    The reference page for the Google ADK instrumentor.
  </Card>
</CardGroup>
