建構及部署使用 Cloud Run MCP 伺服器的 ADK 代理

1. 簡介

本實驗室將著重於實作及部署用戶端代理服務。您將使用 Agent Development Kit (ADK) 建構 AI 代理,串連遠端工具,例如在實驗室 1 中建立的 MCP 伺服器。本實驗室展示「關注點分離」這項關鍵架構原則,也就是讓獨立的推理層 (代理) 和工具層 (MCP 伺服器),透過安全的 API 互相通訊。

在實驗室 1 中,您建立了 MCP 伺服器,為大型語言模型 (可透過 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 基礎架構上執行容器。
  • 不必修補作業系統、設定虛擬機器或煩惱資源調度事宜。

自動調整資源配置:

  • 當應用程式無人使用時,所有執行個體都不會運行 (縮減至零個執行個體,可有效節省費用)。
  • 如果收到 1,000 個要求,系統會視需要啟動足量的執行個體。

預設為無狀態:

  • 每項要求都能傳送至不同的執行個體。
  • 如需儲存狀態,請使用 Cloud SQL、Firestore 或 Memorystore 等獨立於應用程式的服務。

支援任何語言或架構:

  • 無論應用程式是以 Python、Go、Node.js、Java 或 .Net 編寫,只要能在 Linux 容器中執行,Cloud Run 就都支援。

用多少付多少:

3. 設定和需求條件

自行設定環境

  1. 登入 Google Cloud 控制台,然後建立新專案或重複使用現有專案。如果沒有 Gmail 或 Google Workspace 帳戶,請先建立帳戶

fbef9caa1602edd0.png

a99b7ace416376c4.png

5e3ff691252acf41.png

  • 「專案名稱」是這個專案參與者的顯示名稱。這是 Google API 未使用的字元字串。你隨時可以更新。
  • 專案 ID 在所有 Google Cloud 專案中都是不重複的,而且設定後即無法變更。Cloud 控制台會自動產生專屬字串,通常您不需要在意該字串為何。在大多數程式碼研究室中,您需要參照專案 ID (通常標示為 PROJECT_ID)。如果您不喜歡產生的 ID,可以產生另一個隨機 ID。你也可以嘗試使用自己的名稱,看看是否可用。完成這個步驟後就無法變更,且專案期間會維持不變。
  • 請注意,有些 API 會使用第三個值,也就是「專案編號」。如要進一步瞭解這三種值,請參閱說明文件
  1. 接著,您需要在 Cloud 控制台中啟用帳單,才能使用 Cloud 資源/API。完成這個程式碼研究室的費用不高,甚至可能完全免費。如要關閉資源,避免在本教學課程結束後繼續產生費用,您可以刪除建立的資源或專案。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.

5. 建立專案資料夾

建立專案目錄。

這個指令會建立實驗室的主要資料夾,用來存放代理的原始碼。

cd && mkdir zoo_guide_agent && cd zoo_guide_agent

建立 requirements.txt 檔案。這個檔案會列出代理程式所需的 Python 程式庫。下列指令會建立並填入檔案。

cloudshell edit requirements.txt
google-adk==1.14.0
langchain-community==0.3.27
wikipedia==1.4.0

為目前的專案 ID 和專案編號設定變數,並為專案建立專屬的服務帳戶。這是執行這些指令的更健全方式。

export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")
export SA_NAME=lab2-cr-service
export SERVICE_ACCOUNT="${SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com"
gcloud iam service-accounts create ${SA_NAME} \
    --display-name="Service Account for lab 2 "

建立並開啟 .env 檔案,以驗證 zoo_guide_agent 目錄中的代理。

cloudshell edit .env

cloudshell edit 指令會在終端機上方的編輯器中開啟 .env 檔案。在 .env 檔案中輸入下列內容,然後返回終端機。

MODEL="gemini-2.5-flash"

新增 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

建立主要的 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 工具,以及維基百科工具。

將下列程式碼新增至 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 伺服器工具和維基百科工具),然後決定要使用哪些工具來搜尋答案。

回覆生成代理的角色是呈現資訊。這個代理不會使用任何工具尋找新資訊,而是會擷取「研究人員」代理收集的原始資料 (透過 State 傳遞),並運用大型語言模型的語言組織能力,將資料轉換成親切的對話式回覆。

將下列程式碼新增至 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 指令,將變數載入殼層工作階段。

source .env

將 Vertex AI 使用者角色授予服務帳戶,以利服務帳戶進行預測及呼叫 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 上啟動服務,讓使用者透過網路存取。

部署

執行下列指令來部署代理程式。uvx 指令可讓您執行以 Python 套件形式發布的指令列工具,而不需在全域安裝這些工具。

# Run the deployment command
uvx --from google-adk==1.14.0 \
adk deploy cloud_run \
  --project=$PROJECT_ID \
  --region=europe-west1 \
  --service_name=zoo-tour-guide \
  --with_ui \
  . \
  -- \
  --labels=dev-tutorial=codelab-adk \
  --service-account=$SERVICE_ACCOUNT

接受提示

系統可能會顯示下列提示:

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 的網頁介面,並與代理互動。

在網路瀏覽器中開啟公開 Cloud Run 服務網址。由於您使用了 --with_ui flag,因此應該會看到 ADK 開發人員 UI。

將右上角的 Token Streaming 切換為開啟。

現在您可以與動物園導覽員代理互動了。

輸入 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?"

向虛擬服務專員提出以下問題:

Where can I find the polar bears in the zoo and what is their diet?

3244d2f6c3b03088.png e135694253b1be41.png

代理流程說明

您的系統就像一個智慧型多代理團隊,會按明確程序執行作業,確保使用者從提出問題到獲得最終詳細解答的過程順暢有效率。

1. 動物園迎賓員 (迎賓櫃台)

整個流程從迎賓代理開始。

用途:展開對話。這個代理會問候使用者,並詢問他們想瞭解哪種動物。

使用的工具:當使用者回覆時,迎賓代理會使用 add_prompt_to_state 工具完整擷取輸入的文字 (例如「介紹一下獅子」),並儲存在系統記憶體中。

轉接:儲存提示詞後,迎賓代理會立即將控制權轉給子代理 tour_guide_workflow。

2. 全方位研究人員 (超級研究人員)

這是主要工作流程的第一步,也是整個作業的「大腦」。您不必仰賴龐大的團隊,只要一個技能高超的代理就能存取所有可用資訊。

用途:分析使用者的問題,並聰明擬定計畫。這個代理會運用強大的語言模型,判斷是否需要:

  • 取用動物園記錄的內部資料 (透過 MCP 伺服器)。
  • 從網路 (透過 Wikipedia API) 搜尋一般知識。
  • 同時運用上述兩個管道,以回答複雜問題。

執行動作:執行必要工具,收集所有需要的原始資料。舉例來說,如果遊客問「園內的獅子幾歲?牠們在野外吃什麼?」,模型會呼叫 MCP 伺服器取得年齡資訊,並呼叫維基百科工具取得飲食資訊。

3. 回覆生成 (資訊呈現者)

全方位研究人員收集所有事實後,就會交由最後的代理來呈現。

用途:擔任友善的動物園導覽員,將原始資料 (可能來自一個或兩個來源) 整理成實用回覆。

執行動作:將所有資訊統整成單一、連貫且實用的答案。這個代理會按照指示,先提供該動物園的具體資訊,再補充有趣的一般知識。

最終結果:代理會生成完整詳細的文字答案,並顯示在對話視窗中。

請參閱下列資源,進一步瞭解如何建構代理:

  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. 恭喜

恭喜您完成本程式碼研究室。

涵蓋內容

  • 如何建構 Python 專案,以利使用 ADK 指令列介面部署。
  • 如何使用 SequentialAgent 和 ParallelAgent 實作多代理工作流程。
  • 如何使用 MCPToolset 連線至遠端 MCP 伺服器,以取用其中的工具。
  • 如何整合 Wikipedia API 等外部工具,擴充內部資料。
  • 如何使用 adk deploy 指令,將代理程式以無伺服器容器的形式部署至 Cloud Run。

12. 問卷調查

輸出內容:

您會如何使用本教學課程?

僅閱讀內容 閱讀內容並完成練習