<?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: Shir Meir Lador</title>
    <description>The latest articles on DEV Community by Shir Meir Lador (@shirmeirlador).</description>
    <link>https://dev.to/shirmeirlador</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%2Fuser%2Fprofile_image%2F3596246%2F7fba9a43-cbe3-4af2-adff-1871187ffbf8.jpeg</url>
      <title>DEV Community: Shir Meir Lador</title>
      <link>https://dev.to/shirmeirlador</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shirmeirlador"/>
    <language>en</language>
    <item>
      <title>Build a Long-Running Agent in the Cloud for $5.70/Month</title>
      <dc:creator>Shir Meir Lador</dc:creator>
      <pubDate>Thu, 03 Sep 2026 15:54:57 +0000</pubDate>
      <link>https://dev.to/googleai/build-a-long-running-agent-in-the-cloud-for-570month-113c</link>
      <guid>https://dev.to/googleai/build-a-long-running-agent-in-the-cloud-for-570month-113c</guid>
      <description>&lt;p&gt;How do you run an autonomous AI agent in the cloud 24/7 for just $5.70 a month?&lt;/p&gt;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

&lt;/div&gt;


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


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

&lt;/div&gt;

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


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

&lt;/div&gt;

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


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

&lt;/div&gt;

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

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

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

&lt;/div&gt;



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



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

&lt;/div&gt;



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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

&lt;/div&gt;



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

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

&lt;/div&gt;



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

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

&lt;/div&gt;



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

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

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

&lt;/div&gt;



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

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

&lt;/div&gt;



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

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

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

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

&lt;/div&gt;



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

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

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

&lt;/div&gt;



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

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

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

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

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

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

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

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

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

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

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

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

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

&lt;/div&gt;



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

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

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

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

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

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

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

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

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

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

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

&lt;/div&gt;



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

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

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

&lt;/div&gt;



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

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

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

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

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

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

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

**Final Report Format:**  

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

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

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

&lt;/div&gt;



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

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

&lt;/div&gt;



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

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

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

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

&lt;/div&gt;



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

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

&lt;/div&gt;



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

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

&lt;/div&gt;



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

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

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

🔥 Top 5 Trends for Agent Developers  

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

🚀 Top 5 Releases for Agent Developers  

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

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

&lt;/div&gt;



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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

&lt;/div&gt;



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

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

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

&lt;/div&gt;



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

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

&lt;/div&gt;



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

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

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

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

&lt;/div&gt;



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

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

&lt;/div&gt;



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

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

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

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

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

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

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

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

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

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

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

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

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

The report format must be:  

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

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

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

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

&lt;/div&gt;



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

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

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

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

&lt;/div&gt;



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

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

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

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

&lt;/div&gt;



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

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

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

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

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

&lt;/div&gt;



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



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

&lt;/div&gt;



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

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

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


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

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


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

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

🔥 Top 5 Trends for Agent Developers  

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

🚀 Top 5 Releases for Agent Developers  

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

🤔 Top 5 Questions from Agent Developers  

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

&lt;/div&gt;



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

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

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

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

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

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

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

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

&lt;/div&gt;



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



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

&lt;/div&gt;



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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

&lt;/div&gt;



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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

&lt;/div&gt;



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

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

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

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

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

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

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

&lt;/div&gt;



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

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

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

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

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

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

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

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

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

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

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

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

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

</description>
      <category>ai</category>
      <category>agents</category>
      <category>programming</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Google Cloud Labs: Accelerate AI with Cloud Run</title>
      <dc:creator>Shir Meir Lador</dc:creator>
      <pubDate>Tue, 21 Jul 2026 13:00:00 +0000</pubDate>
      <link>https://dev.to/googleai/google-cloud-labs-accelerate-ai-with-cloud-run-md3</link>
      <guid>https://dev.to/googleai/google-cloud-labs-accelerate-ai-with-cloud-run-md3</guid>
      <description>&lt;h2&gt;
  
  
  Moving Beyond the Prototype
&lt;/h2&gt;

&lt;p&gt;The AI landscape has shifted. While "vibe coding" with tools like Antigravity and AI Studio lets you build and deploy complex agents in minutes, the real work begins on "Day 2". Moving from a magical prototype to a hardened, production-grade application requires professional AI engineering. We're excited to bring back the &lt;strong&gt;Accelerate AI with Cloud Run roadshow&lt;/strong&gt; for 2026. This year, we've updated our curriculum to focus on the full AI agent lifecycle, giving you the keys to productionizing and scaling agentic workloads on Google Cloud's serverless platform.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Coffee Shop Journey: A Hands-On Experience
&lt;/h2&gt;

&lt;p&gt;Experience the ease of building advanced AI agents on Cloud Run through 'The Coffee Shop Journey'. This interactive session is designed to guide you through the full lifecycle of an AI agent, moving beyond prototyping to focus on real business use cases. You will solve real-world business problems as you evolve from launching a simple cafe to building complex, intelligent assistants.&lt;/p&gt;

&lt;p&gt;Our curriculum covers the core pillars of modern AI development:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Basics:&lt;/strong&gt; Gain familiarity with Cloud Run by deploying a simple web app (a Coffee Shop launch scenario) to understand the platform fundamentals.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build a Coffee Recommendation Agent:&lt;/strong&gt; Create a personalized AI assistant using Google's Agent Development Kit (ADK) and Retrieval-Augmented Generation (RAG).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimize Coffee Stand Locations:&lt;/strong&gt; Use Gemma 4 and the BigQuery MCP server to identify the most profitable locations for new coffee stands by analyzing popular bike routes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Personal Productivity Assistant for Store Managers:&lt;/strong&gt; Create a personal productivity assistant using Cloud Run to help a coffee shop manager with daily operational tasks and scheduling.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Master Advanced Features with Antigravity 2.0:&lt;/strong&gt; Learn how to use skills, context, rules, and hooks with Antigravity 2.0 to build new features for your Cloud Run applications.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Production-Grade AI on Cloud Run
&lt;/h2&gt;

&lt;p&gt;Get first-hand experience with the platform innovations that make Cloud Run the ideal home for production-grade agentic workloads. Through hands-on exercises, you will learn to build, scale, and orchestrate &lt;strong&gt;long-running agents&lt;/strong&gt; using Google's ADK and Antigravity 2.0. Additionally, you will utilize BigQuery MCP for automated, &lt;strong&gt;data-driven expansion strategies,&lt;/strong&gt; and experience low-latency inference for frontier models using &lt;strong&gt;Cloud Run's GPU offerings&lt;/strong&gt; without the traditional overhead of cluster management.&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%2Fi626y1vwpd7mkpgzicu9.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%2Fi626y1vwpd7mkpgzicu9.png" width="800" height="876"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Ready to Build for Scale? Join us in North America
&lt;/h2&gt;

&lt;p&gt;Don't just witness the AI revolution - build it. Find the workshop in your city and secure your spot today! Let's transform your AI journey from a simple prototype into a powerful, production reality.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;City&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Registration Link&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Atlanta, GA (as a part of Atlanta Tech week)&lt;/td&gt;
&lt;td&gt;August 12-13&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://www.renderatl.com/tickets" rel="noopener noreferrer"&gt;https://www.renderatl.com/tickets&lt;/a&gt;&lt;br&gt;Event tickets grant access to the workshops on a first-come, first-served basis.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sunnyvale, CA&lt;/td&gt;
&lt;td&gt;August 13&lt;/td&gt;
&lt;td&gt;&lt;a href="https://rsvp.withgoogle.com/events/google-cloud-labs-accelerate-ai-on-cloud-run-sunnyvale" rel="noopener noreferrer"&gt;Register now!&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Toronto, Canada&lt;/td&gt;
&lt;td&gt;August 27&lt;/td&gt;
&lt;td&gt;&lt;a href="https://rsvp.withgoogle.com/events/google-cloud-labs-accelerate-ai-on-cloud-run-toronto" rel="noopener noreferrer"&gt;Register now!&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Seattle, WA&lt;/td&gt;
&lt;td&gt;September&lt;/td&gt;
&lt;td&gt;Registration opens late July!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New York City, NY&lt;/td&gt;
&lt;td&gt;October&lt;/td&gt;
&lt;td&gt;Registration opens late July!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Los Angeles, CA&lt;/td&gt;
&lt;td&gt;November&lt;/td&gt;
&lt;td&gt;Registration opens late July!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Boston, MA&lt;/td&gt;
&lt;td&gt;October&lt;/td&gt;
&lt;td&gt;Registration opens late July!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Washington D.C.&lt;/td&gt;
&lt;td&gt;October&lt;/td&gt;
&lt;td&gt;Registration opens late July!&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Registration Update:&lt;/strong&gt; Links for our &lt;strong&gt;September&lt;/strong&gt;, &lt;strong&gt;October&lt;/strong&gt;, and &lt;strong&gt;November&lt;/strong&gt; workshops will be added to this page in &lt;strong&gt;late July.&lt;/strong&gt; Stay tuned!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>googlecloud</category>
      <category>agents</category>
      <category>antigravity</category>
    </item>
    <item>
      <title>Agent Factory Recap: 100X engineering with AI agents in Google Antigravity 2.0</title>
      <dc:creator>Shir Meir Lador</dc:creator>
      <pubDate>Tue, 07 Jul 2026 17:28:25 +0000</pubDate>
      <link>https://dev.to/googleai/agent-factory-recap-100x-engineering-with-ai-agents-in-google-antigravity-20-4p4j</link>
      <guid>https://dev.to/googleai/agent-factory-recap-100x-engineering-with-ai-agents-in-google-antigravity-20-4p4j</guid>
      <description>&lt;p&gt;In this episode of the Agent Factory, I sat down with Rody Davis, one of Google's top agentic engineers. We dive into the massive shift from traditional IDEs to agent-first platforms, the reality of code reviews in an AI-driven world, and how to use "skills" to perform at a 100X level.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/Dk4MD6TNiWE"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;This post guides you through the key ideas from our conversation. Use it to quickly recap topics or dive deeper into specific segments with links and timestamps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Google Antigravity 2.0 - What is it?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://antigravity.google/" rel="noopener noreferrer"&gt;Antigravity 2.0&lt;/a&gt; has evolved from a simple agentic IDE into a full-scale agent-first platform. It now consists of four core pillars: a standalone desktop &lt;strong&gt;Agent Manager&lt;/strong&gt; for orchestration, a robust &lt;strong&gt;CLI&lt;/strong&gt; for server-side work, an &lt;strong&gt;SDK&lt;/strong&gt; for custom Python-based workflows, and a specialized &lt;strong&gt;IDE&lt;/strong&gt;. This unbundled approach allows developers to compose their own environment, managing multiple folders and complex project structures without being forced into a single-workspace layout.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rody Davis on 100X Engineering
&lt;/h2&gt;

&lt;p&gt;We explored the strategies elite engineers use to scale their impact and reduce the "cognitive toil" of daily development.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scaling Impact and Reducing Toil
&lt;/h3&gt;

&lt;p&gt;Timestamp: &lt;a href="https://www.youtube.com/watch?v=Dk4MD6TNiWE&amp;amp;t=115s" rel="noopener noreferrer"&gt;01:55&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Rody explains that AI isn't just about writing code; it's about accelerating the entire lifecycle. He uses agents to write richer test suites and prototype multiple versions of an app before committing to a framework. By offloading "toil", like building marketing sites, he can focus on high-level architecture and problem-solving.&lt;/p&gt;

&lt;h3&gt;
  
  
  Skills as "Context Cheat Sheets"
&lt;/h3&gt;

&lt;p&gt;Timestamp: &lt;a href="https://www.youtube.com/watch?v=Dk4MD6TNiWE&amp;amp;t=185s" rel="noopener noreferrer"&gt;03:05&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A core philosophy in Rody's workflow is the use of "Skills." He views skills as a way to compress context for the model. "It's literally a cheat sheet for the agent," Rody notes. By providing the agent with specific design systems or API documentation, the model becomes significantly faster and more accurate, avoiding the latency of searching through massive, unorganized docs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Customizations, Skills, and MCP Servers
&lt;/h3&gt;

&lt;p&gt;Timestamp: &lt;a href="https://www.youtube.com/watch?v=Dk4MD6TNiWE&amp;amp;list=PLIivdWyY5sqLXR1eSkiM5bE6pFlXC-OSs&amp;amp;index=1&amp;amp;t=257s" rel="noopener noreferrer"&gt;04:17&lt;/a&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%2Fc8fwr93yc18wdpos5fy7.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%2Fc8fwr93yc18wdpos5fy7.jpg" alt="A list of agent skills in the Antigravity 2.0 customizations tab." width="800" height="656"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Rody walks us through the customizations tab in Antigravity 2.0, showing how to extend an agent's capabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Android CLI:&lt;/strong&gt; Building and deploying mobile apps directly from the command line.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modern Web Guidance:&lt;/strong&gt; Grounding the agent in the latest CSS and accessibility standards.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP Servers:&lt;/strong&gt; Using the Model Context Protocol to enable features like hot reloading for Flutter and Dart.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Bonsai Approach to Code Review
&lt;/h3&gt;

&lt;p&gt;Timestamp: &lt;a href="https://www.youtube.com/watch?v=Dk4MD6TNiWE&amp;amp;t=327s" rel="noopener noreferrer"&gt;05:27&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Rody compares maintaining a codebase to being a Bonsai artist: constantly pruning to keep things simple. He advocates for flat architectures where state, UI, and data are strictly separated. This makes it easier for a human to "steer" the agent; if the agent starts putting files in the wrong place, the architectural violation is immediately obvious.&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%2Fw7t9wjvxfxb7a2my9zh3.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%2Fw7t9wjvxfxb7a2my9zh3.jpg" alt="Infographic titled " width="799" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Do you review 100% of agent-generated code?
&lt;/h3&gt;

&lt;p&gt;Timestamp: &lt;a href="https://www.youtube.com/watch?v=Dk4MD6TNiWE&amp;amp;t=431s" rel="noopener noreferrer"&gt;07:11&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Rody's answer depends on the task. For a marketing site, he focuses on the visual output rather than the code. However, for backend logic, he cares deeply about API contracts and schemas. He recommends writing the first example yourself so the agent can simply "copy the pattern" for the rest of the codebase.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building Extensions to Solve Daily Friction
&lt;/h3&gt;

&lt;p&gt;Timestamp: &lt;a href="https://www.youtube.com/watch?v=Dk4MD6TNiWE&amp;amp;t=545s" rel="noopener noreferrer"&gt;09:05&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To solve the problem of managing files across multiple Git projects, Rody used Antigravity to build a custom macOS Finder extension in Swift. This tool allows him to filter files by time boxes (today, last week, etc.), demonstrating how agents can build specialized utilities that reduce daily friction.&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%2Fie080486a0vqcb65ivfe.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%2Fie080486a0vqcb65ivfe.jpg" alt="Screenshot of an Antigravity IDE session titled " width="800" height="738"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Do AI engineers still write code by hand?
&lt;/h3&gt;

&lt;p&gt;Timestamp: &lt;a href="https://www.youtube.com/watch?v=Dk4MD6TNiWE&amp;amp;t=622s" rel="noopener noreferrer"&gt;10:22&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;"Oh yeah," Rody says. He still loves the syntax of languages like Go and the challenge of controlling computers. He believes it's vital to understand the building blocks deeply so that when you face a problem two years down the road, you know exactly which "old project" to reach back for.&lt;/p&gt;

&lt;h3&gt;
  
  
  Powering Personal Websites with Gemma 4
&lt;/h3&gt;

&lt;p&gt;Timestamp: &lt;a href="https://www.youtube.com/watch?v=Dk4MD6TNiWE&amp;amp;t=702s" rel="noopener noreferrer"&gt;11:42&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Rody showcases his personal website, which uses &lt;a href="https://cloud.google.com/blog/topics/developers-practitioners/agent-factory-recap-how-gemma-4-taught-itself-physics?e=48754805" rel="noopener noreferrer"&gt;Gemma 4&lt;/a&gt; and Embedding Gemma to provide dynamic content recommendations offline. By vectorizing post summaries at compile time, the site can suggest related content via a local vector database without needing a live backend server.&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%2Fjzfjovtxrnre9jv5yi93.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%2Fjzfjovtxrnre9jv5yi93.jpg" alt="Screenshot of Rody Davis's personal website rendered in an editor-style layout, showing three dynamic focus-area cards raw `" width="800" height="647"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Factory Floor
&lt;/h2&gt;

&lt;p&gt;The Factory Floor is our segment for getting hands-on. Here, we moved from high-level concepts to practical code with live demos.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multi-Agent Parallelism in Action
&lt;/h3&gt;

&lt;p&gt;Timestamp: &lt;a href="https://www.youtube.com/watch?v=Dk4MD6TNiWE&amp;amp;t=842s" rel="noopener noreferrer"&gt;14:02&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this demo, Rody uses a single stream-of-thought voice prompt to build a full-stack application. We watched as Antigravity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spun up parallel sub-agents, including a dedicated DevOps and QA engineer. (see &lt;a href="https://www.youtube.com/watch?v=Dk4MD6TNiWE&amp;amp;t=1188s" rel="noopener noreferrer"&gt;19:48&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Built a multilingual note-taking app using Vite, Go, and SQLite.&lt;/li&gt;
&lt;li&gt;Orchestrated the entire stack via Docker Compose.&lt;/li&gt;
&lt;li&gt;Localized the app into five different languages simultaneously.&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%2Fsmpmze8mm4cpi8iizdqw.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%2Fsmpmze8mm4cpi8iizdqw.jpg" alt="` endraw Screenshot of the Antigravity Agent Manager during a " width="800" height="650"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Unbundling the IDE Ecosystem
&lt;/h3&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%2Fccuo918brl3fmr0c51bg.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%2Fccuo918brl3fmr0c51bg.png" alt="" width="800" height="231"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Timestamp: &lt;a href="https://www.youtube.com/watch?v=Dk4MD6TNiWE&amp;amp;t=935s" rel="noopener noreferrer"&gt;15:35&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We discussed why Google separated the IDE from the Agent Manager. Rody highlights that this unlocks different workflows: the CLI is perfect for SSH sessions on a Raspberry Pi, while the Agent Manager handles general knowledge work and orchestration across multiple folders.&lt;/p&gt;

&lt;h3&gt;
  
  
  Turning Documentation into Reusable Skills
&lt;/h3&gt;

&lt;p&gt;Timestamp: &lt;a href="https://www.youtube.com/watch?v=Dk4MD6TNiWE&amp;amp;t=1541s" rel="noopener noreferrer"&gt;25:41&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Rody shares his process for turning documentation into skills. He wrote a Go CLI that parses websites into markdown, allowing him to install hundreds of skills for the sites he visits frequently. This ensures the agent always has access to the specific version of the docs he is using.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rapid Fire: Future Tech Predictions
&lt;/h3&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%2Fc4ehwam7n46npmx1qxsz.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%2Fc4ehwam7n46npmx1qxsz.png" alt="Split-screen video call screenshot of two podcast hosts, one clean-shaven with short dark hair on the left and the other smiling with long curly blonde hair on the right. An on-screen caption reads " width="800" height="507"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Timestamp: &lt;a href="https://www.youtube.com/watch?v=Dk4MD6TNiWE&amp;amp;t=1655s" rel="noopener noreferrer"&gt;27:35&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We put Rody on the spot with some controversial takes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Vibe Coding:&lt;/strong&gt; Rody believes a non-technical founder will launch a company using only vibe coding by 2026, but the real test will be maintaining it in years 2 through 5.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Production Failures:&lt;/strong&gt; Rody agrees that vibe coding will cause significant production failures, leading to a new hot job for software engineers: consulting to solve those failures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Codebase Health:&lt;/strong&gt; Rody argues that poor codebase health, not context windows, is the biggest bottleneck in AI speed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Grounding Yourself in a Changing Landscape
&lt;/h3&gt;

&lt;p&gt;Timestamp: &lt;a href="https://www.youtube.com/watch?v=Dk4MD6TNiWE&amp;amp;t=1870s" rel="noopener noreferrer"&gt;31:10&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Rody advises engineers to focus on why they were hired: to solve problems and engineer things that didn't exist before. He suggests using AI to provide better communication handoffs between colleagues, making artifacts so easy to approve that they are "ready to sign off" the moment they are handed over.&lt;/p&gt;

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

&lt;p&gt;The era of agentic engineering is here, but as Rody Davis demonstrated, it requires more architectural discipline, not less. By treating your codebase like a Bonsai tree and your agents like an orchestra, you can move past the "toil" and focus on building the frameworks of the future.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your turn to build
&lt;/h2&gt;

&lt;p&gt;Are you ready to build anything? We've officially launched the &lt;strong&gt;#NapkinChallenge&lt;/strong&gt;. Take a handwritten sketch of an app idea, use Antigravity 2.0 to build it, and share your creation on social media.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Try Antigravity 2.0:&lt;/strong&gt; &lt;a href="https://goo.gle/4fnXilj" rel="noopener noreferrer"&gt;antigravity.google&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Join the Challenge:&lt;/strong&gt; &lt;a href="https://goo.gle/4e0AGF6" rel="noopener noreferrer"&gt;Napkin Challenge Details&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rody's personal&lt;/strong&gt; &lt;a href="https://rodydavis.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;website&lt;/strong&gt;&lt;/a&gt;, &lt;a href="https://github.com/rodydavis/rodydavis" rel="noopener noreferrer"&gt;&lt;strong&gt;github repo&lt;/strong&gt;&lt;/a&gt; and &lt;a href="https://github.com/rodydavis/skills" rel="noopener noreferrer"&gt;skills&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rody Davis&lt;/strong&gt; → &lt;a href="https://goo.gle/Rody-on-X" rel="noopener noreferrer"&gt;X&lt;/a&gt;, &lt;a href="https://goo.gle/Rody-on-LinkedIn" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shir Meir Lador&lt;/strong&gt; → &lt;a href="https://goo.gle/Shir-on-X" rel="noopener noreferrer"&gt;X&lt;/a&gt;, &lt;a href="https://goo.gle/Shir-on-LinkedIn" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>agents</category>
      <category>ai</category>
    </item>
    <item>
      <title>A Guide to AI Cold Starts on Cloud Run</title>
      <dc:creator>Shir Meir Lador</dc:creator>
      <pubDate>Fri, 26 Jun 2026 16:50:58 +0000</pubDate>
      <link>https://dev.to/googleai/a-guide-to-ai-cold-starts-on-cloud-run-c6d</link>
      <guid>https://dev.to/googleai/a-guide-to-ai-cold-starts-on-cloud-run-c6d</guid>
      <description>&lt;p&gt;I saw a developer asking on Reddit if there &lt;a href="https://www.reddit.com/r/googlecloud/comments/1s8yzn1/is_there_a_sane_way_to_manage_cloud_run_cold/" rel="noopener noreferrer"&gt;was any “sane way” to manage Cloud Run cold starts for AI across multiple regions.&lt;/a&gt; They were experiencing startup latencies of up to 20 seconds, a frustrating gap where the infrastructure is spinning up while the user waits for a response.&lt;/p&gt;

&lt;p&gt;The discussion was full of developers who had almost given up on serverless GPUs, with some even migrating back to GKE just to escape the latency. I decided it was time to dive deep into the Mechanics of AI Cold Starts and see if we could find that "sane way."&lt;/p&gt;

&lt;p&gt;During my research into &lt;a href="https://docs.cloud.google.com/run/docs/tutorials/gpu-gemma-with-ollama" rel="noopener noreferrer"&gt;hosting models like Gemma 4 on Cloud Run&lt;/a&gt;, I had the privilege of co-presenting at Google Cloud Next '26 with Oded Shahar (Senior Engineering Manager for Cloud Run) and our guest speaker Ajay Nair (Global VP of Platform at Elastic).&lt;/p&gt;

&lt;p&gt;In our session, "Build AI architectures with custom models on Cloud Run," Ajay shared the production-hardened strategies that allow Elastic to serve millions of daily requests across 17+ model variants, all while maintaining the 'scale-to-zero' efficiency of Cloud Run.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/7L5gQHcinzE"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;center&gt;&lt;small&gt;Build AI architectures with custom models on Cloud Run&lt;/small&gt;&lt;/center&gt;

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

&lt;p&gt;Ajay showed us that the secret isn't just in the model, but in treating GPUs as fungible compute rather than infrastructure to manage.&lt;/p&gt;

&lt;p&gt;I realized then that minimizing cold start latency isn't just about the model, it's about the infrastructure patterns and architectural decisions that keep it fast, scalable, and secure.&lt;/p&gt;

&lt;h2&gt;
  
  
  The anatomy of an AI cold start
&lt;/h2&gt;

&lt;p&gt;As the &lt;a href="https://docs.cloud.google.com/run/docs/configuring/services/gpu-best-practices" rel="noopener noreferrer"&gt;official Google Cloud GPU best practices&lt;/a&gt; explain, an AI cold start is a shift from standard web microservices. You aren't just booting code, you're moving gigabytes of weights into a specialized physical accelerator.&lt;/p&gt;

&lt;p&gt;Think of it as a four-phase race. If you don't optimize each step, you're going to lose your users.&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 1: Infrastructure Provisioning (~5s)
&lt;/h3&gt;

&lt;p&gt;Cloud Run allocates the physical GPU and injects pre-installed NVIDIA drivers. Since Google manages the drivers for you, you don't have to bloat your Dockerfile.&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 2: Block-Level Container Image Streaming (1-2s)
&lt;/h3&gt;

&lt;p&gt;Cloud Run uses "image streaming," meaning it pulls only the blocks needed to boot. Your 15GB CUDA image can actually start as fast as a tiny Node.js app!&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 3: Engine Initialization (5-15s)
&lt;/h3&gt;

&lt;p&gt;This is where your inference engine (vLLM, Ollama) warms up. This is a massive CPU-heavy task, and it's where most people get throttled without realizing it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 4: Model Loading &amp;amp; VRAM Transfer
&lt;/h3&gt;

&lt;p&gt;This is the final hurdle - moving those model weights from storage into the GPU memory. Unlike standard web apps where CPU is king, GPU memory is your primary constraint here. If your &lt;a href="https://cloud.google.com/blog/topics/developers-practitioners/decoding-high-bandwidth-memory-a-practical-guide-to-gpu-memory-for-fine-tuning-ai-models/?e=48754805" rel="noopener noreferrer"&gt;model’s weights don’t fit entirely within the GPU memory&lt;/a&gt;, performance degrades significantly as it swaps to slower system RAM.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best practices to handling AI cold starts
&lt;/h2&gt;

&lt;p&gt;To build a "sane" production environment, here are a few crucial levers you can pull, informed by the &lt;a href="https://docs.cloud.google.com/run/docs/configuring/services/gpu-best-practices" rel="noopener noreferrer"&gt;official Google Cloud documentation&lt;/a&gt; on AI inference with GPUs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optimize Phase 4
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Pick the Right Deployment Option
&lt;/h3&gt;

&lt;p&gt;Phase 4 is the "final hurdle" where you move gigabytes of weights from storage into GPU memory. Your &lt;a href="https://docs.cloud.google.com/run/docs/configuring/services/gpu-best-practices#loading-storing-models-tradeoff" rel="noopener noreferrer"&gt;choice of storage&lt;/a&gt; determines how fast this transfer happens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cloud Storage (Concurrent Download) - Fastest:&lt;/strong&gt; Using the Google Cloud CLI (&lt;code&gt;gcloud storage cp&lt;/code&gt;) allows you to download model files in parallel. This is the &lt;a href="https://codelabs.developers.google.com/codelabs/cloud-run/cloud-run-gpu-rtx-pro-6000?content_ref=can%20complete%20the%20steps%20within%20limited%20storage%20environments%20like%20cloud%20shell%20this%20codelab%20demonstrates%20how%20to%20load%20the%20model%20concurrently%20from%20cloud%20storage%20during%20container%20startup#0" rel="noopener noreferrer"&gt;recommended method&lt;/a&gt; for massive weights because it maximizes network throughput and drastically reduces transfer time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cloud Storage (FUSE) - Easiest:&lt;/strong&gt; This provides "zero-code" changes by mounting a bucket as a local file system. However, because it does not parallelize the initial download, it is significantly slower for large model weights&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Container Image - Best for &amp;lt;10GB:&lt;/strong&gt; Baking weights into your image is efficient for smaller models thanks to Cloud Run's Image Streaming. For models over 10GB, however, the import and streaming overhead can become a bottleneck.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Internet:&lt;/strong&gt; Avoid this. It is the slowest and least predictable path for production inference.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Model Format &amp;amp; Size
&lt;/h3&gt;

&lt;p&gt;Optimizing your model's format and size is a direct "hack" to shorten Phase 4 (Model Loading &amp;amp; VRAM Transfer). Because this phase is constrained by how fast you can move gigabytes of data into VRAM, smaller and more efficient files are critical.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;4-bit Quantization:&lt;/strong&gt; This is the ultimate cold start hack. Smaller weights mean fewer gigabytes to pull from storage, which directly accelerates the download and transfer portion of Phase 4,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Fast Formats:&lt;/strong&gt; Pick a model format with fast load times like &lt;strong&gt;GGUF&lt;/strong&gt; to minimize startup time. For the fastest performance, move away from Python "pickle" files and use Safetensors for zero-copy loading.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ensure VRAM Fit:&lt;/strong&gt; Use quantized models to ensure the weights fit entirely within the GPU memory. If the &lt;a href="https://cloud.google.com/blog/topics/developers-practitioners/decoding-high-bandwidth-memory-a-practical-guide-to-gpu-memory-for-fine-tuning-ai-models/?e=48754805" rel="noopener noreferrer"&gt;model exceeds VRAM&lt;/a&gt;, Phase 4 will stall as the system swaps to significantly slower RAM.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Optimize Phases 3 &amp;amp; 4: Infrastructure &amp;amp; Network Levers
&lt;/h3&gt;

&lt;p&gt;These infrastructure settings provide the necessary resources to accelerate the most demanding parts of the startup process.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;a href="https://docs.cloud.google.com/run/docs/configuring/services/cpu#startup-boost" rel="noopener noreferrer"&gt;&lt;strong&gt;Startup CPU Boost (Accelerates Phase 3)&lt;/strong&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;This feature temporarily doubles your CPU power during startup. A 1 vCPU instance boosts to 2 vCPUs for the duration of startup and the first 10 seconds of serving. It is essential for Phase 3, as engine initialization is a massive CPU-heavy task.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;a href="https://docs.cloud.google.com/run/docs/configuring/networking-best-practices?content_ref=for%20the%20best%20networking%20performance%20for%20cloud%20run%20services%20use%20the%20second%20generation%20execution%20environment%20when%20routing%20traffic%20with%20direct%20vpc%20egress#direct-vpc-throughput" rel="noopener noreferrer"&gt;&lt;strong&gt;Direct VPC Egress &amp;amp; PGA (Accelerates Phase 4)&lt;/strong&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;Utilizing &lt;strong&gt;Direct VPC Egress&lt;/strong&gt; with &lt;strong&gt;Private Google Access (PGA)&lt;/strong&gt; ensures your model weight traffic stays on Google’s internal high-speed backbone. This optimizes the network path to shorten the time spent moving gigabytes of weights into VRAM.&lt;/p&gt;

&lt;h4&gt;
  
  
  Concurrency Tuning (Cold Start Avoidance):
&lt;/h4&gt;

&lt;p&gt;In Cloud Run, "&lt;a href="https://docs.cloud.google.com/run/docs/about-instance-autoscaling?content_ref=request%20concurrency%20calculates%20the%20number%20of%20instances%20by%20averaging%20the%20request%20concurrency%20per%20second%20over%20a%201%20minute%20and%2010%20minute%20period%20and%20divides%20this%20by%20the%20maximum%20concurrency" rel="noopener noreferrer"&gt;concurrency&lt;/a&gt;" refers to the maximum number of requests a single instance can handle before the platform scales out to start a new one. For AI workloads, you must tune this setting in tandem with your model engine's internal parallelism flags (e.g., &lt;code&gt;--max-num-seqs&lt;/code&gt; for vLLM or &lt;code&gt;OLLAMA_NUM_PARALLEL&lt;/code&gt; for Ollama).&lt;/p&gt;

&lt;p&gt;Use the official &lt;a href="https://docs.cloud.google.com/run/docs/configuring/services/gpu-best-practices#max-concurrent-requests" rel="noopener noreferrer"&gt;Google Cloud formula&lt;/a&gt; to find your ideal Cloud Run concurrency:&lt;/p&gt;

&lt;center&gt;&lt;em&gt;(Number of model instances∗parallel queries per model)+(number of model instances∗ideal batch size)&lt;/em&gt;&lt;/center&gt;

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

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; If your instance loads 3 model instances onto the GPU, and each model instance can handle 4 parallel queries with an ideal batch size of 4, you would set your Cloud Run maximum concurrent requests to 24: (3×4)+(3×4)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How the math works:&lt;/strong&gt; The goal is to keep the GPU fully saturated while ensuring users aren't stuck in a long queue. In this example, the total of 24 concurrent requests is split into two functional groups:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Active Processing (12 requests):&lt;/strong&gt; Calculated as (3 instances×4 queries), this represents the total number of requests the GPU can actively process at any given moment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The "Next Batch" Buffer (12 requests):&lt;/strong&gt; Calculated as (3 instances×4 batch size), these are the requests waiting "on deck" inside the container. As soon as the GPU finishes the first batch, it immediately picks up these waiting requests.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By tuning this value as high as your VRAM allows (usually 10-20 users), one warm instance can serve many requests without triggering a new scale-out event and the cold start that comes with it.&lt;/p&gt;

&lt;h4&gt;
  
  
  Scaling Controls (Tuning the Threshold)
&lt;/h4&gt;

&lt;p&gt;While the formula above defines your maximum capacity, you can also tune when Cloud Run decides to start the next instance. Cloud Run's autoscaler typically targets 60% utilization, but for long-running AI cold starts, you can increase this threshold to 80% or 90% via &lt;a href="https://docs.cloud.google.com/run/docs/configuring/scaling-controls" rel="noopener noreferrer"&gt;Scaling Controls&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Concurrency Target&lt;/strong&gt;: Increasing this allows you to "pack" more requests into a single warm instance before triggering a scale-out.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CPU Target&lt;/strong&gt;: Increasing the CPU target prevents the platform from starting a new instance just because initialization or high-intensity inference spiked the CPU utilization.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Scaling &amp;amp; Reliability Strategies
&lt;/h2&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%2F7zisr13xw7yznenhze3d.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%2F7zisr13xw7yznenhze3d.png" alt="scaling and reliability strategies illustration" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;center&gt;&lt;em&gt;&lt;small&gt;Sometimes the best way to handle a cold start is to avoid it entirely or manage it proactively.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;

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

&lt;h3&gt;
  
  
  The Single-Region "Always-On" Tradeoff
&lt;/h3&gt;

&lt;p&gt;If you are deploying globally, the cost of keeping minimum instances set to 1 in every region adds up. Instead, consider an 'always-on' service in just one region. A 100ms global network delay is a much better user experience than a 20s local cold start.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The 15-Minute Grace Period:&lt;/strong&gt; A common question is 'How long will my instance stay warm after a request?' Cloud Run generally keeps instances alive for &lt;strong&gt;15 minutes&lt;/strong&gt; after they become idle (processing zero requests). If your traffic is predictable and comes in every 10–12 minutes, you might not even need an 'always-on' service, the platform’s default shutdown policy will keep a warm instance ready for your next user.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; While this idle time is "free" for standard request-based services, remember that GPU services require instance-based billing, so you will be billed for the duration the instance remains warm between requests.&lt;/p&gt;

&lt;h3&gt;
  
  
  The "Wake-Up Call" Strategy
&lt;/h3&gt;

&lt;p&gt;Sometimes the best way to handle a cold start is to proactively mask it. If your UI can predict an upcoming request, for example, when a user clicks "New Chat" or begins hovering over a text area, you can send a lightweight health check to your service immediately. By the time the user finishes typing their prompt, the first two phases of the cold start (Infrastructure Provisioning and Container Image Streaming) are already finished in the background.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pro-Tip:&lt;/strong&gt; Use &lt;strong&gt;Non-Inference Endpoints&lt;/strong&gt; To make this "wake-up call" as fast as possible, always use a non-inference endpoint rather than sending a dummy prompt like "hi".&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Why it’s faster:&lt;/strong&gt; Non-inference endpoints (like &lt;code&gt;/v1/models&lt;/code&gt; for vLLM or &lt;code&gt;/api/tags&lt;/code&gt;for Ollama) are handled by the container’s web server the moment it starts. They don’t have to wait for the slow "Phase 4" model loading and VRAM transfer to complete before sending a success response.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No Chat Pollution:&lt;/strong&gt; Because these endpoints don't trigger the model's completion logic, they won't interfere with the user's actual chat history or accidentally trigger session creation in your backend.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Recommended Endpoints:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;vLLM: &lt;code&gt;GET /health&lt;/code&gt; or GET &lt;code&gt;GET /v1/models&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ollama: &lt;code&gt;GET /api/tags&lt;/code&gt; or &lt;code&gt;GET /api/version&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Tune Startup Probes for VRAM
&lt;/h3&gt;

&lt;p&gt;AI models take significant time to move gigabytes of weights from storage into GPU memory (Phase 4). If your startup check fails too many times, &lt;a href="https://docs.cloud.google.com/run/docs/configuring/healthchecks?content_ref=prevents+the+containers+from+being+shut+down+prematurely+before+the+containers+are+up+and+running" rel="noopener noreferrer"&gt;Cloud Run will assume your container is broken and kill it&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To prevent this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Increase the Failure Threshold&lt;/strong&gt;: Use a high &lt;code&gt;failureThreshold&lt;/code&gt; (e.g., 60 or more). Since the total allowed startup time is the product of &lt;code&gt;failureThreshold \times periodSeconds&lt;/code&gt;, a threshold of 60 with a 5-second period gives your model a healthy 5-minute window to load.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Utilize the 30-Minute Maximum&lt;/strong&gt;: While standard services are limited to 4 minutes, Cloud Run supports a total startup time of up to 30 minutes (1,800 seconds) for intensive workloads.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Avoid False Positives (The Ollama Fix)&lt;/strong&gt;: Be careful with engines like Ollama, which may open a TCP port as soon as the service starts, but before the model is actually in VRAM. Always ensure you are &lt;strong&gt;preloading models&lt;/strong&gt; during the container's entrypoint script to ensure the startup probe only passes once the model is truly ready for inference.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Lessons from Elastic’s strategy
&lt;/h2&gt;

&lt;p&gt;In our NEXT ‘26 session, Ajay Nair highlighted three architectural decisions that allowed Elastic to treat GPUs as fungible compute, rather than infrastructure to manage:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bypass the Compilation Tax:&lt;/strong&gt; By setting &lt;code&gt;enforce_eager=True&lt;/code&gt; in vLLM, they traded a tiny bit of throughput for cold starts that finish in less than a minute rather than multiple minutes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Standalone Checkpoints:&lt;/strong&gt; They avoided the latency of runtime adapter-switching by pre-merging each LoRA variant into a standalone checkpoint.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;One Workload, One Service:&lt;/strong&gt; Each independently-scalable workload — defined by model, task adapter, and traffic shape — is deployed as its own Cloud Run service. This produces 30+ services across ~15 model families, with some models split by task (e.g., v5 retrieval vs. clustering) or by query/passage role.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Ready to get started?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Optimizing the cold start process&lt;/strong&gt; is the difference between a hobby project and a production-ready application. The best part? Cloud Run handles the NVIDIA driver and CUDA installation for you, starting the instance in about 5 seconds.&lt;/p&gt;

&lt;p&gt;For a deeper dive, the official documentation is your best friend:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.cloud.google.com/run/docs/configuring/services/gpu-best-practices" rel="noopener noreferrer"&gt;Best practices: AI inference on Cloud Run with GPUs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.cloud.google.com/run/docs/configuring/services/gpu" rel="noopener noreferrer"&gt;Configure GPU for Cloud Run services&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.cloud.google.com/run/docs/configuring/services/cpu#startup-boost" rel="noopener noreferrer"&gt;Startup CPU boost for Cloud Run&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the full technical breakdown, I highly recommend watching the recording of the &lt;a href="https://www.youtube.com/watch?v=7L5gQHcinzE" rel="noopener noreferrer"&gt;session&lt;/a&gt; from Google Cloud Next '26. It provides the most comprehensive blueprint for hosting high-performance open models on serverless infrastructure.&lt;/p&gt;

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




&lt;p&gt;&lt;strong&gt;&lt;em&gt;Special thanks to Sara Ford and Shane Ouchi from the Cloud Run team and to Zac Li from Elastic for the helpful review and feedback on this article.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devops</category>
      <category>googlecloud</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Can Google Antigravity 2.0 Pass the "Napkin Challenge"? 📝🚀</title>
      <dc:creator>Shir Meir Lador</dc:creator>
      <pubDate>Wed, 27 May 2026 00:02:51 +0000</pubDate>
      <link>https://dev.to/googleai/can-google-antigravity-20-pass-the-napkin-challenge-2ai2</link>
      <guid>https://dev.to/googleai/can-google-antigravity-20-pass-the-napkin-challenge-2ai2</guid>
      <description>&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/US8lAtHja_s"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;🚀 From Napkin Sketch to data-driven real-estate advisor Agent in Under 40 Minutes? 🚀&lt;/p&gt;

&lt;p&gt;Can a coding agent really work autonomously on complicated problems without human intervention? I decided to put Google’s new Antigravity 2.0 and Gemini 3.5 to the test: The Napkin Challenge. 📝&lt;/p&gt;

&lt;p&gt;The goal: Build and deploy a real estate investment advisor - based on real-world data, starting with nothing but a rough sketch on a napkin. &lt;/p&gt;

&lt;p&gt;The Result? With the right context, yes!&lt;/p&gt;

&lt;p&gt;I used:&lt;br&gt;
Antigravity 2.0 &amp;amp; Gemini 3.5: Architect and execute the plan&lt;br&gt;
Agent CLI Skills: Scaffold, build, test and evaluate the agent using ADK.3&lt;br&gt;
Developer Knowledge MCP: Provided necessary context to connect to BigQuery MCP and integrate the census dataset for grounded investment advice.&lt;br&gt;
Parallelized Workflow using sub-agents: While the system ran the evaluation suite, it simultaneously deployed the agent to Cloud Run.&lt;/p&gt;

&lt;p&gt;The Outcome:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Built and deployed in under 40 minutes.&lt;/li&gt;
&lt;li&gt;Zero human input beyond a napkin sketch (other than approving the plan and setting the model and region).&lt;/li&gt;
&lt;li&gt;100% passing scores on evaluation cases, with responses delivered in under 30 seconds.&lt;/li&gt;
&lt;li&gt;A fully functional real estate advisor providing data-driven analysis on short and long term investments. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The "Napkin Challenge" proves that when you combine the right context with powerful models, the barrier between an idea and a deployed product has virtually disappeared.&lt;/p&gt;

&lt;p&gt;I challenge you: What is your "napkin" project? Try it with Antigravity 2.0 and Gemini 3.5. 📝&lt;/p&gt;

&lt;p&gt;🚀 How to join the challenge - &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sketch an architecture or app idea on a literal napkin.&lt;/li&gt;
&lt;li&gt;Feed it to Antigravity 2.0 + Gemini 3.5. (I recommend making sure you have relevant skills in place for the task - context makes all the difference!)&lt;/li&gt;
&lt;li&gt;Drop a quick video or screenshot of your results on socials with the hashtag #NapkinChallenge. &lt;/li&gt;
&lt;li&gt;Add the link to your demo in the comments to this post!&lt;/li&gt;
&lt;li&gt;Tag 3 other folks and give them 48 hours to match the challenge!
👇 What will you build? Let me know in the comments!&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>antigravity</category>
      <category>napkinchallenge</category>
      <category>autonomousagents</category>
      <category>gemini</category>
    </item>
    <item>
      <title>Agent Factory Recap: How Gemma 4 Taught Itself Physics</title>
      <dc:creator>Shir Meir Lador</dc:creator>
      <pubDate>Thu, 14 May 2026 14:10:49 +0000</pubDate>
      <link>https://dev.to/googleai/agent-factory-recap-how-gemma-4-taught-itself-physics-17e6</link>
      <guid>https://dev.to/googleai/agent-factory-recap-how-gemma-4-taught-itself-physics-17e6</guid>
      <description>&lt;p&gt;In this episode of The Agent Factory, Vlad Kolesnikov and I sat down with Omar Sanseviero from the Developer Experience team at Google DeepMind. We explored the groundbreaking release of Gemma 4: a new family of open models designed to bring high-level intelligence and agentic capabilities directly to consumer hardware and mobile devices. Since the launch last month, Gemma 4 had &lt;strong&gt;over 50 million downloads!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This post guides you through the key ideas from our conversation. Use it to quickly recap topics or dive deeper into specific segments with links and timestamps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gemma 4 - What is it?
&lt;/h2&gt;

&lt;p&gt;Gemma 4 is the latest generation of open models from Google DeepMind, built on the same foundational research as Gemini 3. The family is designed to deliver exceptional "intelligence per parameter" across a range of deployment scenarios, from mobile phones to powerful workstations. The Gemma 4 model family now spans three distinct architectures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Small Sizes (E2B &amp;amp; E4B):&lt;/strong&gt; Optimized for ultra-mobile, edge, and browser deployment (such as Pixel or Chrome).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dense (31B):&lt;/strong&gt; A powerful 31-billion parameter model that provides server-grade performance for local execution on consumer GPUs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mixture-of-Experts (26B MoE):&lt;/strong&gt; A highly efficient architecture designed for high-throughput tasks and advanced reasoning.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With the shift to an &lt;strong&gt;Apache 2 license&lt;/strong&gt;, these models provide developers and startups with the flexibility to build, modify, and commercialize applications while maintaining full control over their infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Omar Sanseviero on how Gemma 4 changes the landscape for agent developers
&lt;/h2&gt;

&lt;p&gt;Timestamp: &lt;a href="https://www.youtube.com/watch?v=ST9mJuTnFqU&amp;amp;list=PLIivdWyY5sqLXR1eSkiM5bE6pFlXC-OSs&amp;amp;index=1&amp;amp;t=100s" rel="noopener noreferrer"&gt;1:40&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Omar highlighted that Gemma 4 brings "very high intelligence per parameter," making it possible to run agentic workflows entirely offline. We saw examples of multiple Gemma instances running locally to generate SVGs (&lt;a href="https://www.youtube.com/watch?v=ST9mJuTnFqU&amp;amp;list=PLIivdWyY5sqLXR1eSkiM5bE6pFlXC-OSs&amp;amp;index=1&amp;amp;t=113s" rel="noopener noreferrer"&gt;1:53&lt;/a&gt;) and an Android-based agent picking specific skills, like playing the piano, to complete tasks (&lt;a href="https://www.youtube.com/watch?v=ST9mJuTnFqU&amp;amp;list=PLIivdWyY5sqLXR1eSkiM5bE6pFlXC-OSs&amp;amp;index=1&amp;amp;t=165s" rel="noopener noreferrer"&gt;2:45&lt;/a&gt;). As Omar noted, "This means that you can run very powerful things with very little hardware overhead...even in the phone that you have in your pocket."&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.amazonaws.com%2Fuploads%2Farticles%2Fre8na48kuuq04m8asknf.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.amazonaws.com%2Fuploads%2Farticles%2Fre8na48kuuq04m8asknf.jpg" alt="Gemma 4 demo screenshot" width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Factory Floor
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Building a Local Food Tour Agent
&lt;/h3&gt;

&lt;p&gt;Timestamp: &lt;a href="https://www.youtube.com/watch?v=ST9mJuTnFqU&amp;amp;list=PLIivdWyY5sqLXR1eSkiM5bE6pFlXC-OSs&amp;amp;index=1&amp;amp;t=329s" rel="noopener noreferrer"&gt;5:29&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We showcased a food tour agent powered by Gemma 4 using the Agent Development Kit (ADK) and a Google Maps MCP server. We demonstrated how a local model can handle complex, multi-step reasoning tasks.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The agent identified the best ramen spots in Seattle under a $30 budget.&lt;/li&gt;
&lt;li&gt;It verified that the locations were within walking distance of each other.&lt;/li&gt;
&lt;li&gt;It processed search results to provide specific tips on what to order and what to avoid.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Autonomous Python Code Execution
&lt;/h3&gt;

&lt;p&gt;Timestamp: &lt;a href="https://www.youtube.com/watch?v=ST9mJuTnFqU&amp;amp;list=PLIivdWyY5sqLXR1eSkiM5bE6pFlXC-OSs&amp;amp;index=1&amp;amp;t=483s" rel="noopener noreferrer"&gt;8:03&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this demo, we pushed Gemma 4's coding capabilities to the limit by asking it to express itself through animation. Using a sandbox execution environment, the model performed the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wrote Python code using the Matplotlib library.&lt;/li&gt;
&lt;li&gt;Attempted to build a physics engine to simulate a bouncing ball.&lt;/li&gt;
&lt;li&gt;Self-corrected when the initial execution environment lacked certain CPU features, finding an alternative path to successfully generate the animation.&lt;/li&gt;
&lt;li&gt;Demonstrated a deep understanding of real-world physics and gravity through code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Shift to Apache 2 Licensing
&lt;/h3&gt;

&lt;p&gt;Timestamp: &lt;a href="https://www.youtube.com/watch?v=ST9mJuTnFqU&amp;amp;list=PLIivdWyY5sqLXR1eSkiM5bE6pFlXC-OSs&amp;amp;index=1&amp;amp;t=245s" rel="noopener noreferrer"&gt;4:05&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A major theme of the conversation was the community-driven decision to move Gemma 4 to an Apache 2 license. This change provides developers and startups with maximum flexibility to build, modify, and commercialize applications. Omar emphasized that this was a direct response to developer feedback, aiming to unlock a new wave of innovation in the open models ecosystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Developer Q&amp;amp;A
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Architectural Decisions and Mixture of Experts (MoE)
&lt;/h3&gt;

&lt;p&gt;Timestamp: &lt;a href="https://www.youtube.com/watch?v=ST9mJuTnFqU&amp;amp;list=PLIivdWyY5sqLXR1eSkiM5bE6pFlXC-OSs&amp;amp;index=1&amp;amp;t=1043s" rel="noopener noreferrer"&gt;17:23&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Omar explained the technical shifts that make Gemma 4 so efficient. For the first time, the Gemma family includes a Mixture of Experts (MoE) architecture, which optimizes for extremely low latency in production. Additionally, the smaller E2B and E4B models utilize per-layer embeddings to remain "cheap" to run on GPUs. For vision tasks, the model now supports variable aspect ratios, allowing it to understand images of various sizes more accurately than previous fixed-resolution versions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Comparing Gemma to Gemini
&lt;/h3&gt;

&lt;p&gt;Timestamp: &lt;a href="https://www.youtube.com/watch?v=ST9mJuTnFqU&amp;amp;list=PLIivdWyY5sqLXR1eSkiM5bE6pFlXC-OSs&amp;amp;index=1&amp;amp;t=1191s" rel="noopener noreferrer"&gt;19:51&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When asked how Gemma stacks up against its larger sibling, Gemini, Omar clarified that they serve different purposes. While Gemini excels at massive-scale tasks and deep "world knowledge" due to its size, Gemma is the "best open model that can run on a single consumer GPU." It is specifically optimized for instruction following, coding, and agentic use cases where local deployment or fine-tuning is required.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fine-Tuning for Specialized Industries
&lt;/h3&gt;

&lt;p&gt;Timestamp: &lt;a href="https://www.youtube.com/watch?v=ST9mJuTnFqU&amp;amp;list=PLIivdWyY5sqLXR1eSkiM5bE6pFlXC-OSs&amp;amp;index=1&amp;amp;t=1271s" rel="noopener noreferrer"&gt;21:10&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The conversation touched on the importance of "Sovereign AI" and privacy. Because Gemma is an open model, developers in regulated industries, like healthcare or finance, can &lt;a href="https://dev.to/googleai/fine-tuning-gemma-4-with-cloud-run-jobs-serverless-gpus-nvidia-rtx-6000-pro-for-pet-breed-45ib"&gt;fine-tune the model on their private data&lt;/a&gt; and deploy it within their own air-gapped infrastructure. This gives developers full control over their data and the model's specialized expertise.&lt;/p&gt;

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

&lt;p&gt;Gemma 4 marks a turning point for agentic development, proving that you don't always need a massive cloud cluster to build something smart. Whether it's running a physics simulation on a laptop or a travel guide on a phone, the barrier to entry for high-performance AI has never been lower. We are entering an era where the "conductor" of the AI orchestra can be any developer with a single GPU and a great idea.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your turn to build
&lt;/h2&gt;

&lt;p&gt;Now that you've seen what Gemma 4 can do, it's time to start building. Check out the resources in our show notes, &lt;a href="https://goo.gle/3OinTFh" rel="noopener noreferrer"&gt;the food tour agent&lt;/a&gt;, &lt;a href="https://goo.gle/4dBDNEY" rel="noopener noreferrer"&gt;the coding agent&lt;/a&gt;, explore the &lt;a href="https://adk.dev/agents/models/google-gemma/" rel="noopener noreferrer"&gt;ADK support&lt;/a&gt;, and try running &lt;a href="https://blog.google/innovation-and-ai/technology/developers-tools/gemma-4/" rel="noopener noreferrer"&gt;Gemma 4&lt;/a&gt; on your local machine or on &lt;a href="https://docs.cloud.google.com/run/docs/run-gemma-on-cloud-run" rel="noopener noreferrer"&gt;Cloud Run&lt;/a&gt;. We can't wait to see what agents you create!&lt;/p&gt;

&lt;p&gt;Watch more of The Agent Factory → &lt;a href="https://www.youtube.com/watch?v=qBOvM7SiDa4&amp;amp;list=PLIivdWyY5sqLXR1eSkiM5bE6pFlXC-OSs&amp;amp;index=1" rel="noopener noreferrer"&gt;Reinforcement learning &amp;amp; fine-tuning on TP...&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Subscribe to Google Cloud Tech → &lt;a href="https://goo.gle/GoogleCloudTech" rel="noopener noreferrer"&gt;https://goo.gle/GoogleCloudTech&lt;/a&gt;&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Shir Meir Lador → &lt;a href="https://www.linkedin.com/in/shirmeirlador/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, &lt;a href="https://x.com/shirmeir86" rel="noopener noreferrer"&gt;X&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Vlad Kolesnikov → &lt;a href="http://www.linkedin.com/in/vkolesnikov/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, &lt;a href="https://x.com/vladkol" rel="noopener noreferrer"&gt;X&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Omar Sanseviero → &lt;a href="https://www.linkedin.com/in/omarsanseviero/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, &lt;a href="https://x.com/osanseviero" rel="noopener noreferrer"&gt;X&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>gemma</category>
      <category>agents</category>
    </item>
    <item>
      <title>Deploying a Multi-Agent System with Terraform and Cloud Run</title>
      <dc:creator>Shir Meir Lador</dc:creator>
      <pubDate>Thu, 07 May 2026 21:04:12 +0000</pubDate>
      <link>https://dev.to/googleai/deploying-a-multi-agent-system-with-terraform-and-cloud-run-2a9c</link>
      <guid>https://dev.to/googleai/deploying-a-multi-agent-system-with-terraform-and-cloud-run-2a9c</guid>
      <description>&lt;p&gt;In support of our mission to accelerate the developer journey on Google Cloud, we built Dev Signal: a multi-agent system designed to transform raw community signals into reliable technical guidance by automating the path from discovery to expert creation.&lt;/p&gt;

&lt;p&gt;In the first three parts of this series, we laid the essential groundwork by establishing its core capabilities and local verification process:&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://dev.to/googleai/building-capabilities-for-a-multi-agent-system-with-google-adk-mcp-and-cloud-run-ab9"&gt;part 1&lt;/a&gt;, we standardize the agent's capabilities through the Model Context Protocol (MCP), connecting it to Reddit for trend discovery and Google Cloud Docs for technical grounding. In &lt;a href="https://dev.to/googleai/architect-a-personalized-multi-agent-system-with-long-term-memory-3o15"&gt;part 2&lt;/a&gt;, we built a multi-agent architecture and integrated the Vertex AI memory bank to allow the system to learn and persist user preferences across different conversations. In &lt;a href="https://dev.to/googleai/local-testing-of-a-multi-agent-system-with-memory-37mm"&gt;part 3&lt;/a&gt;, we verified the full end-to-end lifecycle locally using a dedicated test runner to ensure that research, content creation, and cloud-based memory retrieval were perfectly synchronized.&lt;/p&gt;

&lt;p&gt;If you'd like to dive straight into the code, you can clone the repository &lt;a href="https://github.com/GoogleCloudPlatform/devrel-demos/tree/main/ai-ml/dev-signal" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deployment to Cloud Run and the Path to Production
&lt;/h2&gt;

&lt;p&gt;To help you transition from this local prototype to a production service, this final part focuses on building the production backbone of your agent using the foundational deployment patterns provided by the &lt;a href="https://github.com/GoogleCloudPlatform/agent-starter-pack" rel="noopener noreferrer"&gt;Agent Starter Pack&lt;/a&gt;. We will implement the essential structural components required for monitoring, data integrity, and long-term state management in the cloud. You will learn to implement the application server and helper utilities needed for a production-ready deployment before provisioning secure, reproducible infrastructure with Terraform.&lt;/p&gt;

&lt;p&gt;While the Dockerfile packages your agent's code and its specialized dependencies, such as Node.js for the Reddit MCP tool, Terraform is used to build the platform it lives on. Terraform automates the creation of your Artifact Registry, least-privilege service accounts, and Secret Manager integrations to ensure your API keys remain protected.&lt;/p&gt;

&lt;p&gt;By the end of this part, you will have a standardized application framework deployed on Google Cloud Run and a roadmap for graduating your prototype through continuous evaluation, CI/CD and advanced observability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Production Utilities and Server: Building the System's Body
&lt;/h2&gt;

&lt;p&gt;In this section, you implement the structural components required for monitoring and long-term state management in the cloud.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Application Server:&lt;/strong&gt; Initializing the FastAPI server and establishing a vital connection to the Vertex AI memory bank.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implementing Telemetry:&lt;/strong&gt; Enabling 'Agent Traces' for visibility into internal reasoning.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Application Server
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;fast_api_app.py&lt;/code&gt; file serves as the vital entry point for your agent, transforming the core logic into a production FastAPI server that acts as the "body" of your system. When deploying to Cloud Run, this server is essential because it provides the necessary web interface to listen for incoming HTTP requests and dispatch them to the agent for processing. Beyond basic serving, its most critical role is establishing a connection to the Vertex AI memory bank by defining a &lt;code&gt;MEMORY_URI&lt;/code&gt;, which allows the ADK framework to persist and retrieve user preferences across different production sessions. Additionally, the application server initializes production-grade telemetry for real-time monitoring.&lt;/p&gt;

&lt;p&gt;Go back to the &lt;code&gt;dev_signal_agent folder.&lt;/code&gt;&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;cd&lt;/span&gt; ..
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste the following code in &lt;code&gt;dev_signal_agent/fast_api_app.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google.adk.cli.fast_api&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;get_fast_api_app&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google.cloud&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;cloud_logging&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;vertexai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;agent_engines&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dev_signal_agent.app_utils.env&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;init_environment&lt;/span&gt;

&lt;span class="c1"&gt;# --- Initialization &amp;amp; Secure Secret Retrieval ---
# We now unpack the SECRETS dictionary returned by our updated env.py
&lt;/span&gt;&lt;span class="n"&gt;PROJECT_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MODEL_LOC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SERVICE_LOC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SECRETS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;init_environment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cloud_logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Access sensitive credentials from the SECRETS dictionary
# These keys stay in memory and are NOT injected into os.environ
&lt;/span&gt;&lt;span class="n"&gt;REDDIT_CLIENT_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SECRETS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;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;REDDIT_CLIENT_SECRET&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SECRETS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;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;REDDIT_USER_AGENT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SECRETS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;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;DK_API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SECRETS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DK_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# --- Configuration &amp;amp; Sessions ---
&lt;/span&gt;&lt;span class="n"&gt;AGENT_DIR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abspath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__file__&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="c1"&gt;# Non-sensitive configuration uses environment variables
&lt;/span&gt;&lt;span class="n"&gt;BUCKET&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="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AI_ASSETS_BUCKET&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;USE_IN_MEMORY&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="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;USE_IN_MEMORY_SESSION&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# --- MEMORY BANK CONNECTION ---
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_get_memory_bank_uri&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;USE_IN_MEMORY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="c1"&gt;# We use 'dev_signal_agent' as the display name for the Vertex AI memory bank
&lt;/span&gt;    &lt;span class="n"&gt;name&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="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AGENT_ENGINE_MEMORY_BANK_NAME&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dev_signal_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;existing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;agent_engines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;display_name=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;ae&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;existing&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;existing&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;agent_engines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;display_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;uri&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;agentengine://&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ae&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resource_name&lt;/span&gt;&lt;span class="si"&gt;}&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;DEBUG: Connecting to Memory Bank: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; (display_name=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uri&lt;/span&gt;

&lt;span class="n"&gt;SESSION_URI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MEMORY_URI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;_get_memory_bank_uri&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# --- Initialize FastAPI with ADK ---
&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_fast_api_app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;agents_dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;AGENT_DIR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;web&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;artifact_service_uri&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gs://&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;BUCKET&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;BUCKET&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;allow_origins&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="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ALLOW_ORIGINS&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ALLOW_ORIGINS&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;session_service_uri&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;SESSION_URI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;memory_service_uri&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;MEMORY_URI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# &amp;lt;--- Connects the Memory Bank
&lt;/span&gt;    &lt;span class="n"&gt;otel_to_cloud&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="c1"&gt;# &amp;lt;--- Enables production telemetry
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__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;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;uvicorn&lt;/span&gt;
    &lt;span class="c1"&gt;# Standard Cloud Run port is 8080
&lt;/span&gt;    &lt;span class="n"&gt;uvicorn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.0.0.0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Implementing Telemetry
&lt;/h3&gt;

&lt;p&gt;In a production environment, visibility into your agent's reasoning is critical. We leverage the built-in observability features of the Google ADK by setting the &lt;code&gt;otel_to_cloud=True&lt;/code&gt; flag in our application server. This single parameter handles the majority of the instrumentation automatically, exporting "Agent Traces" directly to the Google Cloud Console. These traces provide a "visual waterfall" of the agent's operation, including individual agent thought processes, LLM invocations, and MCP tool calls.&lt;/p&gt;

&lt;h4&gt;
  
  
  Monitoring vs. Targeted Evaluation
&lt;/h4&gt;

&lt;p&gt;It is essential to understand that production tracing is subject to sampling to balance performance and cost. Because Cloud Run captures only a subset of requests, not every individual user interaction will be visible.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;System Traces (Monitoring):&lt;/strong&gt; Used to analyze behavior "at large," such as identifying latency bottlenecks or system timeouts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reasoning Traces (Evaluation):&lt;/strong&gt; High-quality evaluation mandates targeted trace capture. This means calling the agent specifically for a test case where you know you will evaluate that particular request in full detail.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Viewing the Trace
&lt;/h4&gt;

&lt;p&gt;To see your traces, navigate to the Trace Explorer in the Google Cloud Console and filter for your service (e.g., &lt;code&gt;dev-signal&lt;/code&gt;). Clicking a specific Trace ID opens a Gantt chart that allows you to distinguish between cognitive reasoning failures (wrong decisions) and physical system issues (timeouts).&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.amazonaws.com%2Fuploads%2Farticles%2Fhbe3brcww32j0igfr7zh.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.amazonaws.com%2Fuploads%2Farticles%2Fhbe3brcww32j0igfr7zh.png" alt="Trace Explorer view" width="800" height="354"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For advanced configurations, refer to the following documentation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.cloud.google.com/run/docs/trace#trace_sampling_rate?utm_campaign=CDR_0x91b1edb5_default_b485268863&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;Cloud Run Trace Sampling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.cloud.google.com/stackdriver/docs/instrumentation/ai-agent-adk#configure?utm_campaign=CDR_0x91b1edb5_default_b485268863&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;Configuring ADK Telemetry&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.cloud.google.com/trace/docs/collect-view-multimodal-prompts-responses?utm_campaign=CDR_0x91b1edb5_default_b485268863&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;Multimodal Trace Capture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://google.github.io/adk-docs/integrations/bigquery-agent-analytics/" rel="noopener noreferrer"&gt;BigQuery Agent Analytics Integration&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Infrastructure as Code: Provisioning Secure Cloud Resources
&lt;/h2&gt;

&lt;p&gt;We utilize the infrastructure-as-code patterns provided by the &lt;a href="https://github.com/GoogleCloudPlatform/agent-starter-pack" rel="noopener noreferrer"&gt;Agent Starter Pack&lt;/a&gt;'s security-first design. The starter pack builds the professional platform required to automate the creation of least-privilege service accounts and robust secret management in seconds.&lt;/p&gt;

&lt;p&gt;Using Terraform ensures that your entire Google Cloud environment - from IAM roles to Secret Manager versions - is defined in reproducible, secure code. We break our infrastructure into the following logical blocks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Resources &amp;amp; Variables&lt;/strong&gt;: Define the specific project, region, and sensitive API secrets used by the agent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Core Infrastructure&lt;/strong&gt;: Enable essential APIs and provision a private Artifact Registry to host your agent's container images.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Identity &amp;amp; Access Management (IAM)&lt;/strong&gt;: Configure specialized Service Accounts that strictly follow the Principle of Least Privilege to ensure your system remains secure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secret Management&lt;/strong&gt;: Securely ingest API credentials into Google Secret Manager for protected runtime access.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud Run Configuration&lt;/strong&gt;: Define the container environment, resource limits, and automated secret injection for the final deployment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To begin provisioning, return to the root folder of your project (dev-signal) and create the necessary deployment directories:&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;cd&lt;/span&gt; ..
&lt;span class="nb"&gt;mkdir &lt;/span&gt;deployment
&lt;span class="nb"&gt;cd &lt;/span&gt;deployment
&lt;span class="nb"&gt;mkdir &lt;/span&gt;terraform
&lt;span class="nb"&gt;cd &lt;/span&gt;terraform
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Terraform Resources and Variables
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;variables.tf&lt;/code&gt; file defines the configurable parameters for your deployment, allowing you to customize the infrastructure without altering the underlying logic. It includes variables for the &lt;code&gt;project_id&lt;/code&gt;, the deployment &lt;code&gt;region&lt;/code&gt; (defaulting to &lt;code&gt;us-central1&lt;/code&gt;), and the &lt;code&gt;service_name&lt;/code&gt; for your Cloud Run instance. Furthermore, it defines a &lt;code&gt;secrets&lt;/code&gt; map used to securely ingest sensitive API credentials—such as Reddit and Developer Knowledge keys—into Google Secret Manager for runtime access. This modular approach ensures your production environment remains reproducible, secure, and adaptable across different projects.&lt;/p&gt;

&lt;p&gt;Paste the following code into &lt;code&gt;deployment/terraform/variables.tf&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"project_id"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"The Google Cloud Project ID"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"region"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"The Google Cloud region to deploy to"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"us-central1"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"service_name"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"The name of the Cloud Run service"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"dev-signal"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"secrets"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"A map of secret names and their values (e.g., REDDIT_CLIENT_ID, DK_API_KEY)"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"ai_assets_bucket"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"The GCS bucket for storing AI assets"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Core Infrastructure Logic
&lt;/h3&gt;

&lt;p&gt;We define our infrastructure in logical blocks. Here is what each part does:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Enable APIs&lt;/strong&gt;: Ensures the project has the necessary services active (Cloud Run, Vertex AI, etc.). We use &lt;code&gt;disable_on_destroy = false&lt;/code&gt; to prevent accidental data loss if the Terraform is destroyed.&lt;/p&gt;

&lt;p&gt;Paste the following code into &lt;code&gt;deployment/terraform/main.tf&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"google_project_service"&lt;/span&gt; &lt;span class="s2"&gt;"services"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;project&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;project_id&lt;/span&gt;
  &lt;span class="nx"&gt;for_each&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;toset&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="s2"&gt;"run.googleapis.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"artifactregistry.googleapis.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"cloudbuild.googleapis.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"aiplatform.googleapis.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"secretmanager.googleapis.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"logging.googleapis.com"&lt;/span&gt;
  &lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="nx"&gt;service&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;
  &lt;span class="nx"&gt;disable_on_destroy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&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. Artifact Registry&lt;/strong&gt;: Creates a private Docker registry to store our agent's container images.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"google_artifact_registry_repository"&lt;/span&gt; &lt;span class="s2"&gt;"repo"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;location&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;region&lt;/span&gt;
  &lt;span class="nx"&gt;project&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;project_id&lt;/span&gt;
  &lt;span class="nx"&gt;repository_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"dev-signal-repo"&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Docker repository for Dev Signal Agent"&lt;/span&gt;
  &lt;span class="nx"&gt;format&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"DOCKER"&lt;/span&gt;
  &lt;span class="nx"&gt;depends_on&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;google_project_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;services&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;3. Service Account &amp;amp; IAM: Adhering to the Principle of Least Privilege&lt;/strong&gt; - This is a critical security step. In accordance with the Principle of Least Privilege, we avoid using the default compute service account and instead provision a dedicated user-managed service account (&lt;code&gt;dev-signal-sa&lt;/code&gt;). By designating this as the Cloud Run service identity, we can grant it only the minimum necessary permissions—specifically &lt;code&gt;roles/aiplatform.user&lt;/code&gt;, &lt;code&gt;roles/logging.logWriter&lt;/code&gt;, and &lt;code&gt;roles/storage.objectAdmin&lt;/code&gt;. This granular access control ensures that the agent has the exact permissions required to interact with Vertex AI and Cloud Storage without over-granting access to other sensitive cloud resources, significantly reducing the potential impact of a compromised account. Learn more &lt;a href="https://docs.cloud.google.com/iam/docs/best-practices-service-accounts?content_ref=because%20a%20service%20account%20is%20a%20principal%20you%20must%20limit%20its%20privileges%20to%20reduce%20the%20potential%20harm%20that%20can%20be%20done%20by%20a%20compromised%20service%20account&amp;amp;utm_campaign=CDR_0x91b1edb5_default_b485268863&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;best practices for using service accounts securely&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"google_service_account"&lt;/span&gt; &lt;span class="s2"&gt;"agent_sa"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;project&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;project_id&lt;/span&gt;
  &lt;span class="nx"&gt;account_id&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"${var.service_name}-sa"&lt;/span&gt;
  &lt;span class="nx"&gt;display_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Dev Signal Agent Service Account"&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;4. Secret Management&lt;/strong&gt;: This handles your API keys securely. It creates secrets in Google Secret Manager and gives the agent's Service Account permission to access them at runtime.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"google_secret_manager_secret"&lt;/span&gt; &lt;span class="s2"&gt;"agent_secrets"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;project&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;project_id&lt;/span&gt;
  &lt;span class="nx"&gt;for_each&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;toset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secrets&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="nx"&gt;secret_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;
  &lt;span class="nx"&gt;replication&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;auto&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;depends_on&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;google_project_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;services&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"google_secret_manager_secret_version"&lt;/span&gt; &lt;span class="s2"&gt;"agent_secrets_version"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;for_each&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;toset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secrets&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="nx"&gt;secret&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;google_secret_manager_secret&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;agent_secrets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;secret_data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secrets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"google_secret_manager_secret_iam_member"&lt;/span&gt; &lt;span class="s2"&gt;"secret_accessor"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;project&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;project_id&lt;/span&gt;
  &lt;span class="nx"&gt;for_each&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;toset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secrets&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="nx"&gt;secret_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;google_secret_manager_secret&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;agent_secrets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;role&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"roles/secretmanager.secretAccessor"&lt;/span&gt;
  &lt;span class="nx"&gt;member&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"serviceAccount:${google_service_account.agent_sa.email}"&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;5. Cloud Run Configuration:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security Best Practice:&lt;/strong&gt; To satisfy production security standards, our &lt;code&gt;main.tf&lt;/code&gt; grants the Service Account the &lt;code&gt;secretmanager.secretAccessor&lt;/code&gt; role. Our Python application then uses the &lt;a href="https://docs.cloud.google.com/secret-manager/docs/best-practices#coding-practices" rel="noopener noreferrer"&gt;Secret Manager SDK&lt;/a&gt; to pull these credentials directly into local memory at runtime, ensuring they never touch the container's environment configuration&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# 6. Cloud Run Service Deployment&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"google_cloud_run_v2_service"&lt;/span&gt; &lt;span class="s2"&gt;"default"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;project&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;project_id&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;service_name&lt;/span&gt;
  &lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;region&lt;/span&gt;
  &lt;span class="nx"&gt;ingress&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"INGRESS_TRAFFIC_ALL"&lt;/span&gt;

  &lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;service_account&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;google_service_account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;agent_sa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;

    &lt;span class="nx"&gt;containers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;image&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"us-docker.pkg.dev/cloudrun/container/hello"&lt;/span&gt; &lt;span class="c1"&gt;# Placeholder until first build&lt;/span&gt;

      &lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;name&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"GOOGLE_CLOUD_PROJECT"&lt;/span&gt;
        &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;project_id&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;name&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"GOOGLE_CLOUD_LOCATION"&lt;/span&gt;
        &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"global"&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;name&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"GOOGLE_GENAI_USE_VERTEXAI"&lt;/span&gt;
        &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"True"&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;name&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"AI_ASSETS_BUCKET"&lt;/span&gt;
        &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ai_assets_bucket&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="nx"&gt;resources&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;limits&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;cpu&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"1"&lt;/span&gt;
          &lt;span class="nx"&gt;memory&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"2Gi"&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;traffic&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;type&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST"&lt;/span&gt;
    &lt;span class="nx"&gt;percent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Provision the Infrastructure
&lt;/h3&gt;

&lt;p&gt;Before we can deploy our code, we need to provision the Google Cloud infrastructure we just defined.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Initialize Terraform&lt;/strong&gt;: This downloads the necessary provider plugins. Run this in &lt;code&gt;deployment/terraform&lt;/code&gt; folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;terraform init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Create a Variables File&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;Paste this code in &lt;code&gt;deployment/terraform/terraform.tfvars&lt;/code&gt; and update it with your project details and secrets.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;project_id&lt;/span&gt;       &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"your-project-id"&lt;/span&gt;
&lt;span class="nx"&gt;region&lt;/span&gt;           &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"us-central1"&lt;/span&gt;
&lt;span class="nx"&gt;service_name&lt;/span&gt;     &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"dev-signal"&lt;/span&gt;
&lt;span class="nx"&gt;ai_assets_bucket&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"your-bucket-name"&lt;/span&gt;
&lt;span class="nx"&gt;secrets&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;REDDIT_CLIENT_ID&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"your_client_id"&lt;/span&gt;
  &lt;span class="nx"&gt;REDDIT_CLIENT_SECRET&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"your_client_secret"&lt;/span&gt;
  &lt;span class="nx"&gt;REDDIT_USER_AGENT&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"your_user_agent"&lt;/span&gt;
  &lt;span class="nx"&gt;DK_API_KEY&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"your_dk_api_key"&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;Plan configuration&lt;/strong&gt;: This allows you to review the changes before they are applied. Run this in the &lt;code&gt;deployment/terraform&lt;/code&gt; folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;terraform plan &lt;span class="nt"&gt;-out&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;plan.tfplan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Apply Configuration&lt;/strong&gt;: Once you have reviewed the plan and confirmed it does what you want, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;terraform apply plan.tfplan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deployment: Containerization and the Cloud Build Pipeline
&lt;/h2&gt;

&lt;p&gt;In this final stage of the build process, we package our agent's "body" and "brain" into a portable, production-ready container. This ensures that every component - from our Python logic to the Node.js environment required for the Reddit MCP tool - is bundled together with its exact dependencies.&lt;/p&gt;

&lt;p&gt;We utilize a &lt;strong&gt;Dockerfile&lt;/strong&gt; to define this environment and a &lt;strong&gt;Makefile&lt;/strong&gt; to orchestrate the deployment pipeline. When you trigger the deployment, &lt;a href="https://pantheon.corp.google.com/cloud-build/builds" rel="noopener noreferrer"&gt;Google Cloud Build&lt;/a&gt; takes your local source code, builds the container image according to the Dockerfile, and stores it in the private Artifact Registry created earlier by Terraform. Finally, the pipeline automatically updates your Cloud Run service to serve traffic using this fresh image, completing the journey from local code to a live, secure cloud workload.&lt;/p&gt;

&lt;p&gt;Paste this code in &lt;code&gt;dev-signal/Dockerfile&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; python:3.12-slim&lt;/span&gt;

&lt;span class="c"&gt;# Install Node.js and npm for MCP tools (like reddit-mcp)&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    curl &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://deb.nodesource.com/setup_20.x | bash - &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; nodejs &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; reddit-mcp &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get clean &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /var/lib/apt/lists/&lt;span class="k"&gt;*&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--no-cache-dir&lt;/span&gt; &lt;span class="nv"&gt;uv&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;0.8.13

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /code&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ./pyproject.toml ./README.md ./uv.lock* ./&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ./dev_signal_agent ./dev_signal_agent&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;uv &lt;span class="nb"&gt;sync&lt;/span&gt; &lt;span class="nt"&gt;--frozen&lt;/span&gt;

&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8080&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["uv", "run", "uvicorn", "dev_signal_agent.fast_api_app:app", "--host", "0.0.0.0", "--port", "8080"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;Makefile&lt;/strong&gt; automates the build and deploys.&lt;/p&gt;

&lt;p&gt;Paste this code in &lt;code&gt;dev-signal/Makefile&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;PROJECT_ID&lt;/span&gt; &lt;span class="o"&gt;?=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;shell gcloud config get-value project&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;REGION&lt;/span&gt;     &lt;span class="o"&gt;?=&lt;/span&gt; us-central1
&lt;span class="nv"&gt;IMAGE_REPO&lt;/span&gt; &lt;span class="o"&gt;?=&lt;/span&gt; dev-signal-repo
&lt;span class="nv"&gt;IMAGE&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;REGION&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nt"&gt;-docker&lt;/span&gt;.pkg.dev/&lt;span class="p"&gt;$(&lt;/span&gt;PROJECT_ID&lt;span class="p"&gt;)&lt;/span&gt;/&lt;span class="p"&gt;$(&lt;/span&gt;IMAGE_REPO&lt;span class="p"&gt;)&lt;/span&gt;/agent:latest

&lt;span class="c"&gt;# Deploy via Cloud Build &amp;amp; Container
&lt;/span&gt;&lt;span class="nl"&gt;docker-deploy&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"? Building and deploying to &lt;/span&gt;&lt;span class="p"&gt;$(&lt;/span&gt;&lt;span class="s2"&gt;PROJECT_ID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; via Cloud Build..."&lt;/span&gt;
    gcloud builds submit &lt;span class="nt"&gt;--tag&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;IMAGE&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;--project&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;PROJECT_ID&lt;span class="p"&gt;)&lt;/span&gt; .
    gcloud run services update dev-signal &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--image&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;IMAGE&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--region&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;REGION&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--project&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;PROJECT_ID&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--labels&lt;/span&gt; dev-tutorial&lt;span class="o"&gt;=&lt;/span&gt;dev-signal-agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Deploy Application
&lt;/h3&gt;

&lt;p&gt;Now that our infrastructure is ready, we can build and deploy the application code.&lt;/p&gt;

&lt;p&gt;Run the following command from the root of your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make docker-deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What happens when you run this?&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Build&lt;/strong&gt;: Google Cloud Build takes your local code and the &lt;code&gt;Dockerfile&lt;/code&gt;, builds a container image, and stores it in the Artifact Registry.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy&lt;/strong&gt;: It updates the Cloud Run service defined in Terraform to use this new image.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When the deployment completes, you should get a message like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Service [dev-signal] revision [dev-signal...] has been deployed and is serving 100 percent of traffic.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Service URL: https://dev-signal-...-.us-central1.run.app&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Verification: Accessing and Testing Your Deployed Agent
&lt;/h2&gt;

&lt;p&gt;Since production services are private by default, this section covers how to grant permissions and access the agent securely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Managing IAM Permissions:&lt;/strong&gt; Granting the necessary &lt;code&gt;run.invoker&lt;/code&gt; role to authorized users.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Secure Access via Cloud Run Proxy:&lt;/strong&gt; Using the &lt;code&gt;gcloud&lt;/code&gt; proxy to interact with your live service.&lt;/p&gt;

&lt;h3&gt;
  
  
  Granting User Permissions
&lt;/h3&gt;

&lt;p&gt;Before you can invoke the service, you must grant your Google account the &lt;code&gt;roles/run.invoker&lt;/code&gt; role for this specific service. Run the following command:&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 services add-iam-policy-binding dev-signal &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;"user:&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;gcloud config get-value account&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&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/run.invoker"&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;--project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;gcloud config get-value project&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Launch the Proxy
&lt;/h3&gt;

&lt;p&gt;Now, access your private service securely via the proxy:&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 services proxy dev-signal &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; us-central1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--project&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;gcloud config get-value project&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Visit &lt;strong&gt;http://localhost:8080&lt;/strong&gt; to chat with your deployed agent! See a possible test scenario in &lt;a href="https://cloud.google.com/blog/topics/developers-practitioners/create-expert-content-local-testing-of-a-multi-agent-system-with-memory" rel="noopener noreferrer"&gt;part 3&lt;/a&gt; of the series.&lt;/p&gt;

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

&lt;p&gt;Congratulations! You have successfully built &lt;strong&gt;Dev Signal&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What we covered:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://dev.to/googleai/building-capabilities-for-a-multi-agent-system-with-google-adk-mcp-and-cloud-run-ab9"&gt;&lt;strong&gt;Tooling (MCP)&lt;/strong&gt;&lt;/a&gt;: You connected your agent to &lt;strong&gt;Reddit&lt;/strong&gt;, &lt;strong&gt;Google Docs&lt;/strong&gt;, and a &lt;strong&gt;Local Image Generator&lt;/strong&gt; using the Model Context Protocol.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/googleai/architect-a-personalized-multi-agent-system-with-long-term-memory-3o15"&gt;&lt;strong&gt;Architecture&lt;/strong&gt;&lt;/a&gt;: You implemented a &lt;strong&gt;Root Orchestrator&lt;/strong&gt; managing specialized agents (Scanner, Expert, Drafter).&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/googleai/local-testing-of-a-multi-agent-system-with-memory-37mm"&gt;&lt;strong&gt;Memory&lt;/strong&gt;&lt;/a&gt;: You integrated &lt;strong&gt;Vertex AI memory bank&lt;/strong&gt; to give your agent long-term persistence across sessions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Production&lt;/strong&gt;: You deployed the entire stack to &lt;strong&gt;Google Cloud Run&lt;/strong&gt; using &lt;strong&gt;Terraform&lt;/strong&gt; for secure, reproducible infrastructure.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You now have a solid foundation for building sophisticated, stateful AI applications on Google Cloud.&lt;/p&gt;

</description>
      <category>googlecloud</category>
      <category>terraform</category>
      <category>ai</category>
      <category>agents</category>
    </item>
    <item>
      <title>Local Testing of a Multi-Agent System with Memory</title>
      <dc:creator>Shir Meir Lador</dc:creator>
      <pubDate>Thu, 07 May 2026 21:03:03 +0000</pubDate>
      <link>https://dev.to/googleai/local-testing-of-a-multi-agent-system-with-memory-37mm</link>
      <guid>https://dev.to/googleai/local-testing-of-a-multi-agent-system-with-memory-37mm</guid>
      <description>&lt;p&gt;In support of our mission to accelerate the developer journey on Google Cloud, we built Dev Signal: a multi-agent system designed to transform raw community signals into reliable technical guidance by automating the path from discovery to expert creation.&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://dev.to/googleai/building-capabilities-for-a-multi-agent-system-with-google-adk-mcp-and-cloud-run-ab9"&gt;part 1&lt;/a&gt; and &lt;a href="https://dev.to/googleai/architect-a-personalized-multi-agent-system-with-long-term-memory-3o15"&gt;part 2&lt;/a&gt; of this series, we established the essential groundwork by standardizing the core capabilities through the Model Context Protocol (MCP) and constructing a multi-agent architecture integrated with the Vertex AI memory bank to provide long-term intelligence and persistence. Now, we'll explore how to test your multi-agent system locally!&lt;/p&gt;

&lt;p&gt;If you'd like to dive straight into the code and explore it at your own pace, you can clone the repository &lt;a href="https://github.com/GoogleCloudPlatform/devrel-demos/tree/main/ai-ml/dev-signal" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing the Agent Locally
&lt;/h2&gt;

&lt;p&gt;Before transitioning your agentic system to Google Cloud Run, it is essential to ensure that its specialized components work seamlessly together on your workstation. This testing phase allows you to validate trend discovery, technical grounding, and creative drafting within a local feedback loop, saving time and resources during the development process.&lt;/p&gt;

&lt;p&gt;In this section, you will configure your local secrets, implement environment-aware utilities, and use a dedicated test runner to verify that Dev Signal can correctly retrieve user preferences from the Vertex AI memory bank on the cloud. This local verification ensures that your agent's "brain" and "hands" are properly synchronized before moving to deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Environment Setup
&lt;/h2&gt;

&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; file in your project root. These variables are used for local development and will be replaced by Terraform/Secret Manager in production.&lt;/p&gt;

&lt;p&gt;Paste this code in &lt;code&gt;dev-signal/.env&lt;/code&gt; and update with your own details.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: &lt;code&gt;GOOGLE_CLOUD_LOCATION&lt;/code&gt; is set as &lt;code&gt;global&lt;/code&gt; because that is where &lt;code&gt;gemini-3-flash-preview&lt;/code&gt; is supported. We will use &lt;code&gt;GOOGLE_CLOUD_LOCATION&lt;/code&gt; for the model location.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Google Cloud Configuration
GOOGLE_CLOUD_PROJECT=your-project-id
GOOGLE_CLOUD_LOCATION=global
GOOGLE_CLOUD_REGION=us-central1
GOOGLE_GENAI_USE_VERTEXAI=True
AI_ASSETS_BUCKET=your_bucket_name

# Reddit API Credentials
REDDIT_CLIENT_ID=your_client_id
REDDIT_CLIENT_SECRET=your_client_secret
REDDIT_USER_AGENT=my-agent/0.1

# Developer Knowledge API Key
DK_API_KEY=your_api_key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Helper Utilities
&lt;/h2&gt;

&lt;p&gt;Create a new directory for your application utils:&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;cd &lt;/span&gt;dev_signal_agent
&lt;span class="nb"&gt;mkdir &lt;/span&gt;app_utils
&lt;span class="nb"&gt;cd &lt;/span&gt;app_utils
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Environment Configuration
&lt;/h3&gt;

&lt;p&gt;This module standardizes how the agent discovers the active Google Cloud Project and Region, ensuring a seamless transition between development environments. Using &lt;code&gt;load_dotenv()&lt;/code&gt;, the script first checks for local configurations before falling back to &lt;code&gt;google.auth.default()&lt;/code&gt; or environment variables to retrieve the Project ID. This automated approach ensures your agent is properly authenticated and grounded in the correct cloud context without requiring manual configuration changes.&lt;/p&gt;

&lt;p&gt;Beyond basic project discovery, the script provides a robust &lt;strong&gt;Secret Management&lt;/strong&gt; layer. It attempts to resolve sensitive credentials, such as Reddit API keys, first from the local environment (for rapid development) and then dynamically from the &lt;a href="https://docs.cloud.google.com/secret-manager/docs/reference/rest" rel="noopener noreferrer"&gt;&lt;strong&gt;Google Cloud Secret Manager API&lt;/strong&gt;&lt;/a&gt; for production security. By returning these as a dictionary rather than injecting them into environment variables, the module maintains a clean security posture.&lt;/p&gt;

&lt;p&gt;The script further calibrates the environment by distinguishing between global and regional requirements for different AI services. It specifically assigns the "global" location for models to access cutting-edge preview features while designating a regional location, such as &lt;code&gt;us-central1&lt;/code&gt;, for infrastructure like the Vertex AI Agent Engine.&lt;/p&gt;

&lt;p&gt;Paste this code in &lt;code&gt;dev_signal_agent/app_utils/env.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="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;google.auth&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;vertexai&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google.cloud&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;secretmanager&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_fetch_secrets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project_id&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="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Fetch secrets from Secret Manager and return them as a dictionary.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;secrets_to_fetch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;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="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="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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DK_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;fetched_secrets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="c1"&gt;# First, check local environment (for local development via .env)
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;secrets_to_fetch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;val&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="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;fetched_secrets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;

    &lt;span class="c1"&gt;# If keys are missing (common in production), fetch from Secret Manager API
&lt;/span&gt;    &lt;span class="k"&gt;if&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;fetched_secrets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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;secrets_to_fetch&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;secretmanager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SecretManagerServiceClient&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;secret_id&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;secrets_to_fetch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;secret_id&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;fetched_secrets&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;projects/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;project_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/secrets/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;secret_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/versions/latest&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="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;access_secret_version&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
                    &lt;span class="n"&gt;fetched_secrets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;secret_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;UTF-8&lt;/span&gt;&lt;span class="sh"&gt;"&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="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;Warning: Could not fetch &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;secret_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; from Secret Manager: &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;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fetched_secrets&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;init_environment&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Consolidated environment discovery.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;project_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;google&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;default&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="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;project_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="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GOOGLE_CLOUD_PROJECT&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_location&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="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GOOGLE_CLOUD_LOCATION&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;global&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;service_location&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="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GOOGLE_CLOUD_REGION&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;us-central1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;secrets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;project_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;vertexai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;project_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;service_location&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;secrets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;_fetch_secrets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;project_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model_location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;service_location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;secrets&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Local Testing Script
&lt;/h2&gt;

&lt;p&gt;The Google ADK comes with a built-in Web UI that is excellent for visualizing agent logic and tool composition. &lt;/p&gt;

&lt;p&gt;You can launch it by running in the project root:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;However, the default Web UI will not test the long-term memory integration described in this tutorial because it is not pre-connected to a Vertex AI memory session. By default, the generic UI often relies on in-memory services that do not persist data across sessions. Therefore, we use the dedicated &lt;code&gt;test_local.py&lt;/code&gt; script to explicitly initialize the &lt;code&gt;VertexAiMemoryBankService&lt;/code&gt;. This ensures that even in a local environment, your agent is communicating with the real cloud-based memory bank to validate preference persistence.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;test_local.py&lt;/code&gt; script:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Connects to the real &lt;a href="https://docs.cloud.google.com/agent-builder/agent-engine/overview" rel="noopener noreferrer"&gt;&lt;strong&gt;Vertex AI Agent Engine&lt;/strong&gt;&lt;/a&gt; in the cloud for memory storage.&lt;/li&gt;
&lt;li&gt;Uses an in-memory session service for local chat history (so you can wipe it easily).&lt;/li&gt;
&lt;li&gt;Runs a chat loop where you can talk to your agent.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Go back to the root folder &lt;code&gt;dev-signal&lt;/code&gt;:&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;cd&lt;/span&gt; ../..
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste this code in &lt;code&gt;dev-signal/test_local.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&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;google.auth&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;vertexai&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google.adk.runners&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Runner&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google.adk.memory.vertex_ai_memory_bank_service&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;VertexAiMemoryBankService&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google.adk.sessions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;InMemorySessionService&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;vertexai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;agent_engines&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google.genai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dev_signal_agent.agent&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;root_agent&lt;/span&gt;

&lt;span class="c1"&gt;# Load environment variables
&lt;/span&gt;&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# 1. Setup Configuration
&lt;/span&gt;    &lt;span class="n"&gt;project_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="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GOOGLE_CLOUD_PROJECT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Agent Engine (Memory) MUST use a regional endpoint
&lt;/span&gt;    &lt;span class="n"&gt;resource_location&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;us-central1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;agent_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;dev-signal&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;--- Initializing Vertex AI in &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;resource_location&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;vertexai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;project_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;resource_location&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 2. Find the Agent Engine Resource for Memory
&lt;/span&gt;    &lt;span class="n"&gt;existing_agents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;agent_engines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;display_name=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;agent_name&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="n"&gt;existing_agents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;agent_engine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;existing_agents&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;agent_engine_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;agent_engine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resource_name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&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="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="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;✅ Using persistent Memory Bank from Agent: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;agent_engine_id&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;else&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;❌ Error: Agent Engine &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;agent_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; not found. Please deploy with Terraform first.&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="c1"&gt;# 3. Initialize Services
&lt;/span&gt;    &lt;span class="n"&gt;session_service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;InMemorySessionService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;memory_service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;VertexAiMemoryBankService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;project_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;resource_location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;agent_engine_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;agent_engine_id&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 4. Create a Runner
&lt;/span&gt;    &lt;span class="n"&gt;runner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Runner&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;root_agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;app_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;dev-signal&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;session_service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;session_service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;memory_service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;memory_service&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 5. Run a Test Loop
&lt;/span&gt;    &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;local-tester&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="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;--- TEST SCENARIO ---&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1. Start a session, tell the agent your preference (e.g., &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;write in rhymes&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;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2. Type &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;new&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; to start a FRESH session (local state wiped).&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3. Ask for a blog post. The agent should retrieve your preference from the CLOUD memory.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;current_session_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;session-&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;())[&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;session_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;app_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;dev-signal&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_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;current_session_id&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;--- Chat Session (ID: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;current_session_id&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="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;user_input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&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;You: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;user_input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;exit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;quit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;user_input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;new&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;current_session_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;session-&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;())[&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;session_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;app_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;dev-signal&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_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;current_session_id&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;--- Fresh Session Started (ID: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;current_session_id&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="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;(Local history is empty, retrieval must come from Memory Bank)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;

        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Agent is thinking...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;runner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run_async&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;current_session_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;new_message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Part&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;user_input&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;
        &lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parts&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;part&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;part&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="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;Agent: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;part&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="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="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_function_calls&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;fc&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_function_calls&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;🛠️ Tool Call: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;fc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&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="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;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Running the Test
&lt;/h3&gt;

&lt;p&gt;First, ensure you have your Application Default Credentials set up:&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;p&gt;Then run the script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv run test_local.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Test Scenario
&lt;/h2&gt;

&lt;p&gt;This scenario validates the full end-to-end lifecycle of the agent: from discovery and research to multimodal content creation and long-term memory retrieval.&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 1: Teaching &amp;amp; Multimodal Creation (Session 1)
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Goal: Establish technical context and set a specific stylistic preference.&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Discovery
&lt;/h4&gt;

&lt;p&gt;Ask the agent to find trending Cloud Run topics.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Input&lt;/strong&gt;: &lt;code&gt;"Find high-engagement questions about AI agents on Cloud Run from the last 21 days."&lt;/code&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.amazonaws.com%2Fuploads%2Farticles%2Fhfyh7wc97yzgc413xhwi.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.amazonaws.com%2Fuploads%2Farticles%2Fhfyh7wc97yzgc413xhwi.png" alt="Test 1 - Discovery" width="800" height="174"&gt;&lt;/a&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.amazonaws.com%2Fuploads%2Farticles%2Fhs895zdl1k3z309q3ya5.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.amazonaws.com%2Fuploads%2Farticles%2Fhs895zdl1k3z309q3ya5.png" alt="Test 2 - Discovery Results" width="800" height="485"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Research
&lt;/h4&gt;

&lt;p&gt;Instruct the agent to perform a deep dive on a specific result.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Input&lt;/strong&gt;: &lt;code&gt;"Use the GCP Expert to research topic #1."&lt;/code&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.amazonaws.com%2Fuploads%2Farticles%2Fm3tdx62hxuv8lsumw07k.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.amazonaws.com%2Fuploads%2Farticles%2Fm3tdx62hxuv8lsumw07k.png" alt="Test 3 - Research" width="800" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Personalization
&lt;/h4&gt;

&lt;p&gt;Request a blog post and explicitly set your style preference.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Input&lt;/strong&gt;: &lt;code&gt;"Draft a blog post based on this research. From now on, I want all my technical blogs written in the style of a 90s Rap Song."&lt;/code&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.amazonaws.com%2Fuploads%2Farticles%2Febf7ljsso38maqnetfxt.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.amazonaws.com%2Fuploads%2Farticles%2Febf7ljsso38maqnetfxt.png" alt="Test 4 - Personalization" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Image Generation
&lt;/h4&gt;

&lt;p&gt;Ask the agent to generate an image that demonstrates the main ideas in the blog using the Nano Banana Pro tool. The image will be saved to your bucket in Google Cloud and you should get the path to see it, which will look like: &lt;code&gt;https://storage.mtls.cloud.google.com/...&lt;/code&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.amazonaws.com%2Fuploads%2Farticles%2Fjczvc5cwzymc1qjyuou2.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.amazonaws.com%2Fuploads%2Farticles%2Fjczvc5cwzymc1qjyuou2.png" alt="Token Optimization / Image Generation" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 2: Long-Term Memory Recall (Session 2)
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Goal: Verify the agent recalls preferences across a completely fresh session.&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Type &lt;code&gt;new&lt;/code&gt; in the console to wipe local session history and start a fresh state.&lt;/li&gt;
&lt;li&gt;Retrieval: Inquire about your stored preferences to test the Vertex AI memory bank.&lt;/li&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;em&gt;Input&lt;/em&gt;: &lt;code&gt;"What are my current topics of interest and what is my preferred blogging style?"&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;li&gt;Verification: Confirm the agent successfully retrieves your "AI Agents on Cloud Run" interest and "Rap" style from the cloud.&lt;/li&gt;

&lt;/ol&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.amazonaws.com%2Fuploads%2Farticles%2Fsymbvlaad5owzrjc537x.png" alt="Test 5 - Memory Recall" width="800" height="269"&gt;

&lt;p&gt;&lt;strong&gt;Final Test&lt;/strong&gt;: Ask for a new blog on a different topic (e.g., "GKE Autopilot") and ensure it is automatically written as a rap song without being prompted.&lt;/p&gt;

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

&lt;p&gt;In this part of our series we focused on verifying the agent's functionality in a local environment before proceeding to cloud deployment. By configuring local secrets and utilizing environment-aware utilities, we used a dedicated test runner to confirm that the core reasoning and tool logic are properly integrated. We successfully validated the full lifecycle: from Reddit discovery to expert content creation, confirming that the agent correctly retrieves preferences from the cloud-based Vertex AI memory bank even in completely fresh sessions.&lt;/p&gt;

&lt;p&gt;Ready to run the test scenario yourself? Clone the &lt;a href="https://github.com/GoogleCloudPlatform/devrel-demos/tree/main/ai-ml/dev-signal" rel="noopener noreferrer"&gt;repository&lt;/a&gt; and try the &lt;code&gt;test_local.py&lt;/code&gt; script to see 'Dev Signal' retrieve your preferences from the Vertex AI memory bank in real-time. For a deeper dive into the underlying mechanics of memory orchestration, check out this &lt;a href="https://docs.cloud.google.com/agent-builder/agent-engine/memory-bank/quickstart-adk" rel="noopener noreferrer"&gt;quickstart guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/googleai/deploying-a-multi-agent-system-with-terraform-and-cloud-run-2a9c"&gt;In the final part of this series,&lt;/a&gt; we will transition our prototype into a production service on Google Cloud Run using Terraform for secure infrastructure, and explore the roadmap to production excellence through continuous evaluation and security.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Special thanks to &lt;a href="https://www.linkedin.com/in/remigiusz-samborski/" rel="noopener noreferrer"&gt;Remigiusz Samborski&lt;/a&gt; for the helpful review and feedback on this article.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;For more content like this, follow me on &lt;a href="https://www.linkedin.com/in/shirmeirlador/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; and &lt;a href="https://x.com/shirmeir86" rel="noopener noreferrer"&gt;X&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>googlecloud</category>
      <category>agents</category>
      <category>python</category>
    </item>
    <item>
      <title>Architect A Personalized Multi-Agent System with Long-Term Memory</title>
      <dc:creator>Shir Meir Lador</dc:creator>
      <pubDate>Thu, 07 May 2026 21:01:06 +0000</pubDate>
      <link>https://dev.to/googleai/architect-a-personalized-multi-agent-system-with-long-term-memory-3o15</link>
      <guid>https://dev.to/googleai/architect-a-personalized-multi-agent-system-with-long-term-memory-3o15</guid>
      <description>&lt;p&gt;In support of our mission to accelerate the developer journey on Google Cloud, we built &lt;strong&gt;Dev Signal&lt;/strong&gt; — a multi-agent system designed to transform raw community signals into reliable technical guidance by automating the path from discovery to expert creation.&lt;/p&gt;

&lt;p&gt;In the &lt;a href="https://dev.to/googleai/building-capabilities-for-a-multi-agent-system-with-google-adk-mcp-and-cloud-run-ab9"&gt;first part&lt;/a&gt; of this series for the &lt;strong&gt;Dev Signal&lt;/strong&gt;, we laid the essential groundwork for this system by establishing a project environment and equipping core capabilities through the Model Context Protocol (MCP). We standardized our external integrations, connecting to Reddit for trend discovery, Google Cloud Docs for technical grounding, and building a custom Nano Banana Pro MCP server for multimodal image generation. If you missed &lt;a href="https://dev.to/googleai/building-capabilities-for-a-multi-agent-system-with-google-adk-mcp-and-cloud-run-ab9"&gt;Part 1&lt;/a&gt; or want to explore the code directly, you can find the complete project implementation in our &lt;a href="https://github.com/GoogleCloudPlatform/devrel-demos/tree/main/ai-ml/dev-signal" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now, in Part 2, we focus on building the multi-agent architecture and integrating the &lt;a href="https://docs.cloud.google.com/agent-builder/agent-engine/memory-bank/overview" rel="noopener noreferrer"&gt;Vertex AI memory bank&lt;/a&gt; to personalize these capabilities. We will implement a Root Orchestrator that manages three specialist agents: the Reddit Scanner, GCP Expert, and Blog Drafter, to provide a seamless flow from trend discovery to expert content creation. We will also integrate a long-term memory layer that enables the agent to learn from your feedback and persist your stylistic preferences across different conversations. This ensures that Dev Signal doesn't just process data, but actually learns to match your professional voice over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Infrastructure and Model Setup
&lt;/h2&gt;

&lt;p&gt;First, we initialize the environment and the shared Gemini model.&lt;/p&gt;

&lt;p&gt;Paste this code in &lt;code&gt;dev_signal_agent/agent.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="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.apps&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;App&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google.adk.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Gemini&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="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AgentTool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;load_memory_tool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;preload_memory_tool&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google.adk.tools.tool_context&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ToolContext&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google.genai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dev_signal_agent.app_utils.env&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;init_environment&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dev_signal_agent.tools.mcp_config&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;get_reddit_mcp_toolset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;get_dk_mcp_toolset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;get_nano_banana_mcp_toolset&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;PROJECT_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MODEL_LOC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SERVICE_LOC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SECRETS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;init_environment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;shared_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Gemini&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemini-3-flash-preview&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;vertexai&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;PROJECT_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;MODEL_LOC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;retry_options&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;HttpRetryOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attempts&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="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Memory Ingestion Logic
&lt;/h2&gt;

&lt;p&gt;We want Dev Signal to do more than just follow instructions — we want it to learn from you. By capturing your preferences, such as specific technical interests on Reddit or a preferred blogging style, the agent can personalize its output for future use. To achieve this, we use the &lt;a href="https://docs.cloud.google.com/agent-builder/agent-engine/memory-bank/overview" rel="noopener noreferrer"&gt;&lt;strong&gt;Vertex AI memory bank&lt;/strong&gt;&lt;/a&gt; to persist session history across different conversations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Long-term Memory
&lt;/h3&gt;

&lt;p&gt;We automate this through the &lt;code&gt;save_session_to_memory_callback&lt;/code&gt; function. This callback is configured to run automatically after every turn, ensuring that session details are captured and stored in the memory bank without manual intervention.&lt;/p&gt;

&lt;h4&gt;
  
  
  How Managed Memory Works:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ingestion&lt;/strong&gt;: The &lt;code&gt;save_session_to_memory_callback&lt;/code&gt; sends the conversation data to Vertex AI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Embedding&lt;/strong&gt;: Vertex AI converts the text into numerical vectors (embeddings) that capture the semantic meaning of your preferences.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage&lt;/strong&gt;: These vectors are stored in a managed index, enabling the agent to perform semantic searches and retrieve relevant history in future sessions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retrieval&lt;/strong&gt;: The agent recalls this history using built-in ADK tools. The PreloadMemoryTool proactively brings in context at the start of an interaction, while the LoadMemoryTool allows the agent to fetch specific memories on an as-needed basis.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Paste this code in &lt;code&gt;dev_signal_agent/agent.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;save_session_to_memory_callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Defensive callback to persist session history to the Vertex AI memory bank.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;callback_context&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Check connection to Memory Service
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nf"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;_invocation_context&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_invocation_context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;memory_service&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Save the session!
&lt;/span&gt;        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_invocation_context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;memory_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_session_to_memory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_invocation_context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Short-term Memory
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;add_info_to_state&lt;/code&gt; function serves as the agent's short-term working memory, allowing the &lt;code&gt;gcp_expert&lt;/code&gt; to reliably hand off its detailed findings to the &lt;code&gt;blog_drafter&lt;/code&gt; within the same session. This working memory and the conversation transcript are managed by the Vertex AI Session Service to ensure that active context survives server restarts or transient failures.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The boundary between session-based state and long-term persistence&lt;/strong&gt; — It is important to note that while this service provides stability during an active interaction, this short-term memory does not persist between different sessions. Starting a fresh session ID effectively resets this working state, ensuring a clean slate for new tasks. Cross-session continuity, where the agent remembers your stylistic preferences or past feedback, is handled by the Vertex AI Memory Bank.&lt;/p&gt;

&lt;p&gt;Paste this code in &lt;code&gt;dev_signal_agent/agent.py&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_info_to_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tool_context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ToolContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&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;data&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="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;tool_context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;success&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&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;Saved &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; to state.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Specialist 1: Reddit Scanner (Discovery)
&lt;/h2&gt;

&lt;p&gt;The Reddit Scanner is our "Trend Spotter," it identifies high-engagement questions from the last 21 days (3 weeks) to ensure that all research findings remain both timely and relevant.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Memory Usage:&lt;/strong&gt; It leverages &lt;code&gt;load_memory&lt;/code&gt; to retrieve your past areas of interest and preferred topics from the Vertex AI memory bank. If relevant history exists, the agent prioritizes those specific topics in its search to provide a personalized discovery experience.&lt;/p&gt;

&lt;p&gt;Beyond simple retrieval, each sub-agent actively updates its memories by listening for new preferences and explicitly acknowledging them during the chat. This process captures relevant information in the session history, where an automated callback then persists it to the long-term Vertex AI memory bank for future use.&lt;/p&gt;

&lt;p&gt;This memory management is supported by two distinct retrieval patterns within the Google Agent Development Kit (ADK). The first is the &lt;code&gt;PreloadMemoryTool&lt;/code&gt;, which proactively brings in historical context at the beginning of every interaction to ensure the agent is fully briefed before addressing the current request. The second is the &lt;code&gt;LoadMemoryTool&lt;/code&gt;, which the agent uses on an as-needed basis, calling upon it only when it decides that deeper past knowledge would be beneficial for the current step in the workflow.&lt;/p&gt;

&lt;p&gt;Paste this code in &lt;code&gt;dev_signal_agent/agent.py&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Singleton toolsets
&lt;/span&gt;&lt;span class="n"&gt;reddit_mcp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_reddit_mcp_toolset&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;SECRETS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;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="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;SECRETS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;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="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;SECRETS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;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="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;reddit_scanner&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_scanner&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;shared_model&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="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
You are a Reddit research specialist. Your goal is to identify high-engagement questions
from the last 3 weeks on specific topics of interest, such as AI/agents on Cloud Run.

Follow these steps:
1. **MEMORY CHECK**: Use `load_memory` to retrieve the user&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s **past areas of interest** and **preferred topics**. Calibrate your search to align with these interests.
2. Use the Reddit MCP tools to search for relevant subreddits and posts.
3. Filter results for posts created within the last 21 days (3 weeks).
4. Analyze &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;high-engagement&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; based on upvote counts and the number of comments.
5. Recommend the most important and relevant questions for a technical audience.
6. **CRITICAL**: For each recommended question, provide a direct link to the original thread and a concise summary of the discussion.
7. **CAPTURE PREFERENCES**: Actively listen for user preferences, interests, or project details. Explicitly acknowledge them to ensure they are captured in the session history for future personalization.
&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;reddit_mcp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;load_memory_tool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;LoadMemoryTool&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
    &lt;span class="n"&gt;after_agent_callback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;save_session_to_memory_callback&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;h2&gt;
  
  
  Specialist 2: GCP Expert (Grounding)
&lt;/h2&gt;

&lt;p&gt;The GCP Expert is our "Technical Authority". It triangulates facts by synthesizing official documentation from the Google Cloud Developer Knowledge MCP Server, community sentiment from Reddit, and broader context from Google Search.&lt;/p&gt;

&lt;p&gt;Paste this code in &lt;code&gt;dev_signal_agent/agent.py&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;dk_mcp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_dk_mcp_toolset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;SECRETS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DK_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;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;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;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;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;shared_model&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Execute Google Searches and return raw, structured results (Title, Link, Snippet).&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;google_search&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;gcp_expert&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;gcp_expert&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;shared_model&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="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
You are a Google Cloud Platform (GCP) documentation expert.
Your goal is to provide accurate, detailed, and cited answers to technical questions by synthesizing official documentation with community insights.

For EVERY technical question, you MUST perform a comprehensive research sweep using ALL available tools:
1. **Official Docs (Grounding)**: Use DeveloperKnowledge MCP (`search_documents`) to find the definitive technical facts.
2. **Social Media Research (Reddit)**: Use the Reddit MCP to research the question on social media. This allows you to find real-world user discussions, common pain points, or alternative solutions that might not be in official documentation.
3. **Broader Context (Web/Social)**: Use the `search_agent` tool to find recent technical blogs, social media discussions, or tutorials.

Synthesize your answer:
- Start with the official answer based on GCP docs.
- Add &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Social Media Insights&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; or &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Common Issues&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; sections derived from Reddit and Web Search findings.
- **CRITICAL**: After providing your answer, you MUST use the `add_info_to_state` tool to save your full technical response under the key: `technical_research_findings`.
- Cite your sources specifically at the end of your response, providing **direct links** (URLs) to the official documentation, blog posts, and Reddit threads used.
- **CAPTURE PREFERENCES**: Actively listen for user preferences, interests, or project details. Explicitly acknowledge them to ensure they are captured in the session history for future personalization.
&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;dk_mcp&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;search_agent&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;reddit_mcp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;add_info_to_state&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;after_agent_callback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;save_session_to_memory_callback&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;h2&gt;
  
  
  Specialist 3: Blog Drafter (Creativity)
&lt;/h2&gt;

&lt;p&gt;The Blog Drafter is our Content Creator. It drafts the blog based on the expert's findings and offers to generate visuals.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Memory Usage:&lt;/strong&gt; It checks &lt;code&gt;load_memory&lt;/code&gt; for the user's &lt;strong&gt;preferred writing style&lt;/strong&gt; (e.g. "Witty", "Rap") stored in the &lt;strong&gt;Vertex AI memory bank&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Paste this code in &lt;code&gt;dev_signal_agent/agent.py&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;nano_mcp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_nano_banana_mcp_toolset&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;blog_drafter&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;blog_drafter&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;shared_model&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="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
You are a professional technical blogger specializing in Google Cloud Platform.
Your goal is to draft high-quality blog posts based on technical research provided by the GDE expert and reliable documentation.

You have access to the research findings from the gcp_expert_agent here:
{{ technical_research_findings }}

Follow these steps:
1. **MEMORY CHECK**: Use `load_memory` to retrieve past blog posts, **areas of interest**, and user feedback on writing style. Adopt the user&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s preferred style and depth.
2. **REVIEW &amp;amp; GROUND**: Review the technical research findings provided above. **CRITICAL**: Use the `dk_mcp` (Developer Knowledge) tool to verify key facts, technical limitations, and API details. Ensure every claim in your blog is grounded in official documentation.
3. Draft a blog post that is engaging, accurate, and helpful for a technical audience.
4. Include code snippets or architectural diagrams if relevant.
5. Provide a &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Resources&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; section with links to the official documentation used.
6. Ensure the tone is professional yet accessible, while adhering to any style preferences found in memory.
7. **VISUALS**: After presenting the drafted blog post, explicitly ask the user: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Would you like me to generate an infographic-style header image to illustrate these key points?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; If they agree, use the `generate_image` tool (Nano Banana).
8. **CAPTURE PREFERENCES**: Actively listen for user preferences, interests, or project details. Explicitly acknowledge them to ensure they are captured in the session history for future personalization.
&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;dk_mcp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;load_memory_tool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;LoadMemoryTool&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;nano_mcp&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;after_agent_callback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;save_session_to_memory_callback&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;h2&gt;
  
  
  The Root Orchestrator
&lt;/h2&gt;

&lt;p&gt;The root agent serves as the system's strategist, managing a team of specialist agents and orchestrating their actions based on the specific goals provided by the user. At the start of a conversation, the orchestrator retrieves memory to establish context by checking for the user's past areas of interest, preferred topics, or previous projects.&lt;/p&gt;

&lt;p&gt;Paste this code in &lt;code&gt;dev_signal_agent/agent.py&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;root_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;root_orchestrator&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;shared_model&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="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
You are a technical content strategist. You manage three specialists:
1. reddit_scanner: Finds trending questions and high-engagement topics on Reddit.
2. gcp_expert: Provides technical answers based on official GCP documentation.
3. blog_drafter: Writes professional blog posts based on technical research.

Your responsibilities:
- **MEMORY CHECK**: At the start of a conversation, use `load_memory` to check if the user has specific **areas of interest**, preferred topics, or past projects. Tailor your suggestions accordingly.
- **CAPTURE PREFERENCES**: Actively listen for user preferences, interests, or project details. Explicitly acknowledge them to ensure they are captured in the session history for future personalization.
- If the user wants to find trending topics or questions from Reddit, delegate to reddit_scanner.
- If the user has a technical question or wants to research a specific theme, delegate to gcp_expert.
- **CRITICAL**: After the gcp_expert provides an answer, you MUST ask the user:
  &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Would you like me to draft a technical blog post based on this answer?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;
- If the user agrees or asks to write a blog, delegate to blog_drafter.
- Be proactive in helping the user navigate from discovery (Reddit) to research (Docs) to content creation (Blog).
&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;load_memory_tool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;LoadMemoryTool&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;preload_memory_tool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PreloadMemoryTool&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
    &lt;span class="n"&gt;after_agent_callback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;save_session_to_memory_callback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;sub_agents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;reddit_scanner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gcp_expert&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;blog_drafter&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;App&lt;/span&gt;&lt;span class="p"&gt;(&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;root_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;dev_signal_agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;In this part of our series, we built multi-agent architecture and implemented a robust, dual-layered memory system. We established a Root Orchestrator, managing three specialist agents: a Reddit Scanner for trend discovery, a GCP Expert for technical grounding, and a Blog Drafter for creative content creation. &lt;/p&gt;

&lt;p&gt;By utilizing short-term state to pass information reliably between specialists and integrating the Vertex AI memory bank for long-term persistence, we've enabled the agent to learn from your feedback and remember specific writing styles across different conversations.&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://dev.to/googleai/local-testing-of-a-multi-agent-system-with-memory-37mm"&gt;Part 3&lt;/a&gt;, we will show you how to test the agent locally to verify these components on your workstation, before transitioning to a full production deployment on Google Cloud Run in Part 4. Can't wait for part 3? The full implementation is already available for you to explore on &lt;a href="https://github.com/GoogleCloudPlatform/devrel-demos/tree/main/ai-ml/dev-signal" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To learn more about the underlying technology, explore the &lt;a href="https://docs.cloud.google.com/agent-builder/agent-engine/memory-bank/overview" rel="noopener noreferrer"&gt;Vertex AI Memory Bank overview&lt;/a&gt; or dive into the official &lt;a href="https://docs.cloud.google.com/agent-builder/agent-development-kit/overview" rel="noopener noreferrer"&gt;ADK Documentation&lt;/a&gt; to see how to orchestrate complex multi-agent workflows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Special thanks to &lt;a href="https://www.linkedin.com/in/remigiusz-samborski/" rel="noopener noreferrer"&gt;Remigiusz Samborski&lt;/a&gt; for the helpful review and feedback on this article.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For more content like this, follow me on &lt;a href="https://www.linkedin.com/in/shirmeirlador/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; and &lt;a href="https://x.com/shirmeir86?lang=en" rel="noopener noreferrer"&gt;X&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>googlecloud</category>
      <category>agents</category>
      <category>mcp</category>
    </item>
  </channel>
</rss>
