1. 简介
在本实验中,您将使用智能体开发套件 (ADK) 构建一个智能体!您将学习如何使用 ADK 和各种工具类型来构建软件 bug 助理代理。您将从一个基本智能体开始,逐步添加工具来增强其功能,包括函数工具、内置工具、第三方工具和 Model Context Protocol (MCP) 工具。
学习内容
- 如何设置 Python 项目以进行 ADK 开发。
- 如何创建基本的 ADK 代理。
- 如何实现和使用函数工具。
- 如何集成 Google 搜索等内置工具。
- 如何在 ADK 中利用 LangChain 等框架中的第三方工具。
- 如何使用 MCP 工具与数据库 (Cloud SQL) 和 API 进行交互。
2. 概览
假设您是全球咖啡机公司 QuantumRoast 的项目经理。
您帮助团队成员应对各种工程路线图、突如其来的策略转变(我们现在开始做抹茶了!),以及客户发来的各种问题工单,从有 bug 的账单系统到 24 小时发出尖锐噪音的咖啡机,无所不包。
在平常的一天,您会打开大约 50 个浏览器标签页:内部工单系统、电子邮件、聊天、GitHub、Google 搜索、StackOverflow 等等。您喜欢自己的工作和队友,但有时会感到不堪重负。
如果我们能打造一个助手,帮助您创建和分诊软件工单,并调试问题,会怎样?AI 智能体可实现这一点。
智能体开发套件 (ADK)
智能体开发套件 (ADK) 是一个灵活的模块化框架,用于开发和部署 AI 智能体。尽管 ADK 针对 Gemini 和 Google 生态系统进行了优化,但它仍不限模型、与部署无关,并且可与其他框架兼容。ADK 的设计旨在让智能体开发更像软件开发,从而让开发者能够更轻松地创建、部署和编排从简单任务到复杂工作流的智能体架构。
ADK 是我们将用于构建 QuantumRoast 软件 bug 助理的框架。
工具 101
AI 智能体使用模型(而不仅仅是硬编码的逻辑)来推理解决问题。但 AI 智能体不仅能进行基于 LLM 的推理,还具备独特的强大功能,可以收集外部数据,然后代表用户采取行动。AI 智能体不仅会告诉您如何解决问题,还能帮助您实际解决问题。那要如何做呢?使用工具!
工具是一种功能,可帮助 AI 智能体与世界互动。工具几乎可以是任何东西:内嵌函数、托管数据库、第三方 API,甚至是另一个智能体。智能体开发套件 (ADK) 等 AI 智能体框架内置了对工具的支持,支持多种工具类型,我们稍后会介绍。
但代理不仅知道何时调用特定工具,还知道如何调用该工具,这是怎么做到的?智能体的模型在这里发挥着几个关键作用。
首先是工具选择。我们会向智能体提供工具列表以及有关如何使用这些工具的一些说明。当用户提示智能体时,智能体的模型会帮助确定要调用哪些工具以及调用原因,以便帮助用户。
第二个关键步骤是函数调用。函数调用以下名称有点用词不当,因为模型实际上并没有调用工具,而是通过格式化请求正文来准备调用工具,然后框架会使用该请求正文来调用工具。
最后,该模型有助于解读来自该工具的响应(例如数据库中的开放 bug 列表),并决定是否采取进一步行动,或者是否向用户回复该信息。
为了实际体验上述所有功能,现在让我们使用 ADK Python 构建 QuantumRoast bug 助理代理。
3. 准备工作
Google Cloud 项目设置
- 如果您还没有 Google 账号,则必须先创建一个 Google 账号。
- 请改用个人账号,而不是工作账号或学校账号。工作账号和学校账号可能存在限制,导致您无法启用本实验所需的 API。
- 登录 Google Cloud 控制台。
- 在 Cloud 控制台中启用结算功能。
- 完成本实验的 Cloud 资源费用应不到 1 美元。
- 您可以按照本实验结束时的步骤删除资源,以避免产生更多费用。
- 新用户符合参与 $300 USD 免费试用计划的条件。
- 创建新项目或选择重复使用现有项目。
打开 Cloud Shell Editor
- 前往 Cloud Shell 编辑器
- 如果终端未显示在屏幕底部,请打开它:
- 点击汉堡式菜单
- 点击终端
- 点击 New Terminal
- 点击汉堡式菜单
- 在终端中,使用以下命令设置项目(替换
YOUR_PROJECT_ID
):- 格式:
gcloud config set project YOUR_PROJECT_ID
- 示例:
gcloud config set project lab-project-id-example
- 如果您不记得项目 ID,请执行以下操作:
- 您可以使用以下命令列出所有项目 ID:
gcloud projects list | awk '/PROJECT_ID/{print $2}'
- 您可以使用以下命令列出所有项目 ID:
- 格式:
- 如果系统提示您进行授权,请点击授权继续。
- 您应会看到以下消息:
如果您看到Updated property [core/project].
WARNING
并被问到Do you want to continue (Y/N)?
,则很可能是您输入的项目 ID 有误。按N
,按Enter
,然后尝试再次运行gcloud config set project
命令。 - 在终端中,设置要在后续步骤中使用的
PROJECT_ID
环境变量。export PROJECT_ID=$(gcloud config get project)
启用 API
在终端中,运行以下命令以启用必要的 Google Cloud API:
gcloud services enable sqladmin.googleapis.com \
compute.googleapis.com \
cloudresourcemanager.googleapis.com \
secretmanager.googleapis.com \
servicenetworking.googleapis.com \
aiplatform.googleapis.com \
run.googleapis.com \
artifactregistry.googleapis.com \
cloudbuild.googleapis.com
创建 Cloud SQL for PostgreSQL 实例
QuantumRoast 有一个 bug 工单数据库,其中包含所有内部工单。接下来,我们创建一个 Cloud SQL for PostgreSQL 实例来设置它。
gcloud sql instances create software-assistant \
--database-version=POSTGRES_16 \
--tier=db-custom-1-3840 \
--region=us-central1 \
--edition=ENTERPRISE \
--enable-google-ml-integration \
--database-flags cloudsql.enable_google_ml_integration=on \
--root-password=admin
等待实例创建完成(可能需要几分钟时间)。
创建实例后,您可以点击此处在 Cloud 控制台中查看该实例。
创建 Cloud SQL 数据库
创建 SQL 数据库 (tickets-db
),并授予 Cloud SQL 服务账号对 Vertex AI 的访问权限(以便我们可以创建嵌入来执行相似性搜索)。
gcloud sql databases create tickets-db --instance=software-assistant
SERVICE_ACCOUNT_EMAIL=$(gcloud sql instances describe software-assistant --format="value(serviceAccountEmailAddress)")
echo $SERVICE_ACCOUNT_EMAIL
gcloud projects add-iam-policy-binding $PROJECT_ID --member="serviceAccount:$SERVICE_ACCOUNT_EMAIL" --role="roles/aiplatform.user"
设置 tickets
表
在 Cloud 控制台 (Cloud SQL) 中,为 software-assistant
实例打开 Cloud SQL Studio。
使用 postgres
用户名和 admin
密码登录 tickets-db
数据库。
打开新的 Editor
标签页。
然后,粘贴以下 SQL 代码以设置表并创建向量嵌入。按 Run
按钮执行命令。
CREATE EXTENSION IF NOT EXISTS google_ml_integration CASCADE;
CREATE EXTENSION IF NOT EXISTS vector CASCADE;
GRANT EXECUTE ON FUNCTION embedding TO postgres;
CREATE TABLE tickets (
ticket_id SERIAL PRIMARY KEY, -- PostgreSQL's auto-incrementing integer type (SERIAL is equivalent to INT AUTO_INCREMENT)
title VARCHAR(255) NOT NULL, -- A concise summary or title of the bug/issue.
description TEXT, -- A detailed description of the bug.
assignee VARCHAR(100), -- The name or email of the person/team assigned to the ticket.
priority VARCHAR(50), -- The priority level (e.g., 'P0 - Critical', 'P1 - High').
status VARCHAR(50) DEFAULT 'Open', -- The current status of the ticket (e.g., 'Open', 'In Progress', 'Resolved'). Default is 'Open'.
creation_time TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, -- Timestamp when the ticket was first created. 'WITH TIME ZONE' is recommended for clarity and compatibility.
updated_time TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP -- Timestamp when the ticket was last updated. Will be managed by a trigger.
);
tickets
表已创建,点击 Clear
可清除旧查询。
现在,插入示例数据,然后再次点击 Run
按钮。
INSERT INTO tickets (title, description, assignee, priority, status) VALUES
('Login Page Freezes After Multiple Failed Attempts', 'Users are reporting that after 3 failed login attempts, the login page becomes unresponsive and requires a refresh. No specific error message is displayed.', 'samuel.green@example.com', 'P0 - Critical', 'Open');
INSERT INTO tickets (title, description, assignee, priority, status) VALUES
('Dashboard Sales Widget Intermittent Data Loading Failure', 'The "Sales Overview" widget on the main dashboard intermittently shows a loading spinner but no data. Primarily affects Chrome browser users.', 'maria.rodriguez@example.com', 'P1 - High', 'In Progress');
INSERT INTO tickets (title, description, assignee, priority, status) VALUES
('Broken Link in Footer - Privacy Policy', 'The "Privacy Policy" hyperlink located in the website footer leads to a 404 "Page Not Found" error.', 'maria.rodriguez@example.com', 'P3 - Low', 'Resolved');
INSERT INTO tickets (title, description, assignee, priority, status) VALUES
('UI Misalignment on Mobile Landscape View (iOS)', 'On specific iOS devices (e.g., iPhone 14 models), the top navigation bar shifts downwards when the device is viewed in landscape orientation, obscuring content.', 'maria.rodriguez@example.com', 'P2 - Medium', 'In Progress');
INSERT INTO tickets (title, description, assignee, priority, status) VALUES
('Critical XZ Utils Backdoor Detected in Core Dependency (CVE-2024-3094)', 'Urgent: A sophisticated supply chain compromise (CVE-2024-3094) has been identified in XZ Utils versions 5.6.0 and 5.6.1. This malicious code potentially allows unauthorized remote SSH access by modifying liblzma. Immediate investigation and action required for affected Linux/Unix systems and services relying on XZ Utils.', 'frank.white@example.com', 'P0 - Critical', 'Open');
INSERT INTO tickets (title, description, assignee, priority, status) VALUES
('Database Connection Timeouts During Peak Usage', 'The application is experiencing frequent database connection timeouts, particularly during peak hours (10 AM - 12 PM EDT), affecting all users and causing service interruptions.', 'frank.white@example.com', 'P1 - High', 'Open');
INSERT INTO tickets (title, description, assignee, priority, status) VALUES
('Export to PDF Truncates Long Text Fields in Reports', 'When generating PDF exports of reports containing extensive text fields, the text is abruptly cut off at the end of the page instead of wrapping or continuing to the next page.', 'samuel.green@example.com', 'P1 - High', 'Open');
INSERT INTO tickets (title, description, assignee, priority, status) VALUES
('Search Filter "Date Range" Not Applying Correctly', 'The "Date Range" filter on the search results page does not filter records accurately; results outside the specified date range are still displayed.', 'samuel.green@example.com', 'P2 - Medium', 'Resolved');
INSERT INTO tickets (title, description, assignee, priority, status) VALUES
('Typo in Error Message: "Unathorized Access"', 'The error message displayed when a user attempts an unauthorized action reads "Unathorized Access" instead of "Unauthorized Access."', 'maria.rodriguez@example.com', 'P3 - Low', 'Resolved');
INSERT INTO tickets (title, description, assignee, priority, status) VALUES
('Intermittent File Upload Failures for Large Files', 'Users are intermittently reporting that file uploads fail without a clear error message or explanation, especially for files exceeding 10MB in size.', 'frank.white@example.com', 'P1 - High', 'Open');
在 QuantumRoast,我们可能想知道 bug/工单上次更新的时间。
为此,我们可以创建一个触发器,以便在每次更新记录时更新 updated_time
字段。
点击 Clear
,然后粘贴以下 SQL 以实现触发器。
按 Run
按钮执行。
CREATE OR REPLACE FUNCTION update_updated_time_tickets()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_time = NOW(); -- Set the updated_time to the current timestamp
RETURN NEW; -- Return the new row
END;
$$ language 'plpgsql';
CREATE TRIGGER update_tickets_updated_time
BEFORE UPDATE ON tickets
FOR EACH ROW -- This means the trigger fires for each row affected by the UPDATE statement
EXECUTE PROCEDURE update_updated_time_tickets();
根据 description
字段创建向量嵌入。这样一来,我们的代理就可以对数据库执行相似度搜索。例如,“网站首页是否存在任何未解决的问题?”。
ALTER TABLE tickets ADD COLUMN embedding vector(768) GENERATED ALWAYS AS (embedding('text-embedding-005',description)) STORED;
现在,您可以查询数据库以验证其是否已准备就绪。
SELECT * FROM tickets;
您应该会看到返回的 10 行内容,如下所示:
现在,您可以开始进入有趣的环节了,那就是编码!
4. Python 项目设置
在深入了解如何构建代理之前,我们必须确保已正确设置 Python 项目。我们将在 Cloud Shell 中完成所有操作!
首先,创建一个 quantum-roast
文件夹,然后通过 cd
命令进入该文件夹:
mkdir quantum-roast && cd quantum-roast
现在,我们已经为项目创建了一个文件夹,接下来可以初始化项目并创建所需的相关文件了。
我们将使用 uv
(Python 的极速软件包和项目管理器),该工具已预安装在 Cloud Shell 中,用于管理我们的项目和依赖项。Uv 将帮助我们设置一些文件,并管理虚拟环境、依赖项等,这样我们就无需执行这些操作了!
使用 uv init
初始化新项目:
uv init --description "QuantumRoast Software Bug Assistant with ADK" --bare --python 3.10
运行该命令后,我们应该会获得项目的 pyproject.toml
文件。如需验证,请在 Cloud Shell 终端中运行 cat pyproject.toml
:
cat pyproject.toml
您应该会看到以下输出:
[project] name = "quantum-roast" version = "0.1.0" description = "QuantumRoast Software Bug Assistant with ADK" requires-python = ">=3.10" dependencies = []
现在,我们使用 uv add
将 google-adk
(ADK) 作为依赖项添加到项目中。
uv add google-adk==1.11.0
这会将 google-adk
添加到我们 pyproject.toml
中的 dependencies
列表中。
ADK 需要特定的项目结构才能实现最佳效果。
quantum-roast/ software_bug_assistant/ __init__.py agent.py .env
创建 software_bug_assistant
文件夹及其中的文件:
mkdir software_bug_assistant && touch software_bug_assistant/__init__.py \
software_bug_assistant/agent.py \
software_bug_assistant/tools.py \
software_bug_assistant/.env
使用 ls
验证文件的创建:
ls -a software_bug_assistant/
您应该会看到以下内容:
__init__.py . .. .env agent.py tools.py
现在,我们需要在 .env
文件中填充 ADK 正确调用 Gemini 模型所需的环境变量。我们将通过 Vertex API 访问 Gemini。
echo "GOOGLE_GENAI_USE_VERTEXAI=TRUE" >> software_bug_assistant/.env \
&& echo "GOOGLE_CLOUD_PROJECT=$PROJECT_ID" >> software_bug_assistant/.env \
&& echo "GOOGLE_CLOUD_LOCATION=us-central1" >> software_bug_assistant/.env
如需验证 .env
是否已正确填充,请运行以下命令:
cat software_bug_assistant/.env
您应该会看到以下内容,其中 your-project-id
是您的项目 ID:
GOOGLE_GENAI_USE_VERTEXAI=TRUE GOOGLE_CLOUD_PROJECT=your-project-id GOOGLE_CLOUD_LOCATION=us-central1
现在,我们已准备好开始创建 ADK 代理。
5. 基础 ADK 智能体
让我们先设置一个基本的 ADK 代理,然后在本次研讨会期间逐步添加工具,打造一个强大的 bug 助理!
在 Cloud Shell Editor 中打开 agent.py
:
cloudshell edit software_bug_assistant/agent.py
将以下代码粘贴到 agent.py
中,然后保存文件 Ctrl + s
:
from google.adk.agents import Agent
# --- Agent Definition (model, instructions, tools) ---
root_agent = Agent(
model="gemini-2.5-flash",
name="software_assistant",
instruction="""
You are a skilled expert in triaging and debugging software issues for a
coffee machine company, QuantumRoast.
""",
tools=[],
)
通过启动 ADK 的开发界面 (adk web
) 运行新创建的智能体。使用 uv run
执行此操作会自动创建一个安装了 ADK 的虚拟环境。
uv run adk web --port 8080 --reload_agents
在控制台中,您应该会看到 ADK Web 服务器成功启动。
INFO: Started server process [1557] INFO: Waiting for application startup. +-----------------------------------------------------------------------------+ | ADK Web Server started | | | | For local testing, access at http://localhost:8080. | +-----------------------------------------------------------------------------+ INFO: Application startup complete. INFO: Uvicorn running on http://127.0.0.1:8080 (Press CTRL+C to quit)
打开 Cloud Shell 的网页预览,查看界面。
您应该会看到 ADK Web 界面。
不妨试试与 ADK 代理对话。
询问代理 What day is it today?
。
从回答中可以看出,该代理无法回答这个基本问题!请注意,LLM 是基于过往数据训练的隔离系统。它们无法实时了解近期发生的事件,甚至无法知道当前日期…除非您为它们提供工具!
现在,我们来实现 ADK 的第一种工具类型,即功能工具。
6. 函数工具
第一种也是最简单的 ADK 工具类型是函数工具。顾名思义,它是一个由代理调用的 Python 函数!
函数工具非常强大,因为您可以使用它为代理编写自定义代码,让代理将其作为工具来调用,例如执行计算、调用 API、查询数据库。这些函数可以是简单的函数,也可以是复杂的函数,完全取决于您。
在 QuantumRoast,我们希望定义一个基本函数来获取当前日期,以便稍后在本实验中处理“显示上周的 bug”或“今天是什么日期?”之类的查询。(我们所有人都会遇到这种情况)。
/software_bug_assistant
文件夹中的 tools.py
文件将用于整理我们在整个实验中构建的所有工具。
点击 +
图标,打开新终端。
现在,在新终端中,设置 PROJECT_ID
并打开 tools.py
:
cd quantum-roast
export PROJECT_ID=$(gcloud config get project)
cloudshell edit software_bug_assistant/tools.py
现在,定义将用作函数工具的 get_current_date
函数。
from datetime import datetime
# ----- Example of a Function tool -----
def get_current_date() -> dict:
"""
Get the current date in the format YYYY-MM-DD
"""
return {"current_date": datetime.now().strftime("%Y-%m-%d")}
该函数现已定义!现在,是时候将其作为工具传递给客服人员了。
在 Cloud Shell Editor 中打开 agent.py
:
cloudshell edit software_bug_assistant/agent.py
我们希望从 tools.py
中导入 get_current_date
函数,并将该函数传递给代理的 tools
实参。
更新后的 agent.py
如下所示:
from google.adk.agents import Agent
from .tools import get_current_date
# --- Agent Definition (model, instructions, tools) ---
root_agent = Agent(
model="gemini-2.5-flash",
name="software_assistant",
instruction="""
You are a skilled expert in triaging and debugging software issues for a
coffee machine company, QuantumRoast.
""",
tools=[get_current_date],
)
现在,如果您返回到运行 ADK Web 界面的“网页预览”标签页,并再次询问 What day is it today?
...
智能体可以通过调用 get_current_date
函数工具成功告知日期!🎉
接下来,我们来探索下一个 ADK 工具类型。
7. 内置工具
另一种类型的 ADK 工具是内置工具。这些工具可与 Google 的旗舰模型功能搭配使用,例如在模型本身内进行代码执行。我们可以将 Google 搜索内置工具附加到 bug 助理代理,让代理能够访问网络,从而根据相关背景信息做出回答。这样,智能体就可以收集有关 bug 或已知漏洞的最新信息。
打开 tools.py
文件,以添加对 Google 搜索内置工具的支持。
cloudshell edit software_bug_assistant/tools.py
将以下内容添加到 tools.py
的底部:
# ----- Built-in Tool Imports -----
from google.adk.agents import Agent
from google.adk.tools import google_search
from google.adk.tools.agent_tool import AgentTool
# ----- Example of a Built-in Tool -----
search_agent = Agent(
model="gemini-2.5-flash",
name="search_agent",
description="A specialist in Google Search.",
instruction="""
You're a specialist in Google Search.
""",
tools=[google_search],
)
search_tool = AgentTool(search_agent)
在这里,我们实际上是将 Google 搜索工具封装在具有自己系统指令的智能体中,从而有效地将智能体用作工具。
现在,我们可以导入 search_tool
并将其传递给 agent.py
中的根代理:
cloudshell edit software_bug_assistant/agent.py
您可以将 agent.py
替换为以下代码,以包含 search_tool
:
from google.adk.agents import Agent
from .tools import get_current_date, search_tool
# --- Agent Definition (model, instructions, tools) ---
root_agent = Agent(
model="gemini-2.5-flash",
name="software_assistant",
instruction="""
You are a skilled expert in triaging and debugging software issues for a
coffee machine company, QuantumRoast.
""",
tools=[get_current_date, search_tool],
)
保存该文件,然后返回到运行 ADK Web 界面的打开状态。
QuantumRoast 希望确保我们的网站和软件免受常见漏洞和披露 (CVE) 的侵害,这些都是公开的网络安全漏洞。我们可以使用代理的新 Google 搜索工具在网络上搜索最新发现的 CVE。
运行以下查询:Do a web search for 5 of the most recent CVEs?
。
我们的代理应调用 search_agent
来搜索网页。
我们的代理现已成功解锁通过 ADK 的 内置工具进行 网络搜索的功能!🎉
接下来介绍另一种 ADK 工具类型。
8. 第三方工具
ADK 具有高度可扩展性,可让您无缝集成 CrewAI 和 LangChain 等其他第三方 AI 智能体框架中的工具。这种互操作性至关重要,因为它可以缩短开发时间,并能够重复使用现有工具。
为了将我们的 bug 代理接入 StackOverflow 强大的问答数据,我们可以从 LangChain 的广泛工具库中提取数据,具体来说,就是 StackExchange API 封装容器工具。ADK 支持 LangChain 等第三方工具,因此只需几行代码即可将此工具添加到我们的 ADK 代理中!
首先,我们必须为 LangChain 和 StackOverflow(langchain-community
和 stackapi
)向项目添加新的依赖项:
uv add langchain-community==0.3.27 stackapi==0.3.1
打开 tools.py
文件,以添加对 LangChain StackExchange 工具的支持。
cloudshell edit software_bug_assistant/tools.py
将以下内容添加到 tools.py
的底部:
# ----- Example of a Third-Party Tool -----
from google.adk.tools.langchain_tool import LangchainTool
from langchain_community.tools import StackExchangeTool
from langchain_community.utilities import StackExchangeAPIWrapper
stack_exchange_tool = StackExchangeTool(api_wrapper=StackExchangeAPIWrapper())
langchain_tool = LangchainTool(stack_exchange_tool)
现在,我们可以导入 langchain_tool
并将其传递给 agent.py
中的根代理:
cloudshell edit software_bug_assistant/agent.py
您可以将 agent.py
替换为以下代码,以包含 langchain_tool
:
from google.adk.agents import Agent
from .tools import get_current_date, langchain_tool, search_tool
# --- Agent Definition (model, instructions, tools) ---
root_agent = Agent(
model="gemini-2.5-flash",
name="software_assistant",
instruction="""
You are a skilled expert in triaging and debugging software issues for a
coffee machine company, QuantumRoast.
""",
tools=[get_current_date, search_tool, langchain_tool],
)
保存文件,然后返回到打开的 ADK Web 界面标签页。
您可以尝试向代理询问有关之前 CVE 的问题 "Are there similar issues on stack exchange?"
,也可以询问一些新问题,例如 "Our database queries with SQLAlchemy seem to be timing out, is there anything on StackExchange relevant to this?"
。
我们的代理现已成功利用 ADK 中的 LangChain 工具查询 StackOverflow。🥳
接下来该介绍哪种 ADK 工具类型了呢?MCP 工具!
9. MCP 工具(数据库)
MCP 是 Model Context Protocol 的缩写。它是 Anthropic 于 2024 年推出的开放协议。MCP 在 AI 代理与工具“后端”(API、数据库)之间提供了一个抽象层。
MCP 有一些独特的规范。与标准 HTTP 不同,MCP 在客户端和服务器之间提供有状态的双向连接。它有自己的方式来定义工具和特定于工具的错误消息。工具提供商随后可以在其 API 的基础上构建 MCP 服务器,从而为开发者和用户提供一个或多个预建工具。然后,代理框架可以在代理应用内初始化 MCP 客户端,以发现和调用这些工具。
在 QuantumRoast,我们有一个 Cloud SQL for PostgreSQL 数据库,用于存储内部软件 bug。我们希望创建 ADK 工具,以便我们的代理可以对数据库执行某些查询。
最简单的方法是使用 MCP Toolbox for Databases,这是一个面向数据库的开源 MCP 服务器!Toolbox 支持 15 多个数据库,其中包括 Cloud SQL!
工具箱提供:
- 简化开发:只需不到 10 行代码即可将工具集成到代理中,在多个代理或框架之间重复使用工具,并更轻松地部署新版工具。
- 更出色的性能:连接池、身份验证等最佳实践。
- 增强的安全性:集成式身份验证,可更安全地访问您的数据
- 端到端可观测性:开箱即用的指标和跟踪功能,内置对 OpenTelemetry 的支持。
ADK 支持 MCP Toolbox for Database 工具,可实现快速集成。
将 MCP Toolbox for Databases 服务器部署到 Cloud Run
首先,我们将 MCP Toolbox for Databases Server 部署到 Cloud Run,并将其指向我们的 Cloud SQL 实例。
该工具箱需要一个 YAML 文件进行配置,您可以在其中概述数据库来源和要配置的工具。
为部署创建 tools.yaml
文件。
cloudshell edit tools.yaml
将以下内容粘贴到 tools.yaml
中:
sources:
postgresql:
kind: cloud-sql-postgres
project: ${PROJECT_ID}
region: us-central1
instance: software-assistant
database: tickets-db
user: postgres
password: admin
tools:
search-tickets:
kind: postgres-sql
source: postgresql
description: Search for similar tickets based on their descriptions.
parameters:
- name: query
type: string
description: The query to perform vector search with.
statement: |
SELECT ticket_id, title, description, assignee, priority, status, (embedding <=> embedding('text-embedding-005', $1)::vector) as distance
FROM tickets
ORDER BY distance ASC
LIMIT 3;
get-ticket-by-id:
kind: postgres-sql
source: postgresql
description: Retrieve a ticket's details using its unique ID.
parameters:
- name: ticket_id
type: string
description: The unique ID of the ticket.
statement: SELECT * FROM tickets WHERE ticket_id = $1;
get-tickets-by-assignee:
kind: postgres-sql
source: postgresql
description: Search for tickets based on assignee (email).
parameters:
- name: assignee
type: string
description: The email of the assignee.
statement: SELECT * FROM tickets WHERE assignee ILIKE '%' || $1 || '%';
update-ticket-priority:
kind: postgres-sql
source: postgresql
description: Update the priority of a ticket based on its ID.
parameters:
- name: priority
type: string
description: The priority of the ticket. Can be one of 'P0 - Critical', 'P1 - High', 'P2 - Medium', or 'P3 - Low'.
- name: ticket_id
type: string
description: The ID of the ticket.
statement: UPDATE tickets SET priority = $1 WHERE ticket_id = $2;
update-ticket-status:
kind: postgres-sql
source: postgresql
description: Update the status of a ticket based on its ID.
parameters:
- name: status
type: string
description: The new status of the ticket (e.g., 'Open', 'In Progress', 'Closed', 'Resolved').
- name: ticket_id
type: string
description: The ID of the ticket.
statement: UPDATE tickets SET status = $1 WHERE ticket_id = $2;
get-tickets-by-status:
kind: postgres-sql
source: postgresql
description: Search for tickets based on their current status.
parameters:
- name: status
type: string
description: The status of the tickets to retrieve (e.g., 'Open', 'In Progress', 'Closed', 'Resolved').
statement: SELECT * FROM tickets WHERE status ILIKE '%' || $1 || '%';
get-tickets-by-priority:
kind: postgres-sql
source: postgresql
description: Search for tickets based on their priority.
parameters:
- name: priority
type: string
description: The priority of the tickets to retrieve (e.g., 'P0 - Critical', 'P1 - High', 'P2 - Medium', 'P3 - Low').
statement: SELECT * FROM tickets WHERE priority ILIKE '%' || $1 || '%';
create-new-ticket:
kind: postgres-sql
source: postgresql
description: Create a new software ticket.
parameters:
- name: title
type: string
description: The title of the new ticket.
- name: description
type: string
description: A detailed description of the bug or issue.
- name: assignee
type: string
description: (Optional) The email of the person to whom the ticket should be assigned.
- name: priority
type: string
description: (Optional) The priority of the ticket. Can be 'P0 - Critical', 'P1 - High', 'P2 - Medium', or 'P3 - Low'. Default is 'P3 - Low'.
- name: status
type: string
description: (Optional) The initial status of the ticket. Default is 'Open'.
statement: INSERT INTO tickets (title, description, assignee, priority, status) VALUES ($1, $2, $3, COALESCE($4, 'P3 - Low'), COALESCE($5, 'Open')) RETURNING ticket_id;
get-tickets-by-date-range:
kind: postgres-sql
source: postgresql
description: Retrieve tickets created or updated within a specific date range.
parameters:
- name: start_date
type: string
description: The start date (inclusive) for the range (e.g., 'YYYY-MM-DD').
- name: end_date
type: string
description: The end date (inclusive) for the range (e.g., 'YYYY-MM-DD').
- name: date_field
type: string
description: The date field to filter by ('creation_time' or 'updated_time').
statement: SELECT * FROM tickets WHERE CASE WHEN $3 = 'creation_time' THEN creation_time ELSE updated_time END BETWEEN $1::timestamp AND $2::timestamp;
toolsets:
tickets_toolset:
- search-tickets
- get-ticket-by-id
- get-tickets-by-assignee
- get-tickets-by-status
- get-tickets-by-priority
- get-tickets-by-date-range
- update-ticket-priority
- update-ticket-status
- create-new-ticket
该 YAML 文件定义了与 QuantumRoast 支持请求数据库相关的 9 个工具。
现在,我们需要为 Toolbox Cloud Run 服务配置服务账号,向其授予访问 Cloud SQL 和 Secret Manager 的权限,并为 tools.yaml
文件创建 Secret Manager Secret。
我们将把 tools.yaml
文件存储在 Secret Manager 中,因为它包含敏感的 Cloud SQL 凭据。
gcloud iam service-accounts create toolbox-identity
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member serviceAccount:toolbox-identity@$PROJECT_ID.iam.gserviceaccount.com \
--role roles/secretmanager.secretAccessor
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member serviceAccount:toolbox-identity@$PROJECT_ID.iam.gserviceaccount.com \
--role roles/cloudsql.client
gcloud secrets create tools --data-file=tools.yaml
现在,将 MCP Toolbox for Databases 部署到 Cloud Run。我们将使用 MCP Toolbox 容器映像的最新发布版本。
gcloud run deploy toolbox \
--image us-central1-docker.pkg.dev/database-toolbox/toolbox/toolbox:latest \
--service-account toolbox-identity \
--region us-central1 \
--set-secrets "/app/tools.yaml=tools:latest" \
--set-env-vars="PROJECT_ID=$PROJECT_ID" \
--args="--tools-file=/app/tools.yaml","--address=0.0.0.0","--port=8080" \
--allow-unauthenticated
等待部署完成…
通过查询 Cloud Run 日志,验证 Toolbox 是否正在运行:
gcloud run services logs read toolbox --region us-central1 --limit 10
您应该会看到:
2025-08-20 18:03:55 2025-08-20T18:03:55.465847801Z INFO "Initialized 1 sources." 2025-08-20 18:03:55 2025-08-20T18:03:55.466152914Z INFO "Initialized 0 authServices." 2025-08-20 18:03:55 2025-08-20T18:03:55.466374245Z INFO "Initialized 9 tools." 2025-08-20 18:03:55 2025-08-20T18:03:55.466477938Z INFO "Initialized 2 toolsets." 2025-08-20 18:03:55 2025-08-20T18:03:55.467492303Z INFO "Server ready to serve!"
将 Toolbox 服务的 Cloud Run 网址保存为环境变量,以便 ADK 代理知道在哪里找到它。
export MCP_TOOLBOX_URL=$(gcloud run services describe toolbox --region us-central1 --format "value(status.url)")
echo MCP_TOOLBOX_URL=$MCP_TOOLBOX_URL >> software_bug_assistant/.env
更新 QuantumRoast 代理
其次,我们必须将 MCP Toolbox for Databases SDK (toolbox-core
) 的依赖项添加到我们的项目中:
uv add toolbox-core==0.5.0
打开 tools.py
文件,以添加对 MCP Toolbox 工具的支持。
cloudshell edit software_bug_assistant/tools.py
将以下内容添加到 tools.py
的底部:
# ----- Example MCP Toolbox for Databases tools -----
import os
from toolbox_core import ToolboxSyncClient
TOOLBOX_URL = os.getenv("MCP_TOOLBOX_URL", "http://127.0.0.1:5000")
# Initialize Toolbox client
toolbox = ToolboxSyncClient(TOOLBOX_URL)
# Load all the tools from toolset
toolbox_tools = toolbox.load_toolset("tickets_toolset")
现在,我们可以导入 toolbox_tools
并将其传递给 agent.py
中的根代理:
cloudshell edit software_bug_assistant/agent.py
您可以将 agent.py
替换为以下代码,以包含 toolbox_tools
:
from google.adk.agents import Agent
from .tools import get_current_date, langchain_tool, search_tool, toolbox_tools
# --- Agent Definition (model, instructions, tools) ---
root_agent = Agent(
model="gemini-2.5-flash",
name="software_assistant",
instruction="""
You are a skilled expert in triaging and debugging software issues for a
coffee machine company, QuantumRoast.
""",
tools=[get_current_date, search_tool, langchain_tool, *toolbox_tools],
)
保存文件,然后返回到打开的 ADK Web 界面标签页。
现在,您可以询问有关存储在 Cloud SQL 内部工单数据库中的工单的问题了!
提出如下问题:
I am seeing an issue with database timeouts, has anyone else seen a similar issue?
How many bugs are assigned to samuel.green@example.com? Show a table.
Can you bump the priority of ticket with ID 6 to to P0 - Critical priority
Create a new ticket
(让代理引导您完成 bug 创建流程)
我们的 ADK 代理现已成功通过 MCP Toolbox for Databases 工具查询数据库!🚀
10. 可选:MCP 工具 (API)
如果 MCP 工具没有自己的 SDK(例如 MCP Toolbox for Database),我们该如何将 ADK 代理连接到这些工具?
ADK 通过其 MCPToolset
类支持通用 MCP 工具。MCPToolset
类是 ADK 用于集成 MCP 服务器中的工具的主要机制。
MCPToolset
可用于连接到本地或远程 MCP 服务器,而在 QuantumRoast,我们希望将代理连接到 GitHub 的远程 MCP 服务器,以便轻松调用 GitHub 的 API。这样一来,我们的代理就可以从公共软件代码库甚至我们自己的代码库中提取有关问题的信息。GitHub MCP 服务器公开了 GitHub 功能的不同部分,从问题和拉取请求到通知和代码安全性。
GitHub 个人访问令牌 (PAT)
如需向 GitHub MCP 服务器进行身份验证,您需要 GitHub 个人访问令牌。
如需获取此卡,请按以下步骤操作:
- 前往 GitHub 开发者设置。
- 依次点击“个人访问令牌”和“令牌(经典版)”。
- 依次点击“生成新令牌” ->“生成新令牌(旧版)”。
- 为您的令牌指定一个描述性名称。
- 为令牌设置失效日期。
- 重要提示:出于安全考虑,请为您的令牌授予必要的最小范围。对于对代码库的只读访问权限,
repo:status
、public_repo
和read:user
范围通常就足够了。除非绝对必要,否则请避免授予完整的代码库或管理员权限。 - 点击
Generate token
。 - 复制生成的令牌。
在 Cloud Shell 终端中,运行以下命令以设置 GitHub PAT,以便代理能够使用。将 YOUR_GITHUB_PAT
替换为您生成的 PAT。
export GITHUB_PAT=YOUR_GITHUB_PAT
更新 QuantumRoast 代理
对于我们的 bug 助理,我们将仅公开一些只读 GitHub 工具,以便 QuantumRoast 员工查找与开源依赖项相关的问题,看看这是否有助于找出他们在内部工单系统中发现的 bug 的根本原因。我们将使用 ADK 的 MCPToolset
和 tool_filter
来进行设置。tool-filter
仅公开我们需要的 GitHub 工具,这不仅隐藏了我们不希望用户访问的工具(例如:敏感的代码库操作),还可防止代理的模型在尝试选择合适的工具来完成任务时不堪重负。
打开 tools.py
文件,以添加对 GitHub 工具的支持。
cloudshell edit software_bug_assistant/tools.py
将以下内容添加到 tools.py
的底部:
# ----- Example MCP Tools with MCPToolset (GitHub) -----
from google.adk.tools.mcp_tool import MCPToolset, StreamableHTTPConnectionParams
mcp_tools = MCPToolset(
connection_params=StreamableHTTPConnectionParams(
url="https://api.githubcopilot.com/mcp/",
headers={
"Authorization": "Bearer " + os.getenv("GITHUB_PAT"),
},
),
# Read only tools
tool_filter=[
"search_repositories",
"search_issues",
"list_issues",
"get_issue",
"list_pull_requests",
"get_pull_request",
],
)
请注意,我们还需要向 MCPToolset
定义提供 GitHub 个人访问令牌 (PAT),就像在代码中设置标准 API 客户端时提供身份验证令牌一样。此 PAT 的范围仅限于访问公开代码库数据,不包含与敏感用户或代码库操作相关的范围。
现在,我们可以导入 mcp_tools
并将其传递给 agent.py
中的根代理:
cloudshell edit software_bug_assistant/agent.py
您可以将 agent.py
替换为以下代码,以包含 mcp_tools
:
from google.adk.agents import Agent
from .tools import get_current_date, langchain_tool, mcp_tools, search_tool, toolbox_tools
# --- Agent Definition (model, instructions, tools) ---
root_agent = Agent(
model="gemini-2.5-flash",
name="software_assistant",
instruction="""
You are a skilled expert in triaging and debugging software issues for a
coffee machine company, QuantumRoast.
""",
tools=[get_current_date, search_tool, langchain_tool, *toolbox_tools, mcp_tools],
)
保存文件,然后返回到打开的 ADK Web 界面标签页。
现在,我们有一组代理可以调用的 GitHub MCP 工具。QuantumRoast 的服务依赖于 XZ utils(一种数据压缩工具)。我们的内部 bug 工单系统正在跟踪去年发现的 CVE(安全漏洞),我们可以使用 StackOverflow 和 Google 搜索工具追溯到 XZ Utils GitHub 代码库。然后,我们可以使用 GitHub 的 MCP 工具之一 search_issues
来确定该 CVE 的修补时间和方式:
向代理提出以下问题:
Find the official XZ Utils GitHub repository
Search the repository for issues related to CVE-2024-3094
您应该会看到代理正在调用 GitHub 工具。
QuantumRoast ADK 代理现已能够与 GitHub MCP 服务器工具互动!🤩
11. 恭喜
恭喜!您已使用智能体开发套件 (ADK) 成功构建 QuantumRoast bug 助理智能体,并集成了各种工具类型来增强其功能。您从基本智能体开始,逐步添加了函数工具、内置工具、第三方工具和 MCP 工具。
所学内容
- 如何设置 Python 项目以进行 ADK 开发。
- 如何创建基本的 ADK 代理。
- 如何实现和使用函数工具。
- 如何集成 Google 搜索等内置工具。
- 如何在 ADK 中利用 LangChain 等框架中的第三方工具。
- 如何使用 MCP 工具与数据库 (Cloud SQL) 和 API 进行交互。
清理
您可以删除 Cloud 项目,以避免产生额外费用。
虽然 Cloud Run 不会对未在使用中的服务计费,但您可能仍然需要支付将容器映像存储在 Artifact Registry 中而产生的相关费用。删除 Cloud 项目后,系统即会停止对该项目中使用的所有资源计费。
如果您愿意,可以删除项目:
gcloud projects delete $GOOGLE_CLOUD_PROJECT
您可能还需要从 Cloud Shell 磁盘中删除不必要的资源。您可以:
- 删除 Codelab 项目目录:
rm -rf ~/quantum-roast
- 警告!接下来要执行的操作无法撤消!如果您想删除 Cloud Shell 中的所有内容以释放空间,可以删除整个主目录。请务必将要保留的所有内容保存到其他位置。
sudo rm -rf $HOME