将 Cloud Run 上的 MCP 服务器与 ADK 代理搭配使用

1. 简介

本实验重点介绍客户端代理服务的实现和部署。您将使用智能体开发套件 (ADK) 构建一个使用远程工具(例如在实验 1 中创建的 MCP 服务器)的 AI 智能体。所展示的关键架构原则是关注点分离,即通过安全 API 使不同的推理层(智能体)与不同的工具层(MCP 服务器)进行通信。

在实验 1 中,您创建了一个 MCP 服务器,该服务器可向 LLM 提供有关虚构动物园中动物的数据,例如在使用 Gemini CLI 时。在本实验中,我们将为虚构的动物园构建一个导游代理。代理将使用实验 1 中的同一 MCP 服务器来访问有关动物园动物的详细信息,并使用维基百科来打造最佳导游体验。

f8d4423edbfe993d.png

最后,我们将导游代理部署到 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. 设置和要求

自定进度的环境设置

  1. 登录 Google Cloud 控制台,然后创建一个新项目或重复使用现有项目。如果您还没有 Gmail 或 Google Workspace 账号,则必须创建一个

fbef9caa1602edd0.png

a99b7ace416376c4.png

5e3ff691252acf41.png

  • 项目名称是此项目参与者的显示名称。它是 Google API 尚未使用的字符串。您可以随时对其进行更新。
  • 项目 ID 在所有 Google Cloud 项目中是唯一的,并且是不可变的(一经设置便无法更改)。Cloud 控制台会自动生成一个唯一字符串;通常情况下,您无需关注该字符串。在大多数 Codelab 中,您都需要引用项目 ID(通常用 PROJECT_ID 标识)。如果您不喜欢生成的 ID,可以再随机生成一个 ID。或者,您也可以尝试自己的项目 ID,看看是否可用。完成此步骤后便无法更改该 ID,并且此 ID 在项目期间会一直保留。
  • 此外,还有第三个值,即部分 API 使用的项目编号,供您参考。如需详细了解所有这三个值,请参阅文档
  1. 接下来,您需要在 Cloud 控制台中启用结算功能,以便使用 Cloud 资源/API。运行此 Codelab 应该不会产生太多的费用(如果有的话)。若要关闭资源以避免产生超出本教程范围的结算费用,您可以删除自己创建的资源或删除项目。Google Cloud 新用户符合参与 300 美元免费试用计划的条件。

启动 Cloud Shell

如果终端未显示在屏幕底部,请打开它:

  • 点击终端
  • 点击 New Terminal

d32c46fffa0a30a5.png

在终端中,使用以下命令设置项目。如果您已完成实验 1,请确保您使用的是相同的项目 ID:

gcloud config set project [YOUR-PROJECT-ID]

如果您不记得项目 ID,可以使用以下命令列出所有项目 ID:

gcloud projects list | awk '/PROJECT_ID/{print $2}'

4. 如果系统提示您进行授权,请点击授权继续。

6356559df3eccdda.png

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 服务器:

  1. 向 Cloud Run 服务身份授予调用远程 MCP 服务器的权限
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT" \
  --role="roles/run.invoker"
  1. 将实验 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 步定义工具(代理的功能)

3eb9c6772576b906.jpeg

智能体的能力取决于其可使用的工具。在此部分中,我们将定义代理将具备的所有功能,包括用于保存数据的自定义函数、连接到安全 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())
)

这三款工具的说明

  1. add_prompt_to_state 📝

此工具会记住动物园游客提出的问题。当访问者问“狮子在哪里?”时,此工具会将该具体问题保存到代理的记忆中,以便工作流程中的其他代理知道要研究什么。

方式:这是一个 Python 函数,用于将访问者的提示写入共享的 tool_context.state 字典。此工具上下文表示代理在单次对话中的短期记忆。一个代理保存到状态的数据可以由工作流中的下一个代理读取。

  1. MCPToolset 🦁

用于将导游代理连接到在实验 1 中创建的动物园 MCP 服务器。此服务器具有一些特殊工具,可用于查找有关我们动物的具体信息,例如它们的名称、年龄和围栏。

方式:安全地连接到动物园的私有服务器网址。它使用 get_id_token 自动获取安全的“钥匙卡”(服务账号 ID 令牌)来证明自己的身份并获得访问权限。

  1. LangchainTool 🌍

这样一来,导游代理就能获得一般性的世界知识。当访客提出的问题不在动物园的数据库中时(例如“狮子在野外吃什么?”),此工具可让客服人员在维基百科上查找答案。

方式:它充当适配器,使我们的代理能够使用 LangChain 库中预构建的 WikipediaQueryRun 工具。

资源:

第 3 步:定义专家代理

b8a9504b21920969.jpeg

接下来,我们将定义研究者代理和响应格式化程序代理。研究员代理是我们操作的“大脑”。此代理会从共享的 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
    ]
)

最后一步:组装主工作流 1000b9d20f4e134b.jpeg

此代理被指定为 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?"

3244d2f6c3b03088.png e135694253b1be41.png

智能体流程说明

您的系统可作为智能多代理团队运行。整个流程由清晰的顺序管理,以确保从用户提出问题到最终获得详细解答的流程顺畅高效。

1. 动物园迎宾员(迎宾台

整个流程从迎宾代理开始。

其作用:开始对话。其指令是问候用户,并询问用户想了解哪种动物。

其工具:当用户回复时,Greeter 会使用其 add_prompt_to_state 工具来捕获用户的确切措辞(例如,“告诉我有关狮子的信息”),并将其保存在系统内存中。

交接:保存提示后,它会立即将控制权传递给其子代理 tour_guide_workflow。

2. The Comprehensive Researcher(超级研究员)

这是主工作流中的第一步,也是操作的“大脑”。现在,您不再需要庞大的团队,只需一位技能娴熟的代理即可访问所有可用信息。

其工作:分析用户的问题并制定智能计划。它会利用语言模型强大的工具使用能力来决定是否需要:

  • 动物园记录中的内部数据(通过 MCP 服务器)。
  • 来自网络(通过 Wikipedia API)的常识。
  • 或者,对于复杂的问题,两者都使用。

其操作:执行必要的工具来收集所有必需的原始数据。例如,如果被问到“我们动物园的狮子多大了?它们在野外吃什么?”,它会调用 MCP 服务器来获取年龄信息,并调用 Wikipedia 工具来获取饮食信息。

3. 响应格式化程序(演示器)

在 Comprehensive Researcher 收集完所有事实后,这是要运行的最后一个代理。

其工作:充当动物园导游的友好声音。它会获取原始数据(可能来自一个或两个来源)并对其进行润饰。

其操作:将所有信息整合为连贯且引人入胜的单个答案。按照其指令,它首先呈现具体的动物园信息,然后添加有趣的常规事实。

最终结果:此代理生成的文本是用户在聊天窗口中看到的完整详细的答案。

如果您有兴趣详细了解如何构建代理,请参阅以下资源:

  1. ADK 文档
  2. 为 ADK 代理构建自定义工具

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. 调查问卷

输出如下:

您打算如何使用本教程?

仅通读 阅读并完成练习