<?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>Equip your agent with Google Cloud best practices using google-cloud-developer plugin</title>
      <dc:creator>Remigiusz Samborski</dc:creator>
      <pubDate>Thu, 24 Sep 2026 11:55:12 +0000</pubDate>
      <link>https://dev.to/googleai/equip-your-agent-with-google-cloud-best-practices-using-google-cloud-developer-plugin-1bm1</link>
      <guid>https://dev.to/googleai/equip-your-agent-with-google-cloud-best-practices-using-google-cloud-developer-plugin-1bm1</guid>
      <description>&lt;p&gt;Coding agents in your terminal can scaffold microservices in seconds. But what happens when your agent needs to deploy directly to Google Cloud?&lt;/p&gt;

&lt;p&gt;Without cloud-specific guidance, typical agents struggle. They hallucinate obsolete SDK calls, attempt to run commands without required permissions, or silently enable billable APIs that create surprise costs on your invoice.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/google/skills/tree/main/plugins/cloud/google-cloud-developer" rel="noopener noreferrer"&gt;&lt;code&gt;google-cloud-developer&lt;/code&gt; plugin&lt;/a&gt; changes this dynamic. It equips your agent (such as &lt;a href="https://antigravity.google/product/antigravity-cli?utm_campaign=CDR_0x87fa8d40_default_b563025958&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;Antigravity CLI&lt;/a&gt;, &lt;a href="https://claude.com/product/claude-code" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt;, &lt;a href="https://learn.chatgpt.com/docs/codex/cli" rel="noopener noreferrer"&gt;Codex CLI&lt;/a&gt;) with curated skills and the &lt;a href="https://developers.google.com/knowledge/mcp?utm_campaign=CDR_0x87fa8d40_default_b563025958&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;Developer Knowledge MCP server&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To evaluate the plugin in action, I tasked Antigravity CLI (&lt;code&gt;agy&lt;/code&gt;) with building a complete, cloud-based solution from a fresh Google Cloud project. The scenario: scaffold, containerize, and deploy a secure &lt;a href="https://docs.cloud.google.com/gemini-enterprise-agent-platform/models/start?utm_campaign=CDR_0x87fa8d40_default_b563025958&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;Gemini AP&lt;/a&gt;I streaming proxy on &lt;a href="https://docs.cloud.google.com/run/docs/overview/what-is-cloud-run?utm_campaign=CDR_0x87fa8d40_default_b563025958&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;Cloud Run&lt;/a&gt;, complete with &lt;a href="https://docs.cloud.google.com/iam/docs?utm_campaign=CDR_0x87fa8d40_default_b563025958&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;Cloud IAM&lt;/a&gt; authentication and &lt;a href="https://cloud.google.com/products/firestore?utm_campaign=CDR_0x87fa8d40_default_b563025958&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;Firestore&lt;/a&gt; token tracking.&lt;/p&gt;

&lt;p&gt;While the resulting &lt;a href="https://github.com/rsamborski/vibecoding/tree/main/cloud-run-proxy" rel="noopener noreferrer"&gt;Cloud Run proxy codebase&lt;/a&gt; works, the proxy itself is just an example. The real value is how the plugin guides the agent through every phase of the cloud development process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Application design and SDK code generation:&lt;/strong&gt; Writing Gemini SDK code without hallucinations and selecting the right database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Project onboarding, billing verification, and API enablement:&lt;/strong&gt; Auditing the project, linking a Cloud Billing account, and requesting explicit user approval before enabling billable APIs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Least-privilege IAM and Cloud Run deployment:&lt;/strong&gt; Provisioning dedicated service accounts and deploying the container asynchronously.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;End-to-end verification:&lt;/strong&gt; Testing streaming and token persistence against the live service.&lt;/li&gt;
&lt;/ol&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%2Fumou2bea1rbio78nz5ms.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%2Fumou2bea1rbio78nz5ms.png" alt="Architecture and workflow overview" width="800" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick install: Five skills and an MCP server
&lt;/h2&gt;

&lt;p&gt;Remember the scene in &lt;em&gt;The Matrix&lt;/em&gt; where Trinity calls Tank for a helicopter pilot program and learns it in seconds? Adding the plugin to &lt;code&gt;agy&lt;/code&gt; works the same way with one terminal command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;agy plugin &lt;span class="nb"&gt;install &lt;/span&gt;https://github.com/google/skills/plugins/cloud/google-cloud-developer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CLI clones the plugin repository, registers its components, and makes them available immediately.&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%2F88s8wxwrwzx6lvew9284.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%2F88s8wxwrwzx6lvew9284.png" alt="Installing the google-cloud-developer plugin" width="800" height="168"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In seconds, &lt;code&gt;agy&lt;/code&gt; configures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Five specialized skills covering Google Cloud CLI patterns and workflows.&lt;/li&gt;
&lt;li&gt;Developer Knowledge MCP server providing access to current API syntax and Google Cloud documentation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With the plugin active, &lt;code&gt;agy&lt;/code&gt; pairs its Gemini 3.8 Flash model with authoritative cloud instructions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; As a heavy user of Google Cloud, I already have &lt;code&gt;gcloud&lt;/code&gt; installed and authenticated. I also enabled the Developer Knowledge API in my project. For new users and ones who use a different harness such as Claude Code CLI or Codex CLI, I recommend following the &lt;a href="https://docs.cloud.google.com/docs/get-started/developer-environment?utm_campaign=CDR_0x87fa8d40_default_b563025958&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt; to get started.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Knowledge grounding: Writing modern SDK code without hallucinations
&lt;/h2&gt;

&lt;p&gt;One frequent failure mode with AI coding assistants is API obsolescence. For example, older tutorials rely on deprecated libraries such as &lt;code&gt;google-generativeai&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Because the &lt;code&gt;google-cloud-developer&lt;/code&gt; plugin connects directly to the Developer Knowledge API, the agent checks the latest official syntax before writing a single line of code.&lt;/p&gt;

&lt;p&gt;When scaffolding &lt;code&gt;app/gemini_client.py&lt;/code&gt;, &lt;code&gt;agy&lt;/code&gt; immediately used the current unified Google Gen AI SDK:&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%2Feq51kn6xfmb5m1fh4q4b.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%2Feq51kn6xfmb5m1fh4q4b.png" alt="Scaffolding code with official SDK syntax" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The agent produced clean Python code with Pydantic configuration, structured Cloud Logging formatters, and unit tests using &lt;code&gt;pytest&lt;/code&gt; and FastAPI's &lt;code&gt;TestClient&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Informed architecture: Evaluating database options with Developer Knowledge
&lt;/h2&gt;

&lt;p&gt;Selecting the right database for a serverless proxy requires balancing latency, connection handling, concurrency, and cost. When I asked &lt;code&gt;agy&lt;/code&gt; to track token usage per user and suggest the best database, the agent did not just pick one at random.&lt;/p&gt;

&lt;p&gt;Backed by the Developer Knowledge API, the agent pulled real-time architectural guidance and evaluated Google Cloud database options:&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%2Foab0x7klr4a6qamn7gkv.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%2Foab0x7klr4a6qamn7gkv.png" alt="Evaluating database options for the proxy service" width="799" height="248"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By grounding its analysis in the Developer Knowledge, the agent presented a clear comparison table directly in the terminal. It recommended Cloud Firestore as the most cost-effective and operationally simple fit for Cloud Run. You get an informed architectural decision based on official cloud patterns rather than guessing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost guardrails and onboarding: Verifying billing before enabling APIs
&lt;/h2&gt;

&lt;p&gt;Once the code and Firestore design were ready, the agent needed to enable the Gemini Enterprise, Cloud Run, and Firestore APIs in my project. Autonomous agents need strict boundaries here because enabling an API or provisioning a managed resource can incur costs.&lt;/p&gt;

&lt;p&gt;Two skills in the &lt;code&gt;google-cloud-developer&lt;/code&gt; plugin coordinate this step:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pre-flight billing audit:&lt;/strong&gt; Before enabling billable services, the &lt;code&gt;google-cloud-recipe-onboarding&lt;/code&gt; skill instructs the agent to verify that the target project is linked to an active Cloud Billing account (&lt;code&gt;gcloud billing projects describe&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explicit user consent:&lt;/strong&gt; The &lt;code&gt;gcloud&lt;/code&gt; skill requires explicit user approval before running &lt;code&gt;gcloud services enable&lt;/code&gt; or any destructive action.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When &lt;code&gt;agy&lt;/code&gt; identified the required APIs for the proxy, it first checked my project state and paused for explicit permission:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The system's guardrails require explicit user approval before enabling any API, specifically addressing potential security risks and unexpected costs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This keeps you in the driver's seat and eliminates accidental spend.&lt;/p&gt;

&lt;h3&gt;
  
  
  How &lt;code&gt;agy&lt;/code&gt; helps: Scheduling timers for billing propagation
&lt;/h3&gt;

&lt;p&gt;During the onboarding skill's pre-flight check, I linked a new billing account to my test project so &lt;code&gt;agy&lt;/code&gt; could enable the APIs. In Google Cloud, linking a billing account often takes a few minutes to propagate across backend systems.&lt;/p&gt;

&lt;p&gt;While the &lt;code&gt;google-cloud-developer&lt;/code&gt; plugin tells the agent &lt;em&gt;how&lt;/em&gt; to validate billing status (&lt;code&gt;gcloud billing projects describe&lt;/code&gt; checking for &lt;code&gt;billingEnabled: true&lt;/code&gt;), &lt;code&gt;agy&lt;/code&gt; complements the plugin with its native &lt;code&gt;Schedule&lt;/code&gt; tool so the session does not fail or spin in a retry loop.&lt;/p&gt;

&lt;p&gt;I typed:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Ok. Let's wait now. I just enabled the billing and it needs to propagate. I'll check in 10 minutes."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent scheduled a 600-second timer and freed the terminal prompt:&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%2Fyasaane47mgblblj05ur.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%2Fyasaane47mgblblj05ur.png" alt="Scheduling a billing timer" width="800" height="127"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Exactly 10 minutes later, the timer woke the agent up. It resumed the exact conversation context, checked the billing status with &lt;code&gt;gcloud beta billing projects describe&lt;/code&gt;, verified that &lt;code&gt;billingEnabled&lt;/code&gt; was &lt;code&gt;true&lt;/code&gt;, and prompted to enable the required APIs:&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%2F23rhikrpb8jj7yixczb8.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%2F23rhikrpb8jj7yixczb8.png" alt="Timer triggered and billing confirmed" width="799" height="126"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can walk away, grab a coffee, and let your agent resume right where you left off.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security enforcement: Least-privilege IAM
&lt;/h2&gt;

&lt;p&gt;With the APIs enabled, the next step before deployment was configuring authentication. Without guidance, agents often suggest creating a long-lived Gemini API key or downloading a service account JSON key file.&lt;/p&gt;

&lt;p&gt;Instead, the &lt;code&gt;google-cloud-recipe-auth&lt;/code&gt; skill explicitly forbids downloaded service account keys and steers the agent toward Google Cloud security best practices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dedicated service identity:&lt;/strong&gt; Creates a workload-specific service account (&lt;code&gt;gemini-proxy-sa&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Least-privilege IAM bindings:&lt;/strong&gt; Grants only &lt;code&gt;roles/aiplatform.user&lt;/code&gt; for Gemini invocation and &lt;code&gt;roles/datastore.user&lt;/code&gt; for Firestore token logging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authenticated ingress:&lt;/strong&gt; Protects the Cloud Run endpoint with &lt;code&gt;--no-allow-unauthenticated&lt;/code&gt; so the Google Frontend validates &lt;a href="https://docs.cloud.google.com/docs/authentication/get-id-token?utm_campaign=CDR_0x87fa8d40_default_b563025958&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;Google-signed OpenID Connect (OIDC) ID tokens&lt;/a&gt; before traffic reaches your container.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No secrets live in plaintext, and permissions stay tightly scoped.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cloud Run deployment
&lt;/h2&gt;

&lt;p&gt;To deploy the container, &lt;code&gt;agy&lt;/code&gt; used &lt;code&gt;finding-google-skills&lt;/code&gt; to pull Cloud Run deployment patterns (&lt;code&gt;cloud-run-basics&lt;/code&gt;) from the remote skill catalog and combined them with the &lt;code&gt;gcloud&lt;/code&gt; skill's command formatting rules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud run deploy gemini-38-flash-proxy &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--source&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &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;us-central1 &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;gemini-proxy-sa@[PROJECT_ID].iam.gserviceaccount.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How &lt;code&gt;agy&lt;/code&gt; helps: Running long tasks in the background
&lt;/h3&gt;

&lt;p&gt;Building a container image from source still takes a few minutes. &lt;code&gt;agy&lt;/code&gt; helps by launching the deployment as a background task instead of locking up your interactive session:&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%2Fiikanzccwusv0gw5d7qk.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%2Fiikanzccwusv0gw5d7qk.png" alt="Cloud Run deployment running in the background" width="800" height="160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice the task status bar in the terminal: &lt;code&gt;[14:12:41] gcloud run deploy gemini-38-flash-proxy ... running (1 task(s) · /tasks)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You can continue chatting with the agent, ask questions, or inspect background jobs with &lt;code&gt;/tasks&lt;/code&gt; while Cloud Build compiles your container image.&lt;/p&gt;

&lt;h2&gt;
  
  
  Live verification: Streaming and per-user token persistence
&lt;/h2&gt;

&lt;p&gt;Once the background deployment completed, &lt;code&gt;agy&lt;/code&gt; generated test commands to verify the end-to-end flow.&lt;/p&gt;

&lt;p&gt;Calling the usage endpoint with an authenticated identity token:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; GET https://gemini-38-flash-proxy-[PROJECT_NUMBER].us-central1.run.app/v1/users/me/usage &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;gcloud auth print-identity-token&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Returns real-time Firestore persistence data:&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;"user_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[EMAIL]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"total_input_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"total_output_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;41&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"total_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;55&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"last_active"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-09-21T12:21:21.567000+00:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"models.gemini-3_8-flash.input_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"models.gemini-3_8-flash.output_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;41&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"models.gemini-3_8-flash.total_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;55&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;Atomic increments in Firestore record prompt and completion token counts across requests, giving you immediate visibility into user consumption.&lt;/p&gt;

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

&lt;p&gt;Pairing &lt;code&gt;agy&lt;/code&gt; with the &lt;code&gt;google-cloud-developer&lt;/code&gt; plugin creates a safer, smarter CLI workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Knowledge grounding: Developer Knowledge API prevents outdated SDK hallucinations and ensures accurate code generation.&lt;/li&gt;
&lt;li&gt;Human in the loop: Built-in skill guardrails require explicit permission before running commands that can incur cloud costs.&lt;/li&gt;
&lt;li&gt;Non-blocking workflow: Scheduled timers handle asynchronous cloud operations, while background tasks let long builds run without freezing your prompt.&lt;/li&gt;
&lt;li&gt;Enterprise security defaults: Encourages least-privilege service accounts and IAM authentication over hardcoded secrets.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;Check out more resources on &lt;code&gt;google-cloud-developer&lt;/code&gt; plugin:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/google/skills/tree/main/plugins/cloud/google-cloud-developer" rel="noopener noreferrer"&gt;google-cloud-developer plugin on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cloud.google.com/blog/topics/developers-practitioners/introducing-the-google-cloud-developer-plugin-for-ai-coding-agents?utm_campaign=CDR_0x87fa8d40_default_b563025958&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;Official announcement on the Google Cloud blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://g.dev/cloud/agent-plugins-codelab-agy" rel="noopener noreferrer"&gt;Hands-on codelab: Install and use Google Cloud Developer plugin in Antigravity&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Connect with me
&lt;/h2&gt;

&lt;p&gt;I am always eager to share what I've learned and hear how fellow developers and AI enthusiasts use Antigravity and Google Cloud. If you found this article helpful, feel free to share it and follow me on your favorite social platform:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/remigiusz-samborski/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://x.com/RemikSamborski" rel="noopener noreferrer"&gt;X&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bsky.app/profile/rsamborski.bsky.social" rel="noopener noreferrer"&gt;Bluesky&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

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

</description>
      <category>ai</category>
      <category>agents</category>
      <category>agentskills</category>
      <category>googlecloud</category>
    </item>
    <item>
      <title>Claude Opus 5.5 is now available on Google Cloud</title>
      <dc:creator>Jen Harvey</dc:creator>
      <pubDate>Tue, 22 Sep 2026 17:48:24 +0000</pubDate>
      <link>https://dev.to/googleai/claude-opus-55-is-now-available-on-google-cloud-2oh</link>
      <guid>https://dev.to/googleai/claude-opus-55-is-now-available-on-google-cloud-2oh</guid>
      <description>&lt;p&gt;Everyday complex tasks? No problem. Opus 5.5 handles long-running coding and knowledge work while keeping you in the loop along the way, all at a lower price per token. &lt;a href="https://console.cloud.google.com/agent-platform/publishers/anthropic/model-garden/claude-opus-5-5" rel="noopener noreferrer"&gt;Get started in Model Garden today&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>claude</category>
      <category>googlecloud</category>
    </item>
    <item>
      <title>Build real-time voice applications with Gemini 3.8 Live and 3.5 Transcribe</title>
      <dc:creator>Thor 雷神 Schaeff</dc:creator>
      <pubDate>Wed, 16 Sep 2026 14:30:05 +0000</pubDate>
      <link>https://dev.to/googleai/build-real-time-voice-applications-with-gemini-38-live-and-35-transcribe-4nb5</link>
      <guid>https://dev.to/googleai/build-real-time-voice-applications-with-gemini-38-live-and-35-transcribe-4nb5</guid>
      <description>&lt;p&gt;Yesterday, we &lt;a href="https://blog.google/innovation-and-ai/models-and-research/gemini-models/new-gemini-dialogue-models/" rel="noopener noreferrer"&gt;released&lt;/a&gt; new Gemini Live models in the &lt;a href="https://ai.google.dev/gemini-api/docs/live" rel="noopener noreferrer"&gt;Gemini API&lt;/a&gt; and &lt;a href="http://ai.studio/live" rel="noopener noreferrer"&gt;Google AI Studio&lt;/a&gt;, expanding our developer suite for building real-time, voice-first product experiences:&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://aistudio.google.com/live?model=gemini-3.8-live" rel="noopener noreferrer"&gt;&lt;strong&gt;Gemini 3.8 Live&lt;/strong&gt;&lt;/a&gt; and &lt;strong&gt;&lt;a href="https://aistudio.google.com/live?model=gemini-3.8-live-extended-thinking" rel="noopener noreferrer"&gt;3.8 Live Extended Thinking&lt;/a&gt;:&lt;/strong&gt; Gemini 3.8 Live brings a step change to our native speech-to-speech models, capable of performing tasks while maintaining dialogue. For complex requests, 3.8 Live Extended Thinking delivers deeper reasoning, ranking #1 on Artificial Analysis’ Speech-to-Speech leaderboard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://aistudio.google.com/live?model=gemini-3.5-transcribe-live" rel="noopener noreferrer"&gt;&lt;strong&gt;Gemini 3.5 Transcribe&lt;/strong&gt;&lt;/a&gt;: Our dedicated speech-to-text model brings highly precise transcription across 85+ languages. Released last month, it achieved an average Word Error Rate (WER) of 4.0% (streaming) and 2.6% (non-streaming).&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Gemini 3.8 Live &amp;amp; 3.8 Live Extended Thinking: Build more intelligent conversational agents
&lt;/h2&gt;

&lt;p&gt;Our new models, &lt;a href="https://aistudio.google.com/live?model=gemini-3.8-live" rel="noopener noreferrer"&gt;Gemini 3.8 Live&lt;/a&gt; and &lt;a href="https://aistudio.google.com/live?model=gemini-3.8-live-extended-thinking" rel="noopener noreferrer"&gt;3.8 Live Extended Thinking&lt;/a&gt; enable developers to build voice agents that can reason and execute tasks while maintaining the flow of conversations. Key capabilities include:&amp;nbsp;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Asynchronous function calling:&lt;/strong&gt; Execute API and tool calls in the background while continuing to stream audio responses to the user
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visual context:&lt;/strong&gt; Ground dialogue in live visual inputs to help enable agents that can understand what users say &lt;em&gt;and&lt;/em&gt; see
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alphanumeric precision:&lt;/strong&gt; Accurately parse confirmation codes, claim numbers, and technical data
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multilingual support:&lt;/strong&gt; Reach global audiences with coverage for 97+ languages and accent consistency
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Incremental content updates:&lt;/strong&gt; Seamlessly merge real-time audio with structured data to return context-aware responses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;3.8 Live Extended Thinking also supports &lt;a href="https://ai.google.dev/gemini-api/docs/live-api/thinking" rel="noopener noreferrer"&gt;configurable thinking&lt;/a&gt; to help handle complex, multi-step reasoning in the background, while responding or narrating its progress in the main conversation. These models represent a step-change from our previous live models and provide a more streamlined alternative to cascaded architectures.&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%2Ft3rfv1lvxaopucjkbzcb.webp" 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%2Ft3rfv1lvxaopucjkbzcb.webp" alt="Ambr AI Testimonial" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Gemini 3.8 Live and Gemini 3.8 Live Extended Thinking are available via the &lt;a href="https://ai.google.dev/gemini-api/docs/live" rel="noopener noreferrer"&gt;Live API&lt;/a&gt;. Competitively &lt;a href="http://ai.google.dev/gemini-api/docs/pricing#gemini-3.8-live" rel="noopener noreferrer"&gt;priced&lt;/a&gt; at $0.005/min for audio input and $0.018/min* for audio output, they allow developers to scale voice applications with industry-leading performance.&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%2Fp1g2jotdxaxk2yyrswr8.webp" 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%2Fp1g2jotdxaxk2yyrswr8.webp" alt="AA Speech to Speech Index" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Developers can also access the models through &lt;a href="https://docs.agora.io/en/ai/models/mllm/gemini" rel="noopener noreferrer"&gt;Agora&lt;/a&gt;, &lt;a href="https://docs.fishjam.io/tutorials/gemini-live-integration" rel="noopener noreferrer"&gt;Fishjam&lt;/a&gt;, &lt;a href="https://docs.langchain.com/langsmith/trace-gemini-live" rel="noopener noreferrer"&gt;LangChain&lt;/a&gt;, &lt;a href="https://docs.livekit.io/agents/models/realtime/plugins/gemini/" rel="noopener noreferrer"&gt;LiveKit&lt;/a&gt;, &lt;a href="https://docs.pipecat.ai/pipecat/features/gemini-live" rel="noopener noreferrer"&gt;Pipecat&lt;/a&gt;, &lt;a href="https://vercel.com/docs/ai-gateway/modalities/realtime" rel="noopener noreferrer"&gt;Vercel&lt;/a&gt;, and &lt;a href="https://visionagents.ai/integrations/realtime/gemini" rel="noopener noreferrer"&gt;Vision Agents&lt;/a&gt;, our Live API integration partners that handle media streaming infrastructure for real-world deployment.&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%2Ff1simczwcz8n0vpiwssh.webp" 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%2Ff1simczwcz8n0vpiwssh.webp" alt="Integration Partner logos" width="799" height="269"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Gemini 3.5 Transcribe: Convert streamed speech to text
&lt;/h2&gt;

&lt;p&gt;Real-time speech understanding is critical for voice-first interfaces. Last month, we released Gemini 3.5 Transcribe for low-latency transcription with high precision, achieving a 4.0% WER, and useful features:&amp;nbsp;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Automatic code-switching:&lt;/strong&gt; Handle intra-sentence and inter-sentential code- and language-switching without manual configuration
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom vocabulary biasing:&lt;/strong&gt; Steer speech recognition toward domain-specific terms, uncommon jargon, company names, and proper nouns by passing a &lt;code&gt;custom_vocabulary&lt;/code&gt; list of up to 1,000 terms
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smart transcription mode&lt;/strong&gt;: Deliver polished, reader-ready transcripts with structured formatting, self-corrections, and disfluency removal that eliminates filler words&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;3.5 Transcribe supports 85+ languages and provides a strong listening engine for voice experiences and stateless tasks like sub-second captioning, call center agents, and real-time audio analytics. You can also access the model via the Interactions API to transcribe audio files up to 1 hour long with structured timestamps and speaker labeling. Read our &lt;a href="https://aistudio.google.com/learn/gemini-3-5-transcribe-developer-guide" rel="noopener noreferrer"&gt;developer guide&lt;/a&gt; to learn more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Our complete audio suite for developers
&lt;/h2&gt;

&lt;p&gt;To get started, try out the models in &lt;a href="https://ai.studio/live" rel="noopener noreferrer"&gt;ai.studio/live&lt;/a&gt;, clone example apps from &lt;a href="https://github.com/google-gemini/gemini-live-api-examples" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, or equip your agent with our &lt;a href="https://ai.google.dev/gemini-api/docs/coding-agents#gemini-live-api-dev" rel="noopener noreferrer"&gt;live api skill&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can also create audio experiences with our speech and music generation models, all available in the Gemini API:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://ai.google.dev/gemini-api/docs/live-api/live-translate" rel="noopener noreferrer"&gt;&lt;strong&gt;Gemini 3.5 Live Translate&lt;/strong&gt;&lt;/a&gt;: Speech-to-speech translation across more than 70 languages&amp;nbsp;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ai.google.dev/gemini-api/docs/speech-generation" rel="noopener noreferrer"&gt;&lt;strong&gt;Gemini 3.1 Flash TTS&lt;/strong&gt;&lt;/a&gt;: Highly configurable speech generation (with more updates coming soon)
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ai.google.dev/gemini-api/docs/music-generation" rel="noopener noreferrer"&gt;&lt;strong&gt;Lyria 3.5&lt;/strong&gt;&lt;/a&gt;: Production-grade music generation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The mic is yours, and we can’t wait to hear what you build!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>live</category>
      <category>voice</category>
      <category>gemini</category>
    </item>
    <item>
      <title>How we built a desktop companion robot with Gemma 4 and Raspberry Pi</title>
      <dc:creator>bebechien</dc:creator>
      <pubDate>Wed, 16 Sep 2026 10:15:52 +0000</pubDate>
      <link>https://dev.to/googleai/how-we-built-a-desktop-companion-robot-with-gemma-4-and-raspberry-pi-2oke</link>
      <guid>https://dev.to/googleai/how-we-built-a-desktop-companion-robot-with-gemma-4-and-raspberry-pi-2oke</guid>
      <description>&lt;p&gt;Have you ever wished for a little desk companion—something with the tactile charm of a retro game character that could chat with you, keep track of your desk timers, or talk you through a tricky bug—without a camera staring at you all day?&lt;/p&gt;

&lt;p&gt;That question sparked &lt;strong&gt;DinoDesk AI&lt;/strong&gt;: our LEGO Dino AI Companion Robot.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/pXOTjxcNzdQ" width="710" height="399"&gt;
  &lt;/iframe&gt;
&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%2F0xp2qj95pafrx31ezdtb.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%2F0xp2qj95pafrx31ezdtb.png" alt="dinodesk" width="800" height="602"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I and my colleague Shama set out to build a smart, low-power desk robot that combines the nostalgia of 8-bit audio-visuals and LEGO Technic mechanics with a modern &lt;strong&gt;Hybrid LLM Switching Architecture (Local ↔ Cloud)&lt;/strong&gt;. By pairing a &lt;strong&gt;Raspberry Pi&lt;/strong&gt; on the desk with a local PC gateway running &lt;strong&gt;Gemma 4&lt;/strong&gt; alongside &lt;strong&gt;Gemini Flash&lt;/strong&gt;, we created a companion that offers &lt;strong&gt;100% visual privacy (no camera)&lt;/strong&gt;, instantaneous zero-cost local chat, and deep cloud reasoning on demand.&lt;/p&gt;

&lt;p&gt;Here is the full behind-the-scenes story of how we designed, wired, and programmed DinoDesk AI from the ground up.&lt;/p&gt;




&lt;h1&gt;
  
  
  1. The Hybrid Brain: Local Gemma 4 ↔ Cloud Gemini
&lt;/h1&gt;

&lt;p&gt;One of the biggest dilemmas when building an AI hardware companion is choosing where the brain lives. If everything runs in the cloud, every casual &lt;em&gt;"What time is it?"&lt;/em&gt; costs API tokens, adds network latency, and sends your voice data over the internet. On the other hand, if you strictly limit yourself to a small on-device model, the robot struggles the moment you ask it to create a new feature in your gigantic codebase, or explain a complex topic.&lt;/p&gt;

&lt;p&gt;So we decided to build a &lt;strong&gt;Hybrid LLM Architecture&lt;/strong&gt;, with a &lt;strong&gt;Unified LLM Gateway (Router)&lt;/strong&gt; hosted on the user's main PC. The Raspberry Pi on your desk sends identical OpenAI-compatible requests over Wi-Fi regardless of which engine is active:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; ┌─────────────────────────────────────────────────┐
 │           [ Main PC / Local Gateway ]           │
 │                                                 │
 │   ┌─────────────────────────────────────────┐   │
 │   │      Dynamic Model Router / Switch      │   │
 │   └────────────────────┬────────────────────┘   │
 │                        │                        │
 │     ┌──────────────────┴──────────────────┐     │
 │     v                                     v     │
 │  [ LOCAL ENGINE ]              [ CLOUD ENGINE ] │
 │  LM Studio / Gemma 4           Gemini Flash /   │
 │  (Zero Latency, Private)       Gemini Live      │
 └────────────────────────┬────────────────────────┘
                          │
                          │ Wi-Fi (Unified OpenAI-Compatible Stream)
                          v
 ┌─────────────────────────────────────────────────┐
 │           [ DinoDesk AI (RPi) ]                 │
 │  - Pirate Audio LCD &amp;amp; I2S Beep Speaker          │
 │  - Push Button &amp;amp; Optional Sensors               │
 └─────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Three Modes of Intelligence
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Active Model&lt;/th&gt;
&lt;th&gt;Strengths &amp;amp; Primary Use Case&lt;/th&gt;
&lt;th&gt;How to Switch&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;🟢 Local Mode&lt;/strong&gt; &lt;em&gt;(Default)&lt;/em&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Gemma 4&lt;/strong&gt; (via LM Studio)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Zero-cost, offline, 100% private.&lt;/strong&gt; Delivers ~200 ms first-token latency for casual chats, desk timers, and quick status checks.&lt;/td&gt;
&lt;td&gt;Double-click &lt;strong&gt;Pirate Audio Button X&lt;/strong&gt;, 3s long-press on Capacitive Touch sensor, or voice command (&lt;em&gt;"Switch to Cloud Mode"&lt;/em&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;🟡 Cloud Mode&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Gemini Flash / Gemini Live&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;High reasoning &amp;amp; complex problem solving.&lt;/strong&gt; Ideal for coding help, complex math, deep explanations, or language tutoring (~800 ms first token).&lt;/td&gt;
&lt;td&gt;Same as above&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;⚡ Auto-Hybrid Mode&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Automatic Routing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Defaults to &lt;strong&gt;Gemma 4 locally&lt;/strong&gt;. When the complexity classifier detects multi-step reasoning keywords (&lt;em&gt;"explain"&lt;/em&gt;, &lt;em&gt;"compare"&lt;/em&gt;, &lt;em&gt;"write code"&lt;/em&gt;), it transparently escalates the prompt to &lt;strong&gt;Gemini Flash&lt;/strong&gt;.&lt;/td&gt;
&lt;td&gt;Automatic System Routing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;When Auto-Hybrid Mode escalates a question to the cloud, the robot's indicator temporarily shifts from &lt;strong&gt;🟢 steady green&lt;/strong&gt; to &lt;strong&gt;🟡 steady gold&lt;/strong&gt; for the duration of the response, then returns to green—so you always know at a glance which brain is answering.&lt;/p&gt;




&lt;h1&gt;
  
  
  2. Hardware &amp;amp; Tactile Mechanics: LEGO Meets Pirate Audio
&lt;/h1&gt;

&lt;p&gt;We wanted DinoDesk AI to feel like a physical toy rather than a cold smart speaker. Instead of 3D-printing a sealed plastic shell, we built the body out of &lt;strong&gt;basic LEGO bricks and Technic lever mechanisms&lt;/strong&gt; so anyone can customize or repair it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Bill of Materials (BOM)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Main Controller:&lt;/strong&gt; Raspberry Pi + 32GB MicroSD&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Display &amp;amp; Audio Shield:&lt;/strong&gt; &lt;a href="https://shop.pimoroni.com/products/pirate-audio-mini-speaker?variant=31189753692243" rel="noopener noreferrer"&gt;Pimoroni Pirate Audio Speaker&lt;/a&gt; (1.3" 240×240 ST7789 IPS LCD + I2S 1W Speaker + 4 tactile buttons)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Red Button:&lt;/strong&gt; A mini push button switch that gives you a satisfying tactile click to start or stop voice capture&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audio Input:&lt;/strong&gt; Compact USB Mini Microphone&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Motion System:&lt;/strong&gt; Motors driving Neck movements and Tail wagging&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Before building the full body, I first prototyped the logic using a Raspberry Pi and a simple LEGO set.&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%2Fbebechien.github.io%2Fcozy-corner-future%2Fimages%2Fdinodesk-prototype1.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%2Fbebechien.github.io%2Fcozy-corner-future%2Fimages%2Fdinodesk-prototype1.gif" width="199" height="112"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fbebechien.github.io%2Fcozy-corner-future%2Fimages%2Fdinodesk-prototype2.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%2Fbebechien.github.io%2Fcozy-corner-future%2Fimages%2Fdinodesk-prototype2.gif" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Physical Button Controls
&lt;/h3&gt;

&lt;p&gt;Even with voice and sensor triggers, dedicated hardware buttons feel good for instant physical control:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Button A (GPIO 5) — Cancel / Mute:&lt;/strong&gt; Immediately stops the active response stream, silences audio, and returns the robot to &lt;code&gt;Idle&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Button B (GPIO 6) — Home Re-Center:&lt;/strong&gt; Resets all servos to their neutral center position without interrupting the current state.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Button X (GPIO 16) — Expression &amp;amp; Engine Switch:&lt;/strong&gt; Single-click cycles facial expressions manually; double-click toggles &lt;strong&gt;Local ↔ Cloud Mode&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Button Y (GPIO 24) — Tail Test &amp;amp; Volume:&lt;/strong&gt; Single-press fires a tail-wagging sequence to verify mechanical alignment; a 2-second long-press cycles beep volume (&lt;code&gt;Low → Medium → High → Mute&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;


&lt;h1&gt;
  
  
  3. Bringing the Dino to Life: The 5-State Finite State Machine
&lt;/h1&gt;

&lt;p&gt;A companion robot only feels alive when its eyes, voice, and body move together. We designed a 5-stage &lt;strong&gt;Finite State Machine (FSM)&lt;/strong&gt; that coordinates the 240×240 LCD eye expressions, 8-bit beeps, and motor movements:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────┐  button     ┌───────────┐   release   ┌──────────┐   stream   ┌──────────┐
│ Sleeping │──────────&amp;gt;  │   Idle    │────────────&amp;gt;│Listening │─────────&amp;gt;  │ Thinking │
└──────────┘  (wake)     └───────────┘   (trigger) └──────────┘  (send)    └──────────┘
                             ^                                                  │
                             │              ┌──────────┐                        │
                             └──────────────│ Speaking │&amp;lt;───────────────────────┘
                               (done)       └──────────┘       (tokens arrive)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;State&lt;/th&gt;
&lt;th&gt;Entry Condition&lt;/th&gt;
&lt;th&gt;Pirate Audio LCD Expression&lt;/th&gt;
&lt;th&gt;8-Bit Audio Feedback&lt;/th&gt;
&lt;th&gt;Motor Action (Neck / Tail)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;1. Sleeping&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Inactive for 3 mins OR room dark&lt;/td&gt;
&lt;td&gt;(&lt;code&gt;- _ -&lt;/code&gt;)&lt;br&gt;Closed eyes + &lt;code&gt;zzz&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Silent (or optional soft snore)&lt;/td&gt;
&lt;td&gt;Motors relaxed; head tilted slightly down&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;2. Idle&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Default standby&lt;/td&gt;
&lt;td&gt;(&lt;code&gt;•  •&lt;/code&gt;)&lt;br&gt;Autonomous blinking&lt;/td&gt;
&lt;td&gt;Occasional wake/blink chime&lt;/td&gt;
&lt;td&gt;Head centers; neck sways slowly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3. Listening&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Button click OR sensor trigger&lt;/td&gt;
&lt;td&gt;(&lt;code&gt;O  O&lt;/code&gt;)&lt;br&gt;Eyes widen bright&lt;/td&gt;
&lt;td&gt;
&lt;em&gt;"Beep-Boop!"&lt;/em&gt; rising tone&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Head tilts 15° toward the user&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;4. Thinking&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Audio sent; router inferring&lt;/td&gt;
&lt;td&gt;(&lt;code&gt;º  º&lt;/code&gt;)&lt;br&gt;Spinning pupils + mode badge&lt;/td&gt;
&lt;td&gt;Irregular processing ticks (&lt;code&gt;tick-teek-poh&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Neck sways slowly side-to-side&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;5. Speaking&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Receiving SSE token stream&lt;/td&gt;
&lt;td&gt;Expressive blinking + scrolling subtitles&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;8-bit typewriter beep per token&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Tail wags in sync with text length&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;p&gt;Building DinoDesk AI reminded us that AI doesn't have to stay locked inside a browser tab or a cloud data center. When you give an open model like &lt;strong&gt;Gemma 4&lt;/strong&gt; a pair of pixel eyes, an 8-bit voice, a wiggling LEGO tail, and the ability to call on &lt;strong&gt;Gemini&lt;/strong&gt; when things get heavy, your desk suddenly feels a whole lot more lively. 🦖✨&lt;/p&gt;

&lt;p&gt;It's still a work in progress and not quite perfect yet, but I'll be back soon with fully implemented voice chat capabilities! Until then, please enjoy the fun little 8-bit sound effects every time you press the button. Beep-Boop!&lt;/p&gt;

&lt;p&gt;Clone the repo here : &lt;a href="https://github.com/google-gemma/dinodesk-ai-companion/" rel="noopener noreferrer"&gt;https://github.com/google-gemma/dinodesk-ai-companion/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And drop a comment to share what you're planning to create.&lt;/p&gt;

</description>
      <category>raspberrypi</category>
      <category>gemma</category>
      <category>gemini</category>
      <category>robotics</category>
    </item>
    <item>
      <title>Embedding versions management, TOAST and bloating in PostgreSQL</title>
      <dc:creator>Gleb Otochkin</dc:creator>
      <pubDate>Sat, 12 Sep 2026 00:05:49 +0000</pubDate>
      <link>https://dev.to/googleai/embedding-versions-management-toast-and-bloating-in-postgresql-2g2k</link>
      <guid>https://dev.to/googleai/embedding-versions-management-toast-and-bloating-in-postgresql-2g2k</guid>
      <description>&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%2F4xhl0bc7cqusaitfbsq1.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%2F4xhl0bc7cqusaitfbsq1.png" width="800" height="359"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are working with vector embeddings you probably already know the AI models including embedding models have their own lifecycle. When a new model is released by a service provider the old version will be eventually deprecated and removed from the service. You might have better control with models deployed on your own infrastructure like &lt;a href="https://codelabs.developers.google.com/alloydb-omni-gke-embeddings?utm_campaign=CDR_0x370c34a8_default_b559734139&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;EmbeddingGemma in this codelab&lt;/a&gt; but eventually you might want the new model just because it works better.&lt;/p&gt;

&lt;p&gt;What is the impact of refreshing all the vector embedding in your AlloyDB or PostgreSQL database? Let’s dive in.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prepare the tests data
&lt;/h3&gt;

&lt;p&gt;Let us prepare a test environment. In my tests I am going to use AlloyDB Omni since it is fully PostgreSQL compatible and in this case behaves exactly like any PostgreSQL database.&lt;br&gt;&lt;br&gt;
We create a test table with the vector data type, add some indexes, and generate 20k rows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Install extensions&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;EXTENSION&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;EXTENSION&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;pgstattuple&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Create a function building random vectors&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="k"&gt;REPLACE&lt;/span&gt; &lt;span class="k"&gt;FUNCTION&lt;/span&gt; &lt;span class="n"&gt;random_vector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dim&lt;/span&gt; &lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="k"&gt;RETURNS&lt;/span&gt; &lt;span class="n"&gt;vector&lt;/span&gt;
&lt;span class="k"&gt;LANGUAGE&lt;/span&gt; &lt;span class="k"&gt;sql&lt;/span&gt; &lt;span class="k"&gt;VOLATILE&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="err"&gt;$$&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;array_agg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()::&lt;/span&gt;&lt;span class="nb"&gt;real&lt;/span&gt;&lt;span class="p"&gt;)::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;generate_series&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&gt;$$&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Create a demo table&lt;/span&gt;
&lt;span class="k"&gt;DROP&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;demo_documents&lt;/span&gt; &lt;span class="k"&gt;CASCADE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;demo_documents&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="n"&gt;BIGSERIAL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;category_id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="n"&gt;TIMESTAMPTZ&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="c1"&gt;-- Large text column (&amp;gt; 2.5 KB) to demonstrate TOAST interaction with uncompressed/compressed text&lt;/span&gt;
    &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;-- 768-dim float vector (~3.08 KB) -&amp;gt; pushed to TOAST&lt;/span&gt;
    &lt;span class="n"&gt;embedding&lt;/span&gt; &lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;768&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- Pause autovacuum temporarily&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;demo_documents&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;autovacuum_enabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- Add a few B-tree indexes&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;idx_docs_category_created&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;demo_documents&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;category_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;idx_docs_status&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;demo_documents&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;idx_docs_title&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;demo_documents&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- Create HNSQ index on the vectores&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;idx_docs_embedding_hnsw&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;demo_documents&lt;/span&gt;
&lt;span class="k"&gt;USING&lt;/span&gt; &lt;span class="n"&gt;hnsw&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;embedding&lt;/span&gt; &lt;span class="n"&gt;vector_cosine_ops&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ef_construction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- Generate some data&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;demo_documents&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;category_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;created_at&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="n"&gt;embedding&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;50&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;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ARRAY&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'draft'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'published'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'archived'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'review'&lt;/span&gt;&lt;span class="p"&gt;])[(&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;3&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;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="s1"&gt;'Document title #'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;g&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s1"&gt;' minutes'&lt;/span&gt;&lt;span class="p"&gt;)::&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;-- ~3,000 bytes of repetitive text (&amp;gt; 2 KB TOAST threshold)&lt;/span&gt;
    &lt;span class="n"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'PostgreSQL TOAST and vector storage internals demo '&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;g&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="c1"&gt;-- 768-dim vector&lt;/span&gt;
    &lt;span class="n"&gt;random_vector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;768&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;generate_series&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="k"&gt;g&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Check the size of all segments
&lt;/h3&gt;

&lt;p&gt;Let’s establish a clear baseline for comparison. We will run an initial vacuum analyze and check all our relations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Run an initial vacuum to start with clean baseline metrics&lt;/span&gt;
&lt;span class="k"&gt;VACUUM&lt;/span&gt; &lt;span class="k"&gt;ANALYZE&lt;/span&gt; &lt;span class="n"&gt;demo_documents&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Check all the segments&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;relname&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;object_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;CASE&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;relkind&lt;/span&gt;
        &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="s1"&gt;'r'&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'table'&lt;/span&gt;
        &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="s1"&gt;'t'&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'toast table'&lt;/span&gt;
        &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="s1"&gt;'i'&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'index'&lt;/span&gt;
    &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;pg_size_pretty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pg_relation_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;oid&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="k"&gt;size&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_class&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;relname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'demo_documents'&lt;/span&gt;
   &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;oid&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;indexrelid&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_index&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;indrelid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'demo_documents'&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;regclass&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;oid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;reltoastrelid&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_class&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;relname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'demo_documents'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;pg_relation_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;oid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is what we get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        object_name | kind | size
---------------------------+-------------+---------
 idx_docs_embedding_hnsw | index | 78 MB
 pg_toast_3177242 | toast table | 81 MB
 demo_documents | table | 4336 kB
 idx_docs_category_created | index | 1024 kB
 idx_docs_title | index | 1024 kB
 demo_documents_pkey | index | 512 kB
 idx_docs_status | index | 256 kB
(7 rows)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our demo_documents table with indexes and TOAST occupies about 170 MB. It might be helpful also to check tuples (physical rows):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Dead/Live tuple stats&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="s1"&gt;'Main Table'&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;table_len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;tuple_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;tuple_percent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;dead_tuple_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;free_percent&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pgstattuple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'demo_documents'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;-- TOAST Table Dead/Live tuple stats&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="s1"&gt;'TOAST Table'&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;table_len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;tuple_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;tuple_percent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;dead_tuple_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;free_percent&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pgstattuple&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;reltoastrelid&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_class&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;relname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'demo_documents'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We see the main table and the TOAST have zero dead tuples and reasonable small free space percentage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; component | table_len | tuple_count | tuple_percent | dead_tuple_count | free_percent
------------+-----------+-------------+---------------+------------------+--------------
 Main Table | 4440064 | 20000 | 90.92 | 0 | 1.57

  component | table_len | tuple_count | tuple_percent | dead_tuple_count | free_percent
-------------+-----------+-------------+---------------+------------------+--------------
 TOAST Table | 84492288 | 40000 | 74.52 | 0 | 21.82
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is a basic graph to illustrate the layout:&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%2F1apm1e3eydisxdewanhg.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%2F1apm1e3eydisxdewanhg.png" width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Updating the vectors
&lt;/h3&gt;

&lt;p&gt;We emulate the process of refreshing embeddings by updating all the vectors in the demo_documents table. For example we had all our embeddings created using Google text-embedding-004 model and we updated all of them using gemini-embedding-2 model. Google publishing life cycle for all its models in the &lt;a href="https://docs.cloud.google.com/gemini-enterprise-agent-platform/models/model-versions?utm_campaign=CDR_0x370c34a8_default_b559734139&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; where you can see it and plan your maintenance in advance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Update all vector embeddings&lt;/span&gt;
&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;demo_documents&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;embedding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;random_vector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;768&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After updating all the rows we can check the sizes of all objects again and see how they’ve changed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        object_name | kind | size before update | size after update
---------------------------+-------------+--------------------+-------------------
 idx_docs_embedding_hnsw | index | 78 MB | 156 MB
 pg_toast_3177242 | toast table | 81 MB | 159 MB
 demo_documents | table | 4336 kB | 7376 kB
 idx_docs_category_created | index | 1024 kB | 2048 kB
 idx_docs_title | index | 1024 kB | 2048 kB
 demo_documents_pkey | index | 512 kB | 1024 kB
 idx_docs_status | index | 256 kB | 512 kB
(7 rows)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Almost all objects including table, TOAST and indexes doubled in size. The impact is most visible for the HNSW vector index and the demo_documents table itself. Here is information about dead tuples and space allocation for the main table and TOAST:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; component | table_len | tuple_count | tuple_percent | dead_tuple_count | free_percent
------------+-----------+-------------+---------------+------------------+--------------
 Main Table | 7585792 | 20000 | 47.84 | 20000 | 1.2

  component | table_len | tuple_count | tuple_percent | dead_tuple_count | free_percent
-------------+-----------+-------------+---------------+------------------+--------------
 TOAST Table | 166387712 | 40000 | 37.84 | 40000 | 22.21
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is a diagram:&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%2Fyyw2urvmdvjicwwhgosy.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%2Fyyw2urvmdvjicwwhgosy.png" width="800" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, roughly half of the space is occupied by dead tuples. When I discuss it with some developers they mention the vacuuming process and at least some of them had expectations that it should fix the bloating. Let’s do some vacuuming and see if it changes it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;VACUUM&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;VERBOSE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;ANALYZE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;demo_documents&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The verbose output provides enough information about what was done during the vacuum process and everybody who is curious can check it in detail. We can have a look into the main stats about tuples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; component | table_len | tuple_count | tuple_percent | dead_tuple_count | free_percent
------------+-----------+-------------+---------------+------------------+--------------
 Main Table | 7585792 | 20000 | 47.84 | 0 | 50.16

  component | table_len | tuple_count | tuple_percent | dead_tuple_count | free_percent
-------------+-----------+-------------+---------------+------------------+--------------
 TOAST Table | 166387712 | 40000 | 37.84 | 0 | 60.17

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The vacuum process cleared up the dead tuples leaving the space allocation intact and it was exactly what we expected. We have free space which can be used by the new rows but the allocation on the disk didn’t change.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        object_name | kind | size before vacuum | size after vacuum
---------------------------+-------------+--------------------+-------------------
 pg_toast_3177242 | toast table | 159 MB | 159 MB
 idx_docs_embedding_hnsw | index | 156 MB | 156 MB
 demo_documents | table | 7408 kB | 7408 kB
 idx_docs_category_created | index | 2048 kB | 2048 kB
 idx_docs_title | index | 2048 kB | 2048 kB
 demo_documents_pkey | index | 1024 kB | 1024 kB
 idx_docs_status | index | 512 kB | 512 kB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Alternative layout
&lt;/h3&gt;

&lt;p&gt;What if the bloating is a significant issue for your workload? In such a case you might consider a different layout and place the vectors in a separate table connecting to the main table using primary keys. Then you can use either a view or simple table join to work with the data. And when the vectors are required to be updated — create a new table with a new vector version.&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%2Fg1jxo9dbfv979hla3for.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%2Fg1jxo9dbfv979hla3for.png" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Such an approach can save you some vacuum overhead and bloating. But of course the join of two (or more) tables might perform slightly differently than the single flat table approach. You need to test it with your data and with your vectors.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;The final layout of your table might depend on multiple factors. In real life I very rarely saw a case when the search was performed only in one single table. In most cases it was always a combination of 2,3,4, or more tables with the resulting dataset. Considering other parts like filters on non-vector columns or full-text search combined with the semantic search, the real case might be much more complicated than a demo with one flat table where all the data is stored in one segment. And for a high-loaded scalable environment, the right relational model can be a key for success and requires vigorous testing.&lt;/p&gt;

&lt;p&gt;In the next post I will try to evaluate the performance overhead of keeping the vectors in a separate table vs having them in the same table. Stay tuned!&lt;/p&gt;




</description>
      <category>vectorembeddings</category>
      <category>performance</category>
      <category>databasedesign</category>
      <category>postgres</category>
    </item>
    <item>
      <title>is Graph Engineering just reinventing systems architecture for the AI age?</title>
      <dc:creator>Tilde A. Thurium</dc:creator>
      <pubDate>Thu, 10 Sep 2026 19:23:39 +0000</pubDate>
      <link>https://dev.to/googleai/is-graph-engineering-just-reinventing-systems-architecture-for-the-ai-age-2427</link>
      <guid>https://dev.to/googleai/is-graph-engineering-just-reinventing-systems-architecture-for-the-ai-age-2427</guid>
      <description>&lt;p&gt;&lt;strong&gt;Bringing backend predictability to multi-agent systems&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I've been hearing the phrase "graph engineering" thrown around a lot lately. I originally assumed it had something to do with knowledge graphs, or maybe GraphRAG. Not quite!&lt;/p&gt;

&lt;p&gt;I sat down with &lt;a href="https://www.linkedin.com/in/anniewangtech/" rel="noopener noreferrer"&gt;Annie Wang&lt;/a&gt; and asked her to break it down from the ground up: what graph engineering is, and how it gives developers control over complex AI systems.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's in the video
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Demystifying the terms:&lt;/strong&gt; The actual differences between an agent harness, a loop, and a graph.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;A real-world example:&lt;/strong&gt; Walking through an automated pull request (PR) review pipeline using fan-out, join, and conditional router patterns.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;What it isn't:&lt;/strong&gt; Why graph engineering is fundamentally different from knowledge graphs and agent swarms.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Shared state:&lt;/strong&gt; How to orchestrate shared state and strict schemas using Google's Agent Development Kit (ADK).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The point that stuck with me is that graph engineering basically feels like modern backend architecture —like microservices— applied to agents. Instead of letting LLMs wander in a black-box loop and hoping for the best, you treat nodes with strict schemas and fan-out/join pipelines. It gives us back the predictability and debuggability that software engineers actually need.&lt;/p&gt;

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

&lt;p&gt;&lt;em&gt;(You can also follow along with the hands-on &lt;a href="https://g.dev/ai/adk-2" rel="noopener noreferrer"&gt;ADK Codelab&lt;/a&gt;).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Did your mental model of "graph engineering" match up? Are you still running straight loops for your agents, or have you started breaking them into graph patterns? Let me know in the comments!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>graphengineering</category>
      <category>adk</category>
    </item>
    <item>
      <title>4 pitfalls of loop engineering (and how to fix them)</title>
      <dc:creator>Tilde A. Thurium</dc:creator>
      <pubDate>Wed, 09 Sep 2026 17:37:13 +0000</pubDate>
      <link>https://dev.to/googleai/4-pitfalls-of-loop-engineering-and-how-to-fix-them-1ji2</link>
      <guid>https://dev.to/googleai/4-pitfalls-of-loop-engineering-and-how-to-fix-them-1ji2</guid>
      <description>&lt;p&gt;Perhaps you've heard the term &lt;em&gt;Loop Engineering&lt;/em&gt;: instead of solving a problem by hand, you build a system, set a measurable goal, and let an agent keep iterating until it gets there.&lt;/p&gt;

&lt;p&gt;It sounds great until something goes wrong.&lt;/p&gt;

&lt;p&gt;So I sat down with &lt;a href="https://www.linkedin.com/in/anniewangtech/" rel="noopener noreferrer"&gt;Annie Wang&lt;/a&gt; to talk through the four most common ways Loop Engineering breaks down, and how to fix each one.&lt;/p&gt;

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


&lt;div class="crayons-card c-embed"&gt;

  

&lt;h2&gt;
  
  
  What's in the video
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What Loop Engineering actually means: building an agentic system that retries toward a definable goal&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Failure #1 - runaway loops:&lt;/strong&gt; you need a hard stop rule because tokens cost real $$$. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Failure #2 - unverified autonomy:&lt;/strong&gt; why letting an agent grade its own work is like asking a kindergartner to grade its own homework, and why you want agent A checking agent B's work instead&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Failure #3 - vague or uncheckable goals:&lt;/strong&gt; why "make this better" breaks an LLM, and how to write criteria that are actually non-negotiable&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Failure #4- complexity overflow:&lt;/strong&gt; when a single loop chokes on a big task, and why that's the moment to move from Loop Engineering to Graph Engineering

&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;



&lt;p&gt;Have you hit any of these failure modes yourself? Tell me which one (or more) got you.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Interactive AI Eval Dashboards with Data Studio</title>
      <dc:creator>Katie McLaughlin</dc:creator>
      <pubDate>Tue, 08 Sep 2026 07:00:00 +0000</pubDate>
      <link>https://dev.to/googleai/interactive-ai-eval-dashboards-with-data-studio-1kl9</link>
      <guid>https://dev.to/googleai/interactive-ai-eval-dashboards-with-data-studio-1kl9</guid>
      <description>&lt;p&gt;Welcome to the final entry 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. If this isn’t you, please skip to "Overview of New Pre-Configured Dashboard Components"&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. Furthermore, the math is mine but the formula formatting is AI's.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;If you intend to (re)implement the procedures in this walkthrough, all you need is the CSV export (&lt;code&gt;data_mega_export.csv&lt;/code&gt;) generated during &lt;a href="https://dev.to/googleai/step-up-to-the-sheets-ai-eval-export-and-illustrating-data-bak"&gt;Part 3&lt;/a&gt; (from evaluations performed in &lt;a href="https://dev.to/googleai/designing-ai-evals-clarity-now-and-visualization-next-4eii"&gt;Part 1&lt;/a&gt;) and a Google Workspace account to access Data Studio. &lt;a href="https://dev.to/googleai/ai-evals-at-a-glance-heatmaps-for-stakeholders-2mki"&gt;Part 2&lt;/a&gt; will give you a deeper understanding of evals, trace diagnostics and back-of-the-napkin analysis but is &lt;em&gt;optional&lt;/em&gt; if you just want to build dashboards.&lt;/p&gt;

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

&lt;p&gt;In this final part of our series, we connect our evaluation dataset to &lt;a href="https://datastudio.google.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;Data Studio&lt;/strong&gt;&lt;/a&gt; to build codeless, interactive dashboards.&lt;/p&gt;

&lt;p&gt;While &lt;code&gt;inspect view&lt;/code&gt; provides developer-focused TUI trace diagnostics and Google Sheets gives us tabular sparklines, non-technical stakeholders (product managers, business leads, executive sponsors) need interactive dashboards where they can slice performance across our foundational 3D Evaluation Matrix on the fly without writing code. Beyond macro dimensions like &lt;strong&gt;model&lt;/strong&gt; family and &lt;strong&gt;skill group&lt;/strong&gt;, our dashboard empowers users to dynamically partition data over key operational booleans:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;completed&lt;/code&gt; (Conditional Accuracy)&lt;/strong&gt;: Isolates Model Capability (accuracy on completed runs) from infrastructure noise (quota drops, timeouts, container crashes). Toggling between &lt;code&gt;TRUE&lt;/code&gt; and &lt;code&gt;ALL&lt;/code&gt; exposes Survivorship Bias in task execution.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;is_baseline_or_has_activated_skill&lt;/code&gt; (Conditional Uptake Slicer)&lt;/strong&gt;: Separates baseline control cohorts from active skill interventions where the model invoked &lt;code&gt;activate_skill&lt;/code&gt; (i.e. &lt;strong&gt;uptook&lt;/strong&gt; the skill into context).

&lt;ul&gt;
&lt;li&gt;Crucially, "activated" in Inspect AI telemetry specifically tracks skill &lt;em&gt;uptake&lt;/em&gt; (executing the &lt;code&gt;activate_skill&lt;/code&gt; tool call). Filtering for &lt;code&gt;FALSE&lt;/code&gt; isolates dormant runs where a skill was available but never uptaken.&lt;/li&gt;
&lt;/ul&gt;
&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%2F79egthpwmqvx7h62kamj.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%2F79egthpwmqvx7h62kamj.jpg" 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="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1-click Data Studio template setup
&lt;/h2&gt;

&lt;p&gt;We provide a pre-configured &lt;strong&gt;Master Dashboard Template&lt;/strong&gt; containing all pre-styled components used here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Clone the master template
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Open the &lt;a href="https://datastudio.google.com/reporting/236e070d-6495-4849-9589-28e645cc7838" rel="noopener noreferrer"&gt;&lt;strong&gt;Inspect AI Dashboard Template&lt;/strong&gt;&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Make a copy&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&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%2F9t4wwzbo6qqs8fjv28e3.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%2F9t4wwzbo6qqs8fjv28e3.png" alt="A screenshot of the Data Studio top-right dropdown menu showing the 'Make a copy' option highlighted." width="800" height="593"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  30-second setup and customization
&lt;/h2&gt;

&lt;p&gt;Once cloned:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the new report, press &lt;strong&gt;Add data&lt;/strong&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%2Fzpctrswmr7s61n6o2fm4.png" alt="A screenshot of the Data Studio toolbar showing the 'Add data' button highlighted next to 'Add page' and 'Blend'." width="800" height="512"&gt;
&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Google Sheets&lt;/strong&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%2Fwwintu3mwn2hlasrimu4.png" alt="A screenshot of Data Studio's 'Add data to report' interface, with the Google Sheets connector highlighted among other Google connectors." width="800" height="612"&gt;
&lt;/li&gt;
&lt;li&gt;Select the Spreadsheet and the Worksheet (likely the sole Worksheet) you created in &lt;a href="https://dev.to/googleai/step-up-to-the-sheets-ai-eval-export-and-illustrating-data-bak"&gt;the third entry&lt;/a&gt; and press &lt;strong&gt;Add&lt;/strong&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%2Fil7vtgy1umuvww4m95r7.png" alt="A screenshot of the 'AI Evals' spreadsheet and the 'data\_mega\_export' worksheet selection dialog, with 'Use first row as headers' checked." width="798" height="138"&gt;
&lt;/li&gt;
&lt;li&gt;Select all the components and set their data source to that sheet
&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%2Fvqgz66x5pmgqb7z9xhjv.png" alt="A screenshot of the Data Studio canvas with components showing 'Missing data source' errors, and the 'Data source' panel open on the right showing 'AI Evals - data\_mega\_export' selected." width="799" height="255"&gt;
&lt;/li&gt;
&lt;li&gt;Finally, select the bubble chart and open the &lt;strong&gt;Style&lt;/strong&gt; tab, find the &lt;strong&gt;Bubble color&lt;/strong&gt; dropdown and set it to ‘model’
&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%2F1sppzsreere8tvjx8m0w.png" alt="A screenshot of Data Studio's 'Bubble chart properties' style settings, with the 'Bubble color' dropdown set to 'model'." width="800" height="549"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it! Your interactive dashboard is now live, fully bound to your evaluation data.&lt;/p&gt;

&lt;p&gt;Before diving into the new charts, check out the bottom left corner of the report. There you will find a Pivot Table Heatmap. Like the heatmap I made in the &lt;a href="https://dev.to/googleai/ai-evals-at-a-glance-heatmaps-for-stakeholders-2mki"&gt;second entry in this series&lt;/a&gt;, this heatmap is a 2D visual matrix where color intensity represents numerical magnitude—here, quadratic curved accuracy scores. Since I already discussed how to use these for analysis in the earlier blog entry, I will not be explaining it here. If, on the other hand, you are interested in implementation, feel free to inspect and adjust the settings on the Pivot Table Heatmap in your copied report. &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%2Fz1lu4bh5bije31nyvmgf.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%2Fz1lu4bh5bije31nyvmgf.png" alt="A Data Studio Pivot Table Heatmap displaying score values across models (gemini-3.6-flash, gemini-3.5-flash-lite) and skill groups (gemini-api, gcloud), with cell shading representing score intensity." width="799" height="358"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: This screenshot was done on a later dataset than the rest of the report and the specific metrics should not be taken into account when comparing to the rest of the screenshots here.  &lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Overview of new pre-configured dashboard components
&lt;/h2&gt;

&lt;p&gt;Data Studio translates multi-dimensional evaluation CSV data into intuitive visual dimensions (spatial X/Y coordinates, bubble area scaling, color coding, and hover popovers). Here is how each pre-built dashboard element visually measures evaluation performance:&lt;/p&gt;

&lt;h3&gt;
  
  
  Chart A: Performance and cost (scatter/bubble chart)
&lt;/h3&gt;

&lt;p&gt;This chart maps three core evaluation dimensions onto a single 2D visual canvas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Horizontal Position (X-Axis ➔ Latency)&lt;/strong&gt;: Measures average task duration in seconds. Bubbles placed further to the right represent slower runs.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vertical Position (Y-Axis ➔ Score / Accuracy)&lt;/strong&gt;: Measures average task accuracy from &lt;code&gt;0.0&lt;/code&gt; to &lt;code&gt;1.0&lt;/code&gt;. Bubbles placed higher up represent better accuracy.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bubble Size / Area (Visual Cost &amp;amp; Unit Economics)&lt;/strong&gt;: Circle size scales with average task &lt;code&gt;cost&lt;/code&gt; for a quick visual gut-check.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hover Tooltips &amp;amp; Sub-Cent Formatting&lt;/strong&gt;: Hovering displays latency, accuracy, model, skill group, and cost formatted as &lt;code&gt;Currency &amp;gt; USD&lt;/code&gt; (&lt;code&gt;#,##0.0000&lt;/code&gt;) so sub-cent costs (e.g., &lt;code&gt;$0.0044&lt;/code&gt;) don't round to &lt;code&gt;$0.00&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Chart B: Accuracy and error bars (±1 SEM whiskers)
&lt;/h3&gt;

&lt;p&gt;The second pre-configured chart visualizes accuracy scores alongside standard error of the mean (SEM) whiskers.&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%2Fr22y7axu6dfiff8rzqfi.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%2Fr22y7axu6dfiff8rzqfi.png" alt="A column chart in Data Studio comparing the average accuracy scores of google/gemini-3.5-flash-lite and google/gemini-3.6-flash, complete with standard error of the mean (SEM) whiskers showing upper and lower bounds." width="782" height="544"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Visual Whisker Bounds&lt;/strong&gt;: The bar height shows average accuracy (&lt;code&gt;score&lt;/code&gt;), while floating dots above and below show upper (&lt;code&gt;score_lower&lt;/code&gt;) and lower (&lt;code&gt;score_upper&lt;/code&gt;) standard error bounds.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design Note (Multi-Metric vs. Breakdown Dimension Constraint)&lt;/strong&gt;: Data Studio won't let you use a Breakdown Dimension if you're plotting multiple Y-axis metrics on the same chart. Because our whiskers need three Y-metrics (&lt;code&gt;score&lt;/code&gt;, &lt;code&gt;score_lower&lt;/code&gt;, &lt;code&gt;score_upper&lt;/code&gt;), we put &lt;code&gt;model&lt;/code&gt; on the X-axis and filter by &lt;code&gt;skill_group&lt;/code&gt; using top-level drop-downs instead.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Statistical Rigor Note:&lt;/em&gt; Standard error tracks pass/fail score variation across runs. Our demo (

&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;N&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;4&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
) covers a ~68% confidence range (
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;±&lt;/span&gt;&lt;span class="mord"&gt;1&lt;/span&gt;&lt;span class="mord text"&gt;&lt;span class="mord"&gt;&amp;nbsp;SEM&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
), while production benchmarks require 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;N&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;≥&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;30&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 for standard 95% confidence intervals.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  The 4 dynamic cohort slicers (drop-down controls)
&lt;/h3&gt;

&lt;p&gt;Located across the top control bar, these four drop-down lists act as interactive dynamic filters, immediately re-rendering both canvas charts in real time:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;model&lt;/code&gt; Slicer&lt;/strong&gt;: Filters results by model family (&lt;code&gt;gemini-3.5-flash-lite&lt;/code&gt; vs &lt;code&gt;gemini-3.6-flash&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;skill_group&lt;/code&gt; Slicer&lt;/strong&gt;: Filters by skill setup (&lt;code&gt;gemini-api&lt;/code&gt;, &lt;code&gt;gcloud&lt;/code&gt;, baseline control).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;is_baseline_or_has_activated_skill&lt;/code&gt; Slicer (Conditional Uptake)&lt;/strong&gt;: Separates &lt;strong&gt;Baseline controls&lt;/strong&gt; and &lt;strong&gt;Active Skill runs&lt;/strong&gt; (&lt;code&gt;TRUE&lt;/code&gt; via &lt;code&gt;activate_skill&lt;/code&gt;) from &lt;strong&gt;Dormant runs&lt;/strong&gt; (&lt;code&gt;FALSE&lt;/code&gt;, offered but uncalled). Activation confirms tool uptake, not instruction compliance.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;completed&lt;/code&gt; Slicer (Conditional Accuracy / Infrastructure Noise)&lt;/strong&gt;: Filters clean runs (&lt;code&gt;TRUE&lt;/code&gt;) from system failures (&lt;code&gt;FALSE&lt;/code&gt; for quota drops, timeouts, container crashes).

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Relevance Note:&lt;/em&gt; This is vital for production sweeps hit by rate limits or timeouts—selecting &lt;code&gt;TRUE&lt;/code&gt; measures &lt;strong&gt;Model Capability&lt;/strong&gt; (&lt;strong&gt;Conditional Accuracy&lt;/strong&gt;), while &lt;code&gt;FALSE&lt;/code&gt; or &lt;code&gt;(All)&lt;/code&gt; shows the full audit trail.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  View and interact
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Click the blue &lt;strong&gt;View&lt;/strong&gt; button in the top right corner to see the dashboard as a user would.
&lt;/li&gt;
&lt;li&gt;Use the &lt;strong&gt;model&lt;/strong&gt;, &lt;strong&gt;skill_group&lt;/strong&gt;, &lt;strong&gt;completed&lt;/strong&gt;, and &lt;strong&gt;is_baseline_or_has_activated_skill&lt;/strong&gt; drop-downs at the top.
&lt;/li&gt;
&lt;li&gt;Notice how &lt;strong&gt;both&lt;/strong&gt; the Bubble Chart and the Bar Chart update instantly in unison to show only the models or skills you selected!&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Slicer-based analyses
&lt;/h3&gt;

&lt;p&gt;While the &lt;code&gt;model&lt;/code&gt; slicer would be useful in a situation with more models, since we only have two and you can visualize them using the existing coloring. &lt;code&gt;skill_group&lt;/code&gt; on the other hand is more interesting&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%2Fwrortsg5oge4o41srqb4.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%2Fwrortsg5oge4o41srqb4.png" alt="A screenshot showing the 'skill\_group' dropdown filter panel displaying options for gcloud and gemini-api, placed next to a scatter plot bubble chart." width="799" height="313"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On selecting gemini-api (Skill) and gemini-api (Baseline), there are a couple visually apparent trends. As discussed in previous sections, the gemini-api (Skill) run improved the evaluation score at the price of increased latency and cost.&lt;/p&gt;
&lt;h4&gt;
  
  
  Conditional uptake analysis: Separating skill discovery from capability
&lt;/h4&gt;

&lt;p&gt;By filtering for runs where &lt;code&gt;is_baseline_or_has_activated_skill&lt;/code&gt; is &lt;code&gt;FALSE&lt;/code&gt;, we perform a Conditional uptake analysis: examining dormant runs where a skill was provided in context (Prior), but the agent chose not to call &lt;code&gt;activate_skill&lt;/code&gt; (zero uptake).&lt;/p&gt;
&lt;h5&gt;
  
  
  Baseline or has activated skill = false (notice these both score relatively low)
&lt;/h5&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%2F0hspjuzajlovggor2x8b.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%2F0hspjuzajlovggor2x8b.png" alt="A scatter plot bubble chart showing two orange bubbles representing dormant runs of google/gemini-3.5-flash-lite, plotting score against latency." width="799" height="514"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h5&gt;
  
  
  Baseline or has activated skill = true
&lt;/h5&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%2Frcfolz868zqq9c6wkv5b.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%2Frcfolz868zqq9c6wkv5b.png" alt="A scatter plot bubble chart showing multiple blue and orange bubbles for completed runs, plotting score against latency." width="800" height="515"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One thing to note immediately is that the total number of bubbles is GREATER than 8 (the count of Model x Skill combinations). This is because each of these bubbles are subsets of the Model x Skill x Sample x Epoch space in that &lt;strong&gt;this distinction is made at the samples/epochs level&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In Inspect AI telemetry, "activated" specifically measures &lt;strong&gt;uptake&lt;/strong&gt;—whether the model executed the &lt;code&gt;activate_skill&lt;/code&gt; tool call to load the skill into context. Interestingly, the samples of 3.5-flash-lite where the skills were activated have a much higher visual ceiling than the general case (Baseline or Has Activated Skill = Any) corresponding to the elimination of Baseline or Has Activated Skill = False.&lt;/p&gt;

&lt;p&gt;Noting that only 3.5-flash-lite had samples where it didn’t activate a provided skill, it may be worth investigating if this is a more general trend. &lt;/p&gt;
&lt;h4&gt;
  
  
  Survivorship bias and joint operational uptime (&lt;code&gt;completed&lt;/code&gt; analysis)
&lt;/h4&gt;

&lt;p&gt;For the sake of further exploration, I reran the evals with web search enabled and the same time limit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;inspect &lt;span class="nb"&gt;eval &lt;/span&gt;skills-eval.py &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--model&lt;/span&gt; google/gemini-3.5-flash-lite,google/gemini-3.6-flash &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--time-limit&lt;/span&gt; 300 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--epochs&lt;/span&gt; 2 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--max-tasks&lt;/span&gt; 4 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-T&lt;/span&gt; &lt;span class="nv"&gt;web_access&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running all of these evals serially and in parallel causes them to use too much web search quota and reach the unforgiving &lt;code&gt;time-limit&lt;/code&gt;. As such, &lt;strong&gt;the most realistic run configuration would be to increase the time limit and use the built-in adaptive rate limits.&lt;/strong&gt; The problem is this would last a lot longer and take more resources than I care to ask you to emulate.&lt;/p&gt;

&lt;p&gt;So let’s look instead at the results of the web search enabled, 300 second time limit run:&lt;/p&gt;

&lt;h4&gt;
  
  
  completed: ALL
&lt;/h4&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%2Fvbl4jmgxy6ybtzoruosk.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%2Fvbl4jmgxy6ybtzoruosk.png" alt="A scatter plot bubble chart showing several blue and orange bubbles representing all runs (both completed and system failures) with web search enabled." width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since this graph contains every model x skill x sample x epoch, you can eyeball the average metric values of a number of bubbles by imagining the centroid of the polygon they define on the space. &lt;/p&gt;

&lt;p&gt;Some of the most obvious conclusions in our local web-search enabled eval sweep: 3.5-flash-lite recorded lower latency than 3.6-flash, while their average scores were comparable. To reason about what this might mean, refer to the &lt;a href="https://ai.google.dev/gemini-api/docs/models" rel="noopener noreferrer"&gt;Gemini API Model Documentation&lt;/a&gt; for official model latency, throughput, and performance specifications. Instinctually, this makes me want to check if the timed out runs (counted as score 0) affected 3.6-flash more (since it didn’t complete as quickly in these samples). To test this, let’s see how scores look when we only count completed runs.&lt;/p&gt;

&lt;h4&gt;
  
  
  completed: TRUE
&lt;/h4&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%2F6i6jk8pc0mvq8osjcxc9.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%2F6i6jk8pc0mvq8osjcxc9.png" alt="A scatter plot bubble chart showing completed runs only, where the average score for the google/gemini-3.6-flash cohort is slightly higher than in the completed ALL chart." width="800" height="487"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When filtering the web-search rerun sweep strictly for completed runs (&lt;code&gt;completed = TRUE&lt;/code&gt;), the average score for the 3.6-flash sample cohort trended slightly higher, converging between 0.5 and 0.6 for partially scoring runs (which earlier averaged between 0.35 and 0.60 when &lt;code&gt;completed = ALL&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Isolating &lt;code&gt;completed = TRUE&lt;/code&gt; calculates &lt;strong&gt;Conditional Accuracy&lt;/strong&gt; (Model Capability on completed runs). However, if longer or more complex tasks disproportionately trigger time-limits, filtering out incompletes introduces &lt;strong&gt;Survivorship Bias&lt;/strong&gt;, truncating the difficult tail of your test set. Comparing &lt;code&gt;completed = ALL&lt;/code&gt; against &lt;code&gt;completed = TRUE&lt;/code&gt; bridges the gap between pure model intelligence and total operational system reliability for given limits.&lt;/p&gt;

&lt;h3&gt;
  
  
  Are these findings generalizable to every scenario?
&lt;/h3&gt;

&lt;p&gt;While we’ve uncovered a promising trend, the next step is to validate it with statistical rigor. Think of our current demo (
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;N&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;4&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
) as an exploratory pilot; it’s great for spotting trends, but we need more data to confirm them. To verify these results aren't coincidental, I encourage you to scale your runs to 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;N&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;≥&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;30&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
. With this larger sample size, you can achieve &lt;strong&gt;statistical significance&lt;/strong&gt;, a metric used to ensure that your findings aren't just a random outlier. This is supported by the &lt;strong&gt;p-value&lt;/strong&gt;—a standard calculation that gives you the probability that your results are a fluke. Aiming for a low p-value is the final step in moving from exploratory analysis to building the mathematically sound, launch-ready benchmark required for production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion and next steps: Where to go from here
&lt;/h2&gt;

&lt;p&gt;We’ve come full circle in this series—from running terminal-based evaluation sweeps with Inspect AI in &lt;a href="https://dev.to/googleai/designing-ai-evals-clarity-now-and-visualization-next-4eii"&gt;Part 1&lt;/a&gt;, to analyzing multi-turn LLM reasoning traces in &lt;a href="https://dev.to/googleai/ai-evals-at-a-glance-heatmaps-for-stakeholders-2mki"&gt;Part 2&lt;/a&gt;, modeling tabular metrics with &lt;code&gt;pandas&lt;/code&gt; in &lt;a href="https://dev.to/googleai/step-up-to-the-sheets-ai-eval-export-and-illustrating-data-bak"&gt;Part 3&lt;/a&gt;, and finally assembling interactive, codeless BI dashboards here in Data Studio.&lt;/p&gt;

&lt;p&gt;Now that you have the end-to-end telemetry pipeline running, the floor is yours to explore! Here are a few directions you can take your evaluation harness next:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Custom Calculated Metrics&lt;/strong&gt;: Experiment with custom formulas in Data Studio to track ROI metrics, cost per successful task, or normalized token efficiency ratios.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expanded Matrix Sweeps&lt;/strong&gt;: Scale your evaluation matrix across new LLM provider endpoints, prompt techniques, or tool playbooks.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Direct Database Connectivity&lt;/strong&gt;: Replace the static CSV / Google Sheets ingestion layer with a direct connector to BigQuery, PostgreSQL, or Cloud Storage for automated, streaming evaluation updates.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automated Alerting &amp;amp; Thresholds&lt;/strong&gt;: Set up automated notifications when a new model deployment drops below baseline accuracy or exceeds latency/cost budgets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thank you for following along with this series, and happy evaluating!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>datascience</category>
      <category>productivity</category>
      <category>llm</category>
    </item>
    <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>
  </channel>
</rss>
