<?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: Jonathan Huang</title>
    <description>The latest articles on DEV Community by Jonathan Huang (@jnth).</description>
    <link>https://dev.to/jnth</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F594158%2Ffb2c82f0-a818-4941-a99f-fd79148ba264.png</url>
      <title>DEV Community: Jonathan Huang</title>
      <link>https://dev.to/jnth</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jnth"/>
    <language>en</language>
    <item>
      <title>Google Agent Development Kit (ADK) Introduction (7): Monitoring</title>
      <dc:creator>Jonathan Huang</dc:creator>
      <pubDate>Tue, 20 May 2025 09:23:15 +0000</pubDate>
      <link>https://dev.to/jnth/google-agent-development-kit-adk-introduction-7-monitoring-5an5</link>
      <guid>https://dev.to/jnth/google-agent-development-kit-adk-introduction-7-monitoring-5an5</guid>
      <description>&lt;h2&gt;
  
  
  Application Monitoring &amp;amp; Visualization
&lt;/h2&gt;

&lt;p&gt;Direct Prometheus integration with Cloud Run can be intricate due to its serverless architecture. Google Cloud offers Managed Service for Prometheus (GMP) using a sidecar for streamlined metric collection. However, for maximum simplicity and deep Google Cloud integration, native monitoring tools are the primary path.&lt;/p&gt;




&lt;h3&gt;
  
  
  Collecting Application Metrics (via Cloud Monitoring)
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Option A: Structured Logging &amp;amp; Log-based Metrics (Most Direct)
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;  Output structured (JSON) logs directly to &lt;code&gt;stdout&lt;/code&gt; in your Streamlit app.&lt;/li&gt;
&lt;li&gt;  Cloud Run automatically forwards &lt;code&gt;stdout&lt;/code&gt;/&lt;code&gt;stderr&lt;/code&gt; to Cloud Logging; JSON strings printed to &lt;code&gt;stdout&lt;/code&gt; are parsed as &lt;code&gt;jsonPayload&lt;/code&gt;. This is the simplest mechanism.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sample code snippet:&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;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="c1"&gt;# For realistic duration
&lt;/span&gt;
&lt;span class="c1"&gt;# Example: In your Streamlit application code
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;some_function_processing_a_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;success&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;duration_ms_value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;log_data&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;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;Processed task: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;task_type&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;task_type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;task_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;duration_ms&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;duration_ms_value&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="n"&gt;success&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;# Severity is often inferred by Cloud Logging (stdout=INFO, stderr=ERROR).
&lt;/span&gt;        &lt;span class="c1"&gt;# Explicitly add "severity": "INFO" or "ERROR" if precise control is needed
&lt;/span&gt;        &lt;span class="c1"&gt;# for filtering or log-based metrics derived from severity.
&lt;/span&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;# Print JSON to stdout; Cloud Run forwards this to Cloud Logging.
&lt;/span&gt;    &lt;span class="c1"&gt;# Cloud Logging will parse this into jsonPayload.
&lt;/span&gt;    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;# Example usage:
# start_time = time.monotonic()
# # ... processing logic ...
# success_status = True # or False
# duration = (time.monotonic() - start_time) * 1000
# some_function_processing_a_task("schedule_meeting", success_status, int(duration))
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;In Cloud Monitoring, create log-based metrics:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Navigate: Google Cloud Console → Logging → Log-based Metrics → Create Metric.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Choose Metric Type: Counter (for occurrences) or Distribution (for values like latency).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Define Filter to isolate relevant logs, e.g.:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;resource.type="cloud_run_revision"
resource.labels.service_name="meeting-workflow-agent"
jsonPayload.task_type="schedule_meeting"        

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

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Specify Field Name (for Distribution, e.g., &lt;code&gt;jsonPayload.duration_ms&lt;/code&gt;), units (e.g., ms), and labels for drill-down.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Option B: Using Cloud Monitoring API (Maximum Flexibility, More Code)
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;  Add &lt;code&gt;google-cloud-monitoring&lt;/code&gt; to your &lt;code&gt;requirements.txt&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  Utilize &lt;code&gt;google.cloud.monitoring_v3&lt;/code&gt; to programmatically write custom metrics. This offers granular control.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sample 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="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;monitoring_v3&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

&lt;span class="n"&gt;project_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;adk-learning-journey&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="c1"&gt;# Ensure this is configured or dynamically fetched
&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;monitoring_v3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MetricServiceClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;project_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="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;write_custom_metric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;metric_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="o"&gt;=&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;series&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;monitoring_v3&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;TimeSeries&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;series&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&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;custom.googleapis.com/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;metric_type&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="c1"&gt;# Standard prefix for custom metrics
&lt;/span&gt;    &lt;span class="n"&gt;series&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cloud_run_revision&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="c1"&gt;# These labels are crucial for associating the metric with the correct Cloud Run resource
&lt;/span&gt;    &lt;span class="n"&gt;series&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;service_name&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;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;K_SERVICE&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;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# K_SERVICE is the Cloud Run service name
&lt;/span&gt;    &lt;span class="n"&gt;series&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;revision_name&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;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;K_REVISION&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;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# K_REVISION is the specific revision
&lt;/span&gt;    &lt;span class="n"&gt;series&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;configuration_name&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;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;K_CONFIGURATION&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;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# K_CONFIGURATION is the configuration name
&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;labels&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;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="n"&gt;series&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&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;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Metric labels must be strings
&lt;/span&gt;
    &lt;span class="n"&gt;point&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;monitoring_v3&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;Point&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c1"&gt;# Ensure value is appropriate type (int64_value, double_value, etc.)
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;point&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int64_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;point&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;double_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Handle other types or raise error, e.g. for Distribution for complex types
&lt;/span&gt;        &lt;span class="c1"&gt;# For simplicity, this example assumes int or float.
&lt;/span&gt;        &lt;span class="n"&gt;point&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int64_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 


    &lt;span class="n"&gt;now_ts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;point&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end_time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now_ts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;point&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end_time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nanos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;now_ts&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;point&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end_time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;series&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;point&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Call the API to create the time series
&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;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_time_series&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="n"&gt;project_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time_series&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;series&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="c1"&gt;# Implement proper error handling/logging for production
&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 writing custom metric &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;metric_type&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;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="nb"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="c1"&gt;# Example usage:
# write_custom_metric("streamlit/successful_meetings", 1, {"agent_type": "manager"})
# write_custom_metric("streamlit/processing_latency_ms", 150.5, {"task_category": "report_generation"})
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Set Up Grafana
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Deploy Grafana:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  Option 1 (Recommended for GKE/GCE): Deploy via Google Cloud Marketplace if operating within these environments.&lt;/li&gt;
&lt;li&gt;  Option 2: Install Grafana in your designated environment.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;Connect Grafana to Google Cloud Monitoring:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  Access Grafana.&lt;/li&gt;
&lt;li&gt;  Navigate: Configuration → Data Sources → Add data source.&lt;/li&gt;
&lt;li&gt;  Select "Google Cloud Monitoring".&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Authentication&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;  If Grafana runs on GCE/GKE, leverage the attached service account (grant &lt;code&gt;roles/monitoring.viewer&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;  Otherwise, create a service account, assign &lt;code&gt;roles/monitoring.viewer&lt;/code&gt;, download its JSON key, and upload to Grafana.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  Set Default Project: &lt;code&gt;adk-learning-journey&lt;/code&gt;.&lt;/li&gt;

&lt;li&gt;  Save &amp;amp; Test. A successful test validates the connection.&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  Create Grafana Dashboards
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Create → Dashboard → Add new panel.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Query Configuration:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  Select the "Google Cloud Monitoring" data source.&lt;/li&gt;
&lt;li&gt;  Service: Choose "Cloud Run" for standard metrics or "Custom Metrics" for your defined metrics.&lt;/li&gt;
&lt;li&gt;  Metric: Select your log-based metric, standard Cloud Run metrics (e.g., Request Count, Latency, Instance Count), or your custom metric name (e.g., &lt;code&gt;custom.googleapis.com/streamlit/request_count&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;  Utilize the query editor to filter and aggregate data (e.g., by &lt;code&gt;resource.labels.service_name&lt;/code&gt;, &lt;code&gt;resource.labels.revision_name&lt;/code&gt;, or custom metric labels).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;Visualization:&lt;/strong&gt; Choose the optimal chart type for the data.&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;Alerting:&lt;/strong&gt; Configure alert rules in Grafana for critical metrics to ensure operational awareness.&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  Cost Control &amp;amp; Optimization
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Monitor Costs:&lt;/strong&gt; Regularly audit Google Cloud Billing reports. Filter by service (Cloud Run, Secret Manager, Logging, Monitoring) for granular insight.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Set Budget Alerts:&lt;/strong&gt; Implement budget alerts in Billing for proactive cost management.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Optimize Cloud Run Settings:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  Tune CPU, memory, and min/max instances based on observed performance data from Grafana/Cloud Monitoring.&lt;/li&gt;
&lt;li&gt;  Employ &lt;code&gt;--min-instances 0&lt;/code&gt; for services with intermittent traffic to minimize idle costs.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;Logging &amp;amp; Monitoring Costs:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  Be aware: Logging ingestion, storage, and Monitoring (especially custom metrics &amp;amp; API calls) have associated costs.&lt;/li&gt;
&lt;li&gt;  Reduce log ingestion costs by setting appropriate application log levels at the source. Log-based metric filters refine insights from &lt;em&gt;ingested&lt;/em&gt; logs; they do not reduce the initial volume of logs stored.&lt;/li&gt;
&lt;li&gt;  For custom metrics, govern write frequency to balance granularity with cost.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;Secret Manager Costs:&lt;/strong&gt; Costs are driven by the number of secrets and access frequency. Reading secrets primarily at application startup minimizes these operational costs.&lt;/li&gt;

&lt;/ul&gt;

</description>
      <category>programming</category>
      <category>googlecloud</category>
      <category>adk</category>
    </item>
    <item>
      <title>Google Agent Development Kit (ADK) Introduction (6): Deploy to Google Cloud</title>
      <dc:creator>Jonathan Huang</dc:creator>
      <pubDate>Tue, 20 May 2025 09:19:19 +0000</pubDate>
      <link>https://dev.to/jnth/google-agent-development-kit-adk-introduction-5-deploy-to-google-cloud-1nnb</link>
      <guid>https://dev.to/jnth/google-agent-development-kit-adk-introduction-5-deploy-to-google-cloud-1nnb</guid>
      <description>&lt;h2&gt;
  
  
  Learning Objectives
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Master container deployment and autoscaling on Google Cloud Run, including secure key management.&lt;/li&gt;
&lt;li&gt;Implement performance monitoring and cost control using Cloud Monitoring and Grafana.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Task Overview
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Application Containerization&lt;/strong&gt;: Package the Streamlit Agent as a Docker image, manage &lt;code&gt;credentials.json&lt;/code&gt;/&lt;code&gt;token.json&lt;/code&gt; securely with Secret Manager, and deploy to Cloud Run.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance Monitoring&lt;/strong&gt;: Set up Cloud Monitoring and Grafana.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Environment Setup&lt;/strong&gt;: Install Google Cloud SDK and handle Docker image authentication.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Prerequisites: Install and Configure Google Cloud SDK
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Install following the &lt;a href="https://cloud.google.com/sdk/docs/install" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;macOS (Homebrew):&lt;/strong&gt; &lt;code&gt;brew install --cask google-cloud-sdk&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Initialize: &lt;code&gt;gcloud init&lt;/code&gt; (sign in, set or create a project, e.g. &lt;code&gt;adk-learning-journey&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Set project: &lt;code&gt;gcloud config set project adk-learning-journey&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Docker auth: &lt;code&gt;gcloud auth configure-docker&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Enable required APIs:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  gcloud services &lt;span class="nb"&gt;enable &lt;/span&gt;secretmanager.googleapis.com &lt;span class="se"&gt;\&lt;/span&gt;
      artifactregistry.googleapis.com &lt;span class="se"&gt;\&lt;/span&gt;
      run.googleapis.com &lt;span class="se"&gt;\&lt;/span&gt;
      iam.googleapis.com &lt;span class="se"&gt;\&lt;/span&gt;
      cloudbuild.googleapis.com &lt;span class="se"&gt;\&lt;/span&gt;
      logging.googleapis.com &lt;span class="se"&gt;\&lt;/span&gt;
      monitoring.googleapis.com
  &lt;span class="c"&gt;# If additional APIs are needed (e.g. Calendar, Gemini), enable them as well&lt;/span&gt;
  &lt;span class="c"&gt;# gcloud services enable calendar-json.googleapis.com&lt;/span&gt;
  &lt;span class="c"&gt;# gcloud services enable generativelanguage.googleapis.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Deployment Steps (Detailed)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Prepare Application and Security Config
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;requirements.txt&lt;/strong&gt;: Make sure all required packages are included (such as &lt;code&gt;google-cloud-secret-manager&lt;/code&gt;, etc).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sensitive Files&lt;/strong&gt;: Never include &lt;code&gt;credentials.json&lt;/code&gt; or &lt;code&gt;token.json&lt;/code&gt; in your Git repo or Docker image. Add them to &lt;code&gt;.gitignore&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Using Secret Manager
&lt;/h4&gt;

&lt;p&gt;A. &lt;strong&gt;Upload credentials.json&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud secrets create calendar-credentials &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="s2"&gt;"adk-learning-journey"&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; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"OAuth client credentials for Google Calendar API"&lt;/span&gt;
gcloud secrets versions add calendar-credentials &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="s2"&gt;"adk-learning-journey"&lt;/span&gt; &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="s2"&gt;"path/to/credentials.json"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;B. &lt;strong&gt;Upload token.json&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud secrets create calendar-token &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="s2"&gt;"adk-learning-journey"&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; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"User OAuth token for Google Calendar API"&lt;/span&gt;
gcloud secrets versions add calendar-token &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="s2"&gt;"adk-learning-journey"&lt;/span&gt; &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="s2"&gt;"path/to/token.json"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;C. &lt;strong&gt;Modify your application to read from Secret Manager&lt;/strong&gt;&lt;br&gt;
Your code should load &lt;code&gt;credentials.json&lt;/code&gt; and &lt;code&gt;token.json&lt;/code&gt; from Secret Manager (see &lt;a href="https://github.com/wisehuang/adk-learning-journey/blob/main/meeting_workflow/common/google_auth.py" rel="noopener noreferrer"&gt;example&lt;/a&gt;).&lt;/p&gt;


&lt;h3&gt;
  
  
  2. Docker Packaging
&lt;/h3&gt;

&lt;p&gt;Sample Dockerfile (key points):&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="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; requirements.txt .&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="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&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;ENV&lt;/span&gt;&lt;span class="s"&gt; PYTHONUNBUFFERED 1&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; GOOGLE_CLOUD_PROJECT "adk-learning-journey"&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; PORT 8080&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; streamlit run streamlit_app.py --server.port $PORT --server.address 0.0.0.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Tip: Use &lt;code&gt;--set-env-vars&lt;/code&gt; during Cloud Run deployment to override the project ID for portability.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  3. Build &amp;amp; Test Docker Image
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="nv"&gt;$IMAGE_URI&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:8080 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&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;"adk-learning-journey"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"8080"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nv"&gt;$IMAGE_URI&lt;/span&gt;
&lt;span class="c"&gt;# Verify local access via http://localhost:8080&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  4. Push Image to Artifact Registry (or GCR)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Create repository (if not already created):
&lt;/li&gt;
&lt;/ul&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&lt;/span&gt; &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="s2"&gt;"adk-learning-journey"&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;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Push:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  docker push &lt;span class="nv"&gt;$IMAGE_URI&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  5. Deploy to Cloud Run
&lt;/h3&gt;

&lt;p&gt;A. &lt;strong&gt;Create Service Account (SA):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud iam service-accounts create meeting-workflow &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="s2"&gt;"adk-learning-journey"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Service account for Meeting Workflow Streamlit Agent"&lt;/span&gt; &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;"Meeting Workflow"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;B. &lt;strong&gt;Grant Secret Manager access to SA:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud projects add-iam-policy-binding adk-learning-journey &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:meeting-workflow@adk-learning-journey.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;p&gt;C. &lt;strong&gt;Deploy to Cloud Run:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud run deploy meeting-scheduler &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--image&lt;/span&gt; gcr.io/adk-learning-journey/meeting-workflow &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--platform&lt;/span&gt; managed &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--service-account&lt;/span&gt; meeting-workflow@adk-learning-journey.iam.gserviceaccount.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set-env-vars&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"GOOGLE_CLOUD_PROJECT=adk-learning-journey"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  6. Validate Deployment
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;After deployment, open the Cloud Run URL provided by &lt;code&gt;gcloud&lt;/code&gt; in your browser to test your service.&lt;/li&gt;
&lt;li&gt;In Google Cloud Console &amp;gt; Cloud Run &amp;gt; select your service &amp;gt; Logs, check for errors (env vars, secret access, app startup, etc).&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>googlecloud</category>
      <category>programming</category>
      <category>adk</category>
    </item>
    <item>
      <title>Google Agent Development Kit (ADK) Introduction (5): Developer Mindset</title>
      <dc:creator>Jonathan Huang</dc:creator>
      <pubDate>Fri, 16 May 2025 01:43:54 +0000</pubDate>
      <link>https://dev.to/jnth/google-agent-development-kit-adk-introduction-5-developer-mindset-206b</link>
      <guid>https://dev.to/jnth/google-agent-development-kit-adk-introduction-5-developer-mindset-206b</guid>
      <description>&lt;h2&gt;
  
  
  Conceptual Comparison: Developer Mindset, Responsibility Separation, and Task Decomposition
&lt;/h2&gt;

&lt;p&gt;Building on the previous article, this one will explore the shift in developers' mindset when transitioning from API development to A2A development.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Developer Mindset Shift: Function-Oriented vs. Agent-Oriented.&lt;/strong&gt; Traditional development often involves thinking in terms of &lt;strong&gt;functions or API call sequences&lt;/strong&gt;: starting from input, invoking services step-by-step, and finally producing output. Developers act as "orchestrators," controlling every step. In contrast, agent-oriented architecture requires a new mindset—&lt;strong&gt;designing a community&lt;/strong&gt; of agents, each responsible for a subtask and interacting via messages and protocols. Instead of scripting flows directly, developers configure systems of autonomous agents, each with its own goal. Since agents make decisions independently (via LLMs), developers must shift from controlling every detail to setting up high-level rules and supervision.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Responsibility Separation and Task Decomposition.&lt;/strong&gt; In monolithic models, task decomposition happens at the code level—breaking big functions into smaller ones or chaining API calls. But the entire task remains owned by a single system component. Agent-based architectures promote &lt;strong&gt;system-level separation of responsibilities&lt;/strong&gt;, assigning different subtasks to specialized agents. For example, in the &lt;em&gt;meeting_workflow&lt;/em&gt; project, the workflow is split into three agents: one for input validation (email format), one for Google Calendar scheduling, and one for sending notifications. Each agent does what it's best at, and a sequential agent links them. This clear boundary improves maintainability and debuggability. In a traditional model, the same process would likely be a single script chaining everything, with tightly coupled logic that hinders reuse or evolution.&lt;/p&gt;

&lt;p&gt;This kind of agent-based decomposition is similar to team collaboration: breaking a big goal into professional subtasks executed by different roles. The &lt;em&gt;multi_agent_pm&lt;/em&gt; project demonstrates this: Manager, Engineering, and QA/Test agents work together. The manager plans and assigns tasks, the engineering agent executes them, and QA ensures quality. With A2A, they coordinate like a real team. Each agent keeps context within its domain, avoiding the confusion of a single model tracking everything. Adding new roles (e.g., a design agent) is simple—just define its role and connections.&lt;/p&gt;

&lt;p&gt;Ultimately, the big shift is this: &lt;strong&gt;from commanding computers to enabling agent collaboration.&lt;/strong&gt; Developers need to think at a higher level—turning hardcoded flows into agent-to-agent protocols. It also requires accepting partial autonomy of agents and trusting them to complete subtasks and return results. This shift takes practice, but it enables more &lt;strong&gt;flexible&lt;/strong&gt; and &lt;strong&gt;intelligent&lt;/strong&gt; systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Transitioning Your Developer Mindset (Function-Oriented → Agent-Oriented)
&lt;/h2&gt;

&lt;p&gt;To adopt these new paradigms, engineers must adjust both mindset and skills. As some have put it, "MCP is just the prelude—ADK and A2A are the beginning of the Agent era." Here's how to make that transition:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Think Like an Architect&lt;/strong&gt;: Break problems down into agent roles instead of steps in a script. Ask: what subtasks exist? What kind of agents should own each one? For example, a support system might include an analyzer agent, a retriever agent, and a responder agent—not a monolithic chain.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Learn the New Tools and Protocols&lt;/strong&gt;: Study ADK, A2A, and MCP. Understand how to create tools, define agent metadata files (like &lt;code&gt;.well-known/agent.json&lt;/code&gt;), and integrate MCP services. Start small and build confidence.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Shift Design Philosophy&lt;/strong&gt;: Move from OOP or functional programming to models like &lt;strong&gt;Actor systems&lt;/strong&gt; or &lt;strong&gt;Microservices&lt;/strong&gt;. Each agent is like a self-contained actor with its own state, communicating via protocols. Focus on defining interfaces and message contracts—not just function inputs/outputs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Plan for Asynchrony and Uncertainty&lt;/strong&gt;: Agent interactions are often async and non-deterministic. Responses may be delayed or require multiple exchanges. Agents may misunderstand or misbehave due to model randomness. Plan for retries, validations, and human-in-the-loop steps where needed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Migrate Gradually&lt;/strong&gt;: Don’t overhaul everything. Start by refactoring one sub-feature into a mini-agent workflow or building a multi-agent demo. Limit the number of agents initially. Reflect after each iteration—what got better? What got more complex? Adjust accordingly.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In summary, transitioning to agent-oriented development means evolving from micro-managing logic to &lt;strong&gt;coordinating intelligent actors&lt;/strong&gt;. Developers must expand their skills to cover LLMs, natural language, and distributed architecture. Early adopters of this shift will be well-positioned for the next wave of AI software.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary and Application Suggestions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Key Difference:&lt;/strong&gt; Google ADK + A2A enables highly modular, scalable agent collaboration, while MCP/traditional APIs rely on centralized, sequential flows. ADK/A2A breaks complexity into autonomous parts and uses open protocols for communication. Monolithic models are fine for static, predictable tasks but struggle with complexity or dynamic coordination.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best Use Cases:&lt;/strong&gt; If your app has &lt;strong&gt;multi-step workflows&lt;/strong&gt;, &lt;strong&gt;cross-functional collaboration&lt;/strong&gt;, or &lt;strong&gt;dynamic logic&lt;/strong&gt;, use agent-based design. For example, internal enterprise assistants that interact with marketing, support, and analytics systems benefit from splitting tasks among specialized agents. ADK tools and A2A protocols simplify building and scaling this setup. For &lt;strong&gt;simple, one-off tasks&lt;/strong&gt; (e.g., checking the weather), traditional API calls or function calling may be enough.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; ADK and MCP are not mutually exclusive—you can combine them. Agents built in ADK can call external MCP tools. Future AI systems may involve agents that &lt;strong&gt;collaborate (via A2A)&lt;/strong&gt; and &lt;strong&gt;invoke tools (via MCP)&lt;/strong&gt;. Learning both gives you an edge.&lt;/p&gt;

&lt;p&gt;In short, ADK and A2A represent a shift in &lt;strong&gt;developer thinking&lt;/strong&gt;—not just toolkits, but a whole new mental model. This article aims to highlight that shift. Try it in your projects, validate it in small scopes, and once you're ready, you'll be capable of building smarter, more autonomous, and extensible AI systems ready for what’s next.&lt;/p&gt;

&lt;p&gt;In the upcoming chapter, I want to learn the process of deploying an Agent to Google Cloud Run, containerizing it, and setting up monitoring.&lt;/p&gt;

</description>
      <category>adk</category>
      <category>programming</category>
    </item>
    <item>
      <title>Google Agent Development Kit (ADK) Introduction (4): Google ADK and A2A vs MCP and Traditional APIs</title>
      <dc:creator>Jonathan Huang</dc:creator>
      <pubDate>Thu, 15 May 2025 02:45:10 +0000</pubDate>
      <link>https://dev.to/jnth/google-agent-development-kit-adk-introduction-4-google-adk-and-a2a-vs-mcp-and-traditional-apis-3id7</link>
      <guid>https://dev.to/jnth/google-agent-development-kit-adk-introduction-4-google-adk-and-a2a-vs-mcp-and-traditional-apis-3id7</guid>
      <description>&lt;p&gt;At this stage in my learning, I've paused to reconsider the development differences between the A2A model and the MCP/traditional API models based on experiences from several projects above.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core Architecture and Development of Google ADK and Agent-to-Agent (A2A)
&lt;/h2&gt;

&lt;p&gt;In 2025, Google launched the Agent Development Kit (ADK), an open-source Python toolkit aimed at simplifying AI agent development. ADK emphasizes modularity and flexibility, allowing developers to build agents with memory, tool access, and coordination features. It integrates well with Google services (e.g., Vertex AI, Gemini) but also supports external models and tools.&lt;/p&gt;

&lt;p&gt;The Agent-to-Agent (A2A) protocol, also by Google, standardizes communication between agents. Each agent exposes a /run endpoint and metadata, enabling other agents or systems to send requests and receive responses. A2A solves the interoperability issue among agents from different platforms—acting like a "diplomatic hotline" for direct collaboration.&lt;/p&gt;

&lt;p&gt;In ADK, every agent supports A2A by default, making integration seamless. Developers can compose agents into sequential, parallel, or hierarchical workflows. For example, SequentialAgent handles ordered execution of sub-agents. Simple use cases may use a single multi-tool agent (e.g., multi_tool_agent), while complex flows (e.g., meeting_workflow, multi_agent_pm) coordinate multiple agents to achieve their goals efficiently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Typical Processes of MCP Architecture and Traditional API Calls
&lt;/h2&gt;

&lt;p&gt;The Model Context Protocol (MCP) introduced by Anthropic in 2024 is an open standard often described as the "USB-C interface" of the AI industry. It standardizes how large language models (LLMs) connect with external tools/data sources. MCP specifies how agents (or models) invoke external resources such as database queries, web services, or software APIs through standardized interfaces. In other words, MCP standardizes previously fragmented API integration methods, making interactions between AI agents and software services more consistent. Using MCP, an AI assistant-type agent can conveniently call various tools that implement MCP interfaces—such as querying databases, reading files, or performing web searches—without redesigning communication methods for each new tool.&lt;/p&gt;

&lt;p&gt;Typically, MCP-based architectures adopt a "monolithic command mode" to organize application logic. "Monolithic" means primary logic controlled by a central agent (or application), while the command mode refers to the agent sequentially issuing tool invocation commands as needed to complete subtasks. For example, without multi-agent collaboration, a chatbot arranging travel might internally execute: "input validation → flight API call → hotel API call → integrate results → respond to user". This entire process is orchestrated by a single agent or program, directly invoking external APIs and handling responses traditionally. Developers must manually code the logic for each API call, including parameter preparation, error handling, and result parsing. The key characteristic of traditional API call models is that developers fully control workflow details, explicitly executing each step via function calls or HTTP requests.&lt;/p&gt;

&lt;p&gt;When employing traditional methods to enable AI models to use tools, two typical approaches emerge: one is similar to OpenAI Function Calling, where models reference predefined functions in conversation, intercepted and executed by external code; the other involves developers explicitly coding sequential logic within applications, feeding model responses at appropriate times. Both methods essentially directly connect models and functional modules via code. Due to the lack of standardization, integration methods between different tools vary significantly, and developers' mental models remain largely function-oriented—viewing AI primarily as an initiator of various library or API calls, with themselves acting as orchestrators arranging linear execution sequences. This approach works well for straightforward tasks but can cause code to become difficult to maintain and scale as complexity grows.&lt;/p&gt;

&lt;p&gt;Notably, MCP protocols somewhat enhance the traditional model by allowing some tool integrations to be managed by standardized MCP tool servers. Advanced AI models like Claude can now invoke external knowledge bases or execute programs via MCP interfaces. However, even with MCP, architectures dominated by a single central agent remain monolithic: a single intelligent entity sequentially connects multiple tools. Although MCP creates more consistent interfaces between agents and tools, the overall development process remains traditional, following a "plan → invoke → control results" pattern. Developers must manually dissect complex tasks into steps and code the logic themselves. In short, MCP offers standardized tool integration, enhancing agent interactions with external resources, whereas A2A/ADK introduces an agent collaboration architecture, fundamentally shifting how we organize program logic. Below, I will further detail the technical and conceptual differences between these approaches.&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical Comparison: Modularity, State Management, Workflow Control, etc.
&lt;/h2&gt;

&lt;p&gt;The following table compares &lt;strong&gt;ADK/A2A multi-agent mode&lt;/strong&gt; with &lt;strong&gt;MCP/traditional API monolithic mode&lt;/strong&gt; across critical dimensions from a technical perspective:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;ADK/A2A Development Mode&lt;/th&gt;
&lt;th&gt;MCP/Traditional API Mode&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Modularity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Highly modular&lt;/strong&gt;: Systems composed of multiple specialized Agents cooperating via standardized interfaces, with clear responsibilities.&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Low modularity&lt;/strong&gt;: Typically a single application or agent handling all functions, connected via function calls, with blurred responsibility boundaries and high coupling.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;State Management&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Built-in state management&lt;/strong&gt;: Framework provides session memory and context management (e.g., ADK's Session Service), allowing agents easy access to shared information.&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Manual state management&lt;/strong&gt;: Developers manually maintain context within programs or rely on models' prompt memory, lacking a unified strategy, often causing synchronization issues.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Workflow Control&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Flexible workflow control&lt;/strong&gt;: Supports sequential, parallel, hierarchical execution, using built-in scheduling mechanisms such as SequentialAgent to organize multi-step tasks.&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Linear procedural flow&lt;/strong&gt;: Developers hard-code execution sequences and logic manually, lacking high-level abstraction, leading to complex and tangled workflows.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Error Handling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Granular error handling&lt;/strong&gt;: Frameworks like ADK provide middleware for centralized management of tool errors, retry strategies, fallback plans, enhancing reliability.&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Manual error handling&lt;/strong&gt;: Developers must individually handle each API call error (e.g., try/except), without centralized control. Inconsistent error handling across modules increases complexity.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scalability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Easy expansion&lt;/strong&gt;: Easily expand functionality by adding Agents or Tools, with standardized interfaces minimally impacting existing systems, akin to adding microservices.&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Difficult expansion&lt;/strong&gt;: Monolithic architectures require widespread code modifications when adding new features, becoming unwieldy and costly to maintain as complexity grows.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;(Note: MCP and traditional API methods are grouped as one due to similar single-agent structures, despite differences in standardization.)&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;The comparison clearly shows that ADK/A2A's multi-agent architecture excels in terms of &lt;strong&gt;system cohesion and loose coupling&lt;/strong&gt;. Developers can construct AI agents akin to microservices, communicating via standardized protocols, each focused clearly on their responsibilities without interfering with others. Conversely, traditional monolithic models entangle functional components tightly within a single process, limiting flexibility and scalability. Modifications typically affect entire workflows significantly. Writing up to this point, the length is getting a bit too long. Next, I will look at how this transition affects the daily development of engineers from the perspective of the developer's &lt;strong&gt;mental model and task division&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This article references Simon Liu's introduction to ADK/MCP/A2A and Koyeb's technical blog analysis of the A2A and MCP protocols. The content may contain misunderstandings, but I have done my best to understand and complete this article.&lt;/p&gt;

&lt;p&gt;It is worth noting that since these technologies are relatively new (all launched between the end of 2024 and the beginning of 2025), some details may still be under development, especially since the version of the A2A protocol is only 0.1.0, indicating that it may still be in its early stages. As these technologies mature and see wider adoption, more features and best practices may emerge in the future.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>adk</category>
    </item>
    <item>
      <title>Google Agent Development Kit (ADK) Introduction (3): Building a Multi-Agent Project Management System</title>
      <dc:creator>Jonathan Huang</dc:creator>
      <pubDate>Wed, 14 May 2025 06:12:13 +0000</pubDate>
      <link>https://dev.to/jnth/google-agent-development-kit-adk-introduction-3-building-a-multi-agent-project-management-1in3</link>
      <guid>https://dev.to/jnth/google-agent-development-kit-adk-introduction-3-building-a-multi-agent-project-management-1in3</guid>
      <description>&lt;h2&gt;
  
  
  Learning Objectives
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Master Layered Agent Architecture&lt;/strong&gt;: Learn how to design and implement a hierarchical agent system for real-world collaboration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implement Task Delegation and Coordination&lt;/strong&gt;: See how agents can assign, accept, and complete tasks collaboratively.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build Dynamic Load Balancing&lt;/strong&gt;: Ensure optimal workload distribution among agents to maximize efficiency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Technical Breadth&lt;/strong&gt;: Compare agent-based project management with traditional monolithic approaches.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  System Architecture and Project Structure
&lt;/h2&gt;

&lt;p&gt;This project uses the Google ADK (Agent Development Kit) to build a multi-agent project management system, simulating a real-world team with three specialized agent types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Manager Agent&lt;/strong&gt;: Oversees the project, assigns tasks, and reviews progress.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Engineer Agents&lt;/strong&gt;: Implement assigned tasks and report their status.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tester Agents&lt;/strong&gt;: Test completed tasks and provide feedback.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These agents are coordinated by a workflow engine, forming a complete project management workflow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;multi_agent_pm/
├── __init__.py
├── __main__.py         # Entry point for running as a module
├── main.py             # Main system implementation
├── common.py           # Shared data models and utilities
├── ai/                 # Natural language processing with Gemini
│   ├── __init__.py
│   ├── agent_nlp_handler.py
│   └── gemini_client.py
├── agents/             # Agent implementations
│   ├── __init__.py
│   ├── engineer/
│   ├── manager/
│   └── tester/
├── workflow/           # Workflow coordination
│   ├── __init__.py
│   └── coordinator.py
└── requirements.txt    # Project dependencies
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Agent Implementation and Collaboration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Manager Agent
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Assigns tasks to engineers based on workload.&lt;/li&gt;
&lt;li&gt;Reviews completed and tested tasks.&lt;/li&gt;
&lt;li&gt;Monitors overall project progress.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Engineer Agents
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Accept and work on assigned tasks.&lt;/li&gt;
&lt;li&gt;Mark tasks as completed when done.&lt;/li&gt;
&lt;li&gt;Communicate progress and issues.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Tester Agents
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Pick up completed tasks for testing.&lt;/li&gt;
&lt;li&gt;Submit test results and feedback.&lt;/li&gt;
&lt;li&gt;Help ensure quality before final approval.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each agent exposes a REST API (as defined in their &lt;code&gt;.well-known/agent.json&lt;/code&gt; manifest) and can also be interacted with via natural language commands, thanks to Gemini AI integration.&lt;/p&gt;




&lt;h2&gt;
  
  
  Dynamic Load Balancing
&lt;/h2&gt;

&lt;p&gt;The system features an automatic load balancing mechanism:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Monitor Agent Workloads&lt;/strong&gt;: Regularly checks each agent’s task queue.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redistribute Tasks&lt;/strong&gt;: Moves tasks from overloaded agents to those with spare capacity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adapt to Change&lt;/strong&gt;: Handles new tasks, agent failures, and shifting priorities in real time.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This ensures that no single agent becomes a bottleneck, and the project progresses smoothly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Natural Language Understanding
&lt;/h2&gt;

&lt;p&gt;With Google Gemini integration, you can interact with the system using plain English:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“Create a new high-priority task for payment integration.”&lt;/li&gt;
&lt;li&gt;“Show me all tasks assigned to engineers.”&lt;/li&gt;
&lt;li&gt;“Reassign the authentication task to Engineer2.”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Gemini parses these commands, extracts intent and parameters, and routes them to the appropriate agent and API.&lt;/p&gt;




&lt;h2&gt;
  
  
  A2A Protocol and Agent Manifests
&lt;/h2&gt;

&lt;p&gt;Each agent follows the Agent-to-Agent (A2A) protocol:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Manifest File&lt;/strong&gt;: &lt;code&gt;.well-known/agent.json&lt;/code&gt; describes each agent’s capabilities, API endpoints, and schemas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Standardized Communication&lt;/strong&gt;: Ensures agents can discover and interact with each other seamlessly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extensibility&lt;/strong&gt;: New agent types can be added by defining their manifest and implementing the required APIs.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How to Run This Project
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Install dependencies:&lt;/strong&gt;&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;p&gt;&lt;strong&gt;2. Set up Gemini (optional, for NLU):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get your API key from &lt;a href="https://ai.google.dev/" rel="noopener noreferrer"&gt;Google AI Studio&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Add it to a &lt;code&gt;.env&lt;/code&gt; file:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  GEMINI_API_KEY=your_api_key_here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Run the system:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; multi_agent_pm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Interact via CLI or REST API:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use natural language commands in the CLI.&lt;/li&gt;
&lt;li&gt;Or, send HTTP requests to the agent endpoints (see README for details).&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What You’ll Learn
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Agent System Design&lt;/strong&gt;: How to break down complex workflows into specialized, cooperating agents.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Task Delegation and Coordination&lt;/strong&gt;: Implementing real-world project management logic in code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Load Balancing&lt;/strong&gt;: Keeping your system efficient and responsive.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Natural Language Integration&lt;/strong&gt;: Making your system user-friendly and AI-powered. (Actually, this part wasn't done very well, let's talk about it later.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ADK Best Practices&lt;/strong&gt;: Using manifests and protocols for scalable, maintainable agent systems.&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;Building a multi-agent project management system with Google ADK is a powerful way to learn about modern, distributed, and intelligent software architecture.&lt;br&gt;&lt;br&gt;
You’ll gain hands-on experience with agent design, coordination, and AI integration—skills that are increasingly valuable in today’s tech landscape.&lt;/p&gt;




&lt;p&gt;For complete code and examples, see the &lt;a href="https://github.com/wisehuang/adk-learning-journey/tree/main/multi_agent_pm" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>adk</category>
    </item>
    <item>
      <title>Google Agent Development Kit (ADK) Introduction (2): Building a Multi-Agent Meeting Scheduling System</title>
      <dc:creator>Jonathan Huang</dc:creator>
      <pubDate>Mon, 12 May 2025 15:03:16 +0000</pubDate>
      <link>https://dev.to/jnth/google-agent-sdk-introduction-2-building-a-multi-agent-meeting-scheduling-system-1ach</link>
      <guid>https://dev.to/jnth/google-agent-sdk-introduction-2-building-a-multi-agent-meeting-scheduling-system-1ach</guid>
      <description>&lt;h2&gt;
  
  
  Learning Objectives
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Master Tool Development and Integration Patterns&lt;/strong&gt;: Learn how to design, implement, and integrate multiple tools within a multi-agent architecture.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implement Complex Task Decomposition and Execution&lt;/strong&gt;: Break down complex tasks like meeting scheduling into multiple steps, executed collaboratively by different agents.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Permission Management and Error Handling&lt;/strong&gt;: Understand Google Calendar API permission application, token management, and common error handling strategies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Technical Breadth&lt;/strong&gt;: Compare Google ADK with OpenAI Function Calling for multi-step task planning.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  System Architecture and Project Structure
&lt;/h2&gt;

&lt;p&gt;This project uses the Google ADK (Agent Development Kit) multi-agent architecture, breaking the meeting scheduling process into three specialized agents:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Validator Agent&lt;/strong&gt;: Validates attendee email formats&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scheduler Agent&lt;/strong&gt;: Integrates with Google Calendar API, responsible for scheduling and conflict detection&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Notifier Agent&lt;/strong&gt;: Generates and sends meeting notifications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These three agents are connected via &lt;code&gt;SequentialAgent&lt;/code&gt;, forming a complete multi-step workflow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;meeting_workflow/
├── meeting_workflow_adk.py  # Main ADK implementation
├── streamlit_app.py         # Web interface
├── common/                  # Shared utilities
│   └── google_auth.py       # Google authentication functionality
├── agents/                  # Agent configurations
│   └── .../.well-known/agent.json
├── requirements.txt         # Dependencies
└── README.md                # Project documentation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Tool Development and Integration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Tool Implementation
&lt;/h3&gt;

&lt;p&gt;Each agent’s core capability is implemented as a Tool, inheriting from &lt;code&gt;BaseTool&lt;/code&gt; and implementing the &lt;code&gt;execute&lt;/code&gt; method.&lt;/p&gt;

&lt;h4&gt;
  
  
  Example: Email Validation Tool
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ValidateAttendeesTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseTool&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&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="n"&gt;attendees&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="n"&gt;invalid_emails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;attendees&lt;/span&gt; &lt;span class="k"&gt;if&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="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="ow"&gt;or&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="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;email&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;invalid_emails&lt;/span&gt;&lt;span class="p"&gt;:&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;valid&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;invalid_emails&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;invalid_emails&lt;/span&gt;&lt;span class="p"&gt;}&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;valid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Example: Meeting Scheduling Tool (Google Calendar Integration)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ScheduleMeetingTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseTool&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&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="n"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;duration_min&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attendees&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="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# 1. Get Google Calendar credentials
&lt;/span&gt;        &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_calendar_service&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="c1"&gt;# 2. Check for time conflicts
&lt;/span&gt;        &lt;span class="c1"&gt;# 3. If no conflicts, create the meeting event
&lt;/span&gt;        &lt;span class="c1"&gt;# 4. Return the result
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Example: Notification Tool
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SendMeetingNotificationTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseTool&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&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="n"&gt;event_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;duration_min&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attendees&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="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Generate notification content; can be integrated with Email/Line/Slack, etc.
&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Notification sent&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;h3&gt;
  
  
  Integrating Tools into Agents
&lt;/h3&gt;

&lt;p&gt;Each Agent is built around its tools and can be given an instruction:&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;validate_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;attendee_validator&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemini-pro&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="nc"&gt;ValidateAttendeesTool&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;Validate meeting attendee email formats&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;
  
  
  Multi-Step Task Planning (Workflow)
&lt;/h2&gt;

&lt;p&gt;Use &lt;code&gt;SequentialAgent&lt;/code&gt; to connect the three agents, forming a multi-step workflow:&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;meeting_workflow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SequentialAgent&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;meeting_workflow&lt;/span&gt;&lt;span class="sh"&gt;"&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;validate_agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;scheduling_agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;notification_agent&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;Complete meeting scheduling workflow&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The main process &lt;code&gt;process_meeting_request&lt;/code&gt; will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Validate email formats&lt;/li&gt;
&lt;li&gt;Attempt to schedule the meeting (if conflicts, return suggested times)&lt;/li&gt;
&lt;li&gt;Send meeting notifications&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Google Calendar API Permission Management and Error Handling
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Permissions and Token Management
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You must first create a project in Google Cloud Console, enable the Calendar API, set up OAuth, and download &lt;code&gt;credentials.json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;On first run, &lt;code&gt;token.json&lt;/code&gt; is generated automatically and refreshed as needed.
&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_calendar_service&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="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;token.json&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;creds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Credentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_authorized_user_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;token.json&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SCOPES&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# ... If not, guide through OAuth flow ...
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;calendar&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;v3&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;credentials&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;creds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Error Handling
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Email format errors, API errors, time conflicts, and network issues are all clearly reported.&lt;/li&gt;
&lt;li&gt;All exceptions are logged for easy debugging.
&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="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Google Calendar API operations
&lt;/span&gt;&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;HttpError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&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;Calendar API error: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;error&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="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;error&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;API Error: &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;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Web Interface (Streamlit)
&lt;/h2&gt;

&lt;p&gt;A simple web interface is provided for users to enter meeting information and instantly see scheduling results and conflict suggestions.&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;# streamlit_app.py
&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text_input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Meeting Subject&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;Product Development Discussion&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;meeting_date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;date_input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Meeting Date&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;meeting_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time_input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Meeting Time&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...)&lt;/span&gt;
&lt;span class="c1"&gt;# ... On submit, call process_meeting_request ...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Comparison with OpenAI Function Calling
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Item&lt;/th&gt;
&lt;th&gt;Google ADK Multi-Agent/Tool&lt;/th&gt;
&lt;th&gt;OpenAI Function Calling&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Multi-step Task Flow&lt;/td&gt;
&lt;td&gt;Supports SequentialAgent&lt;/td&gt;
&lt;td&gt;Must design multi-step logic manually&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tool Integration&lt;/td&gt;
&lt;td&gt;Register as Tool class&lt;/td&gt;
&lt;td&gt;Register as function schema&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Permission &amp;amp; API Mgmt&lt;/td&gt;
&lt;td&gt;Handle OAuth yourself&lt;/td&gt;
&lt;td&gt;Handled by external code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Error Handling&lt;/td&gt;
&lt;td&gt;Customizable granularity&lt;/td&gt;
&lt;td&gt;Must wrap yourself&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-Agent Workflow&lt;/td&gt;
&lt;td&gt;Built-in sub-agent support&lt;/td&gt;
&lt;td&gt;Must decompose manually&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
Google ADK is suitable for applications requiring multi-agent collaboration and complex task decomposition, with clear Tool/Agent concepts. OpenAI Function Calling is suitable for single-step, single-model-driven tasks; complex workflows must be designed manually.&lt;/p&gt;

&lt;p&gt;Certainly! Here’s the revised conclusion section, now including clear instructions on how to execute the Python app from both the command line and the web interface:&lt;/p&gt;


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

&lt;p&gt;This project demonstrates how to use Google ADK to develop a multi-agent meeting scheduling system, covering tool development, API integration, multi-step task planning, permission management, and error handling. You are encouraged to further try:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adding cross-timezone support&lt;/li&gt;
&lt;li&gt;Integrating meeting room reservations&lt;/li&gt;
&lt;li&gt;Supporting natural language input and parsing&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  How to Run This Python App
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Command Line Usage:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can schedule a meeting directly from the command line by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python meeting_workflow_adk.py &lt;span class="nt"&gt;--summary&lt;/span&gt; &lt;span class="s2"&gt;"Product Meeting"&lt;/span&gt; &lt;span class="nt"&gt;--time&lt;/span&gt; &lt;span class="s2"&gt;"2025-05-15T14:00:00"&lt;/span&gt; &lt;span class="nt"&gt;--duration&lt;/span&gt; 60 &lt;span class="nt"&gt;--attendees&lt;/span&gt; &lt;span class="s2"&gt;"alice@example.com,bob@example.com"&lt;/span&gt; &lt;span class="nt"&gt;--description&lt;/span&gt; &lt;span class="s2"&gt;"Product development meeting"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or, for a demonstration with example parameters, simply run:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Web Interface:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To use the Streamlit web interface, run:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Then open the displayed URL in your browser (typically &lt;a href="http://localhost:8501" rel="noopener noreferrer"&gt;http://localhost:8501&lt;/a&gt;).&lt;/p&gt;




&lt;p&gt;For complete code and examples, please refer to this project’s &lt;a href="https://github.com/wisehuang/adk-learning-journey/tree/main/meeting_workflow" rel="noopener noreferrer"&gt;GitHub Repo&lt;/a&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  Next Article Preview
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Multi-Agent Collaboration System: Project Management Collaboration Platform&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the next article, we will explore how to build a multi-agent collaboration system for project management, featuring Manager, Engineering, and QA/Test agents. This system will demonstrate advanced agent collaboration patterns for handling project planning, task assignment, and quality assurance workflows. Stay tuned!&lt;/p&gt;

</description>
      <category>adk</category>
      <category>programming</category>
    </item>
    <item>
      <title>Google Agent Development Kit (ADK) Introduction (1): Quickly Build Your First AI Agent</title>
      <dc:creator>Jonathan Huang</dc:creator>
      <pubDate>Mon, 12 May 2025 07:12:03 +0000</pubDate>
      <link>https://dev.to/jnth/google-agent-sdk-introduction-1-quickly-build-your-first-ai-agent-3kp5</link>
      <guid>https://dev.to/jnth/google-agent-sdk-introduction-1-quickly-build-your-first-ai-agent-3kp5</guid>
      <description>&lt;h3&gt;
  
  
  What is Google Agent SDK
&lt;/h3&gt;

&lt;p&gt;Google Agent SDK (also known as Agent Development Kit, ADK) is an open-source SDK developed by Google, primarily in Python, designed to simplify and accelerate the development, testing, and deployment of AI Agents.&lt;/p&gt;

&lt;p&gt;Developers can use this SDK to build modern AI Agents equipped with memory, tool invocation, task coordination, and other capabilities. ADK is deeply integrated with Google Gemini, Vertex AI, and various Google Cloud services.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup Environment and Configure Google Cloud
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Go to &lt;a href="https://console.cloud.google.com/" rel="noopener noreferrer"&gt;Google Cloud Console&lt;/a&gt; and sign in or register an account.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a new project and ensure billing is enabled.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enable the 'Vertex AI API' in the API management.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install Google Cloud CLI (gcloud), &lt;a href="https://cloud.google.com/sdk/docs/install" rel="noopener noreferrer"&gt;official download page&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Update CLI components:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   gcloud components update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Log into your Google account in the terminal and generate Application Default Credentials (ADC):
&lt;/li&gt;
&lt;/ul&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;A browser will open, complete the login to authenticate your Google account&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a Python Virtual Environment and Install ADK
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Create a virtual environment in your project directory:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   python &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Activate the virtual environment (run this every time you open a new terminal):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;macOS/Linux:
&lt;/li&gt;
&lt;/ul&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;  &lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate 
&lt;/code&gt;&lt;/pre&gt;



&lt;ul&gt;
&lt;li&gt;Windows CMD:
&lt;/li&gt;
&lt;/ul&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;  .venv&lt;span class="se"&gt;\S&lt;/span&gt;cripts&lt;span class="se"&gt;\a&lt;/span&gt;ctivate.bat 
&lt;/code&gt;&lt;/pre&gt;



&lt;ul&gt;
&lt;li&gt;Windows PowerShell:
&lt;/li&gt;
&lt;/ul&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;  .venv&lt;span class="se"&gt;\S&lt;/span&gt;cripts&lt;span class="se"&gt;\A&lt;/span&gt;ctivate.ps1
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Install Google Agent SDK（ADK）：&lt;br&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

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

&lt;/div&gt;



&lt;p&gt;(For advanced Vertex AI features, use &lt;code&gt;pip install --upgrade --quiet google-cloud-aiplatform[agent_engines,adk]&lt;/code&gt;)&lt;/p&gt;

&lt;h3&gt;
  
  
  Create project and .env
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Create project and necessary files：
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   mkdir multi_tool_agent
   cd multi_tool_agent
   touch __init__.py agent.py .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;project structure example：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   parent_folder/
     multi_tool_agent/
       __init__.py
       agent.py
       .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Edit the .env file and enter your Google Cloud project information (example):
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   GOOGLE_CLOUD_PROJECT="your-project-id"
   GOOGLE_CLOUD_LOCATION="us-central1"
   GOOGLE_GENAI_USE_VERTEXAI="True"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or, if you're using an API Key (Google AI Studio):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   GOOGLE_GENAI_USE_VERTEXAI=FALSE
   GOOGLE_API_KEY="your-api-key"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Write Your First Agent
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;In agent.py, write a simple example (refer to the official Quickstart):
&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="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="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;hello_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="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="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 friendly assistant answering user questions.&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;ul&gt;
&lt;li&gt;In &lt;code&gt;__init__.py&lt;/code&gt; Add：
&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="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;agent&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Launch the Agent Dev Interface or Run Locally
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Go back to the parent folder and launch the dev UI:
&lt;/li&gt;
&lt;/ul&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;parent_folder/  &amp;lt;&lt;span class="nt"&gt;--&lt;/span&gt; Run &lt;span class="s1"&gt;'adk web'&lt;/span&gt; here
└── your_agent_folder/
    ├── __init__.py
    └── agent.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open the displayed URL in a browser (usually &lt;a href="http://localhost:8000" rel="noopener noreferrer"&gt;http://localhost:8000&lt;/a&gt;) to interact with the Agent.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Or test directly in the terminal:
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Advanced: Quickly Try Official Samples
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Clone the official sample repo:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  git clone https://github.com/google/adk-samples.git cd adk-samples/agents 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Follow each subfolder’s README to quickly try various pre-built agents.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ and Notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;I encountered issues finding available regions and models.

&lt;ul&gt;
&lt;li&gt;Use region: us-central1&lt;/li&gt;
&lt;li&gt;Region list: &lt;a href="https://cloud.google.com/compute/docs/regions-zones?hl=en" rel="noopener noreferrer"&gt;https://cloud.google.com/compute/docs/regions-zones?hl=en&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Use model: gemini-2.5-pro-preview-05-06&lt;/li&gt;
&lt;li&gt;Model list: &lt;a href="https://cloud.google.com/vertex-ai/generative-ai/docs/models" rel="noopener noreferrer"&gt;https://cloud.google.com/vertex-ai/generative-ai/docs/models&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

</description>
      <category>adk</category>
      <category>programming</category>
    </item>
    <item>
      <title>使用 VS Codium 代替 Visual Studio Code</title>
      <dc:creator>Jonathan Huang</dc:creator>
      <pubDate>Mon, 05 Sep 2022 06:21:23 +0000</pubDate>
      <link>https://dev.to/jnth/shi-yong-vs-codium-dai-ti-visual-studio-code-82</link>
      <guid>https://dev.to/jnth/shi-yong-vs-codium-dai-ti-visual-studio-code-82</guid>
      <description>&lt;p&gt;我自己也是很喜歡 Visual Studio Code，可以說他是近幾年來非常成功的 editor，但是最大缺點就是 tracking 跟 telemetry 的問題。如果你跟我一樣不想要被 track，&lt;a href="https://vscodium.com/" rel="noopener noreferrer"&gt;VS Codium&lt;/a&gt; 就是一個好選擇。&lt;/p&gt;

&lt;p&gt;VS Codium 和 Visual Studio Code 幾乎完全相同，唯一的不同是他不會追蹤你的使用行為。&lt;/p&gt;

&lt;p&gt;Visual Studio Code 本身是 open source，但是他的 binary 是經過微軟包裝過的，並且加入了若干追蹤機制。&lt;/p&gt;

&lt;p&gt;當然在 Visual Studio Code 裡面你可以透過設定一系列的參數來 &lt;a href="https://code.visualstudio.com/docs/supporting/faq#_how-to-disable-telemetry-reporting" rel="noopener noreferrer"&gt;disable telemetry reporting&lt;/a&gt;，但是更乾淨的作法會是你可以下載一個完全 open source 的版本，就是 VS Codium。&lt;/p&gt;

&lt;p&gt;VS Codium 是從 Visual Studio Code 的 &lt;a href="https://github.com/Microsoft/vscode" rel="noopener noreferrer"&gt;repository&lt;/a&gt; &lt;a href="https://github.com/VSCodium/vscodium" rel="noopener noreferrer"&gt;folk&lt;/a&gt; 出來的版本，並且在 package 的過程中不會加入 tracking 和 telemetry 的機制。&lt;/p&gt;

&lt;p&gt;至於 extension 的支援，目前為止我覺得是完全相容。Visual Studio Code 有個 extension marketplace，而 VS Codium 也一樣有個 &lt;a href="https://open-vsx.org/" rel="noopener noreferrer"&gt;Open VSX Registry&lt;/a&gt; 的 marketplace。&lt;/p&gt;




&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Visual Studio Code&lt;/th&gt;
&lt;th&gt;VS Codium&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;License&lt;/td&gt;
&lt;td&gt;Microsoft product license&lt;/td&gt;
&lt;td&gt;MIT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tracking/telemetry&lt;/td&gt;
&lt;td&gt;Enabled by default&lt;/td&gt;
&lt;td&gt;Disabled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Marketplace&lt;/td&gt;
&lt;td&gt;Microsoft Visual Studio Code Marketplace&lt;/td&gt;
&lt;td&gt;Open VSX Registry&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Extensions&lt;/td&gt;
&lt;td&gt;All extensions including Microsoft extensions&lt;/td&gt;
&lt;td&gt;Some Microsoft's extensions are restricted&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;p&gt;最後，我在轉移的過程中使用了 &lt;a href="https://open-vsx.org/extension/zokugun/sync-settings" rel="noopener noreferrer"&gt;Sync Settings&lt;/a&gt; 這個 extension，感覺比之前使用的 &lt;a href="https://open-vsx.org/extension/Shan/code-settings-sync" rel="noopener noreferrer"&gt;Settings Sync&lt;/a&gt; 簡單不少。&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
