<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Google AI</title>
    <description>The latest articles on DEV Community by Google AI (googleai).</description>
    <link>https://dev.to/googleai</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F11026%2F386b14d3-cc9a-4270-aba0-3e41cdfb9d85.jpg</url>
      <title>DEV Community: Google AI</title>
      <link>https://dev.to/googleai</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/googleai"/>
    <language>en</language>
    <item>
      <title>Build a Long-Running Agent in the Cloud for $5.70/Month</title>
      <dc:creator>Shir Meir Lador</dc:creator>
      <pubDate>Thu, 03 Sep 2026 15:54:57 +0000</pubDate>
      <link>https://dev.to/googleai/build-a-long-running-agent-in-the-cloud-for-570month-113c</link>
      <guid>https://dev.to/googleai/build-a-long-running-agent-in-the-cloud-for-570month-113c</guid>
      <description>&lt;p&gt;How do you run an autonomous AI agent in the cloud 24/7 for just $5.70 a month?&lt;/p&gt;

&lt;p&gt;I recently wanted to build a background worker with persistent disk storage and an instant web dashboard, but I didn't want the headache of managing a virtual machine or paying a massive monthly bill.&lt;/p&gt;

&lt;p&gt;If you are building long-running agents, you know this exact cloud hosting dilemma:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Standard serverless (like Cloud Run services or Lambda):&lt;/strong&gt; When traffic stops, the container scales to zero — instantly killing your background loops and wiping your agent's active memory (RAM). On the flip side, a sudden traffic spike spins up multiple containers that can overwrite each other's state files and corrupt your data. (Note: Save state using JSON or Markdown files. Avoid SQLite, as &lt;a href="https://cloud.google.com/storage/docs/cloud-storage-fuse/overview?utm_campaign=CDR_0x91b1edb5_default_b555469758&amp;amp;utm_medium=external&amp;amp;utm_source=blog#limitations" rel="noopener noreferrer"&gt;Cloud Run volume mounts&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A regular virtual machine (like EC2 or Compute Engine):&lt;/strong&gt; Keeps your agent running 24/7, but a standard 1-vCPU machine typically costs $15 to $25 a month even when idle. Even if you use a heavily-throttled fractional VM for $7/month, you are still stuck with the full infrastructure management overhead.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Last year, I built a &lt;a href="https://dev.to/googleai/your-first-multi-agent-system-a-beginners-guide-to-building-an-ai-trend-finder-with-adk-48jp"&gt;multi-agent Trend Spotter&lt;/a&gt; with &lt;a href="https://docs.cloud.google.com/gemini-enterprise-agent-platform/build/adk?utm_campaign=CDR_0x91b1edb5_default_b555469758&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;ADK&lt;/a&gt;. It worked well, but I wanted to make it fully autonomous: a continuous, long-running agent that scans and summarizes tech feeds in the background without manual triggers or high hosting costs.&lt;/p&gt;

&lt;p&gt;Google Cloud's new &lt;a href="https://docs.cloud.google.com/run/docs/instances/create-and-manage-instances?utm_campaign=CDR_0x91b1edb5_default_b555469758&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;&lt;strong&gt;Cloud Run instances&lt;/strong&gt;&lt;/a&gt; primitive solves this exact problem. It gives you a single, always-on container that runs 24/7, costs &lt;strong&gt;$5.70 a month&lt;/strong&gt; on a shared CPU, provides a free HTTPS endpoint, and lets you mount cloud storage like a normal local disk.&lt;/p&gt;

&lt;p&gt;Here is how to build and deploy a production long-running agent with this setup (you can follow along with the complete source code in the &lt;a href="https://github.com/GoogleCloudPlatform/devrel-demos/tree/main/ai-ml/tech-briefing-agent" rel="noopener noreferrer"&gt;repo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are we building?
&lt;/h2&gt;

&lt;p&gt;I want to stay up to date with what is happening in AI and agent engineering. But instead of manually opening 20 browser tabs across different websites every morning, I wanted to build my own long-running agent that updates me on recent news anytime I want.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhz2ubxhh8px5g1uujkpu.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhz2ubxhh8px5g1uujkpu.gif" alt="Personal tech briefing agent UI" width="600" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;center&gt;&lt;small&gt;Personal tech briefing agent UI&lt;/small&gt;&lt;/center&gt;

&lt;p&gt;&amp;nbsp;&lt;br&gt;
Here is what the agent does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Runs continuously as a background daemon:&lt;/strong&gt; Wakes up automatically every 30 minutes to collect fresh news. Note that Cloud Run instances restart automatically up to every 7 days, so your agent just needs to gracefully resume its schedule when restarted.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scans Hacker News and other curated AI and agent engineering sources.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accepts real-time alerts &amp;amp; mobile shares:&lt;/strong&gt; Includes an inbound webhook (POST /api/webhook) so you can push breaking tweets, iOS Share Sheet links, or GitHub releases straight into the agent for instant summarization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filters the noise:&lt;/strong&gt; Strips out paywalls, ads, and low-substance articles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Summarizes with Gemini 2.5 Flash:&lt;/strong&gt; We use Gemini 2.5 Flash to keep costs low. You can swap in the newer Gemini 3.5 or 3.6 Flash models if you need advanced reasoning, but note that their input tokens cost 5x as much compared to 2.5 Flash ($1.50 vs $0.30 per 1M tokens). For simple daily summarization, 2.5 Flash (or the equally cheap Gemini 3.5 Flash-Lite) is fast, highly capable, and keeps the monthly API bill to just a few cents.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Saves data safely:&lt;/strong&gt; Stores the daily markdown briefing and seen URLs directly in a mounted cloud storage folder (/data).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Serves a clean web dashboard:&lt;/strong&gt; Gives an instant web page to read your briefing or trigger a fresh run whenever you want.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  How the system works
&lt;/h2&gt;

&lt;p&gt;The whole application runs inside one Cloud Run instance:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnv2ydmvfjkmt3ph1ndxa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnv2ydmvfjkmt3ph1ndxa.png" alt="Tech briefing agent architechture" width="800" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;center&gt;&lt;small&gt;Tech briefing agent architechture&lt;/small&gt;&lt;/center&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;
  
  
  What else can you build with a long-running agent?
&lt;/h2&gt;

&lt;p&gt;A tech briefing agent is just one example. Because Cloud Run instances give you an always-on background worker, a free web endpoint, and safe local disk storage, you can use this exact same pattern for many developer workflows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Persistent Slack, Discord, or Telegram Bot:&lt;/strong&gt; A bot that maintains long-lived connections to chat gateways, answers developer questions, and syncs unresolved issues to your backlog.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security &amp;amp; Vulnerability Watchdog:&lt;/strong&gt; An agent that runs on an internal timer to monitor dependencies and CVE security feeds, caching vulnerability signatures on local disk.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DevOps Incident Triage Co-Pilot:&lt;/strong&gt; An agent that receives incoming webhook alerts from monitoring tools, runs background log queries without timing out, and renders an instant root-cause dashboard.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pull-Based Queue Worker:&lt;/strong&gt; An agent that continuously pulls complex tasks from Pub/Sub, Kafka, or RabbitMQ, performs multi-step LLM reasoning, and writes results to storage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nightly CI/CD &amp;amp; Flaky Test Fixer:&lt;/strong&gt; A background daemon that runs overnight test suites, analyzes test logs to spot flaky tests, and opens pull requests with automated fixes.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Why Cloud Run instances are great for agents
&lt;/h2&gt;

&lt;p&gt;Standard serverless platforms are designed for quick web requests. They wait for a user to click a button, run for one second, and shut down.&lt;/p&gt;

&lt;p&gt;Long-running background agents have different needs:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiopwjw3lmdjnpi04y85t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiopwjw3lmdjnpi04y85t.png" alt="Comparison — Standard Serverless / Regular VMs / Cloud Run Instances" width="720" height="423"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;center&gt;&lt;small&gt;Comparison — Standard Serverless / Regular VMs / Cloud Run Instances&lt;/small&gt;&lt;/center&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;With an instance, you get the simplicity of serverless with the stability of a VM. Because your instance is always hot with a public HTTPS endpoint, it easily handles three trigger styles in one container:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Periodic Background Polling:&lt;/strong&gt; Runs autonomously on an internal asyncio schedule without needing external cron services.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Instant Web Dashboard:&lt;/strong&gt; Zero cold starts when you open the reading dashboard.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-Time Push Webhooks:&lt;/strong&gt; An inbound POST /api/webhook route that lets you push breaking tweets, iOS share sheet links, or GitHub release alerts straight into the agent for immediate summarization.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  When NOT to use this
&lt;/h2&gt;

&lt;p&gt;Cloud Run instances are great for single-worker background agents. You should pick a different tool if you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Massive parallel batch jobs:&lt;/strong&gt; If you need to process 10,000 documents at once across 100 parallel workers, use &lt;strong&gt;Cloud Run Jobs&lt;/strong&gt; or &lt;strong&gt;GKE&lt;/strong&gt;. An instance is a single worker.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High-traffic, bursty web APIs:&lt;/strong&gt; If your website gets sudden spikes of millions of requests, use &lt;strong&gt;standard Cloud Run services&lt;/strong&gt; so your app can automatically autoscale to hundreds of containers and scale down to zero when traffic stops.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Heavy local GPU model hosting:&lt;/strong&gt; If you want to host an open 70B model directly inside your container on a dedicated H100 GPU, use &lt;strong&gt;GKE&lt;/strong&gt; or &lt;strong&gt;Compute Engine&lt;/strong&gt;. Cloud Run instances are built for CPU applications that connect to hosted models like Gemini.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Alternative architecture: Decoupled Job + Service
&lt;/h2&gt;

&lt;p&gt;Instead of a single instance, you could build an event-driven system: a Cloud Scheduler triggers a Cloud Run Job for polling, while a scale-to-zero Cloud Run Service hosts the dashboard and listens for webhooks.&lt;/p&gt;

&lt;p&gt;While this decoupled approach drops compute costs to virtually $0.00 in the free tier, you lose single-container simplicity. You are forced to manage multiple cloud services and message queues (to prevent concurrent webhooks from corrupting your state), while accepting cold starts on your web dashboard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnl1bdgkkjimfk3grbzzh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnl1bdgkkjimfk3grbzzh.png" alt="Compare instances with Decoupled Job + Service for this task" width="720" height="474"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;center&gt;&lt;small&gt;Compare instances with Decoupled Job + Service for this task&lt;/small&gt;&lt;/center&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;
  
  
  Deploy your long-running agent in 6 simple steps
&lt;/h2&gt;

&lt;p&gt;You can deploy this setup to Google Cloud in about five minutes.&lt;/p&gt;
&lt;h2&gt;
  
  
  1. Turn on the cloud services
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PROJECT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your-project-id"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;REGION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"us-west1"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;BUCKET_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_ID&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-agent-data"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;REPO_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"agent-repo"&lt;/span&gt;
gcloud config &lt;span class="nb"&gt;set &lt;/span&gt;project &lt;span class="nv"&gt;$PROJECT_ID&lt;/span&gt;
gcloud services &lt;span class="nb"&gt;enable &lt;/span&gt;run.googleapis.com storage.googleapis.com artifactregistry.googleapis.com cloudbuild.googleapis.com secretmanager.googleapis.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Note: Cloud Run instances are not available in every region. Please pick a supported region near you from the &lt;a href="https://docs.cloud.google.com/run/docs/locations?utm_campaign=CDR_0x91b1edb5_default_b555469758&amp;amp;utm_medium=external&amp;amp;utm_source=blog#instances" rel="noopener noreferrer"&gt;Cloud Run instances locations&lt;/a&gt; page.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Create a storage bucket for your data
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud storage buckets create gs://&lt;span class="nv"&gt;$BUCKET_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$REGION&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--uniform-bucket-level-access&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  3. Build your container
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud artifacts repositories create &lt;span class="nv"&gt;$REPO_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--repository-format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;docker &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$REGION&lt;/span&gt;
gcloud builds submit &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--tag&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;REGION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-docker&lt;/span&gt;.pkg.dev/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_ID&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;REPO_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/tech-briefing-agent:latest &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  4. Create a service account
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud iam service-accounts create briefing-agent-sa &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--display-name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Briefing Agent SA"&lt;/span&gt;
gcloud storage buckets add-iam-policy-binding gs://&lt;span class="nv"&gt;$BUCKET_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--member&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"serviceAccount:briefing-agent-sa@&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_ID&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.iam.gserviceaccount.com"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"roles/storage.objectUser"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  5. Store your API key securely
&lt;/h2&gt;

&lt;p&gt;Never pass API keys in plain text. Store your Gemini API key in Google Cloud Secret Manager and grant your service account permission to read it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"YOUR_GEMINI_API_KEY"&lt;/span&gt; | gcloud secrets create gemini-api-key &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;- &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--replication-policy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"automatic"&lt;/span&gt;
gcloud secrets add-iam-policy-binding gemini-api-key &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--member&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"serviceAccount:briefing-agent-sa@&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_ID&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.iam.gserviceaccount.com"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"roles/secretmanager.secretAccessor"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  6. Launch the instance
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud beta run instances create tech-briefing-agent &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;REGION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-docker&lt;/span&gt;.pkg.dev/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_ID&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;REPO_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/tech-briefing-agent:latest &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$REGION&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;8080 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--cpu&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--memory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1Gi &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--public&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--service-account&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;briefing-agent-sa@&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_ID&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;.iam.gserviceaccount.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--add-volume&lt;/span&gt; mount-path&lt;span class="o"&gt;=&lt;/span&gt;/data,type&lt;span class="o"&gt;=&lt;/span&gt;cloud-storage,mount-options&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"uid=1000;gid=1000;file-mode=0700;dir-mode=0700"&lt;/span&gt;,bucket&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$BUCKET_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set-secrets&lt;/span&gt; &lt;span class="s2"&gt;"GEMINI_API_KEY=gemini-api-key:latest"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set-env-vars&lt;/span&gt; &lt;span class="s2"&gt;"DATA_DIR=/data,POLL_INTERVAL_MINUTES=30"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We set --cpu=1 and --memory=1Gi to keep the cost at $5.70. If you omit these, it defaults to 2 CPUs and 2 GiB (~$11.40/month, see &lt;a href="https://cloud.google.com/run/pricing?utm_campaign=CDR_0x91b1edb5_default_b555469758&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;pricing table&lt;/a&gt;). To improve load times, you can increase the CPU and memory.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[!TIP] Adjust uid=1000;gid=1000 in the mount-options flag to match the specific non-root user ID defined in your Dockerfile, if different.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When this command finishes, Cloud Run gives you a live HTTPS web address. Open it in your browser to see your briefing dashboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does this cost in real life?
&lt;/h2&gt;

&lt;p&gt;Here is the real monthly bill for running this 24/7:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy93lbvq8hx1rh2szuo7y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy93lbvq8hx1rh2szuo7y.png" alt="Monthly cost breakdown" width="720" height="357"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;center&gt;&lt;small&gt;Monthly cost breakdown&lt;/small&gt;&lt;/center&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;For less than the price of two cups of coffee, you have a private agent running day and night.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn more about Cloud Run instances
&lt;/h2&gt;

&lt;p&gt;Want to dive deeper into Cloud Run Instances? Check out these official Google Cloud resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Official Launch Blog:&lt;/strong&gt; &lt;a href="https://cloud.google.com/blog/products/serverless/introducing-cloud-run-instances?utm_campaign=CDR_0x91b1edb5_default_b555469758&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;Introducing Cloud Run instances&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Official Documentation:&lt;/strong&gt; &lt;a href="https://docs.cloud.google.com/run/docs/instances/create-and-manage-instances?utm_campaign=CDR_0x91b1edb5_default_b555469758&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;Create and manage Cloud Run instances&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hands-on Codelab:&lt;/strong&gt; &lt;a href="https://codelabs.developers.google.com/codelabs/cloud-run/deploy-openclaw-cloud-run-instances?utm_campaign=CDR_0x91b1edb5_default_b555469758&amp;amp;utm_medium=external&amp;amp;utm_source=blog#1" rel="noopener noreferrer"&gt;Deploying to Cloud Run instances Codelab&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source Code &amp;amp; ADK Graph:&lt;/strong&gt; &lt;a href="https://github.com/GoogleCloudPlatform/devrel-demos/tree/main/ai-ml/tech-briefing-agent" rel="noopener noreferrer"&gt;Tech-briefing-agent on GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is coming next?
&lt;/h2&gt;

&lt;p&gt;Now that the hosting problem is solved, how do you make the agent smart and resilient? How do you stop it from summarizing noise when it hits a paywall, or build self-correcting reflection loops?&lt;/p&gt;

&lt;p&gt;Join us in the next part where we will dive into graph engineering and the architecture of the agent using ADK 2.0.&lt;/p&gt;

&lt;p&gt;Happy building!&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>googlecloud</category>
    </item>
    <item>
      <title>Your First Multi-agent system: A Beginner's Guide to Building an AI Trend finder with ADK</title>
      <dc:creator>Shir Meir Lador</dc:creator>
      <pubDate>Thu, 03 Sep 2026 15:53:27 +0000</pubDate>
      <link>https://dev.to/googleai/your-first-multi-agent-system-a-beginners-guide-to-building-an-ai-trend-finder-with-adk-48jp</link>
      <guid>https://dev.to/googleai/your-first-multi-agent-system-a-beginners-guide-to-building-an-ai-trend-finder-with-adk-48jp</guid>
      <description>&lt;p&gt;Welcome back to our series on building the ultimate AI research assistant for our AI agent podcast! In our &lt;a href="https://dev.to/googleai/your-first-ai-agent-a-beginners-guide-to-building-an-ai-trend-finder-with-adk-5f8k"&gt;first post,&lt;/a&gt; we built a fantastic agent that could search the web to find the latest AI agent news for the &lt;a href="https://youtu.be/aLYrV61rJG4" rel="noopener noreferrer"&gt;agent factory podcast&lt;/a&gt;. But what if we want to add more specialized skills, like getting the real pulse from developer communities on Reddit? To do that, we need to upgrade our agent's design.&lt;/p&gt;

&lt;p&gt;In this guide, we are going to level up our skills and refactor our simple agent into a powerful &lt;strong&gt;multi-agent system&lt;/strong&gt;. We will build a "Manager" agent that directs a team of specialists, including one with a &lt;strong&gt;custom-built Reddit tool&lt;/strong&gt;, to gather richer, more diverse insights.&lt;/p&gt;

&lt;p&gt;By the end of this post, you'll have an even more powerful Trend Spotter agent that gets information from multiple sources. More importantly, &lt;strong&gt;you will learn the advanced skills needed to build complex agents with&lt;/strong&gt; &lt;a href="https://cloud.google.com/vertex-ai/generative-ai/docs/agent-development-kit/quickstart?utm_campaign=CDR_0x91b1edb5_default_b423225099&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;&lt;strong&gt;ADK&lt;/strong&gt;&lt;/a&gt;. You will know how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Build&lt;/strong&gt; a scalable &lt;strong&gt;multi-agent system.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build a custom tool&lt;/strong&gt; from any Python function (like our new Reddit tool).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create an orchestrator agent&lt;/strong&gt; that delegates tasks to a team of specialists.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write advanced prompts&lt;/strong&gt; to manage a multi-step, multi-tool workflow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debug&lt;/strong&gt; a multi-agent system using the ADK's powerful Trace view.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This architecture is the key to unlocking your agent's full potential. Let's get started!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1h1prp07rqps5pptroq8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1h1prp07rqps5pptroq8.png" alt="Our Multi agent system flow" width="720" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;center&gt;&lt;small&gt;Our Multi agent system flow&lt;/small&gt;&lt;/center&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Get Reddit API Credentials &amp;amp; Install Library
&lt;/h2&gt;

&lt;p&gt;To allow our agent to access Reddit programmatically, we need to get API credentials. This is free and only takes a minute.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Navigate to Reddit Apps:&lt;/strong&gt; Log in to your Reddit account and go to the app preferences page: &lt;a href="https://www.reddit.com/prefs/apps" rel="noopener noreferrer"&gt;https://www.reddit.com/prefs/apps&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create a New App:&lt;/strong&gt; Scroll to the bottom and click the button that says &lt;strong&gt;"are you a developer? create an app…"&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fill out the form:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;name:&lt;/strong&gt; Trend Spotter Agent&lt;/li&gt;
&lt;li&gt;Select the &lt;strong&gt;script&lt;/strong&gt; option for the application type.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;about url:&lt;/strong&gt; You can leave this blank.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;redirect url:&lt;/strong&gt; You must enter &lt;a href="http://localhost:8080" rel="noopener noreferrer"&gt;http://localhost:8080&lt;/a&gt; for this field.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;create app&lt;/strong&gt;. You will now be taken to a new page showing your credentials.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;5. Set Environment Variables:&lt;/strong&gt; For security, we'll store these credentials as environment variables.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your &lt;strong&gt;client ID&lt;/strong&gt; is the string of characters right under "personal use script".&lt;/li&gt;
&lt;li&gt;Your &lt;strong&gt;client secret&lt;/strong&gt; is the long string next to the secret label.&lt;/li&gt;
&lt;li&gt;Open your terminal and run the following export commands:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;REDDIT_CLIENT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;”YOUR_CLIENT_ID”  
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;REDDIT_CLIENT_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;”YOUR_CLIENT_SECRET”  
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;REDDIT_USER_AGENT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;”TrendSpotterAgent/0.1 by u/YourUsername”
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6. Update Dependencies:&lt;/strong&gt; Add the praw library to your requirements.txt file and install it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# requirements.txt  
google-adk  
praw
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Install it from your terminal:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configure Your Cloud Environment
&lt;/h3&gt;

&lt;p&gt;If you haven't done so already, in our previous blog we showed how to define the settings to tell ADK how to securely connect to your Google Cloud account to use services like Vertex AI and Google Search.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GOOGLE_GENAI_USE_VERTEXAI&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true  
export &lt;/span&gt;&lt;span class="nv"&gt;GOOGLE_CLOUD_PROJECT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;your-gcp-project-id&amp;gt;  
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GOOGLE_CLOUD_LOCATION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;your-gcp-project-location&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run this one-time command. It will open a browser for you to sign in, allowing ADK to make authorized requests on your behalf.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud auth application-default login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Create the Project Folder
&lt;/h3&gt;

&lt;p&gt;To organize our new team of agents, we'll create a sub_agents directory inside our main trend_spotter package.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No worries if you haven't gone through the&lt;/strong&gt; &lt;a href="https://medium.com/google-cloud/your-first-ai-agent-a-beginners-guide-to-building-an-ai-trend-finder-with-adk-3a7c6a93ff33" rel="noopener noreferrer"&gt;&lt;strong&gt;first blog post&lt;/strong&gt;&lt;/a&gt;, we got you! here is how you create the folder structure for your main agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create the main project folder  &lt;/span&gt;
&lt;span class="nb"&gt;mkdir &lt;/span&gt;trend-spotter &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;trend-spotter  
&lt;span class="c"&gt;# Create the Python package folder that will hold our code  &lt;/span&gt;
&lt;span class="nb"&gt;mkdir &lt;/span&gt;trend_spotter  
&lt;span class="nb"&gt;touch &lt;/span&gt;trend_spotter/__init__.py  
&lt;span class="nb"&gt;touch &lt;/span&gt;trend_spotter/agent.py  
&lt;span class="nb"&gt;touch &lt;/span&gt;trend_spotter/prompt.py  
&lt;span class="c"&gt;# Create the top-level configuration files  &lt;/span&gt;
&lt;span class="nb"&gt;touch &lt;/span&gt;pyproject.toml requirements.txt  
&lt;span class="c"&gt;# Finally, create and activate a virtual environment  &lt;/span&gt;
python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv venv &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;source &lt;/span&gt;venv/bin/activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(On Windows, use python -m venv venv &amp;amp;&amp;amp; .\venv\Scripts\activate)&lt;/p&gt;

&lt;p&gt;After you have the main agent and your folder structure defined, from your trend-spotter root folder, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create the sub-agents directory and its Python initializer  &lt;/span&gt;
&lt;span class="nb"&gt;mkdir &lt;/span&gt;trend_spotter/sub_agents  
&lt;span class="nb"&gt;touch &lt;/span&gt;trend_spotter/sub_agents/__init__.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Create the Specialist Sub-Agents
&lt;/h3&gt;

&lt;p&gt;Now we'll build our two specialist agents by directly creating instances of the Agent class.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. The Google Search Specialist:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a new file: trend_spotter/sub_agents/google_search_agent.py&lt;/li&gt;
&lt;li&gt;Add this code. Note how we directly create the google_search_agent variable.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# trend_spotter/sub_agents/Google Search_agent.py  
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google.adk.agents&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;  
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google.adk.tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;google_search&lt;/span&gt;  

&lt;span class="n"&gt;MODEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemini-2.5-pro-preview-05-06&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  

&lt;span class="c1"&gt;# A specific, structured prompt to control the output format of this sub-agent.  
&lt;/span&gt;&lt;span class="n"&gt;google_search_SUB_AGENT_PROMPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;  
**Role:**  
- You are a specialist Research Assistant.  
- Your only purpose is to execute a Google Search based on instructions from your manager and return the raw, structured results.  

**Tools:**  
- You have access to one tool: `Google Search`.  

**Context:**  
- You will be given a query by a manager agent.  
- Your output will be read by another agent, so it must be clean, predictable, and structured.  
- You must not summarize, analyze, or interpret the search results. Your job is only to find and format the information directly from the tool&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s output.  

**Task:**  
1.  Take the search query provided to you.  
2.  Execute a search using the `Google Search` tool.  
3.  Format the raw output from the tool into a list, following the **exact** `Output Format` specified below.  

**Output Format:**  
For each search result, you MUST provide the Title, Link, and Snippet. Each complete result must be separated by &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;---&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.  

---  
Title: [Title of the first search result]  
Link: [Full URL of the first search result]  
Snippet: [Snippet text of the first search result]  
---  
Title: [Title of the second search result]  
Link: [Full URL of the second search result]  
Snippet: [Snippet text of the second search result]  
---  
(and so on for all results)  
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;  

&lt;span class="n"&gt;google_search_agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;MODEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;google_search_agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
    &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;An expert at using google_search to find recent information and return a structured list of results including URLs.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
    &lt;span class="c1"&gt;# We assign the new, structured instruction here.  
&lt;/span&gt;    &lt;span class="n"&gt;instruction&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;google_search_SUB_AGENT_PROMPT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;google_search&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. The Reddit Specialist:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First, create a new file for our custom tool's code: trend_spotter/tools.py. Add the following function to it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;  
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;praw&lt;/span&gt;  

&lt;span class="c1"&gt;# The function now accepts a LIST of subreddit names  
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;search_hot_reddit_posts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subreddit_names&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;limit_per_subreddit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;  
    Searches a list of subreddits for their current hot posts and returns their titles and URLs.  

    Args:  
        subreddit_names: A list of subreddit names to search (e.g., [&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;LocalLLaMA&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MachineLearning&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;]).  
        limit_per_subreddit: The number of top posts to retrieve from each subreddit.  

    Returns:  
        A dictionary containing the status and a list of formatted post strings.  
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;  
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;🔎 Searching Reddit for hot posts in: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subreddit_names&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  

        &lt;span class="n"&gt;reddit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;praw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Reddit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
            &lt;span class="n"&gt;client_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;REDDIT_CLIENT_ID&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;  
            &lt;span class="n"&gt;client_secret&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;REDDIT_CLIENT_SECRET&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;  
            &lt;span class="n"&gt;user_agent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;REDDIT_USER_AGENT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;  
            &lt;span class="n"&gt;read_only&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
        &lt;span class="p"&gt;)&lt;/span&gt;  

        &lt;span class="n"&gt;all_posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;  
        &lt;span class="c1"&gt;# Loop through each subreddit name provided in the list  
&lt;/span&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;sub_name&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;subreddit_names&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  - Fetching from r/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;sub_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
            &lt;span class="n"&gt;subreddit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reddit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subreddit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sub_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;subreddit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;limit_per_subreddit&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;  
                &lt;span class="c1"&gt;# We can add a simple filter here if we want, e.g., for score  
&lt;/span&gt;                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  
                    &lt;span class="n"&gt;all_posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Title: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Link: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;all_posts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No hot posts found meeting the criteria in the specified subreddits.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  

        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;✅ Reddit search complete. Found &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;all_posts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; qualifying posts.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;---&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;all_posts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  

    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Error searching Reddit: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, create the Reddit agent itself at trend_spotter/sub_agents/reddit_agent.py:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# trend_spotter/sub_agents/reddit_agent.py  
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google.adk.agents&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;  
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;trend_spotter.tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;search_hot_reddit_posts&lt;/span&gt;  
&lt;span class="n"&gt;MODEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemini-2.5-pro-preview-05-06&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  

&lt;span class="n"&gt;reddit_agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reddit_agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;MODEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
    &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;An expert at finding hot posts on specific Reddit subreddits using its tool.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;search_hot_reddit_posts&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Build the Main Orchestrator Agent
&lt;/h3&gt;

&lt;p&gt;Now we'll modify our main agent from Part 1 to become the "manager" of our new specialist team.&lt;/p&gt;

&lt;p&gt;Open trend_spotter/prompt.py and replace its contents with this new &lt;strong&gt;orchestrator prompt&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# trend_spotter/prompt.py  
&lt;/span&gt;
&lt;span class="n"&gt;ORCHESTRATOR_PROMPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;  
**Role:**  
- You are the highly-capable manager of an AI research team.  
- Your purpose is to produce a high-quality, detailed intelligence report for the &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The Agent Factory&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; podcast.  
- Your focus is exclusively on developments in AI agents that are impactful and relevant to software developers.  

**Tools:**  
- You have a team of two specialist agents available to you as tools:  
  1. `google_search_agent`: An expert at performing general web searches for news, releases, and technical articles.  
  2. `reddit_agent`: An expert at finding real, hands-on developer conversations on specific subreddits.  

**Context:**  
- You must synthesize information from BOTH the `google_search_agent` and the `reddit_agent` to form your conclusions.  
- Your primary filter for all information is its direct and significant impact on developers. Discard anything that is purely business-focused or marketing fluff.  
- Topics that appear in multiple sources (e.g., in both tech news and on Reddit) should be considered more important and prioritized in your report.  
- The final report must be structured exactly as described in the Task section.  

**Task:**  
1.  **Discover the Current Date:** Your very first action is to delegate to your `google_search_agent`. Instruct it to find the current date.  
2.  **Delegate Focused Research:**  
    - Based on the date, calculate the start and end dates for the last 7 days.  
    - Instruct the `google_search_agent` to find news about new open-source agent frameworks, updates to popular libraries (like LangChain, ADK, CrewAI or LlamaIndex), and technical tutorials about building agents within the calculated date range using `after:YYYY-MM-DD` and `before:YYYY-MM-DD` operators.  
    - Instruct the `reddit_agent` to find the hottest developer conversations about practical challenges, new techniques, and opinions on new tools from subreddits like &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;LocalLLaMA&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MachineLearning&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;LangChain&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AI_Agents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;LLMDevs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, and &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;singularity&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.  
3.  **Synthesize and Create the Final Report:**  
    - Review the information provided by **both** specialist agents.  
    - Combine, filter, and deduplicate the findings. Your primary filter is to **only select topics that have a direct and significant impact on developers.**  
    - **Pay special attention to topics that appear in multiple source in the general web search and on Reddit**, as these are likely the most important and should be prioritized.  
    - The report **must begin with a header** specifying the date range used.  
    - The body of the report must have exactly three sections as detailed below.  
    - For each item, you **must provide four pieces of information**: a 1-2 sentence explanation, an indented &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Developer Impact&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; analysis, a &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Prioritization Rationale&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, and a verifiable source URL.  

**Final Report Format:**  

**🔥 Top 5 Trends for Agent Developers**  
1.  **[Trend 1 Name]**: [A 1-2 sentence explanation of this trend.]  
    **(Source: [URL])**  
    * **Developer Impact**: [A 1-sentence explanation of why this matters to developers.]  
    * **Prioritization Rationale**: [A 1-sentence explanation of why this topic was selected, e.g., &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;High volume of discussion on Reddit and mentioned in multiple tech articles.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;]  
2.  ... (up to 5 total)  

**🚀 Top 5 Releases for Agent Developers**  
1.  **[Release 1 Name]**: [A 1-2 sentence explanation of the tool, framework, or model.]  
    **(Source: [URL])**  
    * **Developer Impact**: [A 1-sentence explanation of why this matters to developers.]  
    * **Prioritization Rationale**: [A 1-sentence explanation of why this topic was selected.]  
2.  ... (up to 5 total)  

**🤔 Top 5 Questions from Agent Developers**  
1.  **[Question 1 Topic]**: [A 1-2 sentence explanation of what developers are asking.]  
    **(Source: [URL])**  
    * **Developer Impact**: [A 1-sentence explanation of why this matters to developers.]  
    * **Prioritization Rationale**: [A 1-sentence explanation of why this topic was selected.]  
2.  ... (up to 5 total)  
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open trend_spotter/agent.py and replace its contents to turn it into the orchestrator. Notice how we now import the agent &lt;em&gt;instances&lt;/em&gt; we created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# trend_spotter/agent.py  
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google.adk.agents&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LlmAgent&lt;/span&gt;  
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google.adk.tools.agent_tool&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AgentTool&lt;/span&gt;  
&lt;span class="c1"&gt;# Import the sub-agent INSTANCES  
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;.sub_agents.google_search_agent&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;google_search_agent&lt;/span&gt;  
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;.sub_agents.reddit_agent&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;reddit_agent&lt;/span&gt;  
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;.&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;  
&lt;span class="n"&gt;MODEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemini-2.5-pro-preview-05–06&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  
&lt;span class="c1"&gt;# This is our main "manager" agent, now an LlmAgent  
&lt;/span&gt;&lt;span class="n"&gt;root_agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LlmAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;MODEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TrendSpotterOrchestrator&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The manager of a team of specialist AI agents.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
&lt;span class="n"&gt;instruction&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ORCHESTRATOR_PROMPT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
&lt;span class="c1"&gt;# The Orchestrator's "tools" are its sub-agents, wrapped in AgentTool  
&lt;/span&gt;&lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;  
&lt;span class="nc"&gt;AgentTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;google_search_agent&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  
&lt;span class="nc"&gt;AgentTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;reddit_agent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="p"&gt;],&lt;/span&gt;  
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 5: Running Your Multi-Agent System
&lt;/h3&gt;

&lt;p&gt;The run process remains the same. The adk web tool will automatically load your root_agent, which is now the orchestrator.&lt;/p&gt;

&lt;p&gt;Ensure your pyproject.toml file still correctly points to your main agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[project]&lt;/span&gt;  
&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"trend_spotter"&lt;/span&gt;  
&lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.1.0"&lt;/span&gt;  
&lt;span class="c"&gt;# Setuptools will now auto-discover your trend_spotter package.  &lt;/span&gt;
&lt;span class="nn"&gt;[tool.adk.agents]&lt;/span&gt;  
&lt;span class="py"&gt;trend_spotter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"trend_spotter.agent:root_agent"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install your updated package with the new dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Launch the web interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;adk web
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the "Event" tab of the web UI, you will now see the main orchestrator agent making calls to its new google_search_agent and reddit_agent sub-agents. You've successfully built a more robust and scalable AI system using the correct ADK patterns!&lt;/p&gt;

&lt;p&gt;You should get an output like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Report for the week of June 4, 2025 - June 11, 2025  

🔥 Top 5 Trends for Agent Developers  

Enterprise Adoption of Agent Frameworks: Frameworks like LangChain are showing significant growth in enterprise contexts, indicated by surpassing the OpenAI SDK in Python downloads and new integrations with systems like SAP and Salesforce. (Source: news.knowledia.com - "LangChain Surpasses OpenAI SDK in Monthly Python Downloads" - This specific URL was not in the provided search but is representative of the type of news article that would contain this information from the search summary "LangChain: Surpassed the OpenAI SDK in monthly Python downloads as of June 2025")  
Developer Impact: Developers using or learning LangChain can expect more mature tooling and greater demand for their skills in enterprise settings.  
Prioritization Rationale: This trend is based on download statistics and enterprise integration news, indicating a major shift in the landscape relevant to developers' career opportunities.  
Enhanced Observability and Debugging in Agent Development: There's a clear move towards more sophisticated tools for monitoring, debugging, and managing the cost of AI agents, exemplified by Langfuse's integration with LlamaIndex and new features in LangSmith. (Source: https://news.llamaindex.ai/integrating-langfuse-for-observability-and-debugging-in-llamaindex-5f4f7f8c29ac [Example URL based on search "An article from June 6, 2025, discusses integrating Langfuse with LlamaIndex for observability and debugging."])  
Developer Impact: Developers will have better tools to understand agent behavior, optimize performance, and control operational costs.  
Prioritization Rationale: Addresses a critical developer need for building robust and maintainable agents, highlighted by multiple framework updates.  
Advanced Structured Data Handling by Agents: Agents are becoming more adept at working with structured data, with developments like Microsoft AutoGen's Structured Retrieval Augmentation and LlamaIndex's Spreadsheet Agent. (Source: Daily AI Agent News - "Microsoft AutoGen v0.4: Structured Retrieval Augmentation &amp;amp; MCP" - this URL was not in the search results but the information "Microsoft AutoGen v0.4 implements Structured Retrieval Augmentation" was.)  
Developer Impact: This allows developers to build agents for more complex, real-world use cases involving databases, spreadsheets, and other structured formats.  
Prioritization Rationale: Represents a significant expansion in agent capabilities, enabling new applications and increasing their utility.  
Growth of Local and Open-Source Agent Solutions: New open-source frameworks like "Goose" (from Block) and "OpenHands" emphasize local execution and customization, aligning with developer discussions on platforms like Reddit (r/LocalLLaMA) about gaining more control over their LLM setups. (Source: https://www.reddit.com/r/LocalLLaMA/comments/1l8pem0/i_finally_got_rid_of_ollama/ and news articles on Goose/OpenHands release)  
Developer Impact: Provides developers with more options for privacy-centric, cost-effective, and highly customizable agent development.  
Prioritization Rationale: Supported by both new tool releases in the general tech news and active discussions within the developer community (Reddit).  
Rise of Multi-Agent Systems and Interoperability Standards: The development of orchestrators like Fujitsu's and advancements in frameworks such as CrewAI and AutoGen (with MCP support) highlight a focus on complex systems where multiple agents collaborate. LangGraph is also central to this trend. (Source: Tech news article on "Fujitsu's Agentic Workflow Orchestrator" and https://www.reddit.com/r/LangChain/comments/1l8zy42/built_a_texttosql_multiagent_system_with/ )  
Developer Impact: Developers are increasingly tasked with designing, building, and managing interactions between multiple specialized agents, requiring new skill sets.  
Prioritization Rationale: This is a key area of innovation, mentioned in multiple framework updates and discussed by developers building sophisticated applications.  

🚀 Top 5 Releases for Agent Developers  

LangGraph Platform General Availability: LangChain's LangGraph, a library for creating stateful, multi-actor LLM applications, is now generally available, offering features like 1-click deployment. (Source: LangChain official blog/documentation - the search mentioned "LangGraph Platform is now generally available" as a LangChain update.)  
Developer Impact: Offers a production-ready path for developers to build complex, scalable agentic systems and multi-agent collaborations.  
Prioritization Rationale: Significant release for a popular ecosystem, addressing the need for robust multi-agent system development.  
AutoGen v0.4 (Microsoft): This version introduces Structured Retrieval Augmentation and full support for the Model Context Protocol (MCP), enhancing data handling and enabling interoperability with other agent platforms. (Source: GitHub releases page for Autogen or news articles covering the v0.4 release mentioned in the search: "Microsoft AutoGen v0.4 implements Structured Retrieval Augmentation and full support for the open-source MCP standard")  
Developer Impact: Allows developers to build more powerful AutoGen agents capable of complex data interactions and cross-platform collaboration.  
Prioritization Rationale: Major update to a key framework from Microsoft, improving core functionality and ecosystem compatibility.  
CrewAI v0.126.0: Features real-time task redistribution, Python 3.13 support, persisted tools from a Tool repository, streamable-http transport in MCP, and major documentation restructuring. (Source: CrewAI GitHub releases or their official blog - "CrewAI: Released v0.126.0 on June 5, 2025" was in the search results.)  
Developer Impact: Provides developers with improved performance, better tool management, enhanced interoperability, and easier onboarding through better documentation.  
Prioritization Rationale: A substantial update to a growing agent framework, focusing on efficiency and developer experience.  
LlamaIndex Spreadsheet Agent &amp;amp; Llama Cloud Updates: LlamaIndex launched a production-ready Spreadsheet Agent for natural language Q&amp;amp;A on spreadsheets and announced new MCP integration and Llama Cloud enhancements. (Source: LlamaIndex Newsletter/Blog - "LlamaIndex: ...announcing a new production-ready Spreadsheet Agent...new MCP (Model Context Protocol) integration..." was in the search results.)  
Developer Impact: Delivers a practical tool for a common business analytics task and improves the deployability and connectivity of LlamaIndex agents.  
Prioritization Rationale: Addresses specific, high-value developer use cases (spreadsheet interaction) and improves platform capabilities.  
Goose (Open-Source AI Agent Framework by Block): An extensible AI agent framework from Block designed to run entirely locally, capable of writing/executing code and interacting with the file system. (Source: News articles covering the Goose release - "Goose: Released by Block (formerly Square), Goose is an open-source AI agent framework..." was in the search results.)  
Developer Impact: Gives developers a new, powerful, and locally controllable tool for building agents, especially those focused on coding tasks.  
Prioritization Rationale: A new entrant in the open-source framework space from a well-known company, catering to local-first development.  
🤔 Top 5 Questions from Agent Developers  

Getting Started with AI Agent Development: Newcomers are actively seeking guidance on initial steps, choosing foundational frameworks (LangChain, CrewAI, AutoGen frequently cited), and identifying suitable beginner projects. (Source: Reddit thread from June 5, 2025, providing advice for beginners, or a general link like https://www.reddit.com/r/AI_Agents/ if specific links are too numerous. The search mentioned: "A Reddit thread from June 5, 2025, provides advice for beginners...")  
Developer Impact: Highlights a need for more structured learning paths and accessible resources for developers new to building AI agents.  
Prioritization Rationale: A foundational question indicating growing interest and the need for community/educational support, seen in both search and Reddit results.  
Optimizing and Controlling Local LLM Setups: Developers on subreddits like r/LocalLLaMA are discussing practical challenges and alternatives for local LLM environments (e.g., moving from Ollama to llama.cpp/OpenWebUI). (Source: https://www.reddit.com/r/LocalLLaMA/comments/1l92vr0/as_some_people_asked_me_to_share_some_details/)  
Developer Impact: Reflects the hands-on effort by developers to fine-tune their local development stacks for better performance, control, or feature sets.  
Prioritization Rationale: A practical, developer-driven discussion on Reddit about tooling and local environment optimization.  
Implementing Text-to-SQL Multi-Agent Systems: There is active exploration and sharing of projects on building multi-agent systems for complex database interaction tasks like Text-to-SQL, particularly using LangGraph. (Source: https://www.reddit.com/r/LangChain/comments/1l8zy42/built_a_texttosql_multiagent_system_with/)  
Developer Impact: Shows developers are pushing the capabilities of agents to tackle sophisticated, high-value enterprise tasks with multi-agent designs.  
Prioritization Rationale: Represents advanced application development discussed within the LangChain developer community.  
Seeking Open Source Alternatives for Observability Tools: Developers are interested in and building open-source options for agent observability, such as alternatives to LangSmith, including LangGraph visualization. (Source: https://www.reddit.com/r/LangChain/comments/1l93195/open_source_langsmith_alternative_with_langgraph/)  
Developer Impact: Indicates a community drive for more accessible and customizable tools for monitoring and understanding agent behavior.  
Prioritization Rationale: Highlights a specific tooling need and community-led solutions on Reddit, relevant for the LangChain ecosystem.  
Ensuring Code Quality in AI Training Data: A discussion on r/LLMDevs raises the question of how to ensure AI agents learn from high-quality code, suggesting approaches like using "gold standard files" rather than random code. (Source: https://www.reddit.com/r/LLMDevs/comments/1l8yweo/devs_stop_letting_ai_learn_from_random_code_use/)  
Developer Impact: This points to an evolving concern about data integrity and best practices when fine-tuning or training agents for coding tasks.  
Prioritization Rationale: An important discussion on Reddit regarding the quality and reliability of AI-assisted software development.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Part 6: Next Steps and Conclusion
&lt;/h3&gt;

&lt;p&gt;Congratulations! You have successfully upgraded your simple agent into a powerful, multi-agent system using the Agent Development Kit's orchestrator pattern. This is a huge step in your journey as an agent developer.&lt;/p&gt;

&lt;p&gt;You've now learned some of the most important skills for building complex AI applications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to create &lt;strong&gt;specialist sub-agents&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Build a &lt;strong&gt;custom tool&lt;/strong&gt; from any Python function&lt;/li&gt;
&lt;li&gt;Design a &lt;strong&gt;manager agent&lt;/strong&gt; that orchestrates an entire team to solve a problem.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is how real-world, scalable agentic systems are built.&lt;/p&gt;

&lt;p&gt;But this is just the beginning. You now have a truly powerful foundation that you can expand upon. Think about what other specialists you could add to your team — agents/tools to fetch additional sources of information? an agent that saves the report to a Google Doc? A tool that posts the summary to Slack or email? The possibilities are endless.&lt;/p&gt;

&lt;p&gt;When you're ready to dive deeper and explore all the advanced features the framework has to offer, the best place to go is the &lt;a href="https://cloud.google.com/vertex-ai/generative-ai/docs/agent-development-kit/quickstart?utm_campaign=CDR_0x91b1edb5_default_b423225099&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;&lt;strong&gt;official Google Cloud ADK documentation&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Happy building!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
    </item>
    <item>
      <title>Your First AI Agent: A Beginner's Guide to Building an AI Trend finder with ADK</title>
      <dc:creator>Shir Meir Lador</dc:creator>
      <pubDate>Thu, 03 Sep 2026 15:52:29 +0000</pubDate>
      <link>https://dev.to/googleai/your-first-ai-agent-a-beginners-guide-to-building-an-ai-trend-finder-with-adk-5f8k</link>
      <guid>https://dev.to/googleai/your-first-ai-agent-a-beginners-guide-to-building-an-ai-trend-finder-with-adk-5f8k</guid>
      <description>&lt;p&gt;The world of AI agents is moving at lightning speed. Keeping up with the latest trends, new open-source tools, and important developer conversations can feel like a full-time job. We're facing this exact challenge as we prepare to launch our new &lt;a href="https://youtu.be/aLYrV61rJG4" rel="noopener noreferrer"&gt;podcast&lt;/a&gt; for agent developers, which will be dedicated to all things AI agents (stay tuned!). To make sure we're ready for each episode, we wanted to create an automated way to get up-to-date with the news that matters.&lt;/p&gt;

&lt;p&gt;In this guide, we are going to walk you step-by-step through building your very first AI agent &lt;strong&gt;on Google Cloud&lt;/strong&gt; using the open-source &lt;a href="https://cloud.google.com/vertex-ai/generative-ai/docs/agent-development-kit/quickstart?utm_campaign=CDR_0x91b1edb5_default_b423123674&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;&lt;strong&gt;Agent Development Kit&lt;/strong&gt;&lt;/a&gt; (ADK). We will design a "Trend Spotter" agent whose mission is to act as your personal AI analyst, teaching it to scan the web and sift through the noise to find what truly matters.&lt;/p&gt;

&lt;p&gt;By the end of this post, you will have a practical, working tool that automatically creates a concise intelligence report to keep you up-to-date, saving you hours of manual research. More importantly, &lt;strong&gt;you will learn the fundamental skills to build your own agents with ADK&lt;/strong&gt;. You will know how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Structure&lt;/strong&gt; a simple, powerful ADK agent as a proper Python package.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write a detailed prompt&lt;/strong&gt; to define your agent's logic and workflow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Provide your agent with tools&lt;/strong&gt; like Google Search.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set up, test, and run&lt;/strong&gt; your agent locally using the adk web interface.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy&lt;/strong&gt; your agent to Cloud Run.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 1: Setup and Configuration
&lt;/h2&gt;

&lt;p&gt;This setup uses a standard package structure that allows the ADK tools to discover and run our agent without a main.py file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1.1: Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Python 3.11+&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Cloud CLI:&lt;/strong&gt; Follow the official installation guide &lt;a href="https://cloud.google.com/sdk/docs/install?utm_campaign=CDR_0x91b1edb5_default_b423123674&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Cloud&lt;/strong&gt; Account.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 1.2: Create Your Project Structure
&lt;/h3&gt;

&lt;p&gt;Open your terminal. Create the following folder structure and virtual environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create the main project folder  &lt;/span&gt;
&lt;span class="nb"&gt;mkdir &lt;/span&gt;trend-spotter &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;trend-spotter  
&lt;span class="c"&gt;# Create the Python package folder that will hold our code  &lt;/span&gt;
&lt;span class="nb"&gt;mkdir &lt;/span&gt;trend_spotter  
&lt;span class="nb"&gt;touch &lt;/span&gt;trend_spotter/__init__.py  
&lt;span class="nb"&gt;touch &lt;/span&gt;trend_spotter/agent.py  
&lt;span class="nb"&gt;touch &lt;/span&gt;trend_spotter/prompt.py  
&lt;span class="c"&gt;# Create the top-level configuration files  &lt;/span&gt;
&lt;span class="nb"&gt;touch &lt;/span&gt;pyproject.toml requirements.txt  
&lt;span class="c"&gt;# Finally, create and activate a virtual environment  &lt;/span&gt;
python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv venv &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;source &lt;/span&gt;venv/bin/activate  
&lt;span class="o"&gt;(&lt;/span&gt;On Windows, use python &lt;span class="nt"&gt;-m&lt;/span&gt; venv venv &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; .&lt;span class="se"&gt;\v&lt;/span&gt;&lt;span class="nb"&gt;env&lt;/span&gt;&lt;span class="se"&gt;\S&lt;/span&gt;cripts&lt;span class="se"&gt;\a&lt;/span&gt;ctivate&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 1.3: Install ADK
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open requirements.txt and add our single dependency:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;google-adk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install it from your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 1.4: Configure Your Cloud Environment
&lt;/h3&gt;

&lt;p&gt;These settings tell ADK how to securely connect to your Google Cloud account to use services like Vertex AI and Google Search.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Set Environment Variables:&lt;/strong&gt; In your terminal, run the following export commands. These tell ADK to use the Vertex AI platform in your specific Google Cloud project and region.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GOOGLE_GENAI_USE_VERTEXAI&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true  
export &lt;/span&gt;&lt;span class="nv"&gt;GOOGLE_CLOUD_PROJECT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;your-gcp-project-id&amp;gt;  
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GOOGLE_CLOUD_LOCATION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;your-gcp-project-location&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Log In to Your Account:&lt;/strong&gt; Run this one-time command. It will open a browser for you to sign in, allowing ADK to make authorized requests on your behalf.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud auth application-default login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 2: Building Your Agent
&lt;/h2&gt;

&lt;p&gt;Now we'll write the code and place it inside our trend_spotter package directory.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2.1: Define the Agent's Brain (The Prompt)
&lt;/h3&gt;

&lt;p&gt;The prompt contains all the instructions for our agent.&lt;/p&gt;

&lt;p&gt;Note that we are guiding the LLM to specify the date range in the call to the GoogleSearch tool to make sure we are focusing on trends from the last week.&lt;/p&gt;

&lt;p&gt;Open trend_spotter/prompt.py and add these instructions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# trend_spotter/prompt.py  
&lt;/span&gt;
&lt;span class="n"&gt;TREND_SPOTTER_PROMPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;  
You are a helpful AI assistant and expert tech analyst for a new podcast called &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The Agent Factory&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;. Your goal is to generate a highly relevant and verifiable report about the latest developments in AI agents that specifically impact developers.  

**Your multi-step plan is as follows:**  

**Step 1: Discover the Current Date.**  
Your very first action must be to find the current date.  
- **Action**: Use the `Google Search` tool with a query like &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;what is today&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s date&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.  
- From the search result, identify the current year, month, and day.  

**Step 2: Formulate and Execute Search Queries with Date Operators.**  
Now, you must formulate your search queries by embedding the date range directly into the query string using Google&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s `after:YYYY-MM-DD` and `before:YYYY-MM-DD` operators. Calculate these dates to cover the last 7 days.  
- You must perform at least three initial searches to cover trends, releases, and questions.  
- **Example Query Format**: `&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AI agent trends after:2025-06-01 before:2025-06-08&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;`  
- After the initial searches, you may perform 1-2 additional, more targeted searches if a category is missing information. **Do not perform more than 5 searches in total.**  

**Step 3: Analyze the Results and Create the Report.**  
Read through all the text and links from your searches. Your primary filter is to **only select topics, tools, and questions that have a direct and significant impact on developers building AI agents.**  

**Critical Rule for Sourcing:** For every trend, release, or question you identify, you must first pinpoint the **single best search result** that provides the evidence. You will then use the URL from that **exact search result** as the source link for that item. **If you cannot find a specific source link for an item, do not include that item in the report.**  

Based on these rules, create a report:  
1.  The report **must begin with a header** specifying the date range used.  
2.  The body of the report must have exactly three sections.  
3.  For each item, you **must provide three pieces of information**: a 1-2 sentence explanation, the &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Developer Impact&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; analysis, and the **verifiable source URL**.  

The report format must be:  

**🔥 Top 5 Trends for Agent Developers**  
1.  **[Trend 1 Name]**: [A 1-2 sentence explanation of this trend.] (Source: [URL])  
    * **Developer Impact**: [A 1-sentence explanation of why this matters to developers.]  
2.  ... (up to 5 total)  

**🚀 Top 5 Releases for Agent Developers**  
1.  **[Release 1 Name]**: [A 1-2 sentence explanation of the tool, framework, or model.] (Source: [URL])  
    * **Developer Impact**: [A 1-sentence explanation of why this matters to developers.]  
2.  ... (up to 5 total)  

**🤔 Top 5 Questions from Agent Developers**  
1.  **[Question 1 Topic]**: [A 1-2 sentence explanation of what developers are asking.] (Source: [URL])  
    * **Developer Impact**: [A 1-sentence explanation of why this matters to developers.]  
2.  ... (up to 5 total)  

Begin your work now by executing your plan.  
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2.2: Assemble the Agent
&lt;/h3&gt;

&lt;p&gt;The agent.py file connects our prompt and the search tool to a new ADK Agent.&lt;/p&gt;

&lt;p&gt;Open trend_spotter/agent.py and add this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# trend_spotter/agent.py  
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google.adk.agents&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;  
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google.adk.tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;google_search&lt;/span&gt;  
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;.&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;  
&lt;span class="c1"&gt;# Use the "latest" tag to always get the most recent stable version of the model.  
&lt;/span&gt;&lt;span class="n"&gt;MODEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemini-2.5-pro-preview-05–06&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  
&lt;span class="c1"&gt;# This single agent will perform all the work.  
&lt;/span&gt;&lt;span class="n"&gt;trend_spotter_agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;MODEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;trend_spotter_agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;An agent that finds and reports on AI agent trends.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
&lt;span class="c1"&gt;# The agent's entire logic comes from our detailed prompt.  
&lt;/span&gt;&lt;span class="n"&gt;instruction&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TREND_SPOTTER_PROMPT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
&lt;span class="c1"&gt;# We give the agent a single tool: the ability to search Google.  
&lt;/span&gt;&lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;google_search&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;  
&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="c1"&gt;# We assign it to `root_agent` by convention for ADK to discover.  
&lt;/span&gt;&lt;span class="n"&gt;root_agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;trend_spotter_agent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2.3: Making Your Agent Discoverable
&lt;/h3&gt;

&lt;p&gt;To use the adk web command, we need to tell ADK where to find our agent. We do this in the pyproject.toml file.&lt;/p&gt;

&lt;p&gt;Open pyproject.toml in your root directory and add the following configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[project]&lt;/span&gt;  
&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"trend_spotter"&lt;/span&gt;  
&lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.1.0"&lt;/span&gt;  
&lt;span class="c"&gt;# This section tells the ADK how to find our agent.  &lt;/span&gt;
&lt;span class="nn"&gt;[tool.adk.agents]&lt;/span&gt;  
&lt;span class="py"&gt;trend_spotter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"trend_spotter.agent:root_agent"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 3: Running Your Agent
&lt;/h2&gt;

&lt;p&gt;Now for the exciting part!&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3.1: Install your agent:
&lt;/h3&gt;

&lt;p&gt;Run this command from your project's root directory. The -e . command installs your project in "editable" mode so the adk tool can find it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3.2: Launch the web interface:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;adk web
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open the URL that appears in your terminal. In the web interface, select "trend_spotter" from the dropdown menu. You can now chat with your agent! Ask it: "Generate a report on the latest AI agent news." This might take a few minutes, depending on the amount of searches you instruct the agent to perform in your prompt.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The response will look similar to this:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Okay, I will begin by finding the current date.  


Okay, I have identified the current date as June 7, 2025.  

Now, I will formulate and execute search queries to find information from the last 7 days (June 1, 2025, to June 7, 2025) about AI agent trends, releases, and questions relevant to developers.  


Okay, I have analyzed the search results and will now generate the report on AI agent developments impacting developers for the period of June 1, 2025, to June 7, 2025.  

Report: AI Agent Developments for Developers (June 1, 2025 - June 7, 2025)  

🔥 Top 5 Trends for Agent Developers  

Maturation of Agentic AI: Agentic AI, which involves AI systems that can autonomously handle complex tasks, is moving beyond hype and into practical application, with companies beginning to launch pilot projects. This trend signifies a shift towards more sophisticated AI that can streamline various stages of software development, testing, and maintenance.  
Developer Impact: Developers will increasingly need to build, integrate, and manage these more autonomous AI agents, requiring skills in designing for complex, goal-oriented behaviors.  
Rise of Multi-Agent Systems: There is a growing interest in systems where multiple AI agents collaborate to solve larger, more complex problems than a single agent could handle. This involves individual agents with specific goals and tools working together within a broader workflow.  
Developer Impact: This trend requires developers to think about inter-agent communication protocols, task delegation, and overall system orchestration.  
Emphasis on AI Agent Evaluation and Benchmarking: As AI agents become more capable and undertake more complex tasks, there's a corresponding growth in the need for robust evaluation methods and standardized benchmarks. These benchmarks aim to assess core competencies like planning, reasoning, and tool usage.  
Developer Impact: Developers will need to leverage these evolving benchmarks to test, validate, and improve the reliability and performance of the agents they build.  
Enhanced NLP and Personalization in Conversational AI: Conversational AI agents are advancing to provide more human-like interactions, including better understanding of natural language, emotional cues, and offering highly personalized user experiences.  
Developer Impact: Developers creating conversational interfaces must focus on incorporating these advanced NLP and personalization techniques to build more engaging and effective AI agents.  
Shift Towards AI-Native Development Infrastructure: The rapid generation of code by AI agents is prompting a re-evaluation of existing development platforms like GitHub and GitLab, which were primarily designed for human development speeds. This points towards a need for infrastructure that can better support AI-driven development rhythms.  
Developer Impact: Developers should anticipate changes in their toolchains and workflows, potentially including new platforms designed to handle the increased volume and velocity of AI-generated code and the unique review processes required.  

🚀 Top 5 Releases for Agent Developers  

Embabel Agent Framework: Launched by Spring founder Rod Johnson, Embabel is a new JVM-based, type-safe framework for building AI-powered applications, particularly for integrating Large Language Models (LLMs) with Java applications using Goal-Oriented Action Planning (GOAP).  
Developer Impact: Java developers now have a dedicated, high-level framework that emphasizes production-readiness, type safety, and advanced planning capabilities for creating sophisticated AI agents within the Spring ecosystem.  
Digitate's ignio™ Agentic AI Platform Update: Digitate announced a significant update to its ignio™ platform, introducing a suite of purpose-built AI agents aimed at IT operations, SREs, and CIOs to accelerate the move towards autonomous enterprise and ticketless IT operations.  
Developer Impact: Developers working on enterprise IT and business process automation can leverage these new agents to handle complex tasks more autonomously, improving efficiency and system resiliency.  
Digital Twin Consortium's AI Agent Capabilities Periodic Table (AIA CPT): The DTC launched the AIA CPT, an industry-first standardized framework for evaluating AI agent systems based on their actual capabilities, designed to reduce market confusion.  
Developer Impact: This framework provides developers with a clear, objective way to assess and compare different AI agent technologies and vendor offerings, aiding in technology selection and expectation setting.  
Google's Agent Development Kit (mentioned with Agentspace): Alongside its Agentspace hub for managing AI agents, Google has noted the availability of a new Agent Development Kit designed to help developers build AI agents.  
Developer Impact: Developers within the Google Cloud ecosystem can expect new and refined tools to streamline the creation and deployment of AI agents, fostering more sophisticated agent-based solutions.  
MetaGPT Framework Highlighted: Although an existing open-source framework, MetaGPT continues to be recognized for its capability in allowing multi-agent systems to automate complex software engineering tasks by encoding Standard Operating Procedures (SOPs) into LLM prompts.  
Developer Impact: Developers can utilize MetaGPT to create collaborative multi-agent systems for various development tasks, potentially improving efficiency in areas like game development, web development, and data analysis.  

🤔 Top 5 Questions from Agent Developers  

Determining When to Use AI Agents: Developers are actively discussing the appropriate use cases for AI agents, cautioning against over-engineering solutions with complex agents when simpler AI workflows or even manual intervention would be more efficient.  
Developer Impact: This highlights the need for developers to critically evaluate task complexity and ROI before committing to building an AI agent, ensuring the chosen solution fits the problem.  
Managing Repository Strategy in an AI World: There's ongoing debate about how to structure code repositories when AI agents are involved—whether smaller, focused repositories are better for AI comprehension or if larger, comprehensive ones provide necessary context.  
Developer Impact: Developers need to consider how their repository strategy impacts AI agent performance and collaboration, potentially adapting practices to include AI-generated artifacts like prompts.  
Addressing the Impact of AI on Team Dynamics: As AI tools create a potential "productivity divide" where some engineers significantly increase output, questions arise about how to maintain team cohesion, collaboration, and equitable workload distribution.  
Developer Impact: This requires a conscious effort from development teams and managers to adapt team structures and processes to integrate AI assistance smoothly and support all team members.  
Ensuring Architectural Consistency with Multiple AI Agents: A key concern is how to ensure that different AI agents, possibly working across various repositories or parts of a system, adhere to consistent architectural principles and design patterns.  
Developer Impact: Developers may need to establish clearer architectural guidelines for AI agents or develop new mechanisms to enforce consistency when employing multiple autonomous agents.  
Need for AI-Native Development Infrastructure: Developers are questioning whether current development platforms and their associated workflows (e.g., for code review) are adequate for the speed and volume of code that AI agents can produce.  
Developer Impact: This points to an upcoming need for developers to adapt to, and possibly help shape, new tools and platforms specifically designed for an AI-assisted and AI-native development lifecycle.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3.3: Debugging
&lt;/h3&gt;

&lt;p&gt;The adk web interface is your best debugging tool. On the "&lt;em&gt;Events&lt;/em&gt;" tab, you can see every step your agent takes, including which tools it calls and what the LLM is thinking. If the output isn't right, your first step should always be to adjust the instructions in prompt.py.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 4 - Deployment
&lt;/h2&gt;

&lt;p&gt;The &lt;em&gt;adk deploy cloud_run&lt;/em&gt; command deploys your agent code to Google Cloud Run.&lt;/p&gt;

&lt;p&gt;Ensure you have authenticated with Google Cloud (gcloud auth login and gcloud config set project ) and setup your environment variables to deploy your agent to cloud run with one line command.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4.1: Setup environment variables
&lt;/h3&gt;

&lt;p&gt;Optional but recommended: Setting environment variables can make the deployment commands cleaner.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Set your Google Cloud Project ID  &lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GOOGLE_CLOUD_PROJECT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your-gcp-project-id"&lt;/span&gt;  
&lt;span class="c"&gt;# Set your desired Google Cloud Location  &lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GOOGLE_CLOUD_LOCATION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"us-central1"&lt;/span&gt; &lt;span class="c"&gt;# Example location  &lt;/span&gt;
&lt;span class="c"&gt;# Set the path to your agent code directory  &lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;AGENT_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"./trend_spotter"&lt;/span&gt; &lt;span class="c"&gt;# Assuming capital_agent is in the current directory  &lt;/span&gt;
&lt;span class="c"&gt;# Set a name for your Cloud Run service (optional)  &lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SERVICE_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"trend-spotter-service"&lt;/span&gt;  
&lt;span class="c"&gt;# Set an application name (optional)  &lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;APP_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"trend-spotter-app"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4.2: Deployment to Cloud Run
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;adk deploy cloud_run &lt;span class="se"&gt;\ &lt;/span&gt; 
 - &lt;span class="nv"&gt;project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$GOOGLE_CLOUD_PROJECT&lt;/span&gt; &lt;span class="se"&gt;\ &lt;/span&gt; 
 - &lt;span class="nv"&gt;region&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$GOOGLE_CLOUD_LOCATION&lt;/span&gt; &lt;span class="se"&gt;\ &lt;/span&gt; 
 - &lt;span class="nv"&gt;service_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$SERVICE_NAME&lt;/span&gt; &lt;span class="se"&gt;\ &lt;/span&gt; 
 - &lt;span class="nv"&gt;app_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$APP_NAME&lt;/span&gt; &lt;span class="se"&gt;\ &lt;/span&gt; 
 - with_ui &lt;span class="se"&gt;\ &lt;/span&gt; 
&lt;span class="nv"&gt;$AGENT_PATH&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(more options for Cloud run deployment can be found &lt;a href="https://google.github.io/adk-docs/deploy/cloud-run/" rel="noopener noreferrer"&gt;here&lt;/a&gt;)&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4.3: Testing your deployed agent
&lt;/h3&gt;

&lt;p&gt;You can test your agent by simply navigating to the Cloud Run service URL provided after deployment in your web browser. (The URL should be similar to this: &lt;a href="https://your-service-name-abc123xyz.a.run.app" rel="noopener noreferrer"&gt;https://your-service-name-abc123xyz.a.run.app&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 5: Next Steps and Conclusion
&lt;/h2&gt;

&lt;p&gt;Congratulations! You have successfully designed, built, tested and deployed your very first AI agent using the Agent Development Kit.&lt;/p&gt;

&lt;p&gt;You've learned how to structure a proper agent package, how to write a detailed prompt to control an agent's logic, and how to run and interact with your agent using the &lt;code&gt;adk web&lt;/code&gt; interface. We now have a working "researcher" for our AI agent podcast and you you now have a working foundation that you can expand upon. Try modifying the prompt to &lt;strong&gt;research a different topic&lt;/strong&gt;, or &lt;strong&gt;explore adding new custom tools&lt;/strong&gt; to give your agent more capabilities.&lt;/p&gt;

&lt;p&gt;In our &lt;a href="https://medium.com/google-cloud/your-first-multi-agent-system-a-beginners-guide-to-building-an-ai-trend-finder-with-adk-6991cf587f22" rel="noopener noreferrer"&gt;next post&lt;/a&gt;, we'll continue to build on this foundation and make our agent even more powerful by adding richer, more specialized tools.&lt;/p&gt;

&lt;p&gt;When you're ready to dive deeper and explore all the powerful features the framework has to offer, the best place to go is the &lt;a href="https://cloud.google.com/vertex-ai/generative-ai/docs/agent-development-kit/quickstart?utm_campaign=CDR_0x91b1edb5_default_b423123674&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;&lt;strong&gt;official Google Cloud ADK documentation&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Happy building!&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>googlecloud</category>
    </item>
    <item>
      <title>How to Write Reliable Rubrics for LLM-as-a-Judge Evaluations</title>
      <dc:creator>Jan-Felix Schmakeit</dc:creator>
      <pubDate>Wed, 02 Sep 2026 16:35:00 +0000</pubDate>
      <link>https://dev.to/googleai/how-to-write-reliable-rubrics-for-llm-as-a-judge-evaluations-ndp</link>
      <guid>https://dev.to/googleai/how-to-write-reliable-rubrics-for-llm-as-a-judge-evaluations-ndp</guid>
      <description>&lt;p&gt;&lt;em&gt;Follow up to &lt;a href="https://dev.to/googleai/how-to-design-ai-evaluations-you-can-actually-trust-41c3"&gt;Part 1: How to Design AI Evaluations You Can Actually Trust&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;At Google, we are publishing a suite of &lt;a href="https://github.com/google/skills" rel="noopener noreferrer"&gt;Agent Skills for Google products and technologies on GitHub&lt;/a&gt;. My team is interested in measuring their performance to understand how they perform. Deterministic tests, like checking if generated code compiles, are ideal. Unfortunately they can't be easily created at scale for nuanced, generative responses, such as answers to open-ended questions or information retrieval tasks.&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://dev.to/googleai/how-to-design-ai-evaluations-you-can-actually-trust-41c3"&gt;my previous post we looked at &lt;em&gt;what&lt;/em&gt; you test&lt;/a&gt;, which means the evaluations that are the actions you ask the agent to perform. The next step is to look at &lt;em&gt;how you assert&lt;/em&gt; whether the agent succeeded. This means creating reliable and accurate assessments of the agent's response.&lt;/p&gt;

&lt;p&gt;To assess complex outputs at scale, especially when topics cover broad areas with nuanced parts, we use an "LLM-as-a-judge" approach. Responses are assessed against a structured rubric using a model based grader. The judge evaluates each response using a set of true/false questions. Aggregated, these answers provide an accuracy score for a response.&lt;/p&gt;

&lt;p&gt;Giving an LLM a vague prompt or subjective questions leads to ambiguity in its response. This ambiguity introduces noisy data and causes inconsistent evaluations. Ultimately, it wastes your token budget on metrics that aren't useful.&lt;/p&gt;

&lt;p&gt;To make these assessments more reliable, you must treat your rubrics like formal specifications. By constraining the judge to evaluate strict, objective boolean truths, you reduce the chance of hallucinations. Because evaluating strict boolean truths is a less complex task, you can even use smaller, faster models for grading.&lt;/p&gt;

&lt;p&gt;Here are four lessons we learned to help you write robust rubric questions for your LLM-as-a-judge scorer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep Questions Atomic and Distinct
&lt;/h2&gt;

&lt;p&gt;Evaluating multiple requirements in a single question, such as &lt;em&gt;"Does the response contain a metadata property and format the output as JSON?"&lt;/em&gt;, forces the LLM judge to guess which clause is more important. This ambiguity leads to inconsistent grading and wasted tokens.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Split compound questions:&lt;/strong&gt; Instead of writing one large check, divide your requirements into discrete, atomic &lt;code&gt;TRUE&lt;/code&gt;/&lt;code&gt;FALSE&lt;/code&gt; questions. (e.g., &lt;em&gt;Check 1: Does it contain a metadata property?&lt;/em&gt; AND &lt;em&gt;Check 2: Is the output JSON?&lt;/em&gt;)
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avoid overlapping questions:&lt;/strong&gt; Never test the same underlying concept multiple times across your rubric. Overlap risks double-penalizing the evaluated model for a single mistake, which corrupts your accuracy score.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reduce the reasoning load:&lt;/strong&gt; Eliminate the need for the judge to weigh competing clauses. When every question assesses exactly one distinct fact, your grading becomes more consistent.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Constrain the Judge: Objective Facts Over Subjective Reasoning
&lt;/h2&gt;

&lt;p&gt;The rubric-based approach exists because giving an LLM judge a full prose prompt to evaluate a complex response leads to inconsistent numbers. If you ask the judge subjective questions like &lt;em&gt;"Was this a comprehensive answer?"&lt;/em&gt; or ask it to explain &lt;em&gt;"Why did the agent do this?"&lt;/em&gt;, you introduce ambiguity that creates noisy, unrepeatable data.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Focus on observable facts:&lt;/strong&gt; Do not ask the judge to evaluate concepts that require interpretation, such as intent, quality, or reasoning. Only assess concrete facts that you expect to find in the response.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write formal specifications:&lt;/strong&gt; Use strict, objective language, such as &lt;a href="https://www.rfc-editor.org/info/rfc2119/" rel="noopener noreferrer"&gt;RFC 2119&lt;/a&gt; terminology (MUST, MUST NOT, REQUIRED), to test for observable outcomes. The judge should never have to guess what you mean.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test for negative constraints:&lt;/strong&gt; Explicitly verify what the agent &lt;em&gt;should not&lt;/em&gt; do. Instead of asking if the agent "used best practices", check that it &lt;em&gt;did not&lt;/em&gt; suggest a specific deprecated feature.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Require strict true/false answers:&lt;/strong&gt; By forcing a strict &lt;code&gt;TRUE&lt;/code&gt;/&lt;code&gt;FALSE&lt;/code&gt; classification on objective facts, you reduce the reasoning load and reduce the variance in ratings.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avoid opportunities for cheating:&lt;/strong&gt; Agents will tailor answers to game your tests if given the chance. Keep scoring rubrics isolated in a separate system. Design rubrics that focus on strict functional outcomes or specific topics, rather than broad keywords matches.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Grade Only What You Asked For
&lt;/h2&gt;

&lt;p&gt;When building rubrics, it is easy to accidentally evaluate an agent on requirements that were never stated in the prompt. Doing this creates false negatives and reduces the accuracy of your measurement.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Align the rubric to the prompt:&lt;/strong&gt; Assess only what was explicitly requested. For example, do not penalize a model for failing to provide citations if the prompt never asked for them.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grade the destination, not the journey:&lt;/strong&gt; Avoid writing rubrics that check if the agent used a specific tool or followed a rigid sequence of steps. Pre-trained models might bypass custom tools entirely if they already know the answer.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evaluate the final response:&lt;/strong&gt; Grade the objective output. If you need to evaluate a step-by-step process, prompt the agent to output an execution plan and evaluate the plan itself.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Calibrate Your Judge
&lt;/h2&gt;

&lt;p&gt;Even if you follow these rules and write perfectly atomic, objective questions, your LLM judge might still misinterpret your scoring instructions and rubrics. To guarantee your pipeline generates consistent ratings and reliable signals, you must prove that the judge's scoring aligns with how a human subject matter expert would evaluate the exact same response through &lt;em&gt;calibration&lt;/em&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Establish a human baseline:&lt;/strong&gt; Ask subject matter experts to manually grade a "golden set" of test responses.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run the comparison:&lt;/strong&gt; Run your LLM-as-a-judge against this golden set and compare the automated scores against the human scores.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Identify the delta:&lt;/strong&gt; If the LLM judge disagrees with your human experts, it is usually a sign that your rubric or the grading instructions are too ambiguous.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Iterate until aligned:&lt;/strong&gt; Tweak and calibrate your rubric questions or the scoring instructions until the LLM judge consistently aligns with human experts. Only then is your judge ready.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Once you have this reliable data, the next step is making it visible. In &lt;a href="https://dev.to/googleai/ai-evals-at-a-glance-heatmaps-for-stakeholders-2mki"&gt;AI Evals at a Glance: Heatmaps for Stakeholders&lt;/a&gt; Joe Spiro explains how to take these raw measurements and visualize evaluations.&lt;/p&gt;

&lt;p&gt;When building our agent skills, we learned that ambiguous evaluation rubrics do not provide useful signals and feedback. Forcing your LLM judge to evaluate strict, boolean facts eliminates this noise. It makes your tests repeatable, optimizes your token spend, and lets you confidently measure whether your AI tool is actually improving.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Photo by &lt;a href="https://unsplash.com/@wwarby" rel="noopener noreferrer"&gt;William Warby&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/gray-and-yellow-measures-WahfNoqbYnM" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>evals</category>
      <category>testing</category>
    </item>
    <item>
      <title>What is harness engineering and why should I care?</title>
      <dc:creator>Shir Meir Lador</dc:creator>
      <pubDate>Wed, 02 Sep 2026 15:28:05 +0000</pubDate>
      <link>https://dev.to/googleai/what-is-harness-engineering-and-why-should-i-care-8n0</link>
      <guid>https://dev.to/googleai/what-is-harness-engineering-and-why-should-i-care-8n0</guid>
      <description>&lt;div&gt;
    &lt;iframe src="https://www.youtube.com/embed/04MDDx19yoM" width="315" height="560"&gt;
    &lt;/iframe&gt;
  &lt;/div&gt;


&lt;p&gt;How do you ship a software product with 0 lines of manually-written code?&lt;/p&gt;

&lt;p&gt;A friend asked me this today, and I realized I didn't have a simple answer. So I dug deeper.&lt;/p&gt;

&lt;p&gt;It turns out the answer is in how you engineer your harness.&lt;/p&gt;

&lt;p&gt;Wait now, what? What is harness engineering?&lt;/p&gt;

&lt;p&gt;There is a reason this is &lt;strong&gt;the most important trend&lt;/strong&gt; right now around coding agents. The biggest question these days is how to validate AI-generated code without reading every single line. How do you make sure an agent doesn't break production or delete your data?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://openai.com/index/harness-engineering/" rel="noopener noreferrer"&gt;A blog by OpenAI&lt;/a&gt; shared an interesting experiment where a team of 3 engineers have built and shipped an internal beta of a software product with 0 lines of manually-written code. Every line of code: application logic, tests, CI configuration, documentation, observability, and internal tooling, has been written by Codex.&lt;/p&gt;

&lt;p&gt;How did they do it? They didn't write the app. They designed the harness.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What exactly is a harness?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Think of an AI agent like a powerful racehorse. The harness is the track, the blinders, and the jockey's reins that keep it running in the right direction instead of jumping into the stands.&lt;/p&gt;

&lt;p&gt;As my colleague Arthur Thompson explained today: for agents — the harness is composed of all the deterministic components that wrap the LLM.&lt;/p&gt;

&lt;p&gt;Balaji Subramaniam details those deterministic components in his &lt;a href="https://medium.com/google-cloud/harness-engineering-for-multi-agent-systems-using-google-adk-2-0-e248b885cb95" rel="noopener noreferrer"&gt;blog&lt;/a&gt; &lt;strong&gt;—&lt;/strong&gt; the orchestration layer, execution sandboxing, state persistence, and verification tools.&lt;/p&gt;

&lt;p&gt;If you want to build reliable agentic systems, your job shifts from writing the logic to designing the environment. Here is what you need to focus on:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Set strict boundaries:&lt;/strong&gt; Don't let the agent guess what it can touch. Enforce strict access rules (like confining it to a specific sandbox) so it can't accidentally wipe out production data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build "Repair Loops":&lt;/strong&gt; Agents will inevitably make mistakes. A great harness automatically traps errors, like a failed build or a test failure, and feeds those clean logs right back to the agent so it can fix its own code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Give them a map, not a manual:&lt;/strong&gt; As the OpenAI team discovered, don't overwhelm the agent with massive instruction files. Structure your repository logically so the agent can discover context progressively as it works.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Show me the code&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;What does this look like in practice? Here is a simple example using the &lt;a href="https://antigravity.google/product/antigravity-sdk?utm_campaign=CDR_0x91b1edb5_default_b550513795&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;Google Antigravity SDK&lt;/a&gt; with Google's &lt;a href="https://adk.dev/2.0/" rel="noopener noreferrer"&gt;ADK&lt;/a&gt; to configure a local harness. Notice how we are strictly bounding the agent to a specific workspace (workspaces=["./sandbox"]) and giving it a place to save its memory (save_dir="./trajectories" ) so it can learn from previous experience:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google.adk.labs.antigravity&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AntigravityAgent&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google.antigravity&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LocalAgentConfig&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google.antigravity.hooks&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;policy&lt;/span&gt;

&lt;span class="c1"&gt;# Ensure absolute paths for workspace containment
&lt;/span&gt;&lt;span class="n"&gt;sandbox_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abspath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;./sandbox&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makedirs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sandbox_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exist_ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;save_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abspath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;./trajectories&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 1. Engineer the harness environment
&lt;/span&gt;&lt;span class="n"&gt;sdk_config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LocalAgentConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;system_instructions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You are a helpful local environment assistant.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;workspaces&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sandbox_dir&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="c1"&gt;# Let the agent write safely within the restricted sandbox boundary
&lt;/span&gt;    &lt;span class="n"&gt;policies&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;allow_all&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
    &lt;span class="n"&gt;save_dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;save_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 2. Wrap the config to run the agent inside the harness
&lt;/span&gt;&lt;span class="n"&gt;root_agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AntigravityAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;antigravity_assistant&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Runs an Antigravity SDK agent inside ADK.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sdk_config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F706wjvl4dxy8dnxgkbib.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F706wjvl4dxy8dnxgkbib.png" alt="The policy keeps the agent access only in the Sandbox folder" width="720" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;center&gt;&lt;small&gt;&lt;em&gt;The policy keeps the agent access only in the Sandbox folder&lt;/em&gt;&lt;/small&gt;&lt;/center&gt;

&lt;p&gt;&amp;nbsp; &lt;/p&gt;

&lt;p&gt;With this design in place, you can drop your legacy code into the sandbox, write a simple loop to run unit tests against it, and let the agent iteratively fix its own bugs.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Adding Tests&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;So, how do we actually run tests against this sandboxed agent?&lt;/p&gt;

&lt;p&gt;In modern harness engineering, tests are an active part of the agent's workflow graph. Using Google's &lt;a href="https://adk.dev/2.0/" rel="noopener noreferrer"&gt;ADK 2.0&lt;/a&gt;, which introduces graph-based workflows, you can define a test validation step as a simple routing node.&lt;/p&gt;

&lt;p&gt;If the test passes, the job is done. If it fails, the harness automatically loops the error back to the agent to try again. Notice the &lt;strong&gt;built-in 'kill switch':&lt;/strong&gt; we track the iteration count so if the agent gets stuck in an infinite loop of breaking and fixing code, the harness safely pulls the plug.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google.adk.agents.context&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google.adk&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Event&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google.adk.events.event_actions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;EventActions&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google.genai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt;

&lt;span class="c1"&gt;# 3. Evaluate the code in the sandbox
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;execution_test_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Safely track our attempts to prevent infinite loops
&lt;/span&gt;    &lt;span class="n"&gt;iteration_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;iteration_count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;iteration_count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;iteration_count&lt;/span&gt;

    &lt;span class="n"&gt;test_passed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test_passed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;feedback&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;feedback&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;test_passed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Success! End the workflow.
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;EventActions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;END&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;iteration_count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# The Kill Switch: The agent is stuck. Stop the loop.
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;EventActions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;END&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="c1"&gt;# Failure! Feed the error trace back to the agent and loop it.
&lt;/span&gt;    &lt;span class="n"&gt;feedback_msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The unit tests failed with the following traceback:&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;feedback&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Part&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;feedback_msg&lt;/span&gt;&lt;span class="p"&gt;)]),&lt;/span&gt;
        &lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;EventActions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;loop_back&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to see this test routing pattern in action, you can check out an example with a full implementation in Balaji's &lt;a href="https://github.com/balajismaniam/adk-harness-engineering/blob/main/workflows/workflows.py" rel="noopener noreferrer"&gt;&lt;strong&gt;ADK harness repository&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Wiring it all together using graph-based workflow&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;To connect the agent and the test node, you can use a Workflow graph to map out exactly how the execution should flow without needing complex, nested Python while loops.&lt;/p&gt;

&lt;p&gt;Think of this as drawing the actual lanes on the racetrack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google.adk&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Workflow&lt;/span&gt;

&lt;span class="c1"&gt;# 4. Wire the agent and the test node together into a loop
&lt;/span&gt;&lt;span class="n"&gt;repair_loop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Workflow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;repair_loop&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="c1"&gt;# 1st Step: Define the main sequence (START -&amp;gt; agent -&amp;gt; test node)
&lt;/span&gt;        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;START&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;root_agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;execution_test_node&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;

        &lt;span class="c1"&gt;# 2nd Step: If the test returns "loop_back", go back to the agent
&lt;/span&gt;        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;execution_test_node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;loop_back&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;root_agent&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe6gyazb82hdpd8wqq4dv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe6gyazb82hdpd8wqq4dv.png" alt="The test loop" width="720" height="216"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;center&gt;&lt;small&gt;&lt;em&gt;The test loop&lt;/em&gt;&lt;/small&gt;&lt;/center&gt;

&lt;p&gt;&amp;nbsp; &lt;/p&gt;

&lt;p&gt;Congratulations! you've built an autonomous system. The agent writes the code and hands it off to the test node. If the test fails and returns a loop_back route, the agent tries again with the error log in hand.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;See more examples of loop patterns in&lt;/em&gt; &lt;a href="https://github.com/google/adk-python/tree/main/contributing/samples/workflows/loop" rel="noopener noreferrer"&gt;&lt;em&gt;ADK samples.&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Try it yourself&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;You might wonder why you need a Python script to run an agent. In a normal chat window, &lt;em&gt;you&lt;/em&gt; are the harness: you copy the error logs and babysit the model. A software harness lets the system babysit itself, allowing you to fully automate test-driven coding or safely refactor massive legacy codebases.&lt;/p&gt;

&lt;p&gt;To run this self-healing loop on your own machine today, the setup takes less than five minutes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Install the framework:&lt;/strong&gt; Run pip install "google-adk[antigravity]" in your terminal to get the open-source Agent Development Kit and the Antigravity integration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set your API key:&lt;/strong&gt; Grab a free Gemini API key from &lt;a href="https://aistudio-preprod.corp.google.com/apps" rel="noopener noreferrer"&gt;Google AI Studio&lt;/a&gt; and export it to your environment (export GEMINI_API_KEY="your-key").&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run the loop:&lt;/strong&gt; Save the code blocks above as a Python script, drop a broken Python or Node file into your new ./sandbox directory, and run your script.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expand your graph:&lt;/strong&gt; Unit tests are just the baseline. To make your harness bulletproof, add a second AI agent to your workflow, like a SecurityAuditor, to review the code before it passes, or wire in custom linters to enforce strict architectural rules.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;From there, you can swap out our simple test node for a subprocess that actually executes pytest or npm test against your sandbox, and you will have a fully functioning repair loop.&lt;/p&gt;

&lt;p&gt;If you are ready to scale this up, you can download the full IDE and CLI at &lt;a href="https://antigravity.google/?utm_campaign=CDR_0x91b1edb5_default_b550513795&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;antigravity.google&lt;/a&gt;, explore the &lt;a href="https://ai.google.dev/gemini-api/docs/antigravity-agent?utm_campaign=CDR_0x91b1edb5_default_b550513795&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;Antigravity managed agent&lt;/a&gt; for remote execution and google's &lt;a href="https://adk.dev/2.0/" rel="noopener noreferrer"&gt;ADK 2.0&lt;/a&gt; for using graph based workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Further reading&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;My colleagues at Google have put together some incredible guides on where to go next. To learn how to build secure environments for your agents, check out Sara's codelab showcasing &lt;a href="https://codelabs.developers.google.com/codelabs/cloud-run/cloud-run-personal-agent-coffee-shop?utm_campaign=CDR_0x91b1edb5_default_b550513795&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;Cloud Run sandboxes&lt;/a&gt;. If you want to master self-correction, Balaji Subramaniam recently published a deep dive on &lt;a href="https://medium.com/@BalajiBuilds/61c30c9e36ca" rel="noopener noreferrer"&gt;Loop Engineering for Coding Agents&lt;/a&gt;. And to see all of this applied to a massive enterprise use case, read James O'Reilly's breakdown of &lt;a href="https://codelabs.developers.google.com/automating-modernization-with-antigravity?utm_campaign=CDR_0x91b1edb5_default_b550513795&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;Automating legacy modernization at scale using agentic pipelines and Antigravity&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>programming</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Claude Fable 5.1 is now available on Agent Platform!</title>
      <dc:creator>Jen Harvey</dc:creator>
      <pubDate>Tue, 01 Sep 2026 18:28:57 +0000</pubDate>
      <link>https://dev.to/googleai/claude-fable-51-is-now-available-on-agent-platform-1b16</link>
      <guid>https://dev.to/googleai/claude-fable-51-is-now-available-on-agent-platform-1b16</guid>
      <description>&lt;p&gt;Claude Fable 5.1 is officially available in the Model Garden on Agent Platform.&lt;/p&gt;

&lt;p&gt;Built for long-running, high-stakes work, Fable 5.1 puts frontier intelligence into production across your code, documents, and research.&lt;/p&gt;

&lt;p&gt;👉 Try it today and let us know what you're building: &lt;a href="https://pantheon.corp.google.com/agent-platform/publishers/anthropic/model-garden/claude-fable-5-1?pli=1&amp;amp;project=cai-playground-422820" rel="noopener noreferrer"&gt;Claude Fable 5.1&lt;/a&gt;&lt;/p&gt;

</description>
      <category>claude</category>
      <category>googlecloud</category>
      <category>developer</category>
    </item>
    <item>
      <title>Elevating Antigravity agent skills, Part 2: Image generation</title>
      <dc:creator>James O'Reilly</dc:creator>
      <pubDate>Tue, 01 Sep 2026 16:51:26 +0000</pubDate>
      <link>https://dev.to/googleai/elevating-antigravity-agent-skills-part-2-image-generation-2jno</link>
      <guid>https://dev.to/googleai/elevating-antigravity-agent-skills-part-2-image-generation-2jno</guid>
      <description>&lt;p&gt;By coupling native image generation directly with structured prompt synthesis, you turn your AI agent from a text generator into an image studio producing clean, consistent images grounded in developer specs.&lt;/p&gt;

&lt;p&gt;Here is what you will get out of this deep dive:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to use the &lt;code&gt;generate_image&lt;/code&gt; tool within agent skills.
&lt;/li&gt;
&lt;li&gt;Prompt tokenization strategies for consistent image generation.
&lt;/li&gt;
&lt;li&gt;Full breakdown of a real-world example skill you can use.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;BONUS:&lt;/strong&gt; Three visual asset anti-patterns to avoid in agentic workflows.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;📝 &lt;strong&gt;About this series:&lt;/strong&gt; Welcome to &lt;strong&gt;Elevating Antigravity Agent Skills&lt;/strong&gt; series, a 5-part engineering guide to mastering the agent tools that reduce orchestration tax and transform AI agents into autonomous collaborators: &lt;code&gt;ask_question&lt;/code&gt;, &lt;code&gt;generate_image&lt;/code&gt;, &lt;code&gt;define_subagent&lt;/code&gt; + &lt;code&gt;invoke_subagent&lt;/code&gt;, &lt;code&gt;send_message&lt;/code&gt; and &lt;code&gt;manage_subagents&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Beyond the grey
&lt;/h2&gt;

&lt;p&gt;Many of us building web applications, developer tools, or component libraries have used grey placeholder boxes while waiting for sample visual assets.&lt;/p&gt;

&lt;p&gt;This is where the &lt;a href="https://antigravity.google/docs/hooks?utm_campaign=CDR_0xc0d3ff05_awareness_b536569204&amp;amp;utm_medium=external&amp;amp;utm_source=blog#interaction-and-media" rel="noopener noreferrer"&gt;&lt;code&gt;generate_image&lt;/code&gt;&lt;/a&gt; tool comes in. When an Antigravity agent executes &lt;code&gt;generate_image&lt;/code&gt;, it synthesizes text prompts and visual parameters into images saved directly into the conversation artifact storage.&lt;/p&gt;

&lt;p&gt;Passing un-processed prompts without structure directly to &lt;code&gt;generate_image&lt;/code&gt; leads to inconsistency. By encoding lighting, camera, and scene specifications into your skill's prompt generator, your agent produces images that consistently match your intent.&lt;/p&gt;




&lt;h2&gt;
  
  
  Native artifact rendering and context storage
&lt;/h2&gt;

&lt;p&gt;Before diving into skill authoring, let's review how Antigravity manages generated media.&lt;/p&gt;

&lt;p&gt;When &lt;code&gt;generate_image&lt;/code&gt; runs, the system automatically saves the output asset to the conversation's internal artifacts directory (&lt;code&gt;&amp;lt;appDataDir&amp;gt;/brain/&amp;lt;conversation-id&amp;gt;/&lt;/code&gt;). The tool returns the absolute file path, allowing your skills to render the asset directly in chat responses using standard markdown syntax: &lt;code&gt;![Caption](file:///path/to/image.png)&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  A reference walkthrough of our image generation workflow
&lt;/h2&gt;

&lt;p&gt;To see this architecture in action, let's examine an example &lt;a href="https://github.com/GoogleCloudPlatform/devrel-demos/blob/main/elevating-antigravity/skills/generating-mock-images/SKILL.md" rel="noopener noreferrer"&gt;&lt;code&gt;generating-mock-images&lt;/code&gt;&lt;/a&gt; skill. Using a plant and flower e-commerce store as my example, this skill generates mock product assets, displays the resulting image for interactive review, and handles workspace asset persistence.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgw4uw6nd6itqwdpdhcsr.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgw4uw6nd6itqwdpdhcsr.jpg" alt="Mock photos of flowers" width="800" height="306"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 1: When we prompt "Create mock photo of white lilies." or "...Jasmine", or "...multi-colored roses", the &lt;code&gt;generating-mock-images&lt;/code&gt; skill is auto-discovered by the agent and read into context. The skill instructs the agent to follow the playbook we created.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.agents/skills/generating-mock-images/
├── SKILL.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1. Image prompt synthesis
&lt;/h3&gt;

&lt;p&gt;The skill pairs the selected product subject (user provided houseplant or floral arrangement) with hardcoded photography parameters detailed in the skill:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;### 1. Synthesize Prompt &amp;amp; Call `generate_image`&lt;/span&gt;
Construct the final image prompt by combining subject with photography specifications:
&lt;span class="gt"&gt;
&amp;gt; "Professional studio product photograph of [SUBJECT]. [SCENE: smooth matte light gray surface, seamless background curve with soft infinite horizon, visible water line in vase]. [CAMERA: macro lens photography, sharp focus from front to back, f/11 aperture, crisp details, zero digital noise]. [LIGHTING: three-point soft-diffuse lighting, 48-inch octagonal softbox key light at 45 degrees, gentle fill light, backlit soft ambient glow, no harsh glare, premium e-commerce product catalog style]."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Tool execution and artifact rendering
&lt;/h3&gt;

&lt;p&gt;Following the skill instructions, the agent automatically creates and issues a structured tool call to &lt;code&gt;generate_image&lt;/code&gt;. The following is a mock representation of what that structured tool call would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Prompt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Professional studio product photograph of elegant floral arrangement of fresh seasonal blooms in a clear glass vase filled with crystal-clear water. SCENE: smooth matte light gray surface, seamless background curve with soft infinite horizon. CAMERA: macro lens photography, sharp focus, f/11 aperture, crisp details, zero digital noise. LIGHTING: three-point soft-diffuse lighting, 48-inch octagonal softbox key light at 45 degrees, gentle fill light, backlit soft ambient glow, premium e-commerce catalog style."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ImageName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mock_flower_plant"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"AspectRatio"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1:1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"toolAction"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Generating floral arrangement mock product image"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"toolSummary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Generate mock flower product image"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note, not shown in this example but &lt;code&gt;generate_image&lt;/code&gt; natively supports visual composition. Passing up to three absolute file paths into the &lt;code&gt;ImagePaths&lt;/code&gt; array parameter instructs the agent to blend existing logos, background textures, or reference wireframes into composite graphics.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Upon receiving the generated image path from &lt;code&gt;generate_image&lt;/code&gt;, the agent renders the asset immediately in chat:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;![&lt;/span&gt;&lt;span class="nv"&gt;Mock Flower/Plant Product&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;file://&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;GENERATED_IMAGE_PATH&amp;gt;&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Interactive review loop via &lt;code&gt;ask_question&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;In my previous post, &lt;a href="https://www.linkedin.com/pulse/elevating-antigravity-agent-skills-interactive-ui-james-o-reilly-kz8fc/" rel="noopener noreferrer"&gt;Elevating Antigravity Agent skills with interactive UI workflows&lt;/a&gt;, I established how to convert passive agents into active interviewers using the &lt;code&gt;ask_question&lt;/code&gt; tool. By interrogating developers upfront, we eliminated prompt ambiguity.&lt;/p&gt;

&lt;p&gt;Rather than assuming the generated asset is immediately production-ready, the agent prompts the developer using &lt;code&gt;ask_question&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;Invoke &lt;span class="sb"&gt;`ask_question`&lt;/span&gt; tool:
&lt;span class="p"&gt;*&lt;/span&gt; Question: "What would you like to do with this generated mock image?"
&lt;span class="p"&gt;*&lt;/span&gt; Options: ["Keep", "Regenerate", "Exit"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Workspace lifecycle and asset persistence
&lt;/h3&gt;

&lt;p&gt;If the developer approves the asset, the agent copies the file from temporary artifact storage to &lt;code&gt;&amp;lt;workspace&amp;gt;/public/images/&amp;lt;image_filename&amp;gt;&lt;/code&gt; and returns a clickable markdown link:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;mock_flower_plant.png&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;file://&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;WORKSPACE_ROOT&amp;gt;&lt;/span&gt;/public/images/mock_flower_plant.png)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the developer chooses to delete or regenerate, the agent purges the temporary artifact to prevent uncurated asset accumulation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;If your agent dumps uncurated artifacts directly into production asset paths, you aren't automating design, you're automating visual tech debt.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🎁 Bonus: Three anti-patterns in agent visual asset generation (and beyond)
&lt;/h2&gt;

&lt;p&gt;As you integrate expensive tool calls, like &lt;code&gt;generate_image&lt;/code&gt; into automated developer workflows, observe these three rules to maintain consistency and efficiency:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Avoid raw prompt injection
&lt;/h3&gt;

&lt;p&gt;Avoid passing raw user inputs directly to &lt;code&gt;generate_image&lt;/code&gt;. Build a prompt generator inside your skill that injects specific parameters (such as scene, lighting, camera, and style preferences) to ensure deterministic outputs across runs.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Avoid broken links
&lt;/h3&gt;

&lt;p&gt;Use the absolute artifact path returned by &lt;code&gt;generate_image&lt;/code&gt; and move approved images to a permanent location. Storing assets in temporary directories (&lt;code&gt;/tmp&lt;/code&gt;) causes link decay when context windows clear or workspace sessions restart.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Avoid redundant calls
&lt;/h3&gt;

&lt;p&gt;Before triggering &lt;code&gt;generate_image&lt;/code&gt;, instruct your skill to check if a valid asset with the target &lt;code&gt;ImageName&lt;/code&gt; already exists. Re-running image generation without parameter changes wastes compute budget and slows down workflow execution.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Builder Challenge: Take this workflow further!
&lt;/h2&gt;

&lt;p&gt;Now that you have mastered parameterized image generation with &lt;code&gt;generate_image&lt;/code&gt;, here is an engineering challenge to take your visual asset skills to the next level:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build an Automated Multi-Aspect Ratio Asset Suite Generator.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Currently, our skill requires the user to include details in their prompt.&lt;/p&gt;

&lt;p&gt;Your challenge:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Extend your skill's prompt generator to accept target layout presets (e.g., &lt;code&gt;Hero Banner&lt;/code&gt;, &lt;code&gt;Product Card&lt;/code&gt;, &lt;code&gt;Mobile Thumbnail&lt;/code&gt;) or aspect ratios (e.g. &lt;code&gt;1:1&lt;/code&gt;, &lt;code&gt;2:1&lt;/code&gt;, &lt;code&gt;4:3&lt;/code&gt;, &lt;code&gt;16:9&lt;/code&gt;) using the &lt;code&gt;ask_question&lt;/code&gt; tool.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Extend your skill's prompt generator to use pre-made reference images passed into &lt;code&gt;generate_image&lt;/code&gt; using &lt;code&gt;ImagePaths&lt;/code&gt; param. You can include up to 3 images.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Did you attempt the challenge? &lt;strong&gt;Share your skill's strategy in the comments below!&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Static text descriptions and broken image icons belong to an earlier generation of developer tooling. By leveraging parameterized asset generation in &lt;code&gt;generate_image&lt;/code&gt;, you empower your agents to produce clean, consistent and visually grounded technical artifacts.&lt;/p&gt;

&lt;p&gt;Take 15 minutes today to audit your component scaffolding and asset generation skills.&lt;/p&gt;

&lt;h3&gt;
  
  
  📌 Elevating Antigravity Agent Skills Series Index
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Part 1:&lt;/strong&gt; &lt;a href="https://dev.to/googleai/elevating-antigravity-agent-skills-part-1-interactive-ui-workflows-6l2"&gt;Building interactive UI workflows with &lt;code&gt;ask_question&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Part 2:&lt;/strong&gt; &lt;strong&gt;Automating Image Generation with &lt;code&gt;generate_image&lt;/code&gt;&lt;/strong&gt; &lt;em&gt;(📍 You are here)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Part 3:&lt;/strong&gt; Invoking Subagents with &lt;code&gt;define_subagent&lt;/code&gt;, &lt;code&gt;invoke_subagent&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Part 4:&lt;/strong&gt; Inter-Agent Communication with &lt;code&gt;send_message&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Part 5:&lt;/strong&gt; Managing Active Agent Lifecycles with &lt;code&gt;manage_subagents&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Additional resources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tool Reference:&lt;/strong&gt; &lt;a href="https://antigravity.google/docs/hooks#interaction-and-media" rel="noopener noreferrer"&gt;List of supported Antigravity tools&lt;/a&gt;&amp;nbsp;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example Source&lt;/strong&gt;: &lt;a href="https://github.com/GoogleCloudPlatform/devrel-demos/tree/main/agents/elevating-antigravity" rel="noopener noreferrer"&gt;source code&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Help others find this post
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Save&lt;/strong&gt; this post to find it later.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subscribe&lt;/strong&gt; to my &lt;a href="https://www.linkedin.com/newsletters/the-agentic-developer-7488602281148526592/" rel="noopener noreferrer"&gt;newsletter&lt;/a&gt; and don't miss an article.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Share&lt;/strong&gt; this article across social media.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Follow me&lt;/strong&gt; on &lt;a href="https://www.linkedin.com/in/jamesor/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; or &lt;a href="https://x.com/JamesOR" rel="noopener noreferrer"&gt;X&lt;/a&gt; for more agentic engineering insights.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agentskills</category>
      <category>antigravity</category>
    </item>
    <item>
      <title>How to Design AI Evaluations You Can Actually Trust</title>
      <dc:creator>Jan-Felix Schmakeit</dc:creator>
      <pubDate>Tue, 01 Sep 2026 16:35:00 +0000</pubDate>
      <link>https://dev.to/googleai/how-to-design-ai-evaluations-you-can-actually-trust-41c3</link>
      <guid>https://dev.to/googleai/how-to-design-ai-evaluations-you-can-actually-trust-41c3</guid>
      <description>&lt;p&gt;As part of my work at Google, we are publishing a suite of &lt;a href="https://github.com/google/skills" rel="noopener noreferrer"&gt;Agent Skills for Google products and technologies on GitHub&lt;/a&gt;. These &lt;a href="https://agentskills.io/home" rel="noopener noreferrer"&gt;agent skills&lt;/a&gt; are designed to help AI agents interact with our technologies. But how do you test that these skills are useful and work as expected? My team in Developer Relations has been focused on this question, because having reliable signals on their performance is critical to help us improve them over time.&lt;/p&gt;

&lt;p&gt;Just as you wouldn't deploy a production API without writing unit tests, you should apply the same standard to your AI agents. As Joe Spiro showed in the &lt;a href="https://dev.to/googleai/designing-ai-evals-clarity-now-and-visualization-next-4eii"&gt;&lt;em&gt;Designing AI Evals&lt;/em&gt;&lt;/a&gt; post series, scaling AI tools means moving beyond "vibe testing" in a terminal. Instead, you should set up a structured, automated evaluation pipeline to benchmark your integration. The evaluations (evals) are the &lt;em&gt;actions&lt;/em&gt; you asked the agent to perform, which are graded using scorers (for example rubrics) that &lt;em&gt;assert&lt;/em&gt; whether the agent succeeded. We'll focus on evaluations in this post and tackle tips for scoring rubrics in the next post.&lt;/p&gt;

&lt;p&gt;However, AI evaluations cost real tokens. You need to make sure that you use these tokens as efficiently as possible. They need to provide real value that helps you build better tools. Writing good evaluations is critical. Poor evaluations provide false signals, waste your token budget, and create noise in your metrics.&lt;/p&gt;

&lt;p&gt;Here are five rules we learned to design better evaluations you can trust. Follow them to ensure that every token you spend produces a useful metric.&lt;/p&gt;

&lt;h2&gt;
  
  
  Know Your Evaluation Environment
&lt;/h2&gt;

&lt;p&gt;Before writing evaluations, you need to understand the setup and limitations of your chosen framework. This includes systems like Harbor, Inspect AI, or integrations in development tools like in the &lt;a href="https://docs.cloud.google.com/gemini-enterprise-agent-platform/optimize/evaluation/agent-evaluation" rel="noopener noreferrer"&gt;Agent Development Kit&lt;/a&gt;. Does it use an ephemeral sandbox? What tools are available? How is the output captured&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tailor your graders to the environment:&lt;/strong&gt; For example, if you can deterministically access the sandbox to evaluate code, that's an option. Alternatively, ask the agent to print its response to the console. Your framework can capture this output and pass it directly to your scorers. Adjust your grader to handle these environments.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Be aware of dependency limitations and access to "real" resources:&lt;/strong&gt; If an evaluation task requires access to "real" resources (for example an authenticated &lt;code&gt;gcloud&lt;/code&gt; session with access to a Google Cloud project), create ephemeral resources or credentials that isolate and limit access so they don't impact other evaluations. Alternatively, you could provide mock tools instead of real test credentials.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evaluate plans instead of tasks that are difficult to isolate:&lt;/strong&gt; An easier approach might be to evaluate the &lt;em&gt;plan&lt;/em&gt; to accomplish the task, rather than the actual execution.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avoid interactive prompts:&lt;/strong&gt; Multi-turn agent sessions are complex to evaluate. When getting started, design your evaluations using one-shot prompts.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Avoid the Ceiling Effect
&lt;/h2&gt;

&lt;p&gt;If your evaluations show a high baseline accuracy (i.e., without your agent tool), it might not prove its value, or the evaluation prompts are too easy.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Write harder prompts:&lt;/strong&gt; You cannot measure the impact of a new agent tool or skill if the baseline model already knows the answer.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Require multi-step reasoning:&lt;/strong&gt; Design prompts that reflect complex, real-world use cases where your tool can actually differentiate itself from the model's pre-training.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Revisit the scope of your tool:&lt;/strong&gt; If tests are repeatedly reporting a high accuracy without using your tool, it might be time to revisit it. The underlying model and agent may have improved and are able to accomplish the task without additional help. It might be time to refocus or deprecate your tool.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Prompt-Grader Mismatch
&lt;/h2&gt;

&lt;p&gt;You cannot grade an agent on something you did not explicitly ask it to do. Your evaluation prompts and graders should be complementary. This means that they should only test for things included in the prompt.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Avoid scope creep:&lt;/strong&gt; If you asked a broad question, you can expect a similarly broad response. For example, if your prompt is &lt;em&gt;"How do I secure Google Cloud Run?"&lt;/em&gt;, your grader cannot penalize the agent for missing a specific, unprompted IAM role.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Be explicit:&lt;/strong&gt; If you want to evaluate specific knowledge or exact implementation details, you must state those requirements clearly in the prompt.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Grade the Destination, Not the Journey
&lt;/h2&gt;

&lt;p&gt;Agents possess inherent model knowledge and might skip your custom tools entirely to arrive at the correct answer. (That on its own is some useful feedback!)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Do not evaluate the trajectory:&lt;/strong&gt; Avoid writing graders that check if the agent used a specific &lt;code&gt;help&lt;/code&gt; command or followed a rigid sequence of steps.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evaluate the final answer:&lt;/strong&gt; Grade the objective output. If you absolutely must evaluate the agent's planning phase, explicitly ask it to output a detailed execution plan and evaluate the plan instead.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Curate Your Evaluation Dataset
&lt;/h2&gt;

&lt;p&gt;A strong evaluation suite tests real, diverse use cases. But testing the same capability repeatedly causes overfitting and creates noisy metrics.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Use real-world examples:&lt;/strong&gt; Evaluations should include real user journeys and focus on goals users want to achieve. Consider including additional context, such as sanitized sample data, to ground the evaluations.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maximize your signal:&lt;/strong&gt; Ensure every prompt in your evaluation suite tests a distinct concept or unique capability. Think of this like code coverage for traditional tests.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Remove overlap:&lt;/strong&gt; Consolidate redundant prompts. A smaller, more curated data set provides clearer metrics, prevents overfitting and saves tokens.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;You cannot improve AI tools if you can't measure them accurately. If you treat AI evaluations with the same focus as traditional unit tests, you improve the quality of your metrics and get more robust signals.&lt;/p&gt;

&lt;p&gt;By applying these five rules, you eliminate false signals that waste your token budget. Instead of generating noise, your test suite gives you actionable feedback you can use to guide your engineering decisions and improve your tools.&lt;/p&gt;

&lt;p&gt;Figuring out what to test is only the first step. A well-designed evaluation is only useful if the scorer grading answers is reliable and returns meaningful results. In my next post, we will look at how to test. You will learn how to write lean, atomic rubrics that minimize ambiguity for an LLM grader and make every token count.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Photo by &lt;a href="https://unsplash.com/@wwarby" rel="noopener noreferrer"&gt;William Warby&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/gray-and-yellow-measures-WahfNoqbYnM" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>evals</category>
    </item>
    <item>
      <title>Step up to the Sheets: AI Eval Export and Illustrating Data</title>
      <dc:creator>Katie McLaughlin</dc:creator>
      <pubDate>Tue, 01 Sep 2026 07:00:00 +0000</pubDate>
      <link>https://dev.to/googleai/step-up-to-the-sheets-ai-eval-export-and-illustrating-data-bak</link>
      <guid>https://dev.to/googleai/step-up-to-the-sheets-ai-eval-export-and-illustrating-data-bak</guid>
      <description>&lt;p&gt;Welcome to part three of our series about designing, analyzing and visualizing AI Evals! As with the previous entries you are more than welcome to simply read over my exploration or for those of you looking for extra credit, feel free to play along at home.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: This blog series contains AI-generated diagrams alongside actual screenshots and hand-drawn edits of both. AI also assisted in minor copy editing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Implementation prerequisites
&lt;/h2&gt;

&lt;p&gt;If you intend to (re)implement the walkthrough, all you need to do right now is complete Part 1 (&lt;a href="https://dev.to/googleai/designing-ai-evals-clarity-now-and-visualization-next-4eii"&gt;Designing AI Evals: Clarity Now and Visualization Next&lt;/a&gt;) and then install &lt;code&gt;pandas&lt;/code&gt;; Part 2 (&lt;a href="https://dev.to/googleai/ai-evals-at-a-glance-heatmaps-for-stakeholders-2mki"&gt;AI Evals at a Glance: Heatmaps for Stakeholders&lt;/a&gt;) is illustrative and will give you a deeper understanding going forward both of AI evals and why the following may be useful but it’s more elective than anything else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Back to the story at hand
&lt;/h2&gt;

&lt;p&gt;While engineering teams might evaluate agents using test automations, non-technical stakeholders (product managers, business leads, or executive sponsors) often use spreadsheets as their lingua franca and as such it would make sense to speak to them in a way they are almost certain to understand and which enables you all to collaboratively make visualizations to further get out the word.&lt;/p&gt;

&lt;p&gt;To make this a reality, today we’ll use a &lt;code&gt;pandas&lt;/code&gt; pipeline that transforms raw Inspect AI evaluation logs into a rich CSV optimized for Google Sheets, allowing you or anyone on your team with a little spreadsheet knowledge to make boardroom-ready visuals.&lt;/p&gt;

&lt;p&gt;Drawing again from previous blog entries, the evals we are working on have three dimensions: model x skill x sample [and epoch] that cross to form the following matrix:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fosimtffx3o7lgyyj1jc2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fosimtffx3o7lgyyj1jc2.png" alt="A 3D grid matrix visualizing evaluation conditions: Models on the vertical axis, Skill Conditions on the depth axis, and Samples on the horizontal axis. A callout box shows a grader model evaluating four facts, resulting in a score on a meter." width="800" height="769"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://dev.to/googleai/ai-evals-at-a-glance-heatmaps-for-stakeholders-2mki"&gt;Part 2&lt;/a&gt; we created a simplified heatmap reflecting a planar slice of this space as reduced over the sample dimension. While we will ultimately do something similar in a future blog post using Data Studio, for the time being we actually want to keep all 32 combinations separate and pull more of their underlying stats from the &lt;code&gt;inspect eval&lt;/code&gt; files and derive further information using &lt;code&gt;pandas&lt;/code&gt;. This information will be exported as a flat csv file we can then import and view in Google Sheets.&lt;/p&gt;

&lt;h2&gt;
  
  
  The extractor &lt;a href="https://github.com/GoogleCloudPlatform/devrel-demos/blob/main/agents/inspect-agent-skills-eval/tocsv.py" rel="noopener noreferrer"&gt;&lt;code&gt;tocsv.py&lt;/code&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;This script is used to parse the eval logs using &lt;code&gt;Inspect AI&lt;/code&gt;’s python &lt;code&gt;pandas&lt;/code&gt; interface. The script is relatively self documenting, and you can &lt;a href="https://pandas.pydata.org/docs/user_guide/10min.html" rel="noopener noreferrer"&gt;read up more on pandas&lt;/a&gt; and &lt;a href="https://pandas.pydata.org/docs/user_guide/io.html#" rel="noopener noreferrer"&gt;pandas’ csv IO&lt;/a&gt; if you are unfamiliar.&lt;/p&gt;

&lt;h3&gt;
  
  
  Heavy lifting in Python: Custom telemetry columns
&lt;/h3&gt;

&lt;p&gt;While most of the script deals with mapping scalar metrics the like of which we’ve already discussed, there are two that are purely logical/boolean. They represent specific statistical cases that we will allow end users to partition the data set over for analysis later. These boolean conditions are derived and since we want to pare away excess information and therefore not supply the full eval files to Google Sheets, &lt;code&gt;tocsv.py&lt;/code&gt; does the heavy lifting upstream during log ingestion.&lt;/p&gt;

&lt;p&gt;It pre-computes two key boolean columns to simplify downstream dashboard filtering:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;completed&lt;/code&gt;&lt;/strong&gt;: Flags whether a sample finished cleanly (no API quota 429 errors, timeout truncations, or container crashes) with a valid score, cleanly isolating model capability from infrastructure noise.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;is_baseline_or_has_activated_skill&lt;/code&gt;&lt;/strong&gt;: Distinguishes &lt;strong&gt;Baseline control cohorts&lt;/strong&gt; (always &lt;code&gt;TRUE&lt;/code&gt;) and &lt;strong&gt;Active Skill interventions&lt;/strong&gt; (&lt;code&gt;TRUE&lt;/code&gt; when the skill tool was actually “activated” which in &lt;code&gt;inspect&lt;/code&gt; means uptaken) from &lt;strong&gt;Dormant runs&lt;/strong&gt; (&lt;code&gt;FALSE&lt;/code&gt;, where skills were available but never activated).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In Google Sheets or Data Studio non-technical stakeholders can simply filter/toggle these pre-computed boolean keys to isolate clean, active performance (or otherwise) instantly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exporting to Google Sheets
&lt;/h2&gt;

&lt;p&gt;In order to execute the pipeline I called:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 tocsv.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output file &lt;code&gt;data_mega_export.csv&lt;/code&gt; is a standard comma-separated values file where each cell is surrounded by commas. You can preview the raw and unformatted contents in a standard text editor. While most of this is normal spreadsheet data such as strings and integers, you will also see fairly complicated Google Sheets formulas resulting from interpolating eval metrics into formula templates.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnvzqm5o95s8ac43ups37.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnvzqm5o95s8ac43ups37.png" alt="A screenshot showing raw text lines of a CSV export, highlighting a complex Google Sheets formula involving SPARKLINE and PERCENTILE functions used to generate dynamic bar charts in the sheet." width="800" height="245"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The above formula for instance will be transformed into a bar graph normalized against the range of values in the same column as its source data and tiered into colors by tertile. &lt;/p&gt;

&lt;p&gt;How do you take this text and get it to show its stuff? By opening &lt;a href="https://sheets.new" rel="noopener noreferrer"&gt;sheets.new&lt;/a&gt; of course, and importing &lt;code&gt;data_mega_export.csv&lt;/code&gt;. When presented with the import dialog check &lt;strong&gt;Convert text to numbers, dates, and formulas&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr2m83vhwiinwg0cvcbqg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr2m83vhwiinwg0cvcbqg.png" alt="A screenshot of the Google Sheets Import file dialog for data\_mega\_export.csv, with the checkbox " width="799" height="532"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On clicking &lt;strong&gt;Import data&lt;/strong&gt; Google Sheets will instantly display the standard cells and render active, color-coded visual sparklines directly inside data cells!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8y9jhes042pv9emzwddo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8y9jhes042pv9emzwddo.png" alt="A screenshot of the imported data in Google Sheets, displaying columns like model, skill\_group, score, and latency, with inline yellow and green sparkline bar charts rendering directly inside the cells." width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What conclusions can you draw from what you see? One obvious one in this example is that the correlation between score and latency (how long an agent takes to answer a question) may not be very strict. But what if you wanted to get something deeper?&lt;/p&gt;

&lt;p&gt;Well, since this is a spreadsheet, obviously you can make pivot tables, and custom functions or sort on multiple keys… you know, the whole accountant’s playbook. Let’s say though that you want custom views into the data rather than to permanently mutate it. How would you go about doing that? &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgkanon14o38dtgmkh2os.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgkanon14o38dtgmkh2os.png" alt="A screenshot of the Google Sheets top menu under " width="788" height="594"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Google Sheets, unlike &lt;code&gt;inspect view&lt;/code&gt; and &lt;code&gt;inspect viz&lt;/code&gt; heatmaps, allows you to dynamically sort AND filter on more than one key. Not only that but you can sort on ANY key, so I elected to do so with the previously unavailable &lt;code&gt;score&lt;/code&gt; and &lt;code&gt;latency&lt;/code&gt; fields. As shown in the image above, use &lt;strong&gt;Data&lt;/strong&gt; &amp;gt; &lt;strong&gt;Create filter view&lt;/strong&gt; which presents you with a new set of controls at the top of the main columns.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Filter views do not mutate or change the underlying contents of a sheet; Instead they are (optionally named and shareable) configurations for restricting what rows are displayed and in what order.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxbjv901ugvtpwkkyroui.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxbjv901ugvtpwkkyroui.png" alt="A screenshot showing an active " width="799" height="285"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If, as in the picture, you click the &lt;code&gt;cost&lt;/code&gt; column &amp;gt; &lt;strong&gt;Filter by condition&lt;/strong&gt;, select the  &lt;strong&gt;Less than&lt;/strong&gt; option and fill the comparison with 0.01, you can narrow the displayed rows to only those with costs less than a cent. This can be used (for instance) to only look over the samples that were “less costly” to try to analyze why.&lt;/p&gt;

&lt;p&gt;Filter views (despite their name) also allow you to sort the display of the data. Because the sort operations are cumulative, the “primary” filter needs to be applied last. Thus, after sorting the filter view first by &lt;strong&gt;latency&lt;/strong&gt; and then by &lt;strong&gt;score&lt;/strong&gt; (both ‘Z to A’ aka decreasing) gives us the following: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fddq6a27tij7c9cozbfdj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fddq6a27tij7c9cozbfdj.png" alt="A screenshot of " width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Optionally you can name and save this filter view to toggle it on and off as well as share it with other collaborators. To learn more about Filter views, you can read &lt;a href="https://support.google.com/docs/answer/3540681?hl=en&amp;amp;co=GENIE.Platform%3DDesktop" rel="noopener noreferrer"&gt;Sort &amp;amp; filter your data&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;This ability to sort and filter the display live without changing the underlying information, makes presenting the data and analyzing it during discussions with teammates significantly easier and faster.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why leave the cradle?
&lt;/h3&gt;

&lt;p&gt;Now, in spite of this tremendous flexibility, sheets have some drawbacks as visualization tools:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Spreadsheet formulas are cumbersome for nested IF statements and filters unless you define custom macros or JavaScript functions leading to code that's harder and harder to keep connected in one's mental model.
&lt;/li&gt;
&lt;li&gt;Flattened eval runs need to be inspected under multiple filter views to begin to understand complex trends or correlations across all of them.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So, how can we take this to the next level and circumvent those issues? What about an environment, which while it still offers you the ability to custom script anything you need, comes with a lot of WYSIWYG controllable visualizations and graphs, enabling you, without code, to bring data to an even more vibrant life? Better yet, what if that environment comes with built in visualizations for 3 dimensions or more and has broad compatibility with multiple data source types?&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;Part 4&lt;/strong&gt;, we’ll connect this Google Sheet directly to Data Studio to build a codeless executive summary dashboard and be able to quickly and intuitively display our findings! &lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>datascience</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Stop Wrestling with ASR: The Complete Guide to Gemini 3.5 Transcribe 🎙️</title>
      <dc:creator>Guillaume Vernade</dc:creator>
      <pubDate>Fri, 28 Aug 2026 13:34:29 +0000</pubDate>
      <link>https://dev.to/googleai/stop-wrestling-with-asr-the-complete-guide-to-gemini-35-transcribe-1m6i</link>
      <guid>https://dev.to/googleai/stop-wrestling-with-asr-the-complete-guide-to-gemini-35-transcribe-1m6i</guid>
      <description>&lt;p&gt;You’ve probably used Gemini to analyze hours of video, summarize podcasts, or answer questions from recorded meetings (if you didn't you should, it's extremely useful!). But when all you need is a clean, hyper-accurate, and structured transcript from audio, spinning up a huge reasoning model with complicated prompts often feels like using a sledgehammer to crack a nut.&lt;/p&gt;

&lt;p&gt;Enter &lt;strong&gt;Gemini 3.5 Transcribe&lt;/strong&gt; (&lt;code&gt;gemini-3.5-transcribe&lt;/code&gt;). &lt;/p&gt;

&lt;p&gt;It's Google's dedicated speech-to-text model built on Gemini's audio understanding core, optimized specifically for fast, accurate, and cost-effective transcription. Whether you want an exact court-reporter transcript with millisecond timestamps, or a reading-optimized summary that removes all your awkward &lt;em&gt;"ums"&lt;/em&gt; and &lt;em&gt;"uhs"&lt;/em&gt;, this model handles it natively with zero prompt gymnastics.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🚀 &lt;strong&gt;Hands-on first:&lt;/strong&gt; If you want to jump straight into running the code yourself, open the interactive &lt;a href="https://colab.research.google.com/github/google-gemini/cookbook/blob/main/quickstarts/Get_started_transcribe.ipynb" rel="noopener noreferrer"&gt;&lt;strong&gt;Gemini Transcribe Colab notebook&lt;/strong&gt;&lt;/a&gt;! It's ready to run so you can dirrectly experience how the model work.&lt;br&gt;&lt;br&gt;
Prefer a visual UI with zero coding? You can also test speech recognition directly in &lt;a href="https://aistudio.google.com/prompts/new_chat?model=gemini-3.5-transcribe" rel="noopener noreferrer"&gt;&lt;strong&gt;Google AI Studio&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Here's what you'll find in this guide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;0. Why a Dedicated Transcription Model? (Audio Understanding vs. Transcribe)&lt;/li&gt;
&lt;li&gt;1. Setup &amp;amp; The Files API&lt;/li&gt;
&lt;li&gt;2. Steer Languages &amp;amp; Code-Switching (85+ Locales)&lt;/li&gt;
&lt;li&gt;3. Custom Vocabulary: Never Misspell Technical Jargon Again&lt;/li&gt;
&lt;li&gt;4. The Killer Feature: Smart Transcription vs. Verbatim Mode&lt;/li&gt;
&lt;li&gt;5. Speaker Diarization: Who Said What?&lt;/li&gt;
&lt;li&gt;6. Word-Level Timestamps: Precise Time Offsets for Every Spoken Word&lt;/li&gt;
&lt;li&gt;7. Decision Matrix: Which Configuration Should You Use?&lt;/li&gt;
&lt;li&gt;8. What About Real-Time Live Streaming?&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  0. Why a Dedicated Transcription Model?
&lt;/h2&gt;

&lt;p&gt;Before looking at the code, let's get the mental model straight. You might wonder: &lt;em&gt;"Can't I just upload an MP3 to Gemini 3.7 and say 'Transcribe this'?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You can, but here is why &lt;code&gt;gemini-3.5-transcribe&lt;/code&gt; is different:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;General Audio Understanding (e.g. Gemini 3.7)&lt;/th&gt;
&lt;th&gt;Dedicated Transcribe (&lt;code&gt;gemini-3.5-transcribe&lt;/code&gt;)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Primary Job&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Reasoning, Q&amp;amp;A, sentiment analysis, audio chat&lt;/td&gt;
&lt;td&gt;High-throughput, precise speech-to-text&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Speaker Diarization&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Prompt-dependent (can hallucinate turns)&lt;/td&gt;
&lt;td&gt;Native segment labeling (&lt;code&gt;spk:0&lt;/code&gt;, &lt;code&gt;spk:1&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Timestamps&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Approximate timecodes via text prompt&lt;/td&gt;
&lt;td&gt;True word-level millisecond offsets in metadata&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Vocabulary Biasing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;System prompt instructions&lt;/td&gt;
&lt;td&gt;Native acoustic biasing dictionary (up to 1,000 terms)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost &amp;amp; Latency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Full multimodal LLM generation overhead&lt;/td&gt;
&lt;td&gt;Optimized lightweight speech pipeline&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pro tip:&lt;/strong&gt; If you need to &lt;em&gt;ask questions&lt;/em&gt; about what happened in an audio file ("What was the action item for Alice?"), use a multimodal model like Gemini 3.7. If you need the &lt;em&gt;transcript itself&lt;/em&gt;, subtitles, or cleaned dictation notes, use Gemini Transcribe!&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  1. Setup &amp;amp; The Files API
&lt;/h2&gt;

&lt;p&gt;The Gemini 3.5 Transcribe model runs on the modern &lt;strong&gt;Google GenAI SDK&lt;/strong&gt; (&lt;code&gt;google-genai&lt;/code&gt; v2.0+) using the &lt;a href="https://ai.google.dev/gemini-api/docs/interactions-overview" rel="noopener noreferrer"&gt;Interactions API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First, install the SDK:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-U&lt;/span&gt; &lt;span class="s2"&gt;"google-genai&amp;gt;=2.0.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure you have an API key from &lt;a href="https://aistudio.google.com/app/apikey" rel="noopener noreferrer"&gt;Google AI Studio&lt;/a&gt;, set it as &lt;code&gt;GEMINI_API_KEY&lt;/code&gt;, and let's look at how audio gets passed to the model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;genai&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;genai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# 1. Upload your audio file via the Files API
&lt;/span&gt;&lt;span class="n"&gt;audio_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;meeting_recap.mp3&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 2. Request transcription using the uploaded file's URI
&lt;/span&gt;&lt;span class="n"&gt;interaction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;interactions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemini-3.5-transcribe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;audio&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;uri&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;audio_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;interaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Watch the demo video below to see the baseline transcription in action—handling natural speech and bilingual code-switching with ease:&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/I-leFQpz-j0" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Why use the Files API?
&lt;/h3&gt;

&lt;p&gt;When dealing with audio and video, you never want to inline raw audio bytes as base64 in your API requests—it blows up the payload size by 33%, easily hits network timeouts, and requires re-uploading the same bytes if you want to rerun a query.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;&lt;a href="https://colab.research.google.com/github/google-gemini/cookbook/blob/main/quickstarts/File_API.ipynb" rel="noopener noreferrer"&gt;Files API&lt;/a&gt;&lt;/strong&gt; solves this cleanly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Large file support&lt;/strong&gt;: Upload audio and video files up to &lt;strong&gt;2 GB per file&lt;/strong&gt; (with 20 GB of total project storage).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Temporary lifecycle&lt;/strong&gt;: Files are stored for &lt;strong&gt;48 hours&lt;/strong&gt; and automatically cleaned up afterwards.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It's completely free!&lt;/strong&gt; Storage and uploads in the Files API incur zero additional cost—you only pay for token processing when you actually run inference against the model.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Steer Languages &amp;amp; Code-Switching (85+ Locales)
&lt;/h2&gt;

&lt;p&gt;As you saw in the video above, Gemini Transcribe automatically identifies spoken languages out of the box and seamlessly handles &lt;strong&gt;code-switching&lt;/strong&gt; (when someone mixes multiple languages in the same sentence—like switching between French and English mid-sentence, which happens to me all the time!).&lt;/p&gt;

&lt;p&gt;However, if you know your audio is exclusively in a specific language or regional dialect, you can pass explicit &lt;strong&gt;BCP-47 language codes&lt;/strong&gt; in &lt;code&gt;transcription_config&lt;/code&gt; to bias recognition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;interaction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;interactions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemini-3.5-transcribe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;audio&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;uri&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;spanish_audio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="n"&gt;generation_config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transcription_config&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;# Explicit language hint
&lt;/span&gt;            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;language_codes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;es-ES&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;interaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Leaving &lt;code&gt;language_codes=[]&lt;/code&gt; (or omitting it) enables full automatic detection across &lt;a href="https://ai.google.dev/gemini-api/docs/transcribe#supported-languages" rel="noopener noreferrer"&gt;85+ supported languages and locales&lt;/a&gt;. Check out the &lt;a href="https://ai.google.dev/gemini-api/docs/transcribe" rel="noopener noreferrer"&gt;Audio Transcription Documentation&lt;/a&gt; for the complete list of language codes.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  3. Custom Vocabulary: Never Misspell Technical Jargon Again
&lt;/h2&gt;

&lt;p&gt;Every developer has suffered from an ASR model mangling proper names, confusing specialized libraries with everyday dictionary words (turning &lt;em&gt;"ScaNN"&lt;/em&gt; into &lt;em&gt;"scan"&lt;/em&gt;, or &lt;em&gt;"Qdrant"&lt;/em&gt; into &lt;em&gt;"quadrant"&lt;/em&gt;), or inventing phonetically similar terms (&lt;em&gt;"Sitsi"&lt;/em&gt; instead of &lt;em&gt;"CitC"&lt;/em&gt;, &lt;em&gt;"Thiago"&lt;/em&gt; instead of &lt;em&gt;"Tiago"&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;custom_vocabulary&lt;/code&gt;, you can pass a list of up to &lt;strong&gt;1,000 domain-specific terms&lt;/strong&gt; that the model will bias towards:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;interaction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;interactions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemini-3.5-transcribe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;audio&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;uri&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;team_briefing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="n"&gt;generation_config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transcription_config&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;custom_vocabulary&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Guillaume Vernade&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ScaNN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Qdrant&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Cilium&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Weaviate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Milvus&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Buganizer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Tiago&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CitC&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;spaCy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;interaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Watch the side-by-side comparison video below to see how the model behaves with and without custom vocabulary biasing:&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/fsRINjkzDxw" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Without Custom Vocabulary (Default ASR)&lt;/th&gt;
&lt;th&gt;With &lt;code&gt;custom_vocabulary&lt;/code&gt; (100% Precision)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;em&gt;"For our vector benchmarks, sync with Guillaume **Vernat&lt;/em&gt;* in Paris to compare &lt;strong&gt;Scan&lt;/strong&gt; against &lt;strong&gt;Quadrant&lt;/strong&gt; while &lt;strong&gt;Syllium&lt;/strong&gt; handles the traffic."*&lt;/td&gt;
&lt;td&gt;
&lt;em&gt;"For our vector benchmarks, sync with Guillaume **Vernade&lt;/em&gt;* in Paris to compare &lt;strong&gt;ScaNN&lt;/strong&gt; against &lt;strong&gt;Qdrant&lt;/strong&gt; while &lt;strong&gt;Cilium&lt;/strong&gt; handles the traffic."*&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;em&gt;"We also need to evaluate Weaviate against Milvus, assign the buganizer ticket to **Thiago&lt;/em&gt;&lt;em&gt;, and test the changes in **Sitsi&lt;/em&gt;* before submitting the CL."*&lt;/td&gt;
&lt;td&gt;
&lt;em&gt;"We also need to evaluate Weaviate against Milvus, assign the Buganizer ticket to **Tiago&lt;/em&gt;&lt;em&gt;, and test the changes in **CitC&lt;/em&gt;* before submitting the CL."*&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;em&gt;"Finally, run a quick smoke test with **Spacey&lt;/em&gt;* to validate the tokenization pipeline before deploying."*&lt;/td&gt;
&lt;td&gt;
&lt;em&gt;"Finally, run a quick smoke test with **spaCy&lt;/em&gt;* to validate the tokenization pipeline before deploying."*&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Notice how default speech recognition falls back to phonetic dictionary guesses (&lt;strong&gt;Vernat&lt;/strong&gt;, &lt;strong&gt;Scan&lt;/strong&gt;, &lt;strong&gt;Quadrant&lt;/strong&gt;, &lt;strong&gt;Syllium&lt;/strong&gt;, &lt;strong&gt;Thiago&lt;/strong&gt;, &lt;strong&gt;Sitsi&lt;/strong&gt;, &lt;strong&gt;Spacey&lt;/strong&gt;). By contrast, supplying &lt;code&gt;custom_vocabulary&lt;/code&gt; guarantees that names of team members, niche tools, internal infrastructure, and open-source libraries are transcribed with 100% precision.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pro tip:&lt;/strong&gt; Don't just put acronyms in your custom vocabulary. Add proper names of team members, internal service codenames, GitHub repo handles, product brand names, and niche industry terminology.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  4. The Killer Feature: Smart Transcription vs. Verbatim Mode
&lt;/h2&gt;

&lt;p&gt;This is hands down my favorite capability of Gemini 3.5 Transcribe. &lt;/p&gt;

&lt;p&gt;By default, speech-to-text models operate in &lt;strong&gt;&lt;code&gt;verbatim&lt;/code&gt;&lt;/strong&gt; mode: they write down &lt;em&gt;everything&lt;/em&gt;, including every nervous stutter, throat clear, false start, and verbal tick.&lt;/p&gt;

&lt;p&gt;When you're transcribing a speech rehearsal, interview, or voice memo, reading raw verbatim text is painful:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--- Verbatim output ---
"Uh, hello. Good evening, everyone. Um, I'd like to start by, well, first of all, thank you all for coming. Today is, um, a very special day, or rather, evening? No, afternoon? Right, evening. We are here to celebrate, uh, sorry, let me just find my notes. Ah, here. We are here to honor, no, not honor, but, um, to mark the launch of our new, sorry, my glasses are a bit foggy, the new marketing campaign. No, wait, product campaign? Product, yes. Um, where was I? Ah, yes. It has been a long journey, a very, uh, challenging, well, not challenging in a bad way, but, you know, difficult? No, rewarding. Rewarding is the word. So, um, yes, cheers to, wait, we don't have glasses yet. Thank you."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you switch &lt;code&gt;mode={"type": "smart"}&lt;/code&gt;, the model performs intelligent reading optimization:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Disfluency removal&lt;/strong&gt;: Strips conversational filler words (&lt;em&gt;"um"&lt;/em&gt;, &lt;em&gt;"uh"&lt;/em&gt;, &lt;em&gt;"you know"&lt;/em&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inline self-corrections&lt;/strong&gt;: Automatically resolves verbal slip-ups (&lt;em&gt;"Tuesday, wait no, Wednesday"&lt;/em&gt; $\rightarrow$ &lt;em&gt;"Wednesday"&lt;/em&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structured formatting&lt;/strong&gt;: Formats lists, bullet points, numbers, currencies ($26M), and natural paragraphs.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is how you turn it on:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;interaction_smart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;interactions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemini-3.5-transcribe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;audio&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;uri&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;audio_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="n"&gt;generation_config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transcription_config&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;smart&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;interaction_smart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look at the cleaned result on that exact same rehearsal audio:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--- Smart transcription output ---
Good evening everyone. First of all, thank you all for coming. Today is a very special evening. We are here to mark the launch of our new product campaign.

It has been a long journey, a very rewarding one. So, cheers to that.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Watch the side-by-side comparison video below to see how the raw disfluencies are stripped while listening:&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/I-leFQpz-j0" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(If the video doesn't load, you can &lt;a href="https://storage.googleapis.com/generativeai-downloads/audio/rehearsing.wav" rel="noopener noreferrer"&gt;listen to rehearsing.wav directly&lt;/a&gt;.)&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important caveat:&lt;/strong&gt; Because Smart transcription uses language modeling to clean up disfluencies and structure the output, &lt;strong&gt;it might slightly rewrite, omit, or rephrase parts of what was said&lt;/strong&gt; to make it sound natural and concise. If you are doing verbatim court reporting, medical transcription, or subtitle syncing where every exact syllable matters, stick with &lt;code&gt;verbatim&lt;/code&gt; mode!&lt;/p&gt;

&lt;p&gt;Also note that Smart mode is &lt;strong&gt;incompatible with word-level timestamps and speaker diarization&lt;/strong&gt; (which require &lt;code&gt;{"type": "verbatim"}&lt;/code&gt;).&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  5. Speaker Diarization: Who Said What?
&lt;/h2&gt;

&lt;p&gt;Need to know who spoke during a multi-person meeting or podcast? Enable &lt;strong&gt;diarization&lt;/strong&gt; with &lt;code&gt;diarization_mode="speaker"&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;interaction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;interactions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemini-3.5-transcribe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;audio&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;uri&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;meeting_audio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="n"&gt;generation_config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transcription_config&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;verbatim&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;diarization_mode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;speaker&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To extract each speaker turn cleanly, iterate through the step annotations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;print_diarized_transcript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;interaction&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;interaction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;steps&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;[]:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;[]:&lt;/span&gt;
      &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;annotation&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;annotations&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;[]:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;annotation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;word_info&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;annotation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;current_speaker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
  &lt;span class="n"&gt;current_turn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;speaker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;speaker&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;spk:0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;speaker&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;current_speaker&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;current_turn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;current_speaker&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;]: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_turn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;current_speaker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;speaker&lt;/span&gt;
      &lt;span class="n"&gt;current_turn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;current_turn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;current_turn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;current_speaker&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;]: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_turn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nf"&gt;print_diarized_transcript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;interaction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[spk:0]: One chocolatine, please.
[spk:1]: Tiago, arrête. It is a pain au chocolat.
[spk:0]: Wait, a guy from the south west told me it's chocolatine.
[spk:1]: Do not listen to them. 90% of France and the entire universe calls it pain au chocolat. Chocolatine is a myth.
[spk:0]: Meu Deus, you French are intense. In Brazil, people fight the exact same way over bolacha versus biscoito.
[spk:1]: Well, here pain au chocolat is the only real word.
[spk:0]: Fine. Two pain au chocolat, please. As long as it has chocolate, tá valendo.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Watch the demo video below where two colleagues debate &lt;em&gt;pain au chocolat&lt;/em&gt; vs. &lt;em&gt;chocolatine&lt;/em&gt;. &lt;strong&gt;Notice how the waveform line dynamically changes color (Cyan for Tiago, Orange for his colleague) as each speaker takes turns:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/mdvDSB3c4kg" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Direct audio link: &lt;a href="https://storage.googleapis.com/generativeai-downloads/audio/pain_au_chocolat.wav" rel="noopener noreferrer"&gt;listen to pain_au_chocolat.wav&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Word-Level Timestamps: Precise Time Offsets for Every Spoken Word
&lt;/h2&gt;

&lt;p&gt;When you need exact synchronization—for example, to jump to specific points in a video, build interactive transcripts, or align text with waveforms—you can request word-level millisecond start and end offsets.&lt;/p&gt;

&lt;p&gt;Configure &lt;code&gt;timestamp_granularities=["word"]&lt;/code&gt; (and optionally combine it with &lt;code&gt;diarization_mode="speaker"&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;interaction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;interactions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemini-3.5-transcribe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;audio&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;uri&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;audio_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="n"&gt;generation_config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transcription_config&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;verbatim&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timestamp_granularities&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;word&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;diarization_mode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;speaker&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each recognized word comes back with its exact time offsets (and speaker turn) attached in the content annotations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;interaction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;steps&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;[]:&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;[]:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;annotation&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;annotations&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;[]:&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;annotation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;word_info&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;annotation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
  &lt;span class="n"&gt;spk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;speaker&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;spk:0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_offset&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; -&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end_offset&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;] (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;spk&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;) &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ 0.000s -&amp;gt;  0.400s] (spk:0) One
[ 0.400s -&amp;gt;  1.200s] (spk:0) chocolatine,
[ 1.200s -&amp;gt;  1.800s] (spk:0) please.
[ 3.200s -&amp;gt;  3.700s] (spk:1) Tiago,
[ 3.700s -&amp;gt;  4.200s] (spk:1) arrête.
[ 4.200s -&amp;gt;  4.500s] (spk:1) It
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What can you do with word timestamps?
&lt;/h3&gt;

&lt;p&gt;Having millisecond-level offsets for every individual word unlocks huge capabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Instant subtitles (&lt;code&gt;.srt&lt;/code&gt; / &lt;code&gt;.ass&lt;/code&gt;)&lt;/strong&gt;: Group words into 3-5 second caption blocks for YouTube, Premiere, or Final Cut.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Karaoke &amp;amp; dynamic captions&lt;/strong&gt;: Highlight each word in real-time as it's spoken (like TikTok / YouTube Shorts).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Click-to-play search&lt;/strong&gt;: Build audio/video search indexes where clicking any search keyword immediately seeks the player to that exact millisecond.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Waveform &amp;amp; visual animations&lt;/strong&gt;: Trigger visual events or highlight specific spoken phrases on screen.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Behind the scenes:&lt;/strong&gt; That's actually what I did to make the demo videos above! The word timestamps provided the exact millisecond timing to align the subtitle cards, highlight the custom terms (&lt;em&gt;"oatmilk"&lt;/em&gt;), and trigger the color switch of the waveform line from Cyan to Orange when the speaker changed.&lt;/p&gt;

&lt;p&gt;If you want the complete Python function to convert these word annotations into standard &lt;code&gt;.srt&lt;/code&gt; subtitle files, you can find it directly in the &lt;a href="https://colab.research.google.com/github/google-gemini/cookbook/blob/main/quickstarts/Get_started_transcribe.ipynb" rel="noopener noreferrer"&gt;interactive Cookbook Colab notebook&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  7. Decision Matrix: Which Configuration Should You Use?
&lt;/h2&gt;

&lt;p&gt;Here is a quick cheat sheet to pick the right settings for your use case:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Diarization&lt;/th&gt;
&lt;th&gt;Timestamps&lt;/th&gt;
&lt;th&gt;Custom Vocab&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Meeting Notes / Voice Memos&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;smart&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Optional&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Video Subtitles / Closed Captions&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;verbatim&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Optional&lt;/td&gt;
&lt;td&gt;&lt;code&gt;["word"]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Highly recommended&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Podcast / Multi-speaker Interview&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;verbatim&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;speaker&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;["word"]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Highly recommended&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Legal / Compliance Audio Logs&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;verbatim&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;speaker&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;["word"]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Optional&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Search Indexing &amp;amp; Embeddings&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;smart&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Optional&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  8. What About Real-Time Live Streaming?
&lt;/h2&gt;

&lt;p&gt;Everything we covered above is for &lt;strong&gt;pre-recorded audio files&lt;/strong&gt; (unary mode via the Files API).&lt;/p&gt;

&lt;p&gt;Gemini also supports &lt;strong&gt;real-time live streaming transcription&lt;/strong&gt; over WebSockets using &lt;code&gt;gemini-3.5-transcribe-live&lt;/code&gt; and the Live API. It lets you stream raw 16-bit PCM chunks (100ms each) directly from a microphone and receive instantaneous interim partial hypotheses (&lt;code&gt;interim_input_transcription&lt;/code&gt;) and finalized text as speech occurs.&lt;/p&gt;

&lt;p&gt;However, streaming real-time WebSockets with asynchronous Python workers (&lt;code&gt;asyncio&lt;/code&gt;), handling audio chunking, and managing ephemeral valet tokens for secure client apps is quite a bit more complex and deserves its own dedicated tutorial.&lt;/p&gt;

&lt;p&gt;If you want to dive straight into live streaming code right now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📖 Open the &lt;a href="https://colab.research.google.com/github/google-gemini/cookbook/blob/main/quickstarts/Get_started_transcribe.ipynb" rel="noopener noreferrer"&gt;&lt;strong&gt;Gemini Transcribe Colab Notebook&lt;/strong&gt;&lt;/a&gt; (it includes runnable cells for live streaming and ephemeral token creation!)&lt;/li&gt;
&lt;li&gt;📚 Read the official &lt;a href="https://ai.google.dev/gemini-api/docs/live-api/live-transcribe" rel="noopener noreferrer"&gt;&lt;strong&gt;Gemini Live Transcription Documentation&lt;/strong&gt;&lt;/a&gt; on ai.google.dev.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Gemini 3.5 Transcribe gives you the best of both worlds: strict, millisecond-accurate verbatim data when you need timestamps and diarization, and an intelligent, disfluency-stripping smart mode when you want clean text for human eyes.&lt;/p&gt;

&lt;p&gt;Have you tried using &lt;code&gt;smart&lt;/code&gt; mode on your own voice recordings or meetings? Drop your thoughts and edge cases in the comments below! 🚀🚀🚀&lt;/p&gt;

</description>
      <category>ai</category>
      <category>stt</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>AI Evals at a Glance: Heatmaps for Stakeholders</title>
      <dc:creator>Katie McLaughlin</dc:creator>
      <pubDate>Tue, 25 Aug 2026 07:00:00 +0000</pubDate>
      <link>https://dev.to/googleai/ai-evals-at-a-glance-heatmaps-for-stakeholders-2mki</link>
      <guid>https://dev.to/googleai/ai-evals-at-a-glance-heatmaps-for-stakeholders-2mki</guid>
      <description>&lt;h2&gt;
  
  
  Visualizing AI evals with Inspect Viz
&lt;/h2&gt;

&lt;p&gt;Welcome back to our blog series on running, analyzing and visualizing AI evals. &lt;a href="https://dev.to/googleai/designing-ai-evals-clarity-now-and-visualization-next-4eii"&gt;Last time&lt;/a&gt; we discussed how to design and run evals for analysis and visualization using &lt;code&gt;inspect eval&lt;/code&gt; and &lt;code&gt;inspect view&lt;/code&gt;. Many of these methods, such as rearranging the dashboard columns and sorting on them to determine model vs model and skill vs no-skill differences in metrics, can give you a broad overview of the field. While this can inspire further and deeper inquiry, it runs into issues with how predictive it is and how to communicate findings to other people. Imagine the following:&lt;/p&gt;

&lt;h3&gt;
  
  
  The 40-log gridlock
&lt;/h3&gt;

&lt;p&gt;Imagine a data science lead needing to present a performance breakdown of four LLM candidates across ten internal tools during a high-stakes, time-crunched live meeting. Reordering and filtering the evals across multiple dimensions is hard to read on a presentation screen and requires doing mental math with an audience: riveting stuff that they definitely won’t fall asleep during of course.&lt;/p&gt;

&lt;p&gt;What if instead you had a tool that allowed you to easily automate rendering a comparison of the different configurations? What if lining them up by model or by skill showed clear and legible patterns?&lt;/p&gt;

&lt;p&gt;Well, let me introduce you to &lt;strong&gt;heatmaps&lt;/strong&gt;! A heatmap is a 2D visual matrix where color intensity represents numerical magnitude—in our case, quadratic curved accuracy scores. By leveraging the human eye's natural ability to distinguish color gradients, heatmaps instantly reveal performance spectrums at a single glance. This makes trends across dependent and independent variables clear, intuitive, and highly legible.&lt;/p&gt;

&lt;p&gt;While you can simply read along and learn about using &lt;code&gt;inspect viz&lt;/code&gt; to generate heatmaps for inspect AI evals, if you intend to follow along and recreate the charts, please start by replicating the steps in the &lt;a href="https://dev.to/googleai/designing-ai-evals-clarity-now-and-visualization-next-4eii"&gt;first entry&lt;/a&gt; and come back afterward.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: This blog series contains AI-generated diagrams alongside actual screenshots and hand-drawn edits of both. AI also assisted in minor copy editing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Follow-along requirements
&lt;/h2&gt;

&lt;p&gt;For those playing along at home, in order to perform the following, you will need the &lt;code&gt;inspect_viz&lt;/code&gt; library installed in your environment (alongside &lt;code&gt;inspect_ai&lt;/code&gt; and &lt;code&gt;pandas&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;From there, take a look at the &lt;a href="https://github.com/GoogleCloudPlatform/devrel-demos/blob/main/agents/inspect-agent-skills-eval/inspect_viz_heatmap.py" rel="noopener noreferrer"&gt;heatmap script&lt;/a&gt;. While there are some intricacies to the script (such as establishing its CLI API) the script mainly wraps &lt;code&gt;scores_heatmap(viz_data, orientation="horizontal", ...)&lt;/code&gt; and marshals our data to assemble a heatmap of it.&lt;/p&gt;

&lt;p&gt;If you run the script&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 inspect_viz_heatmap.py logs &lt;span class="nt"&gt;-o&lt;/span&gt; heatmap.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;you will get a visual that looks like the following.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwahzh78quzwkcq5aer3t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwahzh78quzwkcq5aer3t.png" alt="A heatmap matrix with model names on the y-axis and skill names on the x-axis, using color intensity from purple to yellow to represent accuracy scores." width="800" height="488"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This heatmap has two axes, one is the &lt;strong&gt;model&lt;/strong&gt; (vertical) which allows you to visually break down your analysis to just skill inclusions for the same model, the other is the &lt;strong&gt;skills&lt;/strong&gt; (horizontal) and going down the row allows you to demonstrate how changes to the model affect the evaluation.&lt;/p&gt;

&lt;p&gt;Stakeholders (like investors or your boss) can now spot skill gains and model ceilings at a glance without reading line-by-line log values. Some quick takeaways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Top-performing configurations (such as 3.6-flash + &lt;code&gt;gemini_api_skill&lt;/code&gt; at &lt;strong&gt;1.0&lt;/strong&gt;) stand out in high-intensity shades
&lt;/li&gt;
&lt;li&gt;Within the aggregated 2D heatmap view of this dataset, &lt;code&gt;3.6-flash&lt;/code&gt; trended higher in score on average across the evaluated skill configurations compared to &lt;code&gt;3.5-flash-lite&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Skills tended to improve scores, all other things held equal.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbwvjbu92rzpou4aavxzu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbwvjbu92rzpou4aavxzu.png" alt="A 3D grid matrix visualizing eval conditions: Models on the vertical axis, Skill Conditions on the depth axis, and Samples on the horizontal axis." width="800" height="769"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Caption&lt;/strong&gt;: The &lt;code&gt;inspect viz&lt;/code&gt; heatmap projects our full Evaluation Matrix down to a 2D plane by collapsing individual task samples and epochs into aggregate accuracy cells along the Model and Skill axes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cognitive overhead and segue to BI analytics
&lt;/h3&gt;

&lt;p&gt;While matrix scoreboards provide quick visibility into accuracy differences across models, raw heatmaps suffer from key limitations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;2D Constraint&lt;/strong&gt;: Heatmaps map only two axes to a single color intensity (in our case Accuracy).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Missing Business Context&lt;/strong&gt;: A single heatmap cannot simultaneously show token costs, system latency, or operational reliability.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hidden Variance&lt;/strong&gt;: Collapsing samples for a given configuration removes the information necessary to determine if a result is consistent or wildly erratic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To bridge CLI logs with interactive, multidimensional and in-depth reporting, we need a pipeline that exports the raw telemetry metrics into spreadsheets and BI dashboards.&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;Part 3&lt;/strong&gt;, we’ll  build a python script to convert output data for processing first in Google Sheets and ultimately Data Studio!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>datascience</category>
      <category>python</category>
    </item>
    <item>
      <title>Elevating Antigravity agent skills, Part 1: Interactive UI workflows</title>
      <dc:creator>James O'Reilly</dc:creator>
      <pubDate>Mon, 24 Aug 2026 19:55:23 +0000</pubDate>
      <link>https://dev.to/googleai/elevating-antigravity-agent-skills-part-1-interactive-ui-workflows-6l2</link>
      <guid>https://dev.to/googleai/elevating-antigravity-agent-skills-part-1-interactive-ui-workflows-6l2</guid>
      <description>&lt;p&gt;By embedding native chat UI components directly into your SKILL.md instructions, you transform your agent from a passive text parser into an active technical interviewer with a delightful user experience.&lt;/p&gt;

&lt;p&gt;Here is what you will get out of this deep dive:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to use Google Antigravity interactive UI Primitives.&lt;/li&gt;
&lt;li&gt;Round-trip state hydration for user selections with grounding.&lt;/li&gt;
&lt;li&gt;Practical design rules for structuring finite selection lists without overwhelming developers or triggering visual clutter.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;📝 About this series: Welcome to Elevating Antigravity Agent Skills series, a 5-part engineering guide to mastering the agent tools that reduce orchestration tax and transform AI agents into autonomous collaborators: &lt;code&gt;ask_question&lt;/code&gt;, &lt;code&gt;generate_image&lt;/code&gt;, &lt;code&gt;define_subagent&lt;/code&gt; + &lt;code&gt;invoke_subagent&lt;/code&gt;, &lt;code&gt;send_message&lt;/code&gt; and &lt;code&gt;manage_subagents&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Anatomy of an interactive skill
&lt;/h2&gt;

&lt;p&gt;In Antigravity, agent capabilities are packaged as skills. These are dedicated directories containing a &lt;code&gt;SKILL.md&lt;/code&gt; file with YAML frontmatter for discovery and Markdown instructions for execution. By default, agents interpret instructions sequentially and execute terminal commands or file edits. However, when an Antigravity agent encounters explicit instructions to invoke the &lt;a href="https://antigravity.google/docs/hooks?utm_campaign=CDR_0xc0d3ff05_awareness_b531696265&amp;amp;utm_medium=external&amp;amp;utm_source=blog#interaction-and-media" rel="noopener noreferrer"&gt;ask_question&lt;/a&gt; tool, it suspends execution and renders a native, interactive UI modal in the chat window.&lt;/p&gt;

&lt;p&gt;This simple tool invocation bridges the gap between agent autonomy and human-in-the-loop (HITL) alignment. Instead of guessing parameter values or parsing ambiguous prompts, the agent presents structured radio buttons, checkboxes, and write-in fields.&lt;/p&gt;

&lt;p&gt;To eliminate repetitive questioning across sessions and subagents, I pair UI interrogation with persistent state hydration. My agent's lifecycle follows a structured sequence:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Workspace State Hydration&lt;/strong&gt; (Read &lt;code&gt;user_prefs.json&lt;/code&gt;) At the start of the workflow, the agent checks the workspace root for a namespaced configuration file. If found, it extracts saved defaults to use during UI presentation.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interactive UI&lt;/strong&gt; (Render &lt;code&gt;ask_question modals&lt;/code&gt;) The agent invokes &lt;code&gt;ask_question&lt;/code&gt; with finite option arrays and multi-select flags, prefixing hydrated defaults with "(Current Setting) " so the user sees active preferences immediately.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Selection Processing with Fallbacks&lt;/strong&gt; (Clean and Apply) The agent strips UI signaling prefixes from selected strings and preserves existing JSON defaults if an optional question is left blank or skipped.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State Persistence&lt;/strong&gt; (Write &lt;code&gt;user_prefs.json&lt;/code&gt;) The agent serializes updated selections back to &lt;code&gt;user_prefs.json&lt;/code&gt; in the workspace root, establishing an unshakeable source of truth for future subagent invocations. This is not a special Antigravity file, but rather one I've named and created for the use of my project. You should name and place this file in a location most suitable for your needs.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Built-in /grill-me command
&lt;/h2&gt;

&lt;p&gt;Before diving into custom skill authoring, it is worth noting that Antigravity natively supports interactive alignment through the &lt;code&gt;/grill-me&lt;/code&gt; slash command.&lt;/p&gt;

&lt;p&gt;When you trigger &lt;code&gt;/grill-me&lt;/code&gt; during a chat session, the agent temporarily pauses code execution to conduct a rigorous, multi-question interview. Instead of making silent architectural assumptions, the agent systematically interrogates you on design trade-offs, edge cases, and implementation boundaries until ambiguity is resolved.&lt;/p&gt;

&lt;p&gt;While &lt;code&gt;/grill-me&lt;/code&gt; is an exceptional built-in tool for ad-hoc session planning and general requirements gathering, custom Interactive Skills take this concept a step further. By authoring custom markdown skills that invoke UI selection modals, engineering teams can standardize domain-specific interview workflows (like form scaffolding or cloud deployments) and persist the resulting answers directly into workspace configuration files for subagent grounding.&lt;/p&gt;

&lt;p&gt;You can learn more about the &lt;code&gt;/grill-me&lt;/code&gt; command in Richard Seroter's article, &lt;a href="https://seroter.com/2026/06/28/crafting-an-agent-team-that-still-includes-me/" rel="noopener noreferrer"&gt;Crafting an agent team that still includes me&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  A reference walkthrough of our interactive UI workflow
&lt;/h2&gt;

&lt;p&gt;To see this architecture in action, examine how I've implemented the exemplar making-forms-demo skill. This skill interviews developers before generating a web form, ensuring validation rules and label layouts match team standards.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fm31itj8gpayv8yh74vei.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fm31itj8gpayv8yh74vei.gif" alt="Using the  raw `ask_question` endraw  tool" width="600" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 1: When we prompt "Make a web form", our making-forms-demo skill is auto-discovered by the agent and read into context. The skill instructs the agent to present the user with a series of questions using the &lt;code&gt;ask_question&lt;/code&gt; tool.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Stage 1: Workspace State Hydration
&lt;/h3&gt;

&lt;p&gt;Before rendering UI components, the skill instructs the agent to read the existing state from &lt;code&gt;user_prefs.json&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;making-forms-demo&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="s"&gt;Interviews the user for critical implementation details needed to&lt;/span&gt;
  &lt;span class="s"&gt;generate a Web Form. Manages FORM namespace in `user_prefs.json`.&lt;/span&gt;
  &lt;span class="s"&gt;Use when making Web Forms.&lt;/span&gt;
&lt;span class="s"&gt;---&lt;/span&gt;

&lt;span class="c1"&gt;# Making forms&lt;/span&gt;
&lt;span class="s"&gt;Interviews the user for critical implementation details needed to&lt;/span&gt;
&lt;span class="s"&gt;generate a Web Form.&lt;/span&gt;

&lt;span class="c1"&gt;## Workflow Steps&lt;/span&gt;

&lt;span class="s"&gt;1. **Confirm Intent &amp;amp; Hydrate State:**&lt;/span&gt;
   &lt;span class="s"&gt;Check if `user_prefs.json` exists in the workspace root.&lt;/span&gt;
   &lt;span class="s"&gt;If present, read the `"FORMS"` object to identify any previously&lt;/span&gt;
   &lt;span class="s"&gt;saved preferences. Tell the user that a form has been identified&lt;/span&gt;
   &lt;span class="s"&gt;and that a few questions must be answered (or confirmed) before&lt;/span&gt;
   &lt;span class="s"&gt;building the form.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Stage 2: Interactive UI
&lt;/h3&gt;

&lt;p&gt;If previous preferences exist, the agent prefixes those strings with "(Current Setting) " and places them at the top of the options array. When executed, this Markdown block generates an interactive modal supporting multi-selection checkboxes (is_multi_select: true). Because the options are explicitly enumerated, the agent never guesses validation requirements.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;2.&lt;/span&gt; &lt;span class="gs"&gt;**Query Validation Type:**&lt;/span&gt;
   Invoke the &lt;span class="sb"&gt;`ask_question`&lt;/span&gt; tool to present the user with an option
   selection UI. If previously saved values exist in 
   &lt;span class="sb"&gt;`user_prefs.json`&lt;/span&gt;, prefix those option strings with 
   &lt;span class="sb"&gt;`"(Current Setting) "`&lt;/span&gt; and list them first:
&lt;span class="p"&gt;   *&lt;/span&gt; &lt;span class="gs"&gt;**Question:**&lt;/span&gt; "How would you like to handle field validation?
     (select all that apply)"
&lt;span class="p"&gt;   *&lt;/span&gt; &lt;span class="gs"&gt;**Options:**&lt;/span&gt; ["Client-side validation", 
     "Server-side validation"]

   Use the selected value as &lt;span class="sb"&gt;`FIELD_VALIDATION_TYPE`&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Stage 3: Selection Processing with Fallbacks
&lt;/h3&gt;

&lt;p&gt;For mutually exclusive architectural choices, the skill configures single-selection lists. By omitting an explicit "other" string from the options array, the agent automatically enables Antigravity's native default write-in option in the UI modal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;3.&lt;/span&gt; &lt;span class="gs"&gt;**Query Validation Location:**&lt;/span&gt;
   Invoke the &lt;span class="sb"&gt;`ask_question`&lt;/span&gt; tool to present the user with an option
   selection UI. If a previously saved value exists in 
   &lt;span class="sb"&gt;`user_prefs.json`&lt;/span&gt;, prefix that option string with 
   &lt;span class="sb"&gt;`"(Current Setting) "`&lt;/span&gt; and list it first:
&lt;span class="p"&gt;   *&lt;/span&gt; &lt;span class="gs"&gt;**Question:**&lt;/span&gt; "How would you like to handle validation
     messages?"
&lt;span class="p"&gt;   *&lt;/span&gt; &lt;span class="gs"&gt;**Options:**&lt;/span&gt; ["Above the field", "Below the field", 
     "Summary Card", "Tooltip"]

   Use the selected value as &lt;span class="sb"&gt;`FIELD_VALIDATION_LOCATION`&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a developer selects the write-in option in the modal and types "Inline below label", the agent captures that custom string directly into &lt;code&gt;FIELD_VALIDATION_LOCATION&lt;/code&gt; without requiring custom syntax parsing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stage 4: State Persistence
&lt;/h3&gt;

&lt;p&gt;Once the user submits the modal, the agent cleans the input strings by removing "(Current Setting) " prefixes and writes the finalized structure back to the workspace root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;4.&lt;/span&gt; &lt;span class="gs"&gt;**Persist User Preferences:**&lt;/span&gt;
   Write the user's selected form preferences to a &lt;span class="sb"&gt;`user_prefs.json`&lt;/span&gt;
   file in the workspace root directory using the &lt;span class="sb"&gt;`write_to_file`&lt;/span&gt;
   tool (or overwrite existing preferences). This guarantees that 
   future agent invocations and subagents are grounded in the user's 
   exact specifications without needing
   to re-interview them:
   &lt;span class="p"&gt;```&lt;/span&gt;&lt;span class="nl"&gt;json
&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"FORMS"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"FIELD_VALIDATION_TYPE"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;SELECTED_VALUES&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"FIELD_VALIDATION_LOCATION"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;SELECTED_VALUE&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"FIELD_LABEL_TYPE"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;SELECTED_VALUE&amp;gt;"&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;```&lt;/span&gt;

&lt;span class="gu"&gt;## Mock Skill Instructions&lt;/span&gt;
Since this skill is just a mock skill for illustrating how to
create interviewer UI within the chat window, don't actually create
a form. Instead:
&lt;span class="p"&gt;1.&lt;/span&gt; Write the selections to &lt;span class="sb"&gt;`user_prefs.json`&lt;/span&gt; in the workspace root.
&lt;span class="p"&gt;2.&lt;/span&gt; Output the form selections to the user as confirmation using the
   template below:

For each field:
&lt;span class="gs"&gt;**&amp;lt;FIELD_NAME&amp;gt;:**&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;SELECTED_VALUE&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By nesting form preferences under the "FORMS" namespace, the workspace configuration file remains clean and scalable. Other skills, such as deployment or database bootstrappers, can safely manage their own state within the same JSON root without collision.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fega22ziavi64mgr96b2o.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fega22ziavi64mgr96b2o.gif" alt="Recalling user preferences" width="600" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 2: The next time the skill is used it finds the &lt;code&gt;user_prefs.json&lt;/code&gt; file previously created and uses the data to mark appropriate responses as "(Current Selection) ". The preferences file is updated should the user change their selections.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The 4 things to avoid when creating interactive skills
&lt;/h2&gt;

&lt;p&gt;As you transition your team's custom skills from static text prompts to interactive interviewers, adhere to these four best practices to keep your workflows sharp and maintainable:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Avoid option-fatigue
&lt;/h3&gt;

&lt;p&gt;Interactive modals are designed for fast scanability. If a selection list exceeds seven items the user can get overwhelmed with options and revert to guessing. When dealing with large datasets, such as hundreds of marketing campaigns or cloud regions, never dump the raw array directly into an &lt;code&gt;ask_question&lt;/code&gt; block. Instead, instruct the agent to query an MCP tool first to filter the choices down to a top-5 list relevant to the current workspace before rendering the modal.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Avoid the write-in anti-pattern
&lt;/h3&gt;

&lt;p&gt;A common mistake is explicitly adding "Other" or "Custom value" to the options array in &lt;code&gt;SKILL.md&lt;/code&gt;. In Antigravity, the &lt;code&gt;ask_question&lt;/code&gt; tool renders a default write-in text field automatically whenever an interactive question is presented. Explicitly including an "other" string creates redundant, confusing options and forces the agent to handle an unnecessary secondary text-prompting step.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Avoid flat root keys in config files
&lt;/h3&gt;

&lt;p&gt;When persisting user selections to &lt;code&gt;user_prefs.json&lt;/code&gt;, always nest key-value pairs under a high-level domain namespace (such as "FORMS", "DEPLOYMENT", or "TESTING"). If multiple skills write flat keys directly to the root of the JSON object, key collisions become inevitable as your team's skill pack grows. Namespacing guarantees strict boundary isolation across autonomous subagents.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Avoid third-person phrasing
&lt;/h3&gt;

&lt;p&gt;Format option strings as the user's direct voice (e.g., "Floating labels (Labels sit inside the input field)") rather than third-person imperative commands (e.g., "Set form layout to floating"). Direct-response phrasing reduces cognitive friction and makes interactive modals read more naturally.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion: Stop prompting, start interviewing
&lt;/h2&gt;

&lt;p&gt;The era of typing massive, brittle paragraphs into chat prompts to guide autonomous coding agents is over. By combining declarative Markdown instructions, native &lt;code&gt;ask_question&lt;/code&gt; UI components, and round-trip JSON state hydration, skill authors can transform AI assistants into rigorous technical interviewers.&lt;/p&gt;

&lt;h3&gt;
  
  
  📌 Elevating Antigravity Agent Skills Series Index
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Part 1: Building interactive UI workflows with &lt;code&gt;ask_question&lt;/code&gt; &lt;em&gt;(📍 You are here)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Part 2: &lt;a href="https://dev.to/googleai/elevating-antigravity-agent-skills-part-2-image-generation-2jno"&gt;Automating Image Generation with &lt;code&gt;generate_image&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Part 3: Invoking Subagents with &lt;code&gt;define_subagent&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;Part 4: Inter-Agent Communication with &lt;code&gt;send_message&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;Part 5: Managing Active Agent Lifecycles with &lt;code&gt;manage_subagents&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Additional resources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Tool Reference: &lt;a href="https://antigravity.google/docs/hooks?utm_campaign=CDR_0xc0d3ff05_awareness_b531696265&amp;amp;utm_medium=external&amp;amp;utm_source=blog#interaction-and-media" rel="noopener noreferrer"&gt;List of supported Antigravity tools&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Article: &lt;a href="https://javascript.plainenglish.io/migrating-express-to-next-js-using-ai-agents-antigravity-f48b4c206a8e" rel="noopener noreferrer"&gt;How to automate modernization with Antigravity and multi-agent orchestration&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Article: &lt;a href="https://seroter.com/2026/06/28/crafting-an-agent-team-that-still-includes-me/" rel="noopener noreferrer"&gt;Crafting an agent team that still includes me&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Help others find this post
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Save this post to find it later.
&lt;/li&gt;
&lt;li&gt;Subscribe to my &lt;a href="https://www.linkedin.com/newsletters/the-agentic-developer-7488602281148526592/" rel="noopener noreferrer"&gt;&lt;em&gt;The Agentic Developer&lt;/em&gt;&lt;/a&gt; newsletter.&lt;/li&gt;
&lt;li&gt;Share this article across social media.
&lt;/li&gt;
&lt;li&gt;Follow me on &lt;a href="https://www.linkedin.com/in/jamesor/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; or &lt;a href="https://x.com/JamesOR" rel="noopener noreferrer"&gt;X&lt;/a&gt; for more agentic engineering insights.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agentskills</category>
      <category>antigravity</category>
    </item>
  </channel>
</rss>
