2026年7月27日

【2026年7月版】ADK 2.0 × Agent Runtimeで作るマルチエージェント実装ガイド


Content

こんにちは!みっちーです!


以前、「データサイエンスエージェントのADKを2.0 Betaにアップデートしてみた!新しいWorkflowクラスも試してみる」という記事で、ADK 2.0のBeta版(v2.0.0b1)と新しいWorkflowクラスを触ってみたレポートを書きました。あれから2ヶ月ほど経ち、2026年5月19日についにADK 2.0が安定版(2.0.0)としてGA、その後も進化を続けて2026年7月時点では2.4.0まで到達しています。Beta版で気になっていた挙動が正式版でどう変わったのか、そして本番運用を見据えてAgent Runtimeへ実際にデプロイまでできるのかを、今回あらためて検証してみました。


2026年は、いよいよ「マルチエージェント元年」と言える1年になってきました。単体のLLMに全部を任せるのではなく、役割ごとに分けた複数のエージェントを連携させて、複雑なタスクを分担して解かせる。そんな構成が当たり前になりつつあります。ADK 2.0で追加されたWorkflowクラスは、まさにこの流れを後押しするもので、グラフベースでワークフローを明示的に定義できるようになり、マルチエージェントの「どのエージェントからどのエージェントへ処理を渡すか」をコードで決定論的に制御できるようになりました。


この記事では、ADK 2.0のセットアップ → マルチエージェント設計 → 新しいWorkflowクラスでのルーティング → Agent Runtime(旧:Vertex AI Agent Engine)へのデプロイ → 動作確認まで、一連の流れを実装ガイドとしてまとめてみました。すでにGAして本番利用できる状態なので、プレビュー検証ではなくそのまま本番に持っていける手順として書いています。これから2.0でマルチエージェントを組みたい方の、最初の一歩の地図になれば嬉しいです。


なお、ADK 2.0系はすでにGAしたproduction-grade(本番利用可能)のリリースです。この記事でもローカルで動作確認したうえで、Agent Runtimeへの本番デプロイまで通して試しています。1.x系も並行して保守されているので、既存プロジェクトは慌てずに移行できます。

ADK 2.0の全体像

実装に入る前に、2.0で何が変わったのかをざっくり整理しておきます。ここを押さえておくと、後の実装がスムーズになります。

① グラフベースのWorkflowクラス

2.0の最大の目玉がWorkflowクラスです。これまでのマルチエージェント構成は、root_agentの指示に従ってLLMがサブエージェントを呼び分ける「LLM任せのルーティング」でした。2.0ではedgesパラメーターとSTARTノードを使って、実行フローをグラフとして明示的に定義できます。

from google.adk import Agent, Workflow

# edges で「どこからどこへ処理を渡すか」を宣言的に書く
# START は import するシンボルではなく文字列リテラル "START" を使う
workflow = Workflow(
name="support_workflow",
edges=[
("START", classifier_agent, route_fn),
(route_fn, {"ROUTE": next_agent}),
],
)

② 従来のフロー制御クラスとWorkflowの使い分け

これまでフロー制御に使ってきたSequentialAgentParallelAgentLoopAgentは、2.0でもそのままサポートされています(非推奨にはなっていません)。シンプルな直列実行・並列実行なら、これらの従来クラスで書くのがいちばん手軽です。一方で、条件分岐・ループ・ネスト・human-in-the-loopといった複雑なフロー制御が絡むケースでは、新しいWorkflowクラスでグラフとして書くほうが見通しよく組めます。用途に応じて使い分けるのが2.0のスタイルです。

なお、Agent(LlmAgent)クラス自体は非推奨ではありません。エージェント単体の定義はこれまで通りで、「エージェント同士のつなぎ方」だけがWorkflowに変わる、というイメージです。

③ 実行モデルの刷新(グラフ内のノード単位実行)

内部実装として、Agent・Tool・Functionがワークフローグラフ内の個別のノードとして評価される実行モデルに刷新されました(公式チェンジログでも”Flexible Execution Graphs”として明記されています)。実行単位がノードとして統一されたことで、実行ログがノード単位で分かれて表示されるようになり、どのエージェントがどのステップで何を処理したかがぐっと追いやすくなっています。マルチエージェントのデバッグでこれは地味に嬉しいポイントです(この記事の検証でも、イベントトレースがclassifier_agent→retriever_agent→responder_agentのようにノードごとに分かれて出力されることを確認しています)。

前提条件 / 試した環境

今回試した前提条件と環境は以下の通りです。

  • Python 3.10以上(ADK 2.0の要件)。今回はPython 3.12で検証しました。
  • Google Cloudプロジェクトが用意済みで、Vertex AI APIが有効化されていること。
  • gcloud CLIで認証済み(gcloud auth application-default login)であること。
  • ADKでのエージェント開発が初めての方は、まず「Agent Development Kitでデータサイエンスエージェントを開発してみた!」で基本の流れを掴んでおくとスムーズです。

題材としては、シンプルに問い合わせ分類 → 検索 → 回答生成の3エージェント構成のカスタマーサポートBotを組んでみます。

実装してみた

①インストール

ADK 2.0系はすでにGAしているので、通常のpip install google-adkでそのまま安定版(2.x)が入ります。プレリリース用の–preフラグはもう不要です。

pip install google-adk
# バージョンを明示したい場合
pip install "google-adk>=2.0"

poetryでプロジェクトを管理している場合も、poetry add google-adkで問題なく導入できます。特別な回避策は必要ありません。

# poetryを使っている場合
poetry add google-adk

インストール後、バージョンを確認しておきます。

python -c "import google.adk; print(google.adk.__version__)"
# 2.4.0

無事に2.4.0が入りました(執筆時点の最新版です)。

②サブエージェント定義

まずは各エージェントを定義します。今回は分類(classifier)検索(retriever)回答生成(responder)の3つに役割を分けました。エージェント単体の定義は1.xとほぼ変わらず、Agentクラスをそのまま使います。

# agents/sub_agents.py
from google.adk.agents import Agent

# ① 問い合わせ分類エージェント
classifier_agent = Agent(
name="classifier_agent",
model="gemini-2.5-flash",
instruction=(
"ユーザーの問い合わせを分類してください。"
"技術的な質問やドキュメント検索が必要なら 'SEARCH'、"
"雑談・あいさつなら 'CHAT' とだけ出力します。"
),
)

# ② 検索エージェント(社内ナレッジ検索ツールを想定)
retriever_agent = Agent(
name="retriever_agent",
model="gemini-2.5-flash",
instruction="ユーザーの質問に関連する社内ドキュメントを検索し、要点を抜き出してください。",
tools=[search_knowledge_base], # 別途定義した検索ツール
# Workflowのノードとして使うLlmAgentはデフォルトでmode="single_turn"になり、
# include_contentsを明示しないと自動的に"none"へ上書きされる。
# その結果、直前のノード(ここではclassifier_agent)の出力だけしか見えず、
# 元のユーザー発言(検索したい内容そのもの)を見失ってしまう。
# 会話履歴全体を見せたい場合は"default"を明示する。
include_contents="default",
)

# ③ 回答生成エージェント
responder_agent = Agent(
name="responder_agent",
model="gemini-2.5-pro",
instruction="検索結果を踏まえて、丁寧でわかりやすい日本語の回答を生成してください。",
include_contents="default", # 同上。省略すると質問内容を無視した的外れな回答になる
)

役割ごとにmodelを使い分けているのがポイントです。分類・検索は軽量なgemini-2.5-flash、最終的な回答生成だけgemini-2.5-proにすることで、コストと品質のバランスを取っています。

ここでinclude_contents=”default”を明示しているのは重要な落とし穴です。Workflowのノードとして動くLlmAgentは、内部的にデフォルトでmode=”single_turn”として扱われ、include_contentsを明示しないと自動的に“none”(直前のノードの出力しか見ない)に上書きされてしまいます。この記事の構成では、retriever_agentやresponder_agentがclassifier_agentの出力(”SEARCH”という一語)しか見えず、ユーザーが本当に知りたかった内容(例:エラーコードE403)が伝わらないという不具合を実際に確認しました。include_contents=”default”を明示して会話履歴全体を見せることで解決します。

③Workflowクラスでルーティングを制御

いよいよ2.0の本命です。3つのエージェントをWorkflowでつなぎます。ここで、分類結果に応じて処理を振り分けるroute関数を挟むのがコツです。route関数はLLMではなくPythonコードで動くので、ルーティングの結果が予測可能になります。

# agents/workflow.py
from google.adk import Workflow
from google.adk.events import Event
from .sub_agents import classifier_agent, retriever_agent, responder_agent

def route(node_input: str) -> Event:
"""分類エージェントの出力を見て次のノードを決めるルーター関数"""
label = node_input.strip().upper()
if "SEARCH" in label:
return Event(route="SEARCH")
return Event(route="CHAT")

# グラフ定義:START → 分類 → route関数 → 検索 or 直接回答 → 回答生成
# START はインポートするシンボルではなく文字列リテラル "START" を使う
workflow = Workflow(
name="support_workflow",
edges=[
("START", classifier_agent, route),
(route, {
"SEARCH": retriever_agent, # 検索が必要ならまず検索
"CHAT": responder_agent, # 雑談ならそのまま回答へ
}),
(retriever_agent, responder_agent), # 検索後は回答生成へ
],
)

edgesを上から読むと、そのまま処理の流れになっているのが分かると思います。STARTから分類エージェントに入り、route関数でSEARCHCHATに分岐、検索が必要ならretriever_agentを通ってからresponder_agentで回答を作る、という流れです。

「検索の質問のつもりだったのに雑談扱いされた」というLLMの気まぐれが起きにくくなるのが、Workflowにする一番のメリットだと感じました。フローが1つのグラフとしてコードに書いてあるので、後から読み返したときの見通しも良いです。

④adk webでローカル動作確認

デプロイの前に、必ずローカルで動作を確認します。adk webでローカルサーバーを立ち上げ、ブラウザのチャットUIから試せます。

cd agents
adk web
# http://localhost:8000 にアクセスしてチャットUIで動作確認



「ログイン時のエラーコード E403 の意味を教えて」と入力すると分類がSEARCHに振られて検索エージェントを経由し、「こんにちは」だとCHATで直接回答に行く、という挙動を確認できました。2.0では実行ログがノード単位で分かれて表示されるので、どのルートを通ったかが一目で分かります。なお、検索エージェントに投げる質問は「調べ方を教えて」のような曖昧な言い回しだと検索ツールを呼ばずに聞き返してしまうことがあるため、この記事のように具体的なキーワード(今回であればE403というエラーコード)を含めるのがおすすめです(詳しくは後述の「つまずいたポイント①」を参照)。



⑤Agent Runtimeへデプロイ

ローカルで問題なければ、いよいよAgent Runtime(旧:Vertex AI Agent Engine)へデプロイします。名称は変わりましたが、マネージドでエージェントをホストしてくれるサービスという位置づけは同じです。

vertexaiのSDKからデプロイします。作成したWorkflowはAdkAppでラップしてから渡します。

# deploy.py
import vertexai
from vertexai import agent_engines
from vertexai.preview.reasoning_engines import AdkApp
from agents.workflow import workflow

vertexai.init(
project="your-gcp-project",
location="us-central1",
staging_bucket="gs://your-staging-bucket",
)

# Workflow は AdkApp でラップしてから Agent Runtime へデプロイする
app = AdkApp(agent=workflow)

remote_app = agent_engines.create(
app,
requirements=[
"google-adk>=2.0",
"google-cloud-aiplatform[adk,agent_engines]",
],
# 自作の agents パッケージ(sub_agents.py / workflow.py)は
# pip requirements には乗らないので extra_packages で明示的に同梱する。
# これを忘れると cloudpickle でシリアライズされた Workflow がリモート側で
# 「No module named 'agents'」となり、デプロイ自体は成功してもエージェントが
# 起動できずに落ちる。
extra_packages=["agents"],
display_name="support-workflow",
)
print(remote_app.resource_name)



デプロイ時に見落としがちなのがIAM権限です。デプロイを実行するアカウントにVertex AI ユーザー(roles/aiplatform.user)、そしてステージング用バケットへのStorage オブジェクト管理者(roles/storage.objectAdmin)を付与しておきます。

gcloud projects add-iam-policy-binding your-gcp-project \
--member="user:you@example.com" \
--role="roles/aiplatform.user"

デプロイ後は、返ってきたresource_nameを使ってリモートのエージェントに問い合わせられます。デプロイの詳しい流れは「データサイエンスエージェントをAgent Engineにデプロイしてみた!」でも解説しているので、あわせて参考にしてみてください。

# デプロイ済みエージェントを取得して動作確認
remote_app = agent_engines.get("projects/.../reasoningEngines/...")

for event in remote_app.stream_query(
user_id="user-001",
message="ログイン時のエラーコード E403 の意味を教えて",
):
print(event)



ローカルのadk webと同じ挙動でリモートでも回答が返ってきたら成功です。お疲れさまでした!

つまずいたポイント・気づいたこと

① Workflowノードは会話履歴が見えない(include_contentsを明示する)

今回の検証で一番深刻だった不具合がこれです。「ログイン時のエラーコード E403 の意味を教えて」のような具体的な質問を投げても、retriever_agentが検索ツールを呼ばずに「検索したいキーワードを教えてください」と聞き返し、responder_agentもエラーコードと無関係な一般論を返す、という頓珍漢な挙動を複数回再現しました。

原因は、Workflowのノードとして使われるLlmAgentはデフォルトでmode=”single_turn”として実行され、include_contentsを明示しない限り自動的に”none”へ上書きされるという仕様です。これにより各ノードは会話履歴全体ではなく直前のノードの出力だけしか見えなくなり、retriever_agentやresponder_agentはclassifier_agentが出力した”SEARCH”という一語しか受け取れず、ユーザーの元の質問文(E403の話)を見失っていました。実際に4回連続で試したところ、3回は的外れな回答になり、1回だけ(たまたまツールを呼んだ場合)正しい回答になるという、非常に不安定な状態でした。

対処は簡単で、retriever_agentresponder_agentの定義にinclude_contents=”default”を明示するだけです。これを追加した状態で同じ質問を3回試したところ、3回とも正しくE403を検索し、権限不足に関する的確な回答が返ってくることを確認しました。この記事のコード例には反映済みですが、Workflowでエージェントをつなぐ際はノードごとに何が見えているかを意識しておくことを強くおすすめします。

② 1.xからの移行はセッションスキーマの破壊的変更に注意

既存の1.x系プロジェクトから2.0へ上げるときは、セッション周りのスキーマに破壊的変更が入っている点に注意です。1.xで保存したセッション状態をそのまま2.0で読み込もうとすると噛み合わないことがあるので、移行時は新しいスキーマ前提でセッションを作り直すのが安全でした。エージェント単体の定義(Agentクラス)はほぼ変わらないので、詰まりやすいのはこのつなぎ目の部分です。

③ route関数はシンプルに保つ

route関数にLLMを使わない分、分類エージェントの出力ラベルの揺れがそのままルーティング精度に直結します。分類エージェントには「SEARCH か CHAT だけを出力する」とはっきり指示し、route関数側でもupper()や部分一致で吸収しておくのが安全でした。ここを曖昧にすると、分岐が意図せず片方に偏ります。

④ extra_packagesで自作パッケージの同梱を忘れない

実際に検証用プロジェクトへデプロイして踏んだ、一番ハマりやすい落とし穴がこれです。agent_engines.create()のrequirementsに渡すのはpipパッケージのリストであり、自分で書いたagentsパッケージ(sub_agents.py・workflow.py)はそこには含まれません

AdkAppはWorkflowをcloudpickleでシリアライズしてアップロードしますが、リモート側のコンテナに元のPythonモジュールが存在しないと、デプロイ自体(agent_engines.createの呼び出し)は成功したように見えても、実際にはコンテナ起動時に「No module named ‘agents’」で失敗し、LROがエラーで終わります。extra_packages=[“agents”]のように自作パッケージを明示的に指定して同梱する必要があります。

また、ローカル環境にcloudpickleが入っていないと、そもそもagent_engines.create()を呼んだ時点でローカルでModuleNotFoundError: No module named ‘cloudpickle’となるので、pip install “google-cloud-aiplatform[agent_engines]”でローカル側の依存関係も先に揃えておくのがおすすめです。

⑤ requirementsにagent_enginesエクストラを忘れない

デプロイ時のrequirementsgoogle-cloud-aiplatform[adk,agent_engines]を入れ忘れると、リモート側でインポートエラーになって起動しませんでした。ローカルでは動くのにデプロイ後だけ落ちる、という状況になりやすいので、依存関係の指定は丁寧に確認しておくのがおすすめです。

⑥ デフォルトモデルの変更に注意(2.2.0以降)

2.0系は本番利用できるリリースなので、Agent Runtimeへそのままデプロイして問題ありません。ただしバージョンアップ時に一点注意で、2.2.0でデフォルトモデルが gemini-3-flash-preview に変更されています。さらに執筆時点の最新2.4.0では、デフォルトモデルはgemini-3.5-flashまで更新されていました。modelを明示せずにエージェントを定義していると、バージョンアップのたびに挙動やコストが変わってしまうので、この記事のように役割ごとにmodelを明示指定しておくのがおすすめです。なお2.4.0ではWorkflow as ToolManagedAgentも追加され、より柔軟な構成が組めるようになっています。

まとめ

GA済みのADK 2.0系で、マルチエージェントをAgent Runtimeにデプロイするところまで一通り試してみました。

  • ADK 2.0系はGA済みで、pip install google-adk(またはpoetry add)でそのまま安定版が導入できる(–preは不要)
  • エージェント単体はAgentクラスのまま。役割ごとにモデルを使い分けるとコスト効率が良い
  • 新しいWorkflowクラスとedges / START / route関数で、ルーティングをコードで明示的に制御できる
  • Workflowのノードはmode=”single_turn”がデフォルトで、include_contents=”default”を明示しないと会話履歴が見えず的外れな回答になる。retriever_agent・responder_agentには必ず明示する
  • SequentialAgentParallelAgentLoopAgentも引き続きサポート。シンプルな直列/並列は従来クラス、複雑なフロー制御はWorkflowで使い分ける
  • デプロイ先はAgent Runtime(旧:Vertex AI Agent Engine)。IAM権限・requirementsに加えて、自作パッケージのextra_packages指定を忘れずに(これを忘れるとリモート起動時に「No module named …」で落ちる)
  • 2.0系は本番利用可能。1.xからの移行はセッションスキーマの破壊的変更、2.2.0以降はデフォルトモデルの変更に注意

グラフでフローを書けるようになったことで、マルチエージェントの「見通しの良さ」と「動作の予測可能性」が一気に上がった印象です。まずはローカルのadk webで小さく試してみるところから、ぜひ2.0のマルチエージェント開発に触れてみてください!最後まで読んでいただき、ありがとうございました!

システムサポートでは、Google Cloudの導入や活用を支援しております。

Google Cloudを導入したい・導入したけど使いこなせていない…という方は、お気軽にご相談ください!

Google Cloud 導入・活動支援に関するご相談はこちら

2026年7月27日 【2026年7月版】ADK 2.0 × Agent Runtimeで作るマルチエージェント実装ガイド

Category Google Cloud

ご意見・ご相談・料金のお見積もりなど、
お気軽にお問い合わせください。

お問い合わせはこちら