この記事はNTTドコモソリューションズ Advent Calendar 2025 9日目の記事です。
はじめに
最近、生成AIを使った開発において、単なるチャットボットではなく、タスクを自律的にこなす「AI Agent(エージェント)」への注目が高まっています。
しかし、実際にエージェントを作ろうとすると、プロンプトの管理やフローの制御、外部ツールとの連携など、設計するべき点も多く、実装するまでたどり着かないことも多いかと思います。
そこで今回は、Googleが提供する 「Agent Development Kit」 を試してみました。
ADKを使うと、エージェントを機能ごとにモジュール化して管理しやすくなります。
本記事では、ADKの基本的な概念から、実際に複数のエージェントを組み合わせた実装例までを紹介します。
この記事の対象読者
- Google ADKの概要をサクッと知りたい方
- Agent開発における「構成管理」に興味がある方
- 実際に動くコードを見たい方
エージェントとは
エージェントとは、与えられた目的を達成するために、自律的に判断・行動するシステムのことです。
これまでは困難だった「状況に応じた柔軟な判断」が、近年のLLM(大規模言語モデル)の進化によって可能になり、急速に注目を集めています。
Agent Developer Kit(ADK)とは
Googleが開発・公開した、AIエージェントの開発・評価・導入を行うためのフレームワークです。
正式名称は 「Agent Development Kit」 です。
ADKを採用する主なメリットは以下の通りです。
- モジュール化: 個々の機能(プロンプトやツール)を部品として管理しやすい。
- フロー制御: 順次実行や分岐などの複雑なワークフローをコードで直感的に書ける。
- 拡張性: 自作のAPIや外部ツールとの連携(Function Calling)が容易。
基本的な使い方は、後述する実装例で解説します。
なお、ADKの全体像やセットアップの詳細については、参考文献に分かりやすい記事がありましたので、そちらも併せてご参照ください。
エージェントの種類
エージェントと一言に言っても、実は様々なものがあります。
ここではADKが分類している3つの主要なタイプについてご紹介します。
LLM Agent
みなさんが真っ先に思い浮かべる、LLM(GeminiやChatGPT等)を使って推論を行うエージェントです。
単に会話するだけでなく、Tools(ツール) を使って外部APIを叩いたり、計算を行ったりすることができます。
Workflow Agent
LLM AgentやCustom Agent(後述)を組み合わせる際、決まった手順(ワークフロー)で実行させたいときに使うエージェントです。
動き方に合わせて以下の3種類があります。
Sequential Agent

出典: Sequential agents - Agent Development Kit https://google.github.io/adk-docs/agents/workflow-agents/sequential-agents/ (参照日: 2025年12月3日)
図のように直列でエージェントを実行したいときに使います。
- 例: 「報告書を作るエージェント」→「それをレビューするエージェント」のように、前工程の結果を後工程に渡すケース。
Parallel Agent

出典: Parallel agents - Agent Development Kit https://google.github.io/adk-docs/agents/workflow-agents/parallel-agents/ (参照日: 2025年12月3日)
図のように並列でエージェントを実行したいときに使います。
- 例: 同じテーマについて、「Web検索エージェント」と「社内Wiki検索エージェント」を同時に走らせて情報収集するケース。
Loop Agent

出典: Loop agents - Agent Development Kit https://google.github.io/adk-docs/agents/workflow-agents/loop-agents/ (参照日: 2025年12月3日)
図のように特定の条件を満たすまで繰り返し実行したいときに使います。
- 例: 記事の要約を行い、「指定文字数以下になるまで」何度も修正させるケース。
Custom Agent
標準のクラスでは対応できない、独自のロジックを実装するエージェントです。
Pythonコードで書ける処理なら何でも組み込めるため、以下のような高度な制御を行いたい場合に使用します。
- Human-in-the-loop(HITL): 処理の途中で人間に承認を求める。
- Router(動的分岐): ユーザーの入力内容に応じて、次に呼ぶエージェントを動的に切り替える。
- Legacy System: AI非対応の古いシステムやデータベースを操作する。
余談
ちなみに、ADKのクラス継承関係は以下のようになっています。
あまり意識することはないですが、カスタマイズする際の参考になるかもしれません。
実際の実装例
実際に日記を作るエージェントを作ってみたいと思います。
構成図
日記といえば天気の記録が欠かせませんよね。天気を必ず取得するためRESTAPIを使うべく、CustomAgentで実装しています。
その情報をもとに日記を執筆させたいので、LlmAgentで実装したうえでSequentialAgentを利用しています。
ソースコード
ソースコードの全量は下記のとおりです。
google-adkは1.17.0を利用しています。
長いので、ピックアップして下記で説明していきます。
import asyncio
from typing import AsyncGenerator
from google.adk.agents import BaseAgent, LlmAgent, SequentialAgent
from google.adk.agents.invocation_context import InvocationContext
from google.adk.events import Event
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
from google.genai.types import Content, Part
# 天気情報を取得するエージェント
class WeatherAgent(BaseAgent):
def __init__(self) -> None:
super().__init__(
name="weather_agent",
description="指定された場所の現在の天気情報を取得します。",
)
async def _run_async_impl(
self, ctx: InvocationContext
) -> AsyncGenerator[Event, None]:
# ここではダミーの天気情報を返します。
yield Event(
author="weather_agent",
content=Content(
role="model",
parts=[Part(text="12/8の東京の天気は晴れ、気温は25度です。")],
),
partial=False,
invocation_id=ctx.invocation_id,
)
# 日記を書くエージェント
class DiaryWriterAgent(LlmAgent):
def __init__(self) -> None:
super().__init__(
name="diary_writer_agent",
description="提供された天気情報を基に日記を書きます。",
model="gemini-2.5-flash",
instruction="あなたは優れた日記作家です。提供された天気情報を基に、感情豊かな日記を書いてください。",
)
# 天気情報と日記を書くエージェントを組み合わせたシーケンシャルエージェント
class DiaryAgent(SequentialAgent):
def __init__(self) -> None:
weather_agent = WeatherAgent()
diary_writer_agent = DiaryWriterAgent()
super().__init__(
name="diary_agent",
description="天気情報を取得し、その情報を基に日記を書きます。",
sub_agents=[weather_agent, diary_writer_agent],
)
def main() -> None:
session_service = InMemorySessionService()
diary_agent = DiaryAgent()
app_name = "write daily"
user_id = "user_123"
runner = Runner(
agent=diary_agent,
app_name=app_name,
session_service=session_service,
)
content = Content(
role="user",
parts=[
Part(
text="12/8は渋谷に買い物に行きました。欲しいものがたくさんあって、とても楽しかったです。",
)
],
)
session = asyncio.run(
session_service.create_session(app_name=app_name, user_id=user_id)
)
events = runner.run(
user_id="user_123",
session_id=session.id,
new_message=content,
)
for event in events:
if event.is_final_response() and event.content:
print(f"{event.author}の出力:")
for part in event.content.parts:
print(part.text)
if __name__ == "__main__":
main()
CustomAgent(WeatherAgent)
実態としてはBaseAgentになるので、BaseAgentを継承して記載する必要があります。
実行する内容は_run_async_implをオーバーライドして記載します。
Eventはcontentのroleをmodelに指定しておくか、stateに入れる必要があるため、今回はAgentの回答として、contentで後続のエージェントに渡しています。
# 天気情報を取得するエージェント
class WeatherAgent(BaseAgent):
def __init__(self) -> None:
super().__init__(
name="weather_agent",
description="指定された場所の現在の天気情報を取得します。",
)
async def _run_async_impl(
self, ctx: InvocationContext
) -> AsyncGenerator[Event, None]:
# ここではダミーの天気情報を返します。
yield Event(
author="weather_agent",
content=Content(
role="model",
parts=[Part(text="12/8の東京の天気は晴れ、気温は25度です。")],
),
partial=False,
invocation_id=ctx.invocation_id,
)
LlmAgent(DiaryWriterAgent)
今回はGemini2.5-flashを利用して、日記を書かせています。
instructionとなっているのが、システムプロンプトです。現在のバージョンでは、static_instructionの指定有無によって、システムプロンプトの指定する場所が違うのでご注意ください。
# 日記を書くエージェント
class DiaryWriterAgent(LlmAgent):
def __init__(self) -> None:
super().__init__(
name="diary_writer_agent",
description="提供された天気情報を基に日記を書きます。",
model="gemini-2.5-flash",
instruction="あなたは優れた日記作家です。提供された天気情報を基に、感情豊かな日記を書いてください。",
)
SequentialAgent(DiaryAgent)
上記2つのエージェントを順々に実行するため、サブエージェントに指定しています。
# 天気情報と日記を書くエージェントを組み合わせたシーケンシャルエージェント
class DiaryAgent(SequentialAgent):
def __init__(self) -> None:
weather_agent = WeatherAgent()
diary_writer_agent = DiaryWriterAgent()
super().__init__(
name="diary_agent",
description="天気情報を取得し、その情報を基に日記を書きます。",
sub_agents=[weather_agent, diary_writer_agent],
)
main部
Agentとして使うためのクラウド基盤(SessionやRunner)を定義しています。
そのあとに実際に実行して結果を得ています。
def main() -> None:
session_service = InMemorySessionService()
diary_agent = DiaryAgent()
app_name = "write daily"
user_id = "user_123"
runner = Runner(
agent=diary_agent,
app_name=app_name,
session_service=session_service,
)
content = Content(
role="user",
parts=[
Part(
text="12/8は渋谷に買い物に行きました。欲しいものがたくさんあって、とても楽しかったです。",
)
],
)
session = asyncio.run(
session_service.create_session(app_name=app_name, user_id=user_id)
)
events = runner.run(
user_id="user_123",
session_id=session.id,
new_message=content,
)
for event in events:
if event.is_final_response() and event.content:
print("各エージェントの出力:")
for part in event.content.parts:
print(part.text)
実行結果
pythonで実行すると下記のようなものが各エージェントから取得できます。
weather_agentの出力:
12/8の東京の天気は晴れ、気温は25度です。
diary_writer_agentの出力:
12月8日
今日は、冬の足音が聞こえ始めるはずの12月だというのに、東京はまさかの快晴、気温はなんと25度!まるで春のような陽気に包まれた一日でした。厚手のコートは必要なく、身軽な格好で渋谷の街を闊歩できるなんて、なんだか不思議な感覚です。こんなにも穏やかな日差しの中で、心ゆくまでショッピングを楽しめるなんて、本当に贅沢な時間でした。
渋谷の街は、どこか浮き足立つようなクリスマスの気配と、この季節外れの暖かさが相まって、いつも以上にキラキラと輝いて見えました。ウィンドウに並ぶ魅力的な商品たちの一つ一つが、私の心を強く惹きつけます。あれも欲しい、これも素敵!と、目がいくつあっても足りないくらい。
特に目的を決めずに歩き始めたはずなのに、気づけば時間が経つのも忘れて、たくさんのお店を巡っていました。お洋服、雑貨、アクセサリー…どれもこれもが、今の私に「おいでよ!」と手招きしているよう。実際に手に取ったり、鏡の前で合わせてみたりするたびに、胸が高鳴るのを感じました。まさに、宝探しをしているような気分。
欲しいものがたくさん見つかって、今日は本当に大満足!両手にいっぱいのショップバッグを抱えて、充実感に満たされた笑顔で家路につきました。冬なのに暖かな日差しが降り注ぐ中、こんなにも楽しい時間を過ごせるなんて、最高の贈り物をもらった気分です。心も体もぽかぽかと温かくなった、幸せな一日でした。
さいごに
ADKを使うことで比較的簡単にエージェントを実装することができます。
変化が激しい領域なので、バージョンもご確認しながら試してもらえばと思います。
参考文献
- Index - Agent Development Kit https://google.github.io/adk-docs/ (参照日: 2025年12月3日)
- 🤖 Google Agent Development Kit (ADK) 入門ガイド #LLM - Qiita https://qiita.com/okikusan-public/items/9f351edda089f431ed26 (参照日: 2025年12月3日)
- google/adk-samples: A collection of sample agents built with Agent Development (ADK) https://github.com/google/adk-samples?tab=readme-ov-file (参照日: 2025年12月3日)
記載されている会社名、製品名、サービス名は、各社の商標または登録商標です。