Tech Waves

produced by Hakuhodo DY ONE

本ブログは、株式会社Hakuhodo DY ONEの開発チームによるエンジニアブログです。
それぞれのメンバーが業務を通して得た技術情報や、各種セミナーの参加レポート、またその他トピックについて情報発信を行っています。

Google ADKでシンプルなAgentを開発してみる

1. はじめに

Agent Development Kit(ADK)とは、Google社が提供するエージェント作成用のオープンソースPythonフレームワークです。2025年4月にオープンソース化された比較的新しいフレームワークであり、現在も活発に開発が進んでいます。

ADKを使うと、LLM(大規模言語モデル)に対してツールや指示を与えることで、単なるチャットボット以上の「自律的に判断・行動するエージェント」を比較的シンプルなコードで構築することが可能です。

本記事では、初心者でもわかりやすいよう、以下の順番でシンプルなエージェントの作り方を紹介します。

  • 最小構成のエージェント
  • ツール(関数)を持つエージェント
  • 外部APIと連携するエージェント
  • 複数のエージェントを組み合わせるマルチエージェント

エージェントの基本概念

エージェントとは、ユーザーからの入力に対して、LLMが自律的に判断を行い、必要に応じてツール(関数)を呼び出しながら回答を生成する仕組みです。

ユーザーの質問に対し、与えられたinstructionとツールの説明(docstring)を読み、どのツールをいつ使うべきかを自律的に判断します。そのため、ツールのdocstringを丁寧に書くことが、エージェントの精度向上につながります。

ユーザーの質問
 ↓
Agent
 ├─ model:                           LLM(Gemini)  
 ├─ instruction:                    指示文
 └─ tools:                           ツール群(関数) 各種操作を行うための機能
 ↓
回答

2. 環境構築

2.1 インストール

pip install google-adk

2.2 APIキーの設定

GOOGLE_API_KEY=[your-api-key]

今回はローカルで実行するため、APIキーを設定します。 Google Cloud上でVertex AIからmodelを呼び出す場合は不要です。

2.3 ディレクトリ構成

ADKはディレクトリ構成に厳密なルールがあり、必ず以下の構成にしないと読み込まれない仕様となっています。

my_project/          ← adk run / adk web を実行するディレクトリ
├── .env             ← API キー を設定
└── my_agent/        ← エージェント名(= フォルダ名)
    └── agent.py     ← 必須: `root_agent` という変数を定義する
  • agent.py 内で root_agent という変数名を定義する。ADKが自動検出し、実行する。
  • .env には環境変数を設定する。この場合は、GOOGLE_API_KEYを設定する。

2.4 起動方法

Web UIで起動する方法と、ターミナルで起動する方法の2通りがあります。

# 親ディレクトリに移動
cd my_project

# Web UI で起動(ブラウザで http://localhost:8000 を開く)
adk web

# ターミナルで対話
adk run [my_agent]

Web UI起動画面

ターミナル起動

3. 最小構成エージェント

まずは、会話ができる最小のAgentを作成してみます。以下のプログラムだけで日本語で応答するチャットボットが作成できます。

from google.adk.agents import Agent

root_agent = Agent(
    model='gemini-3-flash-preview',
    name='root_agent',
    description='ユーザーの質問に答えるアシスタント',
    instruction='ユーザーの質問に日本語で丁寧に答えてください。',
)

各パラメータの意味

パラメータ説明
model使用する LLM モデル"gemini-3-flash-preview"
nameエージェントの内部名(英数字とアンダースコア)"root_agent"
descriptionエージェントの説明(マルチエージェントでの振り分けに使用)"天気情報を回答する"
マルチエージェントを扱う際、どのAgentに指示していいかを判断する。
instructionエージェントへの指示文(= System Prompt)"あなたは旅行アシスタントです…"
instruction がエージェントの「性格」と「行動ルール」を決めます ここを変えるだけで全く違う振る舞いになります。

4. ツール付きAgent

エージェントにツール(関数)を持たせると、LLMが質問に応じて自動で判断し呼び出します。

LLMはリアルタイムデータ(天気、時刻)や独自の企業データなど一般的な知識外からの質問に対しては、モデル単独では応答することができません。そこで、LLMに特定の機能を加えるための関数を用意します。

LLMは計算を間違えることがあるため、複雑な四則演算などはツールを使ったほうが正確な答えになります。

4.1 ツールの作り方

ツールは普通のPython関数です。

今回は例として『東京の天気を聞かれると必ず「雨」と回答する関数』を用意してみます。

関数には必ず以下の情報を付与します。

  • docstring: LLMがこの説明を読み、いつ使うかを判断する。
  • 型ヒント: 引数と戻り値に型をつける(location: str, -> str )
  • (推奨)dictでstatusを返す {”status”: “success”, “report”: “雨”} 今回は str で返しています。
def get_weather(location: str) -> str:
    """
    指定された都市の天気を返す。
    都市の名前は英語にすること。(例:東京→tokyo)
    """
    if location.lower() == 'tokyo':
        return '雨'
    else:
        return 'わかりません。'

4.2 エージェントにツールを渡す

先ほどのroot_agent作成時に、toolsパラメータに作成した関数を指定する。

root_agent = Agent(
    model='gemini-3-flash-preview',
    name='root_agent',
    description='ユーザーの質問に答えるアシスタント',
    instruction='ユーザーの質問に日本語で丁寧に答えてください。',
    tools=[get_weather]
)

4.3 動作イメージ

東京の天気について質問すると、toolを使って回答します。 「東京」と入力してもツール使用時に tokyoに変換して実行します。

4.4 複数のツールを設定することも可能

docstringに関数の内容を記載していれば自動的に最適なツールを選択して回答することができます。

get_timeという時刻を返答するtoolも用意し、get_weatherとあわせて設定することが可能です。

tools=[get_weather, get_time]

5. プロンプト設計で振る舞いを変える

同じLLM・ツールであっても、instruction次第で挙動を変えることができます。

root_agent = Agent(
    name="travel_agent",
    model="gemini-3-flash-preview",
    description="都市の天気、時刻、観光情報を回答するエージェント",
    instruction=(
        "あなたは天気予報士です。"
        "ユーザーの質問内容に応じて、適切なツールを選んで回答してください。"
        "天気を聞かれたらget_weatherを使用してください"
        "絵文字をたくさん使って、楽しい雰囲気で回答してね 🎉✈️"
    ),
    tools=[get_weather]  
    )

絵文字を使って回答

instruction 設計

テクニック説明
ペルソナ設定エージェントの「キャラ」を決める"あなたはプロの旅行コンシェルジュです"
出力形式の指定回答のフォーマットを強制する"Markdown の表形式で出力してください"
ツール使用ルールどのツールをいつ使うか明示する"天気を聞かれたら get_weather を使ってください"
制約条件やってはいけないことを明示する"対応外の都市を聞かれたら対応都市を案内して"

6. 外部APIを使うエージェント

ここまでは「東京の天気は必ず雨」という固定の返答しかできないエージェントを例に説明してきました。しかし実際のユースケースでは、リアルタイムの情報を取得したり、社内システムや外部サービスと連携したりする場面が多くあります。

その解決策として、ツールとして外部APIを呼び出す関数を用意することで、エージェントの回答をよりリアルで実用的なものにすることが可能です。

以下の例では、OpenWeather APIを使用して、任意の都市のリアルタイムな天気情報を取得するツールを実装しています。APIキーは .env ファイルに OPENWEATHER_API_KEY として設定しておく必要があります。

このように、外部APIやデータベース、社内システムなど、あらゆる機能をツールとして実装しエージェントに付与することができます。ツールを増やすほどエージェントが対応できる範囲が広がり、より実用的なアプリケーションへと発展させることが可能です。

import os
import requests
from google.adk.agents import Agent
from dotenv import load_dotenv

def get_realtime_weather(city: str) -> dict:
    """指定された都市のリアルタイム天気情報を取得する。
    cityは英語の都市名で指定すること(例: Tokyo, Paris, London)。"""
    load_dotenv()
    api_key = os.getenv("OPENWEATHER_API_KEY")
    
    try:
        response = requests.get(
            "https://api.openweathermap.org/data/2.5/weather",
            params={"q": city, "appid": api_key, "units": "metric", "lang": "ja"},
            timeout=5,
            verify=False
        )
        response.raise_for_status()
        data = response.json()
        return {
            "status": "success",
            "report": f"{city}の天気: {data['weather'][0]['description']}, "
                      f"気温: {data['main']['temp']}°C"
        }
    except requests.exceptions.Timeout:
        return {"status": "error", "error_message": "APIがタイムアウトしました"}
    except requests.exceptions.RequestException as e:
        return {"status": "error", "error_message": str(e)}

7. マルチエージェント

これまで、単一のエージェントに機能を付与する構成を紹介してきました。 ここから複数のエージェントを組み合わせて、より複雑な処理を行うマルチエージェント構成について紹介します。

1つのエージェントに複数の機能をもたせる(Toolを複数付与する)ことも可能ですが、以下のような理由からマルチエージェント構成が有効な場面があります。

メリット説明
関心の分離各エージェントに専門的な役割を持たせることで、コードが整理しやすくなる
プロンプトの明確化役割ごとに短く的確な指示を書くことができ、LLMの精度が向上する
モデルの使い分け処理の重要度や複雑さに応じて、エージェントごとに異なるLLMモデルを選択できる
スケーラビリティ機能追加の際に既存のエージェントに影響を与えず、新しいエージェントを追加できる

エージェントを組み合わせるデザインパターンとして以下のドキュメントが参考になります。

エージェント AI システムの設計パターンを選択する  |  Cloud Architecture Center  |  Google Cloud Documentation

次に、直列、並列、コーディネーターパターンについて実装しながら紹介していきます。

7.1 直列(Sequential)パターン Aの結果をBに渡す

Sequentialパターンは、複数のエージェントを順番に実行し、前のエージェントの出力を次のエージェントへの入力として引き渡すパターンです。

処理の流れが一方向に決まっており、各エージェントが前段の結果を受け取って処理を行うため、段階的に情報を加工・変換していくようなユースケースに適しています。

from google.adk.agents import Agent, SequentialAgent

# Agent A: 質問を分析する
analyzer_agent = Agent(
    name="analyzer_agent",
    model="gemini-3-flash-preview",
    description="ユーザーの質問を分析・分類するエージェント",
    instruction=(
        "ユーザーの質問を分析して、以下の形式で分類結果を出力してください。\n"
        "- カテゴリ: [天気 / 時刻 / 観光 / その他]\n"
        "- 都市名: [都市名(英語)]\n"
        "- 要約: [質問の要約]\n"
        "分類結果のみを出力し、回答はしないでください。"
    ),
)

# Agent B: 分析結果をもとに回答する
responder_agent = Agent(
    name="responder_agent",
    model="gemini-3-flash-preview",
    description="分析結果をもとに最終回答を生成するエージェント",
    instruction=(
        "前のエージェントの分析結果を読み、それに基づいて"
        "ユーザーにわかりやすい日本語で回答してください。"
    ),
    tools=[get_weather, get_time,],
)

# A → B の順で実行
root_agent = SequentialAgent(
    name="sequential_pipeline",
    sub_agents=[analyzer_agent, responder_agent],
)

7.2 並列(Parallel)パターン 同時に実行して統合

Parallelパターンは、複数のエージェントを同時に実行し、それぞれの結果を最後にまとめるパターンです。
各エージェントの処理が互いに依存していない場合、逐次実行するよりも並列で同時に処理することで、全体の応答時間を短縮することができます。複数の情報を同時に取得したい場面や、処理に時間がかかるAPIを複数呼び出す必要がある場面に特に有効です。

from google.adk.agents import Agent, SequentialAgent, ParallelAgent

# 並列で動く専門エージェント
weather_agent = Agent(
    name="weather_agent",
    model="gemini-3-flash-preview",
    description="天気情報を取得するエージェント",
    instruction="ユーザーが言及した都市の天気をget_weatherで取得してください。",
    tools=[get_realtime_weather],
)
time_agent = Agent(
    name="time_agent",
    model="gemini-3-flash-preview",
    description="現在時刻を取得するエージェント",
    instruction="ユーザーが言及した都市の現在時刻をget_current_timeで取得してください。",
    tools=[get_current_time],
)

# 2つを同時実行
parallel_fetch = ParallelAgent(
    name="parallel_fetch",
    sub_agents=[weather_agent, time_agent],
)

# 結果を統合するエージェント
summarizer_agent = Agent(
    name="summarizer_agent",
    model="gemini-3-flash-preview",
    description="並列取得した情報を統合して回答するエージェント",
    instruction="これまでの会話に含まれる天気・時刻の情報をすべて統合して回答してください。",
)

# 並列取得 → 統合 のパイプライン
root_agent = SequentialAgent(
    name="travel_pipeline",
    sub_agents=[parallel_fetch, summarizer_agent],
)

7.3 コーディネーター パターン 質問に応じて振り分け

コーディネーターパターンは、ルーターとなるエージェントがユーザーの意図を判断し、適切な専門エージェントに処理を委譲するパターンです。

7.1の直列パターンや7.2の並列パターンとは異なり、実行されるエージェントがユーザーの入力内容によって動的に変わる点が特徴です。ルーターエージェントはLLMの判断力を活かして振り分けを行うため、複雑な条件分岐をコードで書く必要がなく、instructionに振り分けルールを自然言語で記述するだけで実現できます。

from google.adk.agents import Agent

# 専門エージェントたち
weather_agent = Agent(
    name="weather_agent",
    model="gemini-3-flash-preview",
    description="都市の天気情報を回答する専門エージェント",
    instruction="天気情報をget_realtime_weatherで取得して回答してください。",
    tools=[get_realtime_weather],
)
time_agent = Agent(
    name="time_agent",
    model="gemini-3-flash-preview",
    description="都市の現在時刻を回答する専門エージェント",
    instruction="現在時刻をget_current_timeで取得して回答してください。",
    tools=[get_current_time],
)

# ルーターAgent: 質問を見て適切なエージェントに振り分ける
root_agent = Agent(
    name="router_agent",
    model="gemini-3-flash-preview",
    description="ユーザーの質問を適切な専門エージェントに振り分けるルーター",
    instruction=(
        "あなたはルーターです。ユーザーの質問内容を判断して、"
        "適切な専門エージェントに処理を委譲してください。\n"
        "- 天気の質問 → weather_agent\n"
        "- 時刻の質問 → time_agent\n"
        "自分では回答せず、必ず専門エージェントに委譲してください。"
    ),
    sub_agents=[weather_agent, time_agent],  # ← sub_agents で委譲先を指定
)

8. まとめ

本記事では Google ADKを使ったエージェント開発の基本について以下の内容を紹介しました。

セクション内容
最小構成エージェントmodelinstructionname の3つの要素でエージェントを構築する
ツール付きエージェントPython関数をツールとして付与し、LLMが自律的に呼び出す仕組みを実装する
外部API連携OpenWeather APIなどの外部サービスをツールとして組み込み、リアルタイム情報を取得する
マルチエージェントSequential・Parallel・コーディネーターの3パターンで複数エージェントを組み合わせる

ADKはシンプルなコードでエージェントを構築できる一方で、マルチエージェント構成や外部API連携を組み合わせることで、実用的なアプリケーションへと発展させることができます。

また、エージェントの振る舞いの多くは instruction の設計によって決まります。どのような役割を持たせるか、どのツールをいつ使うかを明確に記述することが、精度の高いエージェントを構築するうえで最も重要なポイントです。

この記事を書いた人

つぼた (id:one_tabo)

AI Agent 系のプラットフォームをさわっています。