Instrument a Gemini agent (5-minute quickstart)
Add Dobby governance + evidence to any agent that calls Gemini directly through the google-genai SDK (from google import genai) with one import and one call. No agent code changes.
pip install "dobby-collector[google_genai]" + instrument_google_genai() once at startup. Every client.models.generate_content(...) emits llm.start + llm.completion with the model, prompt, completion, and token usage — landing on the run you open with start_run().@track decorators. Note this integration does not open a run per call: it adds llm events to the ambient run you open with start_run() (or a fresh run if none is active, so the call still lands).1. Get a connector + bearer token
- Open the Dobby dashboard and pick a tenant.
- Click Workloads → Connect → Dobby SDK, choose Python, and pick Google Gen AI (Gemini) as the framework.
- Copy the
connector_id(wc_...) andapi_key(dsdk_...) — the api_key is shown ONCE, store it in your secrets manager immediately.
2. Install
pip install "dobby-collector[google_genai]"The [google_genai] extra pulls google-genai >= 1.0 (the google.genai package, NOT the legacy google-generativeai). If you already have it in your venv, the base dobby-collector package is enough.
3. Instrument your calls
from google import genai
from dobby_collector import init, start_run, end_run
from dobby_collector.integrations.google_genai import instrument_google_genai
# 1. Initialise the Dobby SDK once at process startup
init(
api_key="dsdk_...", # from your Dobby Workloads page
connector_id="wc_...", # ditto
base_url="https://dobby-ai.com",
)
# 2. Instrument google-genai ONCE — patches client.models.generate_content
# (sync + async + stream). The model is read from each call's model= arg,
# so there is NOTHING else to configure.
instrument_google_genai()
# 3. Call Gemini as usual. Wrap related calls in start_run / end_run so the
# llm events land on ONE workload_run.
client = genai.Client(api_key="...")
run = start_run(name="weekly_report", inputs={"week": "2026-W19"})
resp = client.models.generate_content(
model="gemini-2.5-flash",
contents="Summarise today's incidents",
)
end_run(run, outputs={"summary": resp.text}, status="success")
# → one workload_run in Dobby: model + prompt + completion + token usage- One init + one instrument call per process. Both are idempotent — calling twice is a no-op.
uninstrument_google_genai()restores the originals. - You own the run boundaries. Wrap related Gemini calls in
start_run() / end_run()so they group into oneworkload_run. Calls made with no active run still land — each in its own fresh run. - Non-blocking. Events buffer in-process; a background thread ships them every 10s (or sooner). Instrumentation NEVER raises into your agent — failures are logged and swallowed.
Streaming and async are supported too:
# Streaming is captured too — chunks aggregate into a single llm.completion
# when the stream finishes, and every chunk still passes through unchanged.
run = start_run(name="draft_report")
for chunk in client.models.generate_content_stream(
model="gemini-2.5-flash",
contents="Draft the incident report",
):
print(chunk.text, end="") # your handling — Dobby observes transparently
end_run(run, status="success")
# Async works identically: await client.aio.models.generate_content(...) and
# async for chunk in await client.aio.models.generate_content_stream(...).4. Production: use env vars
# Production: read from env vars instead of hardcoding
export DOBBY_API_KEY="dsdk_..."
export DOBBY_CONNECTOR_ID="wc_..."
export DOBBY_BASE_URL="https://dobby-ai.com"
# Then in code:
from dobby_collector import init
init() # auto-reads DOBBY_* env vars5. Verify it worked
Within ~10 seconds of end_run() (or your generate_content() call when run-less), a new run appears on Workloads → Runs. Click into it to see the per-event timeline (model, prompt, completion, token usage). For programmatic verification in BigQuery:
SELECT
external_run_id,
status,
JSON_VALUE(metadata_json, '$.framework') AS framework, -- "google_genai"
JSON_VALUE(metadata_json, '$.sdk_version') AS sdk_version, -- "0.5.0" or newer
JSON_VALUE(metadata_json, '$.llm_calls[0].model') AS model, -- "gemini-2.5-flash"
ARRAY_LENGTH(JSON_QUERY_ARRAY(metadata_json, '$.llm_calls')) AS llm_calls
FROM `workload_run_payloads`
WHERE connector_id = 'wc_...'
ORDER BY created_at DESC
LIMIT 5Expected on a successful run: framework="google_genai", model = the model you passed (e.g. gemini-2.5-flash), and llm_calls >= 1.
What the integration captures
| google-genai | Dobby SdkEvent | Becomes… |
|---|---|---|
| generate_content() called | llm.start | Adds an llm_calls[] entry to the ambient run (model + prompt) |
| response returned | llm.completion | Fills completion + token usage (usage_metadata) on that llm_call |
| generate_content_stream() | llm.start → llm.completion | Chunks aggregate into one completion when the stream finishes |
| start_run() / end_run() | run.started / run.completed | Open + close the workload_run + trigger the compliance scan |
Troubleshooting
The run has no llm_calls
Call instrument_google_genai() AFTER init() and BEFORE you construct the client / make the call. The patch is applied at call time, so a client created before instrumenting is fine — but the call itself must run after the patch.
My Gemini calls each land in a separate run
Expected when there is no active run. Wrap the calls you want grouped in start_run() … end_run() — the llm events inherit that ambient run. Without it, each call lands in its own fresh run so nothing is dropped.
ImportError / instrumentation does nothing
Install the extra: pip install "dobby-collector[google_genai]" (or pip install "google-genai>=1.0"). Make sure you import from google.genai, not the legacy google-generativeai package — only the former is instrumented.
No run shows up in Dobby
The background sender may be killed before it flushes. Call dobby_collector.shutdown() before process exit (or rely on the atexit handler on normal exit). For short-lived processes, set flush_interval_seconds=2.0 on init().
Related
- OpenClaw quickstart — the same SDK, OpenClaw handler
- Python Gateway SDK — synchronous LLM/MCP policy enforcement
- Gemini API docs — upstream google-genai SDK
connector_id in the subject line for faster triage.