最新AIエージェントフレームワーク「Agent Development Kit(ADK)」と「Mastra」でエージェント構築してみた
はじめに
こんにちは!クラウドエース株式会社 CTO 室所属の茜です。
今回は、Google Cloud NEXT'25 で発表された AI エージェントフレームワーク「Agent Development Kit(ADK)」と最近注目を集めている「Mastra」におけるエージェントの構築方法をご紹介します。
Agent Development Kit(ADK)とは
ADK とは、Google Cloud が開発したオープンソースの AI エージェントフレームワークです。
Google Cloud NEXT'25 において発表されました。
ADK を使用すると、Gemini モデルと Google AI ツールを活用したシンプルなエージェントだけでなく、より複雑なアーキテクチャやオーケストレーションを備えたエージェントの開発が可能です。
Mastra とは
Mastra とは、Gatsby の開発チームが作成したオープンソースの TypeScript AI エージェントフレームワークです。
ワークフロー、エージェント、RAG、統合、評価といった、必要な一連の基本要素を提供しており、迅速にエージェント開発を行うことができます。
GitHub の Star 数が急増しており、LangGraph を追い抜いています。
主要コンポーネント
ADK、Mastra では、以下 3 つのコンポーネント(機能)を使用しエージェントシステムを構築することが可能です。
- Agent
- Workflow
- Multi-Agent
本記事では、「Agent」にフォーカスして説明します。
Agent とは
それぞれのフレームワークにおいて、Agent は以下のように定義されています。
ADK
The LlmAgent (often aliased simply as Agent) is a core component in ADK, acting as the "thinking" part of your application. It leverages the power of a Large Language Model (LLM) for reasoning, understanding natural language, making decisions, generating responses, and interacting with tools.
Unlike deterministic Workflow Agents that follow predefined execution paths, LlmAgent behavior is non-deterministic. It uses the LLM to interpret instructions and context, deciding dynamically how to proceed, which tools to use (if any), or whether to transfer control to another agent.
Mastra
Agents in Mastra are systems where the language model can autonomously decide on a sequence of actions to perform tasks. They have access to tools, workflows, and synced data, enabling them to perform complex tasks and interact with external systems.
「与えられたタスクを達成するために、何かしらの LLM 処理を行い、時にはツール等を活用しながらアクションを決定・実行するコンポーネント」と自分は認識しています。
ADK
ADK で Agent を実装していきます。
ADK をインストールします。
uv add google-adk
以下のディレクトリ構成を作成します。
parent_folder
└── agent_folder
├── __init__.py
├── agent.py
└── .env
agent.py モジュールを読み込むよう記載します。
from . import agent
Agent 実装
Agent を実装していきます。
Agent オブジェクトは、「Agent」クラスを使用して作成できます。
以下のようなパラメータが使用できます。
- name(必須):各エージェントの一意の識別子
- model(必須):エージェントで使用するモデル
- description:エージェントの能力(どのようなタスクを実行できるか)の説明
- instruction:エージェントに対する指示
- etc...
from google.adk.agents import Agent
root_agent = Agent(
name="weather_time_agent",
model="gemini-2.0-flash-exp",
description=(
"Agent to answer questions about the time and weather in a city."
),
instruction=(
"I can answer your questions about the time and weather in a city."
),
)
モデル設定
1. Google Cloud 提供モデルを使用する場合
エージェントの「model」パラメータにモデル名を記載します。
Google AI Studio で払い出した API キーを使用する場合は、環境変数に以下を設定します。
GOOGLE_API_KEY="YOUR_GOOGLE_API_KEY"
GOOGLE_GENAI_USE_VERTEXAI=FALSE
Vertex AI 経由でモデルを使用する場合は、以下を実行します。
- ADC を使用して認証
gcloud auth application-default login
- 以下の環境変数を設定
GOOGLE_CLOUD_PROJECT="YOUR_PROJECT_ID"
GOOGLE_CLOUD_LOCATION="YOUR_VERTEX_AI_LOCATION"
export GOOGLE_GENAI_USE_VERTEXAI=TRUE
2. Google エコシステム外のモデルを使用する場合
以下設定を行い、LiteLLM でモデルを呼び出します。
- LiteLLMをインストール
uv add litellm
- 以下の環境変数を設定
# OpenAIの例
OPENAI_API_KEY="YOUR_OPENAI_API_KEY"
# Anthropic (非 Vertex AI) の例
ANTHROPIC_API_KEY="YOUR_ANTHROPIC_API_KEY"
- エージェントの「model」パラメータに LiteLLM を使用してモデルを定義
root_agent = Agent(
name="weather_time_agent",
# LiteLLM を使用
model=LiteLlm(model="openai/gpt-4o"),
description=(
"Agent to answer questions about the time and weather in a city."
),
instruction=(
"I can answer your questions about the time and weather in a city."
),
)
tools
ツールとは、エージェントに提供される特定の能力を指します。
これは、エージェントが基本的なテキスト生成や推論能力を超えて、具体的な行動を起こしたり、外部と対話したりすることを可能にするものです。
ツールは通常、関数やクラスメソッド、あるいは別の特化したエージェントのような、モジュール化されたコードコンポーネントとして実装されます。
それぞれのツールは、外部システムとの連携やデータの操作など、明確に定義された特定のタスクを実行するように設計されています。
ADK では、組み込みツールや Google Cloud ツールなど、事前に定義されたツールが複数提供されており、簡単にエージェントで使用することができます。
「tools」パラメータを使用することでツールを提供できます。
今回は、関数をツールとしてエージェントに提供します。
import datetime
from zoneinfo import ZoneInfo
from google.adk.agents import Agent
# 天気を取得する関数(ツール)を定義
def get_weather(city: str) -> dict:
"""Retrieves the current weather report for a specified city.
Args:
city (str): The name of the city for which to retrieve the weather report.
Returns:
dict: status and result or error msg.
"""
if city.lower() == "new york":
return {
"status": "success",
"report": (
"The weather in New York is sunny with a temperature of 25 degrees"
" Celsius (41 degrees Fahrenheit)."
),
}
else:
return {
"status": "error",
"error_message": f"Weather information for '{city}' is not available.",
}
# 時刻を取得する関数(ツール)を定義
def get_current_time(city: str) -> dict:
"""Returns the current time in a specified city.
Args:
city (str): The name of the city for which to retrieve the current time.
Returns:
dict: status and result or error msg.
"""
if city.lower() == "new york":
tz_identifier = "America/New_York"
else:
return {
"status": "error",
"error_message": (
f"Sorry, I don't have timezone information for {city}."
),
}
tz = ZoneInfo(tz_identifier)
now = datetime.datetime.now(tz)
report = (
f'The current time in {city} is {now.strftime("%Y-%m-%d %H:%M:%S %Z%z")}'
)
return {"status": "success", "report": report}
root_agent = Agent(
name="weather_time_agent",
model="gemini-2.0-flash-exp",
description=(
"Agent to answer questions about the time and weather in a city."
),
instruction=(
"I can answer your questions about the time and weather in a city."
),
# ツールを提供
tools=[get_weather, get_current_time],
)
エージェントは、与えられたタスクの遂行に必要なツールを選択・実行します。
この際、ツールの「関数名」「DocString」をもとに選択が行われます。
Within an agent's instructions, you can directly reference a tool by using its function name. If the tool's function name and docstring are sufficiently descriptive, your instructions can primarily focus on when the Large Language Model (LLM) should utilize the tool. This promotes clarity and helps the model understand the intended use of each tool.
入出力形式
「input_schema」「output_schema」パラメータを使用し、入出力構造を指定することができます。
-
input_schema
期待される入力構造を表す Pydantic BaseModel クラスを定義します。
設定された場合、このエージェントに渡されるユーザーメッセージの内容は、このスキーマに準拠した JSON 文字列でなければなりません。 -
output_schema
期待する出力構造を表す Pydantic BaseModel クラスを定義します。
設定された場合、エージェントの最終レスポンスはこのスキーマに準拠した JSON 文字列でなければなりません。
なお、output_schema を使用した場合、エージェントによるツール使用、他のエージェントに制御を移すといったことはできなくなるようです。
Using output_schema enables controlled generation within the LLM but disables the agent's ability to use tools or transfer control to other agents. Your instructions must guide the LLM to produce JSON matching the schema directly.
以下のように実装することができます。
from pydantic import BaseModel, Field
class CountryInput(BaseModel):
country: str = Field(description="The name of the country.")
class CapitalOutput(BaseModel):
capital: str = Field(description="The capital of the country.")
structured_capital_agent = Agent(
# ... name, model, description
instruction="""You are a Capital Information Agent. You will receive a JSON object containing a country name like {"country": "country_name"}. Respond ONLY with a JSON object containing the capital of that country, formatted as {"capital": "capital_name"}.""",
input_schema=CountryInput,
output_schema=CapitalOutput
)
Agent 実行
エージェントの実行方法は以下の 3 パターンがあります。
- UI(Playground)
- ターミナル
- API サーバー
なお、コマンドはエージェントディレクトリ(プロジェクト)の親ディレクトリ(今回の場合は parent_folder)で実行する必要があります。
UI(Playground)
以下コマンドを実行し、Playground を起動します。
uv run adk web
localhost:8000 で Playground が起動しました。
リクエストを投げるとレスポンスが返ってきました。
リクエストに対して適切なツールを使用していることが確認できます。
ツールとのやりとりも視覚化されています。
ターミナル
次に、ターミナルでエージェントとチャットを行います。
以下コマンドを実行します。
uv run adk run agent_folder #エージェントプロジェクト名
レスポンスを取得することができました。
API サーバー
以下コマンドを実行することで、ローカルで FastAPI サーバーを起動することができます。
uv run adk api_server
INFO: Started server process [14679]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
以下コマンドを実行し、セッションを作成します。
curl -X POST http://0.0.0.0:8000/apps/agent_folder/users/u_123/sessions/s_123 \
-H "Content-Type: application/json"
# agent_folder: エージェントのプロジェクト名
# u_123: ユーザーID
# s_123: セッションID
{"id":"s_123","app_name":"agent_folder","user_id":"u_123","state":{},"events":[],"last_update_time":1744354340.22097}
以下コマンドを実行し、リクエストを送信します。
curl -X POST http://0.0.0.0:8000/run \
-H "Content-Type: application/json" \
-d '{
"app_name": "agent_folder",
"user_id": "u_123",
"session_id": "s_123",
"new_message": {
"role": "user",
"parts": [{
"text": "Hey whats the weather in new york today"
}]
}
}'
レスポンスを取得することができました。
...
{"content":{"parts":[{"text":"OK. The weather in New York is sunny with a temperature of 25 degrees Celsius (41 degrees Fahrenheit).\n"}],
...
Mastra
続いて、Mastra で Agent を実装します。
Mastra プロジェクトを作成します。
npx create-mastra@latest
ターミナル上での指示に従いインストールを進めていきます。
What do you want to name your project?
Where should we create the Mastra files? (default: src/)
Choose components to install:
◯ Agents
◯ Workflows
...
ここで注目したいのが、以下の表示です。
◆ Make your AI IDE into a Mastra expert? (installs Mastra docs MCP server)
│ ● Skip for now (default)
│ ○ Cursor
│ ○ Windsurf
Cursor や Windsurf といった MCP ホストを選択すると、MCP の設定ファイルが作成されます。
{
"mcpServers": {
"mastra": {
"command": "npx",
"args": [
"-y",
"@mastra/mcp-docs-server@latest"
]
}
}
}
Cursor Settings で Mastra の MCP サーバーを有効化します。
この設定を行うことで、Cursor から Mastra のナレッジベースにアクセスすることができるようになります。
@mastra/mcp-docs-server provides direct access to Mastra's complete knowledge base in Cursor, Windsurf, Cline, or any other IDE that supports MCP.
It has access to documentation, code examples, technical blog posts / feature announcements, and package changelogs which your IDE can read to help you build with Mastra.
The MCP server tools have been designed to allow an agent to query the specific information it needs to complete a Mastra related task - for example: adding a Mastra feature to an agent, scaffolding a new project, or helping you understand how something works.
従来であれば、Mastra のような LLM の学習データに含まれていないフレームワーク等の実装を AI エディターで行う場合、コンテキストとしてドキュメントなどの情報をユーザーが与える必要がありました。
しかしこの設定により、リクエストを解決するために必要な情報を MCP を使用して自動的に取得し、適切なアウトプットを生成してくれます。
Mastra では、以下のディレクトリ構成が使用されます。
root
├── .env
└── src
└── mastra
├── index.ts
├── agents
│ └── index.ts
├── tools
│ └── index.ts
└── workflows
└── index.ts
Agent 実装
Agent を実装していきます。
ADK と同様、Mastra でも「Agent」クラスを使用して Agent オブジェクトを作成します。
import { Agent } from "@mastra/core/agent";
import { openai } from "@ai-sdk/openai";
export const myAgent = new Agent({
name: "My Agent",
instructions: "You are a helpful assistant.",
model: openai("gpt-4o-mini"),
});
Mastra では、作成したエージェントを登録するという作業が必要です。
src/mastra/index.ts に以下のように記載することで登録可能です。
import { Mastra } from "@mastra/core";
import { myAgent } from "./agents";
export const mastra = new Mastra({
agents: { myAgent },
});
モデル設定
Mastra では、内部的に AI SDK が使用されています。
そのため、AI SDK がサポートしているモデルは使用可能です。
例えば、Vertex AI 経由で使用するモデルは、AI SDK を使用し以下のように定義可能です。
import { createVertex } from '@ai-sdk/google-vertex';
export const vertex = createVertex({
project: 'my-project',
location: 'us-central1',
});
ADC を使用して認証を行えばモデルを使用できます。
gcloud auth application-default login
エージェントの「model」パラメータに作成したモデルを指定します。
import { Agent } from "@mastra/core/agent";
import { vertex } from '../models/vertex';
export const myAgent = new Agent({
name: "My Agent",
instructions: "You are a helpful assistant.",
model: vertex("gemini-2.0-flash-exp"),
});
tools
Mastra では、組み込みのツールは提供されていません。
以下 2 パターンの作成方法があります。
- 関数を作成しツールとする
- MCP クライアントとして機能させ、MCP サーバーを呼び出す処理をツールとする
- ADK でも可能です
今回は、関数をツールとしてエージェントに提供します。
まずはツールを定義します。
import { createTool } from "@mastra/core/tools";
import { z } from "zod";
interface WeatherResponse {
current: {
time: string;
temperature_2m: number;
apparent_temperature: number;
relative_humidity_2m: number;
wind_speed_10m: number;
wind_gusts_10m: number;
weather_code: number;
};
}
function getWeatherCondition(code: number): string {
const conditions: Record<number, string> = {
0: "Clear sky",
1: "Mainly clear",
2: "Partly cloudy",
3: "Overcast",
45: "Foggy",
48: "Depositing rime fog",
51: "Light drizzle",
53: "Moderate drizzle",
55: "Dense drizzle",
56: "Light freezing drizzle",
57: "Dense freezing drizzle",
61: "Slight rain",
63: "Moderate rain",
65: "Heavy rain",
66: "Light freezing rain",
67: "Heavy freezing rain",
71: "Slight snow fall",
73: "Moderate snow fall",
75: "Heavy snow fall",
77: "Snow grains",
80: "Slight rain showers",
81: "Moderate rain showers",
82: "Violent rain showers",
85: "Slight snow showers",
86: "Heavy snow showers",
95: "Thunderstorm",
96: "Thunderstorm with slight hail",
99: "Thunderstorm with heavy hail",
};
return conditions[code] || "Unknown";
}
const getWeather = async (location: string) => {
const geocodingUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(location)}&count=1`;
const geocodingResponse = await fetch(geocodingUrl);
const geocodingData = await geocodingResponse.json();
if (!geocodingData.results?.[0]) {
throw new Error(`Location '${location}' not found`);
}
const { latitude, longitude, name } = geocodingData.results[0];
const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=temperature_2m,apparent_temperature,relative_humidity_2m,wind_speed_10m,wind_gusts_10m,weather_code`;
const response = await fetch(weatherUrl);
const data: WeatherResponse = await response.json();
return {
temperature: data.current.temperature_2m,
feelsLike: data.current.apparent_temperature,
humidity: data.current.relative_humidity_2m,
windSpeed: data.current.wind_speed_10m,
windGust: data.current.wind_gusts_10m,
conditions: getWeatherCondition(data.current.weather_code),
location: name,
};
};
export const weatherTool = createTool({
id: "get-weather",
description: "Get current weather for a location",
inputSchema: z.object({
location: z.string().describe("City name"),
}),
outputSchema: z.object({
temperature: z.number(),
feelsLike: z.number(),
humidity: z.number(),
windSpeed: z.number(),
windGust: z.number(),
conditions: z.string(),
location: z.string(),
}),
execute: async ({ context }) => {
return await getWeather(context.location);
},
});
次に、エージェントを定義します。
「tools」パラメータでツールを提供します。
import { Agent } from "@mastra/core/agent";
import { vertex } from "../models/vertex";
import { weatherTool } from "../tools";
export const weatherAgent = new Agent({
name: "Weather Agent",
instructions: `You are a helpful weather assistant that provides accurate weather information.
Your primary function is to help users get weather details for specific locations. When responding:
- Always ask for a location if none is provided
- If the location name isn't in English, please translate it
- Include relevant details like humidity, wind conditions, and precipitation
- Keep responses concise but informative
Use the weatherTool to fetch current weather data.`,
model: vertex("gemini-2.0-flash-exp"),
tools: { weatherTool },
});
最後に、エージェントを登録します。
import { Mastra } from "@mastra/core";
import { weatherAgent } from "./agents";
export const mastra = new Mastra({
agents: { weatherAgent },
});
エージェントは、与えられたタスクの遂行に必要なツールを選択・実行します。
ドキュメントには明記されていませんが、コードベースを調査したところ(Cursor 使用)「ツール名」「description」をもとに選択が行われているようです。
入出力形式
エージェントは、JSON スキーマを提供するか、Zod スキーマを使用することで構造化データを返すことができます。
今回はスコープ外ですが、ワークフローでは「inputSchema」「outputSchema」パラメータを使用して、型安全にエージェント間でのデータの受け渡しを行います。
上記コードのように、ツールにおいても inputSchema、outputSchema を使用します。
Agent 実行
エージェントの実行方法は以下のパターンがあります。
-
Mastra サーバー起動
- UI(Playground)
- API サーバー
- クライアント SDK
- スクリプト実行
Mastra サーバー起動
以下コマンドを実行すると、Mastra サーバーが起動します。
npm run dev
INFO [2025-04-11 20:09:03.047 +0900] (Mastra CLI): [Mastra Dev] - Starting server...
INFO [2025-04-11 20:09:04.192 +0900] (Mastra): 🦄 Mastra API running on port 4111/api
INFO [2025-04-11 20:09:04.195 +0900] (Mastra): 📚 Open API documentation available at http://localhost:4111/openapi.json
INFO [2025-04-11 20:09:04.196 +0900] (Mastra): 🧪 Swagger UI available at http://localhost:4111/swagger-ui
INFO [2025-04-11 20:09:04.196 +0900] (Mastra): 👨💻 Playground available at http://localhost:4111/
localhost:4111 で Playground が起動しています。
リクエストを投げるとレスポンスが返ってきました。
リクエストに対して適切なツールを使用していることが確認できます。
また、API サーバーも起動しており、エンドポイントをテストできます。
以下コマンドを実行します。
curl -X POST http://localhost:4111/api/agents/weatherAgent/generate \
-H "Content-Type: application/json" \
-d '{"messages": ["What is the weather in London?"]}'
レスポンスを取得することができました。
{"text":"The weather in London is clear with a temperature of 15.5 degrees Celsius, but it feels like 14.1 degrees. The humidity is 47%, and the wind is blowing at 7.8 m/s with gusts up to 21.2 m/s.\n",
...
クライアント SDK、スクリプト実行の説明は割愛します。
まとめ
本記事では、AI エージェントフレームワークである ADK と Mastra を使用したエージェント構築方法を紹介しました。
ADK は Python ベースで Google Cloud との連携が容易です。組み込みツールやサードパーティツールなど、事前に準備されているツールが豊富で、エージェントで簡単に使用できます。
一方、Mastra は TypeScript ベースで AI SDK を活用しており、MCP と連携した開発支援機能も備えています。さらに、Zod を用いて入出力を明確に定義できる点も特徴です。
今回紹介した「Agent」は、より複雑な処理を実現するための基本的な構成要素です。
複数の Agent を組み合わせることで、「Workflow」や「Multi-Agent」の構築を行います。
Workflow や Multi-Agent の構築方法についても、今後の記事で詳しく解説していきたいと考えています。
本記事の内容について、誤りや改善点など、お気づきの点がございましたら、お気軽にコメントいただけますと幸いです。
Discussion