
In the ever-evolving landscape of AI, agents are becoming increasingly powerful tools for automating tasks and providing intelligent responses. Google’s Agent Development Kit (ADK) offers a streamlined framework for developers to create their own AI agents.
In this tutorial, we will walk through the entire process, from setup to deployment, to build a “Travel Buddy” agent to provide weather, time, and practical travel guidance for any city in the world.
Our “Travel Buddy” agent will have three primary functions, all powered by live Google Search results:
- Get Current Weather: Takes a city name, performs a Google search, and extracts the temperature and weather conditions from the top results.
- Get Current Time: Takes a city name, performs a Google search, and extracts the current local time.
- Get Travel Information: Takes a city name and a topic (e.g., “power outlets,” “culture,” “transportation”), performs a Google search, and summarizes the content from a reliable source.
To ensure a smooth process with no local installation, we will perform all development directly in Google Cloud Shell.
- Navigate to the Google Cloud Console.
- In the top-right corner, click the “Activate Cloud Shell” icon.
- Once the terminal appears at the bottom of the screen, click “Open Editor” for a more comfortable, full-screen working environment.
- In the Cloud Shell terminal, set your active Google Cloud project. Replace
YOUR-PROJECT-ID
with your actual project ID.
gcloud config set project YOUR-PROJECT-ID
2. Enable the Vertex AI API, which the agent requires.
gcloud services enable aiplatform.googleapis.com
A correct folder structure is crucial. Run the following command in the terminal to create a directory structure that follows the official Codelabs best practice.
# Create the main folder structure
mkdir -p travel_project/agents/travel_buddy
# Create the necessary __init__.py files
touch travel_project/__init__.py
touch travel_project/agents/travel_buddy/__init__.py
Your structure should now look like this in the editor:
travel_project/
└── agents/
| └── travel_buddy/
| | ├── __init__.py
| | ├── agent.py
| └── .env
├── __init__.py
└── Dockerfile
To use the Google search feature, we need to get the Search Engine ID from Google’s Programmable Search Engine. (https://programmablesearchengine.google.com/)
First, Create your new Search Engine
After the form appears, give it a name and select the “Search entire web” option. Leave the rest of the settings as they are, and finally, click “Create”.
When you’re done, note the search engine ID.
Now, let’s populate the files we’ve created.
- Location:
travel_project/agents/travel_buddy/.env
- Purpose: Configures the ADK to use Vertex AI for its generative model.
- Content:
GOOGLE_CLOUD_PROJECT="YOUR_PROJECT_ID"
GOOGLE_CLOUD_LOCATION="YOUR_CHOSEN_REGION" # e.g., us-central1 or asia-southeast1
GOOGLE_GENAI_USE_VERTEXAI="True"
GOOGLE_API_KEY="YOUR_GOOGLE_AI_STUDIO_API_KEY"
File 1 (inside agents
):
- Location:
travel_project/
- Content: Leave this file completely empty. Its presence is enough to mark the directory as a Python package.
File 2 (inside travel_buddy
):
- Location:
travel_project/agents/travel_buddy/__init__.py
- Content: Leave this file completely empty. Its presence is enough to mark the directory as a Python package.
- Location:
travel_project/agents/travel_buddy/agent.py
- Content: Copy and paste the complete code below. This file contains all the logic for searching Google, scraping results, and defining the agent’s tools.
import os
import requests
from google.adk.agents import Agent
from bs4 import BeautifulSoup
import re
GOOGLE_API_KEY = "YOUR_GOOGLE_AI_STUDIO_API_KEY"
GOOGLE_CX = "YOUR_PROGRAMMABLE_SEARCH_ENGINE_ID"def google_custom_search(query: str, num_results: int = 3) -> list[str]:
if not GOOGLE_API_KEY or not GOOGLE_CX:
print("❌ Error: GOOGLE_API_KEY & GOOGLE_CX is not set")
return []
try:
url = "https://www.googleapis.com/customsearch/v1"
params = {
'key': GOOGLE_API_KEY,
'cx': GOOGLE_CX,
'q': query,
'num': num_results
}
response = requests.get(url, params=params, timeout=10)
response.raise_for_status()
search_results = response.json()
return [item['link'] for item in search_results.get('items', [])]
except Exception as e:
print(f"Error saat melakukan Google Custom Search: {e}")
return []
def _extract_content_from_url(url: str, content_type: str = "general") -> str:
"""
Mengekstrak teks dari URL dengan membersihkan elemen yang tidak relevan.
Fungsi ini tidak diubah.
"""
try:
headers = {'User-Agent': 'Mozilla/5.0'}
response = requests.get(url, headers=headers, timeout=15)
response.raise_for_status()
soup = BeautifulSoup(response.content, 'html.parser')
for element in soup(["script", "style", "nav", "header", "footer", "aside", "ads"]):
element.decompose()
extracted_text = ""
if content_type == "weather":
weather_selectors = [
'[class*="temperature"]', '[class*="weather"]', '[class*="temp"]',
'[id*="temperature"]', '[id*="weather"]', '[id*="current"]',
'span[class*="deg"]', 'div[class*="current"]', 'div[data-testid="current-temperature"]'
]
for selector in weather_selectors:
elements = soup.select(selector)
for elem in elements:
text = elem.get_text().strip()
if text and any(char.isdigit() for char in text):
extracted_text += text + " "
if not extracted_text.strip():
extracted_text = soup.get_text()
elif content_type == "time":
time_selectors = [
'[class*="time"]', '[class*="clock"]', '[id*="time"]',
'span[class*="current"]', 'div[class*="local"]', 'div[data-testid="current-time"]'
]
for selector in time_selectors:
elements = soup.select(selector)
for elem in elements:
text = elem.get_text().strip()
if ":" in text:
extracted_text += text + " "
if not extracted_text.strip():
extracted_text = soup.get_text()
else:
extracted_text = soup.get_text()
lines = (line.strip() for line in extracted_text.splitlines())
chunks = (phrase.strip() for line in lines for phrase in line.split(" "))
text = ' '.join(chunk for chunk in chunks if chunk)
return text[:1500] + "..." if len(text) > 1500 else text
except Exception as e:
return f"Could not extract content from {url}: {str(e)}"
def search_and_extract_content(query: str, num_results: int = 3, content_type: str = "general") -> list:
search_results_urls = google_custom_search(query, num_results=num_results)
if not search_results_urls:
return []
print(f"Get content from {len(search_results_urls)} URL...")
extracted_data = []
for url in search_results_urls:
content = _extract_content_from_url(url, content_type)
if content and not content.startswith("Could not extract"):
extracted_data.append({"url": url, "content": content})
return extracted_data
def get_weather(city: str) -> dict:
try:
queries = [f"current weather {city} temperature celsius", f"cuaca hari ini {city} suhu"]
for query in queries:
results = search_and_extract_content(query, num_results=2, content_type="weather")
for item in results:
content, url = item['content'], item['url']
if len(content) > 50:
weather_info = {}
# --- Bagian Pengecekan Suhu (Tidak berubah) ---
temp_patterns = [r'(-?\d{1,3}(?:\.\d+)?)\s*°C', r'(-?\d{1,3}(?:\.\d+)?)\s*C\b']
for pattern in temp_patterns:
match = re.search(pattern, content, re.IGNORECASE)
if match:
weather_info['temperature'] = match.group(1) + "°C"
break
# --- Bagian Pengecekan Kondisi Cuaca (DIUBAH) ---
condition_patterns = [
r'\b(cerah|berawan|hujan|mendung|panas|sejuk|dingin|kabut|angin|salju|badai)\b',
r'\b(sunny|cloudy|rainy|clear|hot|cold|foggy|windy|snowy|storm|overcast)\b'
]
for pattern in condition_patterns:
# DIUBAH: dari re.findall menjadi re.search
match = re.search(pattern, content, re.IGNORECASE)
if match:
# DIUBAH: Ambil hanya hasil pertama yang cocok
weather_info['condition'] = match.group(1).lower()
break # Keluar dari loop setelah menemukan kondisi pertama
if weather_info:
report = f"🌤️ Weather in {city}:\n"
if 'temperature' in weather_info:
report += f"Temperature: {weather_info['temperature']}\n"
if 'condition' in weather_info:
report += f"Condition: {weather_info['condition'].title()}\n" # Dibuat jadi huruf kapital di awal
report += f"Source: {url}"
return {"status": "success", "report": report}
return {"status": "error", "error_message": f"No weather info found for {city}."}
except Exception as e:
return {"status": "error", "error_message": f"Weather search failed: {str(e)}"}
def get_current_time(city: str) -> dict:
try:
query = f"waktu sekarang di {city} current time"
results = search_and_extract_content(query, num_results=2, content_type="time")
for item in results:
content, url = item['content'], item['url']
match = re.search(r'\b(\d{1,2}:\d{2}(?::\d{2})?)', content)
if match:
return {"status": "success", "report": f"⏰ Current time in {city} is {match.group(1)}.\nSource: {url}"}
return {"status": "error", "error_message": f"No time info found for {city}."}
except Exception as e:
return {"status": "error", "error_message": f"Time search failed: {str(e)}"}
def get_travel_info(city: str, info_type: str) -> dict:
try:
query = f"{info_type} di {city} travel guide"
results = search_and_extract_content(query, num_results=1, content_type="general")
if results:
first_result = results[0]
report = f"Travel info about '{info_type}' in {city}:\n\nSource: {first_result['url']}\n{first_result['content']}"
return {"status": "success", "report": report}
else:
return {"status": "error", "error_message": f"No travel info found for '{info_type}' in {city}."}
except Exception as e:
return {"status": "error", "error_message": f"Travel info search failed: {str(e)}"}
root_agent = Agent(
name="travel_buddy_agent",
model="gemini-1.5-flash-002",
description="An intelligent travel buddy agent that uses Google Search to provide real-time weather, time, and travel information.",
instruction=(
"You are a friendly and helpful travel buddy agent. "
"You provide users with live, up-to-date information about weather, time, and travel tips for any city in the world. "
"Always cite your source."
),
tools=[get_weather, get_current_time, get_travel_info]
)
Once testing is successful, it’s time to make your agent publicly accessible by deploying it to Cloud Run. We’ll use the robust and explicit Dockerfile
method.
- In the root directory of your project (
travel_project
), create a new file namedDockerfile
. - Populate the
Dockerfile
with the following content. This file contains the recipe for building your application’s container.
Why a Dockerfile? The default
adk deploy
command sometimes fails to pass arguments correctly. By creating our ownDockerfile
, we gain full control and explicitly tell Cloud Run exactly how to start our application, ensuring theagents
argument is included. This is the standard, production-grade way to deploy applications.
Dockerfile
FROM python:3.11-slimWORKDIR /app
COPY . .
RUN pip install google-adk geopy timezonefinder beautifulsoup4 googlesearch-python
EXPOSE 8080
CMD ["adk", "web", "--host", "0.0.0.0", "--port", "8080", "agents"]
Make sure you are still in the travel_project
directory, then run the command below. This single command will build and deploy your agent.
gcloud run deploy travel-buddy-service \
--source . \
--region="YOUR-CHOSEN-REGION" \
--allow-unauthenticated \
--project="YOUR-PROJECT-ID"
The deployment process will take a few minutes. Once successful, the terminal will provide you with a public URL.
Click the URL provided by the gcloud
command. You will see the same ADK interface, but this time it’s running live on Google’s global infrastructure, ready to be shared or integrated into other applications.
Try asking the agent some questions in the chat box on the right.
- “What’s the weather like in London?”
- “Can you tell me the current time in Tokyo?”
- “I’m planning a trip to New York. What’s the weather there right now?”
- “What kind of power outlets do they use in Paris?”
- “Tell me about the culture in Surabaya.
By leveraging the Google Agent Development Kit, we have successfully created a dynamic and capable agent that provides real-time information. This tutorial demonstrates how the ADK can streamline the agent-building process, allowing developers to focus on the core logic of their tools. From this foundation, you can add more tools, connect to more APIs, and create even more sophisticated and helpful AI agents. Happy coding!
Source Credit: https://medium.com/google-cloud/build-and-deploy-a-live-ai-travel-agent-in-minutes-with-google-adk-google-search-and-cloud-run-fd29d11d3e56?source=rss—-e52cf94d98af—4