เริ่มต้นใช้งาน MCP และ A2A ด้วย ADK

1. ภาพรวม

AI Agent กำลังได้รับความนิยมเพิ่มขึ้นอย่างรวดเร็ว โดยปฏิวัติการทำงานอัตโนมัติและการตัดสินใจด้วยความสามารถในการทำงานอย่างอิสระ เรียนรู้ และโต้ตอบกับสภาพแวดล้อมเพื่อบรรลุเป้าหมาย

Codelab นี้จะช่วยให้คุณเริ่มต้นใช้งานด้วยการสร้างระบบ Multi-Agent แบบครบวงจร คุณจะได้สร้างเซิร์ฟเวอร์ MCP สำหรับสกุลเงิน สร้างAgent สำหรับสกุลเงินที่ใช้เซิร์ฟเวอร์ MCP และแสดงผ่านโปรโตคอล Agent2Agent (A2A) สร้างตัวแทนท่องเที่ยวที่มีAgent ย่อยสำหรับสภาพอากาศในกระบวนการที่ใช้ Agent สำหรับสกุลเงินผ่าน A2A และสุดท้ายคือติดตั้งใช้งานบริการทั้งหมดใน Cloud Run

สถาปัตยกรรม

Core Technologies

Model Context Protocol (MCP)

Model Context Protocol (MCP) เป็นโปรโตคอลแบบเปิดที่กำหนดมาตรฐานวิธีที่แอปพลิเคชันให้บริบทและเครื่องมือแก่ LLM ลองนึกถึง MCP ว่าเป็นเหมือนพอร์ต USB-C สำหรับแอปพลิเคชัน AI ซึ่งเป็นวิธีมาตรฐานในการเชื่อมต่อโมเดล AI กับแหล่งข้อมูล, API และเครื่องมือภายนอก

ใน Codelab นี้ currency_mcp_server จะแสดงเครื่องมือ get_exchange_rate ผ่าน Streamable HTTP (/mcp) ซึ่งสนับสนุนโดย Frankfurter API สาธารณะ

Agent Development Kit (ADK)

Agent Development Kit (ADK) เป็นเฟรมเวิร์กการจัดเรียงที่ยืดหยุ่นสำหรับการพัฒนาและติดตั้งใช้งาน AI Agent ADK ไม่ขึ้นอยู่กับโมเดล ไม่ขึ้นอยู่กับการติดตั้งใช้งาน และสร้างขึ้นเพื่อให้เข้ากันได้กับเฟรมเวิร์กอื่นๆ ADK ช่วยให้การพัฒนา Agent เป็นเหมือนวิศวกรรมซอฟต์แวร์มาตรฐาน ซึ่งช่วยให้สร้าง ทดสอบ และจัดการเวิร์กโฟลว์ Agent ที่ซับซ้อนได้ง่าย

ADK จะจัดการการสนทนากับผู้ใช้ แสดง UI บนเว็บแบบอินเทอร์แอกทีฟ เชื่อมต่อกับเครื่องมือ MCP ผ่าน McpToolset และจัดการการสื่อสารแบบ A2A

โปรโตคอล Agent2Agent (A2A)

โปรโตคอล Agent2Agent (A2A) เป็นมาตรฐานแบบเปิดที่ออกแบบมาเพื่อเปิดใช้การสื่อสารและการทำงานร่วมกันระหว่าง AI Agent A2A จะกำหนดมาตรฐานการทำงานร่วมกันระหว่าง Agent กับ Agent เช่นเดียวกับที่ MCP กำหนดมาตรฐานการเชื่อมต่อระหว่าง Agent กับเครื่องมือ ในโลกที่เอเจนต์สร้างขึ้นจากเฟรมเวิร์ก สภาพแวดล้อมการโฮสต์ และองค์กรที่หลากหลาย A2A จะเป็นภาษาทั่วไปสำหรับการค้นพบและการมอบสิทธิ์งาน

ADK แสดง currency_agent เป็นบริการ A2A (to_a2a) และอนุญาตให้ travel_agent ใช้บริการจากระยะไกลเป็น AgentTool (RemoteA2aAgent)

Subagent ในเครื่องเทียบกับ A2A Agent ระยะไกล

สถาปัตยกรรมนี้เน้นรูปแบบที่สำคัญในการออกแบบ Multi-Agent ดังนี้

  • เครื่องมือ Agent ในเครื่อง (weather_agent): ทำงานในกระบวนการภายใน Orchestrator เป็น AgentTool โดยไม่มีเวลาในการตอบสนองของเครือข่ายหรือค่าใช้จ่ายเพิ่มเติมในการจัดรูปแบบโปรโตคอล
  • เครื่องมือตัวแทนระยะไกล (currency_agent): ทำงานเป็น Microservice อิสระ ซึ่งเรียกใช้ทั่วทั้งเครือข่ายผ่านโปรโตคอล A2A

สิ่งที่คุณจะได้เรียนรู้

  • วิธีสร้างและทดสอบเซิร์ฟเวอร์ MCP ในเครื่องโดยใช้ FastMCP ผ่าน HTTP ที่สตรีมได้
  • วิธีสร้าง Agent ด้วย ADK ที่ใช้เครื่องมือ MCP (McpToolset)
  • วิธีแสดง ADK Agent เป็นเซิร์ฟเวอร์ A2A (to_a2a)
  • วิธีทดสอบเซิร์ฟเวอร์ A2A โดยใช้ไคลเอ็นต์ Python ของ A2A (a2a.client)
  • วิธีสร้าง Agent ผู้จัดเรียงที่รวมเครื่องมือ Subagent ในเครื่องเข้ากับ A2A Agent ระยะไกล
  • วิธีเรียกใช้และทดสอบระบบ Multi-Agent ที่สมบูรณ์ในเครื่องด้วย ADK Web UI
  • วิธีสร้างคอนเทนเนอร์และติดตั้งใช้งานคอมโพเนนต์ทั้ง 3 รายการใน Google Cloud Run

สิ่งที่คุณต้องมี

  • เบราว์เซอร์ เช่น Chrome
  • โปรเจ็กต์ Google Cloud ที่เปิดใช้การเรียกเก็บเงิน

2. ก่อนเริ่มต้น

สร้างโปรเจ็กต์

หากไม่มีโปรเจ็กต์ Google Cloud ให้สร้างโปรเจ็กต์

ในคอนโซล Google Cloud ในหน้าตัวเลือกโปรเจ็กต์ ให้เลือกหรือสร้างโปรเจ็กต์ Google Cloud

และตรวจสอบว่าได้เปิดใช้การเรียกเก็บเงินสำหรับโปรเจ็กต์ที่อยู่ในระบบคลาวด์แล้ว ดูวิธีตรวจสอบว่ามีการเปิดใช้การเรียกเก็บเงินในโปรเจ็กต์หรือไม่

เปิดใช้งาน Cloud Shell

Google Cloud Shell เป็นสภาพแวดล้อมในการพัฒนาซอฟต์แวร์แบบอินเทอร์แอกทีฟบนเบราว์เซอร์ที่ให้บริการโดยตรงภายในคอนโซล Google Cloud ซึ่งเป็นวิธีที่ง่ายที่สุดในการเริ่มต้นใช้งาน Google Cloud โดยไม่ต้องติดตั้งเครื่องมือในเครื่อง

เปิดใช้งาน Cloud Shell โดยคลิกลิงก์นี้ คุณสลับระหว่างเทอร์มินัล Cloud Shell (สำหรับการเรียกใช้คำสั่งระบบคลาวด์) และตัวแก้ไข (สำหรับการดูไฟล์) ได้โดยคลิกปุ่มที่เกี่ยวข้องใน Cloud Shell

เมื่อเชื่อมต่อกับ Cloud Shell แล้ว ให้ยืนยันว่าคุณได้รับการตรวจสอบสิทธิ์แล้ว โดยทำดังนี้

gcloud auth list

ตรวจสอบว่าคำสั่ง gcloud รู้จักโปรเจ็กต์ของคุณโดยทำดังนี้

gcloud config list project

ตั้งค่ารหัสโปรเจ็กต์โดยทำดังนี้

export PROJECT_ID=<YOUR_GOOGLE_CLOUD_PROJECT_ID>
gcloud config set project $PROJECT_ID

เปิดใช้ Cloud APIs

เปิดใช้ API ที่จำเป็นสำหรับ Cloud Run, Cloud Build, Artifact Registry และ Vertex AI โดยทำดังนี้

gcloud services enable run.googleapis.com \
                       cloudbuild.googleapis.com \
                       artifactregistry.googleapis.com \
                       aiplatform.googleapis.com

รับโค้ด

โคลนที่เก็บและไปที่ไดเรกทอรี python:

git clone https://github.com/meteatamel/getting-started-mcp-a2a-adk.git
cd getting-started-mcp-a2a-adk/python

ติดตั้งทรัพยากร Dependency ด้วย uv

uv เป็นเครื่องมือจัดการแพ็กเกจและโปรเจ็กต์ Python ที่รวดเร็ว เนื่องจากมีการติดตั้งไว้ล่วงหน้าแล้วใน Cloud Shell หากเรียกใช้ในเครื่อง คุณจะติดตั้งได้ดังนี้

# macOS and Linux
curl -LsSf https://astral.sh/uv/install.sh | sh

# Windows (PowerShell)
# powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

ไดเรกทอรี Python มีโครงสร้างเป็น uv แบบรวม

Workspace ติดตั้งทรัพยากร Dependency ทั้งหมดในสมาชิก Workspace ทั้งหมด (currency_mcp_server, currency_agent และ travel_agent) ลงในสภาพแวดล้อมเสมือนเดียวโดยเรียกใช้คำสั่งต่อไปนี้

uv sync

กำหนดค่าตัวแปรสภาพแวดล้อม

กำหนดค่าตัวแปรสภาพแวดล้อมในไฟล์ .env ในไดเรกทอรี python ดังนี้

ตัวเลือก ก: Gemini Enterprise (Google Cloud / Cloud Shell)

echo "GOOGLE_GENAI_USE_ENTERPRISE=TRUE" >> .env \
&& echo "GOOGLE_CLOUD_PROJECT=$PROJECT_ID" >> .env \
&& echo "GOOGLE_CLOUD_LOCATION=global" >> .env

ตัวเลือก ข: Google AI Studio (คีย์ API ในเครื่อง)

หากต้องการใช้คีย์ API จาก Google AI Studio แทน ให้ทำดังนี้

echo "GOOGLE_API_KEY=<your_api_key_here>"<>>/span>  .env \
&& echo "GOOGLE_GENAI_USE_ENTERPRISE=FALSE" >> .env

3. สร้างเซิร์ฟเวอร์ MCP สำหรับสกุลเงิน

ก่อนสร้าง Agent คุณจะต้องสำรวจเซิร์ฟเวอร์ MCP ที่แสดงเครื่องมือแปลงสกุลเงินก่อน

เซิร์ฟเวอร์ MCP ช่วยให้คุณเขียนโปรแกรมขนาดเล็กเพื่อแสดงความสามารถเป็นเครื่องมือได้ จากนั้น Agent (หรือหลาย Agent) จะเข้าถึงเครื่องมือเหล่านี้ได้โดยใช้ Model Context Protocol ที่ได้มาตรฐาน

คุณสามารถใช้แพ็กเกจ Python FastMCP เพื่อสร้างเซิร์ฟเวอร์ MCP ที่แสดงเครื่องมือเดียวชื่อ get_exchange_rate ได้ เครื่องมือ get_exchange_rate จะเรียกใช้ Frankfurter API เพื่อรับอัตราแลกเปลี่ยนปัจจุบันระหว่าง 2 สกุลเงิน

โค้ดสำหรับเซิร์ฟเวอร์ MCP อยู่ใน currency_mcp_server/server.py:

import asyncio
import logging
import os

import httpx
from fastmcp import FastMCP

logger = logging.getLogger(__name__)
logging.basicConfig(format="[%(levelname)s]: %(message)s", level=logging.INFO)

mcp = FastMCP("Currency MCP Server 💵")


@mcp.tool()
def get_exchange_rate(
    currency_from: str = "USD",
    currency_to: str = "EUR",
    currency_date: str = "latest",
):
    """Use this to get current exchange rate.

    Args:
        currency_from: The currency to convert from (e.g., "USD").
        currency_to: The currency to convert to (e.g., "EUR").
        currency_date: The date for the exchange rate or "latest". Defaults to "latest".

    Returns:
        A dictionary containing the exchange rate data, or an error message if the request fails.
    """
    logger.info(
        f"--- 🛠️ Tool: get_exchange_rate called for converting {currency_from} to {currency_to} ---"
    )
    try:
        response = httpx.get(
            f"https://api.frankfurter.dev/v1/{currency_date}",
            params={"from": currency_from, "to": currency_to},
        )
        response.raise_for_status()

        data = response.json()
        if "rates" not in data:
            logger.error(f"❌ rates not found in response: {data}")
            return {"error": "Invalid API response format."}
        logger.info(f"✅ API response: {data}")
        return data
    except httpx.HTTPError as e:
        logger.error(f"❌ API request failed: {e}")
        return {"error": f"API request failed: {e}"}
    except ValueError:
        logger.error("❌ Invalid JSON response from API")
        return {"error": "Invalid JSON response from API."}


if __name__ == "__main__":
    port = int(os.getenv("PORT", 8080))
    logger.info(f"🚀 MCP server started on port {port}")
    # Could also use 'sse' transport, host="0.0.0.0" required for Cloud Run.
    asyncio.run(
        mcp.run_async(
            transport="http",
            host="0.0.0.0",
            port=port,
        )
    )

เริ่มต้นเซิร์ฟเวอร์ MCP ในเครื่อง

เริ่มเซิร์ฟเวอร์ MCP ในเทอร์มินัลโดยทำดังนี้

uv run python currency_mcp_server/server.py

เซิร์ฟเวอร์จะเริ่มทำงานในพอร์ต 8080 โดยมีปลายทาง HTTP ที่สตรีมได้พร้อมใช้งานที่ /mcp (http://localhost:8080/mcp)

ทดสอบเซิร์ฟเวอร์ MCP

เปิดหน้าต่างเทอร์มินัลที่ 2 (ปล่อยให้เซิร์ฟเวอร์ MCP ทำงานในหน้าต่างแรก) ไปที่โฟลเดอร์ python (cd getting-started-mcp-a2a-adk/python) แล้วเรียกใช้สคริปต์ทดสอบดังนี้

uv run python currency_mcp_server/test_server.py

สคริปต์ทดสอบจะเชื่อมต่อกับปลายทาง MCP โดยใช้ Client ของ FastMCP, แสดงรายการเครื่องมือ และเรียกใช้ get_exchange_rate ดังนี้

Connecting to MCP server at: http://localhost:8080/mcp
--- 🛠️  Tool found: get_exchange_rate ---
--- 🪛  Calling get_exchange_rate tool for USD to EUR ---
--- ✅  Success: {"amount":1.0,"base":"USD","date":"2026-09-29","rates":{"EUR":0.84919}} ---

ยอดเยี่ยม! คุณมีเซิร์ฟเวอร์ MCP ที่ใช้งานได้ซึ่งแสดงเครื่องมือสกุลเงินแบบเรียลไทม์ เปิดเทอร์มินัลนี้ไว้เพื่อทำขั้นตอนถัดไป

4. สร้าง Currency Agent ด้วย ADK

ตอนนี้ก็ถึงเวลาสร้าง Currency Agent โดยใช้ Agent Development Kit (ADK) แล้ว

ADK รองรับเครื่องมือ MCP ในตัวผ่านคลาส McpToolset Currency Agent จะเชื่อมต่อกับเซิร์ฟเวอร์ MCP ของเราโดยใช้ StreamableHTTPConnectionParams

ดูคำจำกัดความของ Agent สกุลเงินใน currency_agent/agent.py

import logging
import os
from urllib.parse import urlparse

from dotenv import load_dotenv
from google.adk.agents import LlmAgent
from google.adk.a2a.utils.agent_to_a2a import to_a2a
from google.adk.tools.mcp_tool import McpToolset, StreamableHTTPConnectionParams

logger = logging.getLogger(__name__)
logging.basicConfig(format="[%(levelname)s]: %(message)s", level=logging.INFO)

load_dotenv()

SYSTEM_INSTRUCTION = (
    "You are a specialized assistant for currency conversions. "
    "Your sole purpose is to use the 'get_exchange_rate' tool to answer questions about currency exchange rates. "
    "If the user asks about anything other than currency conversion or exchange rates, "
    "politely state that you cannot help with that topic and can only assist with currency-related queries. "
    "Do not attempt to answer unrelated questions or use tools for other purposes."
)

mcp_server_url = os.getenv("MCP_SERVER_URL", "http://localhost:8080/mcp")
if not mcp_server_url.endswith("/mcp"):
    mcp_server_url = f"{mcp_server_url.rstrip('/')}/mcp"

logger.info(f"--- 🔧 Loading MCP tools from MCP Server at {mcp_server_url}... ---")
logger.info("--- 🤖 Creating ADK Currency Agent... ---")

root_agent = LlmAgent(
    model="gemini-3.8-flash",
    name="currency_agent",
    description="An agent that can help with currency conversions",
    instruction=SYSTEM_INSTRUCTION,
    tools=[
        McpToolset(
            connection_params=StreamableHTTPConnectionParams(
                url=mcp_server_url
            )
        )
    ],
)

สังเกตว่า McpToolset ค้นพบและโหลดเครื่องมือ get_exchange_rate โดยอัตโนมัติจากเซิร์ฟเวอร์ MCP ที่ทำงานอยู่ผ่าน HTTP ได้อย่างไร

ทดสอบ Currency Agent ด้วย ADK Web UI

คุณสามารถทดสอบ Agent แยกต่างหากได้โดยใช้อินเทอร์เฟซเว็บสำหรับการพัฒนาของ ADK ในเทอร์มินัลที่ 2 ให้เรียกใช้คำสั่งต่อไปนี้

uv run adk web --allow_origins "*" currency_agent

เปิดเบราว์เซอร์ที่ http://localhost:8000 (หรือคลิกตัวอย่างบนเว็บใน Cloud Shell)

ADK Web Currency Agent

ถาม Agent:

"250 USD เท่ากับกี่ยูโร"

คุณจะเห็น Agent เรียกใช้เครื่องมือ MCP get_exchange_rate และแสดงผลจำนวนเงินที่แปลงแล้ว หยุดกระบวนการ adk web โดยใช้ Ctrl+C ก่อนดำเนินการต่อ

5. โปรโตคอล Agent2Agent (A2A)

โปรโตคอล Agent2Agent (A2A) เป็นมาตรฐานแบบเปิดที่ออกแบบมาเพื่อเปิดใช้การสื่อสารและการทำงานร่วมกันระหว่าง AI Agent

ในระบบ Multi-Agent สมัยใหม่ มักจะสร้าง Agent โดยใช้เฟรมเวิร์กที่แตกต่างกัน (ADK, LangChain, CrewAI, AutoGen) และติดตั้งใช้งานในโครงสร้างพื้นฐานที่แตกต่างกัน A2A จะช่วยลดการจัดการข้อมูลแบบแยกส่วนเหล่านี้ด้วยการกำหนดสัญญาการสื่อสารที่เป็นมาตรฐาน

โปรโตคอล A2A

แนวคิดหลักของ A2A

  • การค้นพบ Agent (การ์ด Agent): Agent ที่เป็นไปตามข้อกำหนด A2A ทุกตัวจะโฆษณาความสามารถ โหมด I/O ที่รองรับ ข้อกำหนดในการตรวจสอบสิทธิ์ และทักษะผ่านไฟล์ JSON มาตรฐานที่โฮสต์ที่ /.well-known/agent-card.json
  • ทักษะของ Agent (AgentSkill): ความสามารถหรือเครื่องมือเฉพาะที่ Agent สามารถดำเนินการได้ Agent อื่นๆ จะอ่านทักษะเหล่านี้เพื่อตัดสินใจว่าจะมอบหมายงานเมื่อใด
  • การสื่อสาร JSON-RPC: Agent จะแลกเปลี่ยนข้อความ งาน และอาร์ติแฟกต์ที่มีโครงสร้างผ่านการรับส่งมาตรฐาน เช่น HTTP JSON-RPC 2.0

การ์ด A2A Agent

ในขั้นตอนถัดไป คุณจะแสดง ADK Currency Agent เป็นเซิร์ฟเวอร์ A2A เพื่อให้ Agent อื่นๆ ค้นพบและมอบหมายงานการแปลงสกุลเงินให้ได้

6. แสดง Currency Agent เป็นเซิร์ฟเวอร์ A2A

ADK ช่วยให้การเปลี่ยน LlmAgent เป็นเซิร์ฟเวอร์ที่เข้ากันได้กับ A2A เป็นเรื่องง่ายด้วยฟังก์ชันยูทิลิตี to_a2a()

ตรวจสอบส่วนล่างของ currency_agent/agent.py ดังนี้

# Make the agent A2A-compatible
PORT = int(os.getenv("PORT", 8081))
AGENT_URL = os.getenv("AGENT_URL")

if AGENT_URL:
    parsed = urlparse(AGENT_URL)
    protocol = parsed.scheme or "https"
    host = parsed.hostname
    port = parsed.port or 443
else:
    protocol = "http"
    host = "localhost"
    port = PORT

a2a_app = to_a2a(root_agent, host=host, port=port, protocol=protocol)

if __name__ == "__main__":
    import uvicorn

    logger.info(f"🚀 Starting currency_agent on port {PORT}")
    uvicorn.run(a2a_app, host="0.0.0.0", port=PORT)

ผู้ช่วย to_a2a() จะดำเนินการต่อไปนี้โดยอัตโนมัติ

  1. ตรวจสอบเครื่องมือและวิธีการของ LlmAgent
  2. สร้าง A2A AgentCard ที่อธิบายทักษะของตน (เช่น currency_agent-get_exchange_rate)
  3. รวม Agent ไว้ในแอปพลิเคชัน FastAPI (a2a_app) ที่รองรับปลายทาง JSON-RPC
  4. กำหนดค่า url ที่โฆษณาในการ์ดตัวแทนแบบไดนามิกตาม AGENT_URL (หรือ localhost)

เริ่มเซิร์ฟเวอร์ A2A ของ Currency Agent

ในเทอร์มินัลที่ 2 ให้เริ่ม Agent สกุลเงินโดยทำดังนี้

uv run python currency_agent/agent.py

เซิร์ฟเวอร์จะเริ่มทำงานในพอร์ต 8081:

[INFO]: --- 🔧 Loading MCP tools from MCP Server at http://localhost:8080/mcp... ---
[INFO]: --- 🤖 Creating ADK Currency Agent... ---
[INFO]: 🚀 Starting currency_agent on port 8081
INFO:     Started server process
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8081 (Press CTRL+C to quit)

ตรวจสอบการ์ด Agent

ในเบราว์เซอร์ ให้ไปที่ปลายทางการ์ดตัวแทน: http://localhost:8081/.well-known/agent-card.json

คุณจะเห็นข้อมูลเมตา JSON ที่สร้างขึ้นโดยอัตโนมัติ ดังนี้

{
  "name": "currency_agent",
  "description": "An agent that can help with currency conversions",
  "supportedInterfaces": [
    {
      "url": "http://localhost:8081",
      "protocolBinding": "JSONRPC",
      "protocolVersion": "1.0"
    }
  ],
  "version": "0.0.1",
  "capabilities": {
    "streaming": true
  },
  "defaultInputModes": [
    "text/plain"
  ],
  "defaultOutputModes": [
    "text/plain"
  ],
  "skills": [
    {
      "id": "currency_agent",
      "name": "model",
      "description": "An agent that can help with currency conversions",
      "tags": [
        "llm"
      ]
    },
    {
      "id": "currency_agent-get_exchange_rate",
      "name": "get_exchange_rate",
      "description": "Use this to get current exchange rate.",
      "tags": [
        "llm",
        "tools"
      ]
    }
  ]
}

ทดสอบกับไคลเอ็นต์ A2A

เปิดเทอร์มินัลที่ 3 ไปที่โฟลเดอร์ python (cd getting-started-mcp-a2a-adk/python) และทดสอบปลายทาง A2A โดยใช้สคริปต์ไคลเอ็นต์ทดสอบ A2A โดยเฉพาะ ดังนี้

uv run python currency_agent/test_a2aclient.py

ไคลเอ็นต์จะแก้ไขการ์ดตัวแทนโดยใช้ A2ACardResolver และส่งข้อความ JSON-RPC ดังนี้

🔄 Fetching the agent card at http://localhost:8081
✅ Successfully fetched the agent card
====================================================
                     AgentCard                      
====================================================
Name        : currency_agent
Description : An agent that can help with currency conversions
Interfaces  : [0] http://localhost:8081  (JSONRPC 1.0)
Skills      : currency_agent, currency_agent-get_exchange_rate
====================================================
🔄 Initializing a non-streaming client
Sending request: "how much is 100 USD in GBP?"
Response:
100 USD is currently equal to approximately 73.37 GBP...

ตอนนี้ Currency Agent ทำงานเป็นเซิร์ฟเวอร์ A2A ที่ทำงานได้อย่างสมบูรณ์แล้ว

7. สร้างตัวแทนท่องเที่ยว

ตอนนี้คุณจะสร้างตัวแทนท่องเที่ยวที่ทำหน้าที่ประสานงาน Agent นี้แสดงให้เห็นว่า Agent ของ ADK สามารถรวมกระบวนทัศน์เครื่องมือที่แตกต่างกัน 2 แบบเข้าด้วยกันได้อย่างง่ายดาย ดังนี้

  1. เครื่องมือ Agent ในเครื่อง (weather_agent): Agent ย่อยของ ADK ในกระบวนการที่ทำงานในรันไทม์ Python เดียวกัน ซึ่งจะช่วยหลีกเลี่ยงเวลาในการตอบสนองของเครือข่ายหรือการจัดลำดับ
  2. เครื่องมือ Agent ระยะไกล (currency_agent): Agent ภายนอกที่เชื่อมต่อผ่านเครือข่ายผ่านโปรโตคอล A2A โดยใช้ RemoteA2aAgent
                    +-----------------------------+
                    |        travel_agent         |
                    | (Orchestrator with Web UI)  |
                    +--------------+--------------+
                                   |
             +---------------------+---------------------+
             | (In-process call)                         | (A2A Network Hop)
             v                                           v
+-------------------------+                 +-------------------------+
|   weather_agent         |                 |   currency_agent        |
|  (Local AgentTool)      |                 |  (Remote A2A Agent)     |
|  Calls wttr.in API      |                 |  Calls Currency MCP Svc |
+-------------------------+                 +-------------------------+

1. Agent ย่อยสภาพอากาศในพื้นที่

ลองดู travel_agent/subagents/weather_agent.py:

import logging
import httpx
from google.adk.agents import LlmAgent

logger = logging.getLogger(__name__)

SYSTEM_INSTRUCTION = (
    "You are a specialized assistant for providing weather forecasts and conditions for travel destinations. "
    "Your sole purpose is to use the 'get_weather' tool to fetch weather information. "
    "Provide clear, concise summaries of current weather conditions, temperatures, and forecasts to help travelers pack and plan."
)


def get_weather(location: str = "London") -> dict:
    """Gets the current weather and forecast for a given location or city."""
    logger.info(f"--- 🌤️ Tool: get_weather called for {location} ---")
    try:
        response = httpx.get(
            f"https://wttr.in/{location}?format=j1",
            headers={"User-Agent": "curl/7.68.0"},
            timeout=8.0,
        )
        response.raise_for_status()
        data = response.json()
        current = data["current_condition"][0]
        return {
            "location": location,
            "condition": current.get("weatherDesc", [{}])[0].get("value", "Unknown"),
            "temperature_celsius": f"{current.get('temp_C', 'N/A')}°C",
            "temperature_fahrenheit": f"{current.get('temp_F', 'N/A')}°F",
            "humidity": f"{current.get('humidity', 'N/A')}%",
            "wind_speed_kmph": f"{current.get('windspeedKmph', 'N/A')} km/h",
        }
    except Exception as e:
        logger.warning(f"⚠️ Weather lookup failed: {e}. Returning simulated estimate.")
        return {
            "location": location,
            "condition": "Partly Cloudy",
            "temperature_celsius": "20°C",
            "temperature_fahrenheit": "68°F",
            "humidity": "55%",
            "wind_speed_kmph": "10 km/h",
            "note": f"Live data unavailable ({e}); showing estimated conditions.",
        }


weather_agent = LlmAgent(
    model="gemini-3.8-flash",
    name="weather_agent",
    description="A local specialist agent that provides current weather reports and forecasts for travel destinations.",
    instruction=SYSTEM_INSTRUCTION,
    tools=[get_weather],
)

เอเจนต์สภาพอากาศคือ LlmAgent ที่มีเครื่องมือฟังก์ชันซึ่งดึงข้อมูลสภาพอากาศแบบเรียลไทม์จาก wttr.in พร้อมฟังก์ชันสำรองที่ยืดหยุ่น

2. Travel Agent Orchestrator

ตอนนี้ให้ดูที่ travel_agent/agent.py

import logging
import os
from dotenv import load_dotenv
from google.adk.agents import LlmAgent
from google.adk.tools.agent_tool import AgentTool
from google.adk.agents.remote_a2a_agent import RemoteA2aAgent, AGENT_CARD_WELL_KNOWN_PATH

try:
    from travel_agent.subagents.weather_agent import weather_agent
except ImportError:
    from subagents.weather_agent import weather_agent

logger = logging.getLogger(__name__)
logging.basicConfig(format="[%(levelname)s]: %(message)s", level=logging.INFO)

load_dotenv()

SYSTEM_INSTRUCTION = (
    "You are a helpful travel assistant. You help users plan trips, recommend places, "
    "and answer travel-related questions.\n\n"
    "- Whenever a user asks about currency exchange rates or money conversions, "
    "delegate the request to the 'currency_agent' tool.\n"
    "- Whenever a user asks about the weather, climate, or forecasts for a destination, "
    "delegate the request to the 'weather_agent' tool."
)

CURRENCY_AGENT_URL = os.getenv("CURRENCY_AGENT_URL", "http://localhost:8081").rstrip("/")

logger.info(
    "--- 🔗 Connecting to Remote A2A Currency Agent at %s... ---",
    CURRENCY_AGENT_URL,
)

currency_remote_agent = RemoteA2aAgent(
    name="currency_agent",
    agent_card=f"{CURRENCY_AGENT_URL}{AGENT_CARD_WELL_KNOWN_PATH}",
    description="An agent that can help with currency conversions and exchange rates.",
)

logger.info("--- 🤖 Creating ADK Travel Agent... ---")

root_agent = LlmAgent(
    model="gemini-3.8-flash",
    name="travel_agent",
    description="A travel assistant that can help plan trips, check weather forecasts via the local weather agent, and convert currencies via the remote currency agent.",
    instruction=SYSTEM_INSTRUCTION,
    tools=[
        AgentTool(agent=currency_remote_agent),
        AgentTool(agent=weather_agent),
    ],
)

if __name__ == "__main__":
    import uvicorn
    from google.adk.cli.fast_api import get_fast_api_app

    PORT = int(os.getenv("PORT", 8082))
    logger.info(f"🚀 Starting travel_agent Web UI on port {PORT}")
    app = get_fast_api_app(web=True, allow_origins=["*"], agents_dir=os.path.dirname(__file__) or ".")
    uvicorn.run(app, host="0.0.0.0", port=PORT)

ไฮไลต์สำคัญ

  • RemoteA2aAgent ดึงข้อมูลการ์ดของ Currency Agent จาก http://localhost:8081/.well-known/agent-card.json
  • ทั้ง currency_remote_agent และ weather_agent จะรวมกันโดยใช้ AgentTool ของ ADK
  • การเรียกใช้ travel_agent/agent.py จะบูต ADK Web UI โดยตรงบนพอร์ต 8082 โดยใช้ get_fast_api_app(web=True)

8. เรียกใช้และทดสอบระบบหลาย Agent ในเครื่อง

ตอนนี้คุณมีองค์ประกอบทั้ง 3 อย่างพร้อมแล้ว มาเรียกใช้และทดสอบทั้งระบบในเครื่องกัน

กำลังเรียกใช้บริการทั้ง 3 รายการ

ตรวจสอบว่าบริการทำงานในหน้าต่างเทอร์มินัล 3 หน้าต่างแยกกัน (จากไดเรกทอรี getting-started-mcp-a2a-adk/python) ตามลำดับต่อไปนี้

เทอร์มินัล 1 (เซิร์ฟเวอร์ MCP ของสกุลเงิน):

uv run python currency_mcp_server/server.py

(ทำงานบนพอร์ต 8080)

Terminal 2 (Currency A2A Agent):

uv run python currency_agent/agent.py

(ทำงานบนพอร์ต 8081)

Terminal 3 (ตัวแทนท่องเที่ยวที่มี UI บนเว็บ):

uv run python travel_agent/agent.py

(ทำงานบนพอร์ต 8082)

ทดสอบผ่าน ADK Web UI

เปิดเบราว์เซอร์ที่ http://localhost:8082 (หรือใช้ตัวอย่างบนเว็บในพอร์ต 8082 ใน Cloud Shell)

ถามคำถามแบบผสมกับตัวแทนท่องเที่ยวซึ่งต้องใช้เครื่องมือทั้ง 2 อย่าง ดังนี้

"ฉันกำลังวางแผนจะไปเที่ยวลอนดอน อากาศเป็นอย่างไรบ้าง และ 200 ยูโรเท่ากับกี่ปอนด์"

ดูขั้นตอนการดำเนินการ

  1. ตัวแทนท่องเที่ยวจะได้รับคำขอใน UI บนเว็บ
  2. โดยจะมอบสิทธิ์คำถามเกี่ยวกับสภาพอากาศที่อยู่ระหว่างดำเนินการให้กับ weather_agent ในเครื่อง ซึ่งจะดึงข้อมูลสภาพอากาศปัจจุบันจาก wttr.in
  3. โดยจะมอบสิทธิ์การแปลงสกุลเงินผ่านโปรโตคอล A2A ให้กับ currency_agent บนพอร์ต 8081
  4. currency_agent จะเรียก currency_mcp_server ในพอร์ต 8080 ผ่าน MCP เพื่อดึงข้อมูลอัตราแลกเปลี่ยน
  5. ระบบจะสังเคราะห์ผลลัพธ์ทั้งหมดและแสดงคำตอบที่เป็นประโยชน์และครอบคลุมให้คุณ

ADK Web Remote Currency Agent

ทดสอบผ่านบรรทัดคำสั่ง

นอกจากนี้ คุณยังทดสอบการค้นหาได้โดยตรงจาก CLI โดยไม่ต้องเปิดเบราว์เซอร์ ดังนี้

uv run adk run travel_agent "What is the weather in London and how much is 100 USD in EUR?"

เมื่อทุกอย่างทำงานได้อย่างราบรื่นในเครื่องของคุณแล้ว เรามาติดตั้งใช้งานทั้งระบบใน Google Cloud Run กัน

9. ทำให้ระบบแบบหลาย Agent ใช้งานได้ใน Cloud Run

แต่ละคอมโพเนนต์มี Dockerfile และ pyproject.toml ในตัวของตัวเอง จึงสามารถสร้างและติดตั้งใช้งานใน Cloud Run ได้อย่างอิสระ

เมื่อใช้ gcloud คุณจะติดตั้งใช้งานแต่ละบริการและเชื่อมต่อ URL ของบริการเหล่านั้นเข้าด้วยกันโดยอัตโนมัติ

ตั้งค่าตัวแปรสภาพแวดล้อม

ตั้งค่ารหัสโปรเจ็กต์ที่อยู่ในระบบคลาวด์และภูมิภาคเป้าหมาย

export PROJECT_ID=<YOUR_GOOGLE_CLOUD_PROJECT_ID>
export REGION=us-central1

ขั้นตอนที่ 1: ติดตั้งใช้งานเซิร์ฟเวอร์ MCP สำหรับสกุลเงิน

ติดตั้งใช้งานเซิร์ฟเวอร์ MCP โดยตรงจากแหล่งที่มาโดยทำดังนี้

# 1. Deploy MCP server
gcloud run deploy currency-mcp-server \
  --source currency_mcp_server \
  --region $REGION \
  --allow-unauthenticated

# 2. Capture the deployed MCP server URL
MCP_SERVER_URL=$(gcloud run services describe currency-mcp-server --region $REGION --format='value(status.url)')/mcp
echo "MCP Server URL: $MCP_SERVER_URL"

ขั้นตอนที่ 2: ติดตั้งใช้งาน Currency Agent

เนื่องจาก URL สาธารณะของ currency-agent ได้รับการกำหนดในการติดตั้งใช้งานครั้งแรก ให้ติดตั้งใช้งานบริการก่อน บันทึก URL และอัปเดตตัวแปรสภาพแวดล้อม AGENT_URL เพื่อให้การ์ด A2A Agent แสดงที่อยู่ HTTPS สาธารณะที่ถูกต้อง

# 1. Deploy Currency Agent connected to the deployed MCP Server
gcloud run deploy currency-agent \
  --source currency_agent \
  --region $REGION \
  --allow-unauthenticated \
  --update-env-vars MCP_SERVER_URL="$MCP_SERVER_URL",GOOGLE_GENAI_USE_ENTERPRISE="true",GOOGLE_CLOUD_PROJECT="$PROJECT_ID",GOOGLE_CLOUD_LOCATION="global"

# 2. Capture its assigned Cloud Run URL
CURRENCY_AGENT_URL=$(gcloud run services describe currency-agent --region $REGION --format='value(status.url)')
echo "Currency Agent URL: $CURRENCY_AGENT_URL"

# 3. Update AGENT_URL so the agent advertises its public HTTPS endpoint in its Agent Card
gcloud run services update currency-agent \
  --region $REGION \
  --update-env-vars AGENT_URL="$CURRENCY_AGENT_URL"

ขั้นตอนที่ 3: ติดตั้งใช้งาน Travel Agent

ตอนนี้ให้ติดตั้งใช้งาน Travel Agent โดยกำหนดค่าด้วย CURRENCY_AGENT_URL ดังนี้

# 1. Deploy Travel Agent (with ADK Web UI) connected to Currency Agent
gcloud run deploy travel-agent \
  --source travel_agent \
  --region $REGION \
  --allow-unauthenticated \
  --update-env-vars CURRENCY_AGENT_URL="$CURRENCY_AGENT_URL",GOOGLE_GENAI_USE_ENTERPRISE="true",GOOGLE_CLOUD_PROJECT="$PROJECT_ID",GOOGLE_CLOUD_LOCATION="global"

# 2. Capture its assigned Cloud Run URL
TRAVEL_AGENT_URL=$(gcloud run services describe travel-agent --region $REGION --format='value(status.url)')
echo "Travel Agent URL: $TRAVEL_AGENT_URL"

10. ทดสอบระบบแบบหลาย Agent ใน Cloud Run

เมื่อติดตั้งใช้งาน Microservice ทั้ง 3 รายการแล้ว เรามาตรวจสอบแต่ละเลเยอร์ใน Cloud Run กัน

1. ทดสอบเซิร์ฟเวอร์ MCP ระยะไกล

ทดสอบเซิร์ฟเวอร์ Cloud Run MCP ที่ติดตั้งใช้งานจากบรรทัดคำสั่ง โดยทำดังนี้

MCP_SERVER_URL="$MCP_SERVER_URL" uv run python currency_mcp_server/test_server.py

คุณควรเห็นเครื่องมือแสดงอยู่และเรียกใช้ใน Cloud Run ได้สำเร็จ

2. ทดสอบ Currency Agent ผ่าน A2A

ทดสอบ Currency Agent ที่ติดตั้งใช้งานโดยใช้ไคลเอ็นต์ทดสอบ A2A ดังนี้

AGENT_URL="$CURRENCY_AGENT_URL" uv run python currency_agent/test_a2aclient.py

ไคลเอ็นต์จะดึงข้อมูลการ์ดตัวแทนระยะไกลจาก Cloud Run และแลกเปลี่ยนข้อความผ่าน HTTPS JSON-RPC

3. ทดสอบ Travel Agent Web UI ใน Cloud Run

เปิด $TRAVEL_AGENT_URL ในเบราว์เซอร์

UI บนเว็บของ ADK ที่สมบูรณ์จะแสดงจาก Cloud Run โดยตรง ลองถาม

"ฉันกำลังวางแผนจะไปเที่ยวโตเกียว อากาศเป็นอย่างไรบ้าง และ 500 USD เท่ากับกี่ JPY"

[Browser] 
   │
   ▼ (HTTPS)
[Cloud Run: travel-agent]
   ├──> Local in-process tool: weather_agent (wttr.in)
   └──> A2A JSON-RPC (HTTPS)
           │
           ▼
        [Cloud Run: currency-agent]
           └──> MCP Streamable HTTP (HTTPS)
                   │
                   ▼
                [Cloud Run: currency-mcp-server] (Frankfurter API)

บริการทั้ง 3 รายการจะปรับขนาดแยกกันบนโครงสร้างพื้นฐานแบบ Serverless โดยสื่อสารกันอย่างราบรื่นผ่านโปรโตคอลแบบเปิด

11. ยินดีด้วยและทำความสะอาด

สิ่งที่คุณทำสำเร็จ

ยินดีด้วย คุณได้สร้างและติดตั้งใช้งานระบบ Multi-Agent ระดับเวอร์ชันที่ใช้งานจริงแล้ว

  • Model Context Protocol (MCP): สร้างเซิร์ฟเวอร์ FastMCP ที่แสดงเครื่องมือ API แบบเรียลไทม์ผ่าน HTTP ที่สตรีมได้
  • Agent Development Kit (ADK): สร้าง Agent แบบโมดูลาร์โดยใช้ LlmAgent, เชื่อมต่อเครื่องมือ MCP กับ McpToolset และโฮสต์ ADK Web UI
  • โปรโตคอล Agent2Agent (A2A): แสดง Agent เป็นบริการ A2A (to_a2a), เผยแพร่การ์ด Agent (agent-card.json) และใช้ Agent ระยะไกลโดยใช้ RemoteA2aAgent
  • สถาปัตยกรรมแบบ Multi-Agent: รวม Agent ย่อยในกระบวนการภายในเครื่อง (weather_agent) เข้ากับ Agent ระยะไกลแบบกระจาย (currency_agent)
  • การทำให้ใช้งานได้แบบ Serverless ของ Cloud Run: สร้างโดยใช้คอนเทนเนอร์และทำให้ใช้งานได้ทั้ง 3 บริการด้วยการเชื่อมต่อการกำหนดค่าอัตโนมัติ

ดูโค้ดแบบเต็ม (รวมถึงการติดตั้งใช้งานทั้ง Python และ Java) และการอัปเดตในอนาคตได้ที่ที่เก็บ getting-started-mcp-a2a-adk

ล้างข้อมูล

วิธีหลีกเลี่ยงการเรียกเก็บเงินในบัญชี Google Cloud สำหรับบริการ Cloud Run ที่สร้างขึ้นใน Codelab นี้มีดังนี้

ลบบริการ Cloud Run ที่ติดตั้งใช้งานแล้ว

gcloud run services delete currency-mcp-server --region $REGION --quiet
gcloud run services delete currency-agent --region $REGION --quiet
gcloud run services delete travel-agent --region $REGION --quiet

หรือหากคุณสร้างโปรเจ็กต์เฉพาะสำหรับ Codelab นี้ คุณสามารถปิดทั้งโปรเจ็กต์ได้โดยทำดังนี้

gcloud projects delete $PROJECT_ID