1. 简介
本实验重点介绍客户端代理服务的实现和部署。您将使用智能体开发套件 (ADK) 构建一个使用远程工具(例如在实验 1 中创建的 MCP 服务器)的 AI 智能体。所展示的关键架构原则是关注点分离,即通过安全 API 使不同的推理层(智能体)与不同的工具层(MCP 服务器)进行通信。
在实验 1 中,您创建了一个 MCP 服务器,该服务器可向 LLM 提供有关虚构动物园中动物的数据,例如在使用 Gemini CLI 时。在本实验中,我们将为虚构的动物园构建一个导游代理。代理将使用实验 1 中的同一 MCP 服务器来访问有关动物园动物的详细信息,并使用维基百科来打造最佳导游体验。
最后,我们将导游代理部署到 Google Cloud Run,以便所有动物园游客都可以访问它,而不仅仅是在本地运行。
前提条件
- Cloud Run 上正在运行的 MCP 服务器或其关联的服务网址。
- 启用了结算功能的 Google Cloud 项目。
学习内容
- 如何构建 Python 项目以进行 ADK 部署。
- 如何使用 google-adk 实现使用工具的代理。
- 如何将代理连接到远程 MCP 服务器以获取其工具集。
- 如何将 Python 应用作为无服务器容器部署到 Cloud Run。
- 如何使用 IAM 角色配置安全的服务到服务身份验证。
- 如何删除 Cloud 资源,以避免日后产生费用。
所需条件
- Google Cloud 账号和 Google Cloud 项目
- 网络浏览器,例如 Chrome
2. 为何要部署到 Cloud Run?
Cloud Run 是托管 ADK 代理的绝佳选择,因为它是一个无服务器平台,这意味着您可以专注于代码,而无需管理底层基础设施。我们会为您处理运营工作。
您可以将其视为一家快闪店:只有在客户(请求)到来时才会开门营业并使用资源。如果没有客户,它会完全关闭,您无需为空店支付费用。
主要功能
在任何位置运行容器:
- 您提供包含应用的容器 (Docker 映像)。
- Cloud Run 会在 Google 的基础设施上运行该容器。
- 无需进行操作系统修补、虚拟机设置或扩展,省心省力。
自动扩缩:
- 如果无人使用您的应用 → 运行 0 个实例(空闲时您无需付费)。
- 如果有 1,000 个请求命中该函数 → 它会根据需要启动尽可能多的副本。
默认无状态:
- 每个请求都可以发送到不同的实例。
- 如果您需要存储状态,请使用 Cloud SQL、Firestore 或 Redis 等外部服务。
支持任何语言或框架:
- 只要在 Linux 容器中运行,Cloud Run 就不在乎它是 Python、Go、Node.js、Java 还是 .Net。
用多少,付多少:
- 按请求次数和计算时间(精确到 100 毫秒)结算。
- 您无需像使用传统虚拟机那样为闲置资源付费。
3. 设置和要求
自定进度的环境设置
- 登录 Google Cloud 控制台,然后创建一个新项目或重复使用现有项目。如果您还没有 Gmail 或 Google Workspace 账号,则必须创建一个。
- 项目名称是此项目参与者的显示名称。它是 Google API 尚未使用的字符串。您可以随时对其进行更新。
- 项目 ID 在所有 Google Cloud 项目中是唯一的,并且是不可变的(一经设置便无法更改)。Cloud 控制台会自动生成一个唯一字符串;通常情况下,您无需关注该字符串。在大多数 Codelab 中,您都需要引用项目 ID(通常用
PROJECT_ID
标识)。如果您不喜欢生成的 ID,可以再随机生成一个 ID。或者,您也可以尝试自己的项目 ID,看看是否可用。完成此步骤后便无法更改该 ID,并且此 ID 在项目期间会一直保留。 - 此外,还有第三个值,即部分 API 使用的项目编号,供您参考。如需详细了解所有这三个值,请参阅文档。
- 接下来,您需要在 Cloud 控制台中启用结算功能,以便使用 Cloud 资源/API。运行此 Codelab 应该不会产生太多的费用(如果有的话)。若要关闭资源以避免产生超出本教程范围的结算费用,您可以删除自己创建的资源或删除项目。Google Cloud 新用户符合参与 300 美元免费试用计划的条件。
启动 Cloud Shell
前往 Cloud Shell 编辑器
如果终端未显示在屏幕底部,请打开它:
- 点击终端
- 点击 New Terminal
在终端中,使用以下命令设置项目。如果您已完成实验 1,请确保您使用的是相同的项目 ID:
gcloud config set project [YOUR-PROJECT-ID]
如果您不记得项目 ID,可以使用以下命令列出所有项目 ID:
gcloud projects list | awk '/PROJECT_ID/{print $2}'
4. 如果系统提示您进行授权,请点击授权继续。
5. 您应会看到以下消息:
Updated property [core/project].
If you see a `WARNING` and are asked `Do you want to continue (Y/n)?`,
then you have likely entered the project ID incorrectly. Press `n`,
press `Enter`, and try to run the `gcloud config set project` command again.
4. 准备工作
启用 API 并设置环境变量
启用所有必要的服务:
gcloud services enable \
run.googleapis.com \
artifactregistry.googleapis.com \
cloudbuild.googleapis.com \
aiplatform.googleapis.com \
compute.googleapis.com
预期输出
Operation "operations/acat.p2-[GUID]" finished successfully.
配置默认区域以使用 Vertex AI 嵌入模型。详细了解 Vertex AI 的可用位置。在本示例中,我们使用的是 europe-west1 区域。
gcloud config set compute/region europe-west1
5. 下载并安装 ADK,然后创建项目文件夹
创建项目目录。
此命令会为代理的源代码创建实验主文件夹。
cd && mkdir zoo_guide_agent && cd zoo_guide_agent
创建虚拟环境。
python3 -m venv .venv
激活虚拟环境
source .venv/bin/activate
创建 requirements.txt
文件。此文件列出了您的代理所需的 Python 库。以下命令会创建该文件并填充内容。
cloudshell edit requirements.txt
google-adk==1.12.0
langchain-community
wikipedia
您应从主项目目录 zoo_guide_agent
运行该命令。
pip install -r requirements.txt
为当前项目、区域和用户设置变量。这是运行这些命令的更稳健的方式。
export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_REGION=$(gcloud config get-value compute/region)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")
export SERVICE_ACCOUNT="${PROJECT_NUMBER}-compute@developer.gserviceaccount.com"
创建并打开 .env
文件,以对 zoo_guide_agent
目录中的代理进行身份验证。
cloudshell edit .env
cloudshell edit 命令会在终端上方的编辑器中打开 .env
文件。在 .env
文件中输入以下内容,然后返回到终端。
MODEL="gemini-2.5-flash"
SERVICE_ACCOUNT="${PROJECT_NUMBER}-compute@developer.gserviceaccount.com"
添加 MCP 服务器网址。如果您已完成实验 1,请按照以下步骤使用您在实验 1 中创建的 MCP 服务器:
- 向 Cloud Run 服务身份授予调用远程 MCP 服务器的权限
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT" \
--role="roles/run.invoker"
- 将实验 1 中的 MCP 服务器网址保存到环境变量中。
echo -e "\nMCP_SERVER_URL=https://zoo-mcp-server-${PROJECT_NUMBER}.europe-west1.run.app/mcp/" >> .env
如果您使用的是公共 MCP 服务器链接,请运行以下命令,并将 PROJECT_NUMBER
替换为提供的链接。
echo -e "\nMCP_SERVER_URL=https://zoo-mcp-server-${PROJECT_NUMBER}.europe-west1.run.app/mcp/" >> .env
6. 创建代理工作流
创建 init.py 文件
创建 init.py 文件。此文件会告知 Python zoo_guide_agent 目录是一个软件包。
cloudshell edit __init__.py
上述命令会打开代码编辑器。将以下代码添加到 __init__.py
:
from . import agent
创建 main agent.py 文件
创建主 agent.py 文件。此命令会创建 Python 文件,并将多代理系统的完整代码粘贴到其中。
cloudshell edit agent.py
第 1 步:导入和初始设置
第一个代码块会从 ADK 和 Google Cloud 中引入所有必需的库。它还会设置日志记录并从 .env
文件中加载环境变量,这对于访问模型和服务器网址至关重要。
将以下代码添加到您的 agent.py 文件中:
import os
import logging
import google.cloud.logging
from dotenv import load_dotenv
from google.adk import Agent
from google.adk.agents import SequentialAgent
from google.adk.tools.mcp_tool.mcp_toolset import MCPToolset, StreamableHTTPConnectionParams
from google.adk.tools.tool_context import ToolContext
from google.adk.tools.langchain_tool import LangchainTool
from langchain_community.tools import WikipediaQueryRun
from langchain_community.utilities import WikipediaAPIWrapper
import google.auth
import google.auth.transport.requests
import google.oauth2.id_token
# --- Setup Logging and Environment ---
cloud_logging_client = google.cloud.logging.Client()
cloud_logging_client.setup_logging()
load_dotenv()
model_name = os.getenv("MODEL")
第 2 步: 定义工具(代理的功能)
智能体的能力取决于其可使用的工具。在此部分中,我们将定义代理将具备的所有功能,包括用于保存数据的自定义函数、连接到安全 MCP 服务器的 MCP 工具以及 Wikipedia 工具。
将以下代码添加到 agent.py 的底部:
# Greet user and save their prompt
def add_prompt_to_state(
tool_context: ToolContext, prompt: str
) -> dict[str, str]:
"""Saves the user's initial prompt to the state."""
tool_context.state["PROMPT"] = prompt
logging.info(f"[State updated] Added to PROMPT: {prompt}")
return {"status": "success"}
# Configuring the MCP Tool to connect to the Zoo MCP server
mcp_server_url = os.getenv("MCP_SERVER_URL")
if not mcp_server_url:
raise ValueError("The environment variable MCP_SERVER_URL is not set.")
def get_id_token():
"""Get an ID token to authenticate with the MCP server."""
target_url = os.getenv("MCP_SERVER_URL")
audience = target_url.split('/mcp/')[0]
request = google.auth.transport.requests.Request()
id_token = google.oauth2.id_token.fetch_id_token(request, audience)
return id_token
"""
# Use this code if you are using the public MCP Server and comment out the code below defining mcp_tools
mcp_tools = MCPToolset(
connection_params=StreamableHTTPConnectionParams(
url=mcp_server_url
)
)
"""
mcp_tools = MCPToolset(
connection_params=StreamableHTTPConnectionParams(
url=mcp_server_url,
headers={
"Authorization": f"Bearer {get_id_token()}",
},
),
)
# Configuring the Wikipedia Tool
wikipedia_tool = LangchainTool(
tool=WikipediaQueryRun(api_wrapper=WikipediaAPIWrapper())
)
这三款工具的说明
add_prompt_to_state
📝
此工具会记住动物园游客提出的问题。当访问者问“狮子在哪里?”时,此工具会将该具体问题保存到代理的记忆中,以便工作流程中的其他代理知道要研究什么。
方式:这是一个 Python 函数,用于将访问者的提示写入共享的 tool_context.state
字典。此工具上下文表示代理在单次对话中的短期记忆。一个代理保存到状态的数据可以由工作流中的下一个代理读取。
MCPToolset
🦁
用于将导游代理连接到在实验 1 中创建的动物园 MCP 服务器。此服务器具有一些特殊工具,可用于查找有关我们动物的具体信息,例如它们的名称、年龄和围栏。
方式:安全地连接到动物园的私有服务器网址。它使用 get_id_token
自动获取安全的“钥匙卡”(服务账号 ID 令牌)来证明自己的身份并获得访问权限。
LangchainTool
🌍
这样一来,导游代理就能获得一般性的世界知识。当访客提出的问题不在动物园的数据库中时(例如“狮子在野外吃什么?”),此工具可让客服人员在维基百科上查找答案。
方式:它充当适配器,使我们的代理能够使用 LangChain 库中预构建的 WikipediaQueryRun 工具。
资源:
第 3 步:定义专家代理
接下来,我们将定义研究者代理和响应格式化程序代理。研究员代理是我们操作的“大脑”。此代理会从共享的 State
中获取用户提示,检查其强大的工具(动物园的 MCP 服务器工具和 Wikipedia 工具),并决定使用哪些工具来查找答案。
响应格式化代理的角色是呈现。它不使用任何工具来查找新信息。相反,它会获取 Researcher 代理收集的原始数据(通过 State 传递),并使用 LLM 的语言技能将其转换为友好、对话式的回答。
将以下代码添加到 agent.py
的底部:
# 1. Researcher Agent
comprehensive_researcher = Agent(
name="comprehensive_researcher",
model=model_name,
description="The primary researcher that can access both internal zoo data and external knowledge from Wikipedia.",
instruction="""
You are a helpful research assistant. Your goal is to fully answer the user's PROMPT.
You have access to two tools:
1. A tool for getting specific data about animals AT OUR ZOO (names, ages, locations).
2. A tool for searching Wikipedia for general knowledge (facts, lifespan, diet, habitat).
First, analyze the user's PROMPT.
- If the prompt can be answered by only one tool, use that tool.
- If the prompt is complex and requires information from both the zoo's database AND Wikipedia,
you MUST use both tools to gather all necessary information.
- Synthesize the results from the tool(s) you use into preliminary data outputs.
PROMPT:
{{ PROMPT }}
""",
tools=[
mcp_tools,
wikipedia_tool
],
output_key="research_data" # A key to store the combined findings
)
# 2. Response Formatter Agent
response_formatter = Agent(
name="response_formatter",
model=model_name,
description="Synthesizes all information into a friendly, readable response.",
instruction="""
You are the friendly voice of the Zoo Tour Guide. Your task is to take the
RESEARCH_DATA and present it to the user in a complete and helpful answer.
- First, present the specific information from the zoo (like names, ages, and where to find them).
- Then, add the interesting general facts from the research.
- If some information is missing, just present the information you have.
- Be conversational and engaging.
RESEARCH_DATA:
{{ research_data }}
"""
)
第 4 步:工作流智能体
工作流代理充当动物园游览的“后台”管理员。它会接收研究请求,并确保我们上面定义的两个代理按正确的顺序执行其工作:先研究,然后格式化。这样一来,回答访问者的问题就成了一个可预测且可靠的过程。
实现方式:它是一个 SequentialAgent
,一种不会自行思考的特殊类型的代理。它的唯一任务是按固定顺序运行 sub_agents
(研究员和格式化工具)列表,并自动将共享内存从一个传递到下一个。
将此代码块添加到 agent.py
的底部:
tour_guide_workflow = SequentialAgent(
name="tour_guide_workflow",
description="The main workflow for handling a user's request about an animal.",
sub_agents=[
comprehensive_researcher, # Step 1: Gather all data
response_formatter, # Step 2: Format the final response
]
)
最后一步:组装主工作流 
此代理被指定为 root_agent
,ADK 框架将其用作所有新对话的起点。其主要作用是编排整个流程。它充当初始控制器,管理对话的第一个回合。
将以下最后一个代码块添加到 agent.py
的底部:
root_agent = Agent(
name="greeter",
model=model_name,
description="The main entry point for the Zoo Tour Guide.",
instruction="""
- Let the user know you will help them learn about the animals we have in the zoo.
- When the user responds, use the 'add_prompt_to_state' tool to save their response.
After using the tool, transfer control to the 'tour_guide_workflow' agent.
""",
tools=[add_prompt_to_state],
sub_agents=[tour_guide_workflow]
)
您的 agent.py
文件现已完成!通过这种构建方式,您可以了解每个组件(工具、工作器代理和管理器代理)在创建最终的智能系统中发挥的具体作用。接下来,我们来了解部署!
7. 准备应用以进行部署
准备好本地环境后,下一步是准备 Google Cloud 项目以进行部署。这包括对代理的文件结构进行最终检查,以确保其与部署命令兼容。更重要的是,您需要配置一项关键的 IAM 权限,以允许已部署的 Cloud Run 服务代表您调用 Vertex AI 模型。完成此步骤可确保云环境已准备就绪,能够成功运行您的代理。
运行 source 命令,将变量加载到您的 shell 会话中。
source .env
向服务账号授予 Vertex AI User 角色,使其有权进行预测和调用 Google 的模型。
# Grant the "Vertex AI User" role to your service account
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT" \
--role="roles/aiplatform.user"
8. 使用 ADK CLI 部署代理
本地代码准备就绪,Google Cloud 项目也已准备好,现在可以部署代理了。您将使用 adk deploy cloud_run
命令,这是一个可自动执行整个部署工作流的便捷工具。此单个命令会打包您的代码,构建容器映像,将其推送到 Artifact Registry,并在 Cloud Run 上启动服务,使其可通过网络访问。
创建 .gcloudignore 文件
为了缩短部署时间,我们希望创建一个 .gcloudignore
文件。为此,请运行以下命令。以下命令可用于部署代理。
cloudshell edit .gcloudignore
cloudshell edit 命令会在终端上方的编辑器中打开 .gcloudignore
文件。在文件中写入以下内容并保存。然后,返回到终端,运行下一部分中的部署命令。
.venv/
部署
运行以下命令以部署代理。
# Run the deployment command
adk deploy cloud_run \
--project=$PROJECT_ID \
--region=europe-west1 \
--service_name=zoo-tour-guide \
--with_ui \
.
gcloud run services update zoo-tour-guide \
--region=europe-west1 \
--update-labels=dev-tutorial=codelab-adk
接受提示
系统可能会提示您执行以下操作:
Deploying from source requires an Artifact Registry Docker repository to store built containers. A repository named [cloud-run-source-deploy] in region [europe-west1] will be created. Do you want to continue (Y/n)?
输入 Y,然后按 Enter 键。
系统可能会提示您执行以下操作:
Allow unauthenticated invocations to [your-service-name] (y/N)?.
在本实验中,我们希望允许未经身份验证的调用,以便轻松进行测试,因此请输入 y
并按 Enter 键。
获取部署链接
成功执行后,该命令将提供已部署的 Cloud Run 服务的网址。(该网址类似于 https://zoo-tour-guide-123456789.europe-west1.run.app)。复制此网址以供下一个任务使用。
9. 测试已部署的代理
现在,您的代理已在 Cloud Run 上线,接下来您将执行测试,以确认部署成功且代理运行正常。您将使用公共服务网址(例如 https://zoo-tour-guide-123456789.europe-west1.run.app/)访问 ADK 的 Web 界面并与代理互动。
在网络浏览器中打开公开的 Cloud Run 服务网址。由于您使用了 --with_ui flag
,因此您应该会看到 ADK 开发者界面。
开启右上角的 Token Streaming
。
您现在可以与 Zoo 代理互动了。
输入 hello
并按 Enter 键,即可开始新的对话。
观察结果。代理应快速做出响应,并发送问候语:
"Hello! I'm your Zoo Tour Guide. I can help you learn about the amazing animals we have here. What would you like to know or explore today?"
智能体流程说明
您的系统可作为智能多代理团队运行。整个流程由清晰的顺序管理,以确保从用户提出问题到最终获得详细解答的流程顺畅高效。
1. 动物园迎宾员(迎宾台)
整个流程从迎宾代理开始。
其作用:开始对话。其指令是问候用户,并询问用户想了解哪种动物。
其工具:当用户回复时,Greeter 会使用其 add_prompt_to_state 工具来捕获用户的确切措辞(例如,“告诉我有关狮子的信息”),并将其保存在系统内存中。
交接:保存提示后,它会立即将控制权传递给其子代理 tour_guide_workflow。
2. The Comprehensive Researcher(超级研究员)
这是主工作流中的第一步,也是操作的“大脑”。现在,您不再需要庞大的团队,只需一位技能娴熟的代理即可访问所有可用信息。
其工作:分析用户的问题并制定智能计划。它会利用语言模型强大的工具使用能力来决定是否需要:
- 动物园记录中的内部数据(通过 MCP 服务器)。
- 来自网络(通过 Wikipedia API)的常识。
- 或者,对于复杂的问题,两者都使用。
其操作:执行必要的工具来收集所有必需的原始数据。例如,如果被问到“我们动物园的狮子多大了?它们在野外吃什么?”,它会调用 MCP 服务器来获取年龄信息,并调用 Wikipedia 工具来获取饮食信息。
3. 响应格式化程序(演示器)
在 Comprehensive Researcher 收集完所有事实后,这是要运行的最后一个代理。
其工作:充当动物园导游的友好声音。它会获取原始数据(可能来自一个或两个来源)并对其进行润饰。
其操作:将所有信息整合为连贯且引人入胜的单个答案。按照其指令,它首先呈现具体的动物园信息,然后添加有趣的常规事实。
最终结果:此代理生成的文本是用户在聊天窗口中看到的完整详细的答案。
如果您有兴趣详细了解如何构建代理,请参阅以下资源:
10. 清理环境
gcloud run services delete zoo-tour-guide --region=europe-west1 --quiet
gcloud artifacts repositories delete cloud-run-source-deploy --location=europe-west1 --quiet
11. 恭喜
恭喜您完成此 Codelab。
所学内容
- 如何使用 ADK 命令行界面构建 Python 项目以进行部署。
- 如何使用 SequentialAgent 和 ParallelAgent 实现多代理工作流。
- 如何使用 MCPToolset 连接到远程 MCP 服务器以使用其工具。
- 如何通过集成 Wikipedia API 等外部工具来扩充内部数据。
- 如何使用 adk deploy 命令将代理部署为无服务器容器到 Cloud Run。
12. 调查问卷
输出如下: