4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【ADK 2.0 新機能】グラフベースのエージェントワークフローでより正確なAI制御を実現

4
Posted at

はじめに

Agent Development Kit (ADK) の新しいバージョン ADK 2.0 Beta が発表されました。
このアップデートにより、「グラフベースのエージェントワークフロー」がサポートされました。

「AIの柔軟な推論」と「プログラムの厳密なロジック」をいいとこ取りできる機能ということで、今回は基本的なノードとエッジと条件分岐に絞って早速試してみました。

本記事は基本的に ADK 1.x を触ったことがある方 を対象にしています。
ADKの基本概念は既知として進めます。

ADK 2.0 Beta を使用する際の注意点

  • ADK 2.0はベータ版リリースであり、以前のバージョンのADKと併用すると互換性の問題が発生する可能性があります。

グラフベースのワークフローとは?

これまでエージェントに複雑な作業をさせようとすると、どうしてもプロンプトが長くなりがちでした。
そして、指示が長くなればなるほど、AI が途中のステップを飛ばしたり、指示を無視したりして思った通りに動いてくれず、信頼性が低下する問題もあります。
そこで、全体のワークフローをコードで具体的に定義できるグラフワークフローが使えるようになりました。

全体の流れを一つの巨大なプロンプトで指示するのではなく、処理のステップを「ノード(Node)」として細かく分割し、それらを「エッジ(Edge)」で繋ぐようにコードで定義します。
これにより、AIに任せる部分(非決定論的な処理)と、自作コードやツールで確実に動かす部分(決定論的な処理)を組み合わせて、タスクの順序やデータの受け渡しを開発者側で完全にコントロールできるようになりました。

従来のプロンプトベースからの4つの利点

利点 詳細
正確なロジックの定義 ノード間の遷移を管理するルーティングロジックを、コード上で明示的にマッピングできます。
複雑な構造の実装 条件分岐やステート(状態)管理をサポートする高度なエージェントワークフローの構築が容易になります。
AIを介さない関数チェーンの実行 LLM(生成AIモデル)を都度呼び出すことなく、エージェントツールや独自のコードのみを連携して実行できます。これにより、意図しないハルシネーションを防ぎつつ処理を完了させることが可能です。
信頼性の強化 プロンプトの解釈(揺らぎ)だけに依存するのではなく、構造化されたノード定義に基づくため、エージェントの挙動の予測可能性と安定性が大幅に向上します。

「AIに判断させる範囲」と「コードで制御する範囲」のバランスを意識して設計することが重要です。

実装方法

Python 3.11以降で以下を実行。

インストール方法

pip install google-adk==2.0.0b1

or

pip install google-adk --pre

ADK の設定方法は以下を参照。

1. ノード(Nodes)とエッジ(Edges)の基本構文

グラフの構成要素となる「ノード」には、AIエージェント、ADKツール、人間の入力タスク、あるいは開発者が記述したPython関数(FunctionNode)などを割り当てることができます。
各ノードは Event オブジェクトを通じてデータを出力し、次のノードへ情報を伝播させます。

フローの実行経路は edges 配列で定義します。
最もシンプルな「順次実行(Sequence)」は以下のように書きます。

from google.adk import Workflow

root_agent = Workflow(
    name="sequential_workflow",
    edges=[("START", task_A_node, task_B_node, task_C_node)],
)

配列の最初に START キーワードを置くことでグラフの起点を宣言し、以降は記述された順序でノードが実行されます。

2. 条件分岐の実装

実際の業務プロセスでは、状況に応じた条件分岐が不可欠です。
ルーティング判定用の関数ノードを用意し、その出力する route の値に応じて次に実行するノードを振り分けることができます。

from google.adk import Event, Workflow

def router(node_input: str):
    # 何らかの判定ロジック
    return Event(route="RUN_TASK_C")

root_agent = Workflow(
    name="routing_workflow",
    edges=[
        ("START", task_A_node, router),
        (router, {
            "RUN_TASK_B": task_B_node,
            "RUN_TASK_C": task_C_node,  # 今回はこちらにルーティングされる
        }),
    ],
)

このように辞書型を用いてマッピングを行うため、分岐ロジックがコード上で極めて見やすくなります。

試してみた

ユーザーの入力内容に応じて AI が判断し、適切なプログラム処理へ受け渡すワークフローを定義してみました。
例として、簡易的なカスタマーサポート自動ルーティングシステムとしました。

1. AIエージェントを「分類器(Classifier)」として定義

まず、ユーザーの意図を汲み取るための AI エージェントを定義しています。

# 判定を行うLLMエージェント
classifier_agent = Agent(
    name="classifier_agent",
    model="gemini-2.5-flash",
    instruction="""ユーザーのメッセージを分析し、以下のいずれかのカテゴリに分類してください。
指定されたカテゴリ名(英字)のみを出力してください。
- COMPLAINT: クレームや不満、対応の遅れに関する内容
- INQUIRY: 商品の仕様や使い方などの一般的な問い合わせ
- OTHER: 上記に該当しないもの""",
    output_schema=str,
)

ここでは LLM に対して「特定のキーワード(COMPLAINT, INQUIRY, OTHER)のみを出力せよ」と指示しています。
これにより、プログラムが扱いやすい構造化データ(特定の文字列)に変換しています。

2. ルーター(Router)の定義

AI の出力結果を受け取って「次にどのノードを実行するか」を決定する関数を定義しています。

def router(node_input: str):
    """エージェントの分類結果を受け取り、経路を決定するノード"""
    category = node_input.strip()
    
    # AIの出力結果に基づいてルーティングイベントを発行
    if category == "COMPLAINT":
        return Event(route="ROUTE_COMPLAINT")
    elif category == "INQUIRY":
        return Event(route="ROUTE_INQUIRY")
    else:
        return Event(route="ROUTE_OTHER")

Event(route="...") を返すことで、グラフ上の分岐を制御します。

3. ロジック(ハンドラー)の切り出し

各ルートの先にある処理(ノード)を独立した関数として定義しています。

def complaint_handler():
    """クレーム対応ノード"""
    return Event(output="【優先対応部署】ご不便をおかけし申し訳ございません。至急確認いたします。")

def inquiry_handler():
    """一般問い合わせ対応ノード"""
    return Event(output="【一般サポート】お問い合わせありがとうございます。お調べいたします。")

def other_handler():
    """その他対応ノード"""
    return Event(output="【総合受付】メッセージを承りました。担当部署へ確認いたします。")

今回はテキストを返しているだけですが、実際にはここで「データベースへの登録」「Slack への通知」「API の呼び出し」など、AI を介さない処理を記述します。

4. ワークフローの定義

最後に、これら全ての部品を Workflow クラスで繋ぎます。

root_agent = Workflow(
    name="ai_routing_workflow",
    edges=[
        # STARTから始まり、AI分類エージェント -> ルーターの順に実行
        ("START", classifier_agent, router),
        
        # ルーターが出力した 'route' の値に基づいて処理を分岐
        (router, {
            "ROUTE_COMPLAINT": complaint_handler,
            "ROUTE_INQUIRY": inquiry_handler,
            "ROUTE_OTHER": other_handler,
        }),
    ],
)

edges の定義を見るとどのようなワークフローか理解できます。

全コード
from google.adk import Agent, Workflow, Event

# ==========================================
# 1. エージェントとノード(タスク)の定義
# ==========================================

# 判定を行うLLMエージェント
classifier_agent = Agent(
    name="classifier_agent",
    model="gemini-2.5-flash",
    instruction="""ユーザーのメッセージを分析し、以下のいずれかのカテゴリに分類してください。
指定されたカテゴリ名(英字)のみを出力してください。
- COMPLAINT: クレームや不満、対応の遅れに関する内容
- INQUIRY: 商品の仕様や使い方などの一般的な問い合わせ
- OTHER: 上記に該当しないもの""",
    output_schema=str,
)

def router(node_input: str):
    """エージェントの分類結果を受け取り、経路を決定するノード"""
    category = node_input.strip()
    print(f"[*] AIによる分類結果: {category}")
    
    # AIの出力結果に基づいてルーティングイベントを発行
    if category == "COMPLAINT":
        return Event(route="ROUTE_COMPLAINT")
    elif category == "INQUIRY":
        return Event(route="ROUTE_INQUIRY")
    else:
        return Event(route="ROUTE_OTHER")

def complaint_handler():
    """クレーム対応ノード"""
    return Event(output="【優先対応部署】ご不便をおかけし申し訳ございません。至急確認いたします。")

def inquiry_handler():
    """一般問い合わせ対応ノード"""
    return Event(output="【一般サポート】お問い合わせありがとうございます。お調べいたします。")

def other_handler():
    """その他対応ノード"""
    return Event(output="【総合受付】メッセージを承りました。担当部署へ確認いたします。")


# ==========================================
# 2. ワークフロー(グラフ)の構築
# ==========================================

root_agent = Workflow(
    name="ai_routing_workflow",
    edges=[
        # STARTから始まり、AI分類エージェント -> ルーターの順に実行
        ("START", classifier_agent, router),
        
        # ルーターが出力した 'route' の値に基づいて処理を分岐
        (router, {
            "ROUTE_COMPLAINT": complaint_handler,
            "ROUTE_INQUIRY": inquiry_handler,
            "ROUTE_OTHER": other_handler,
        }),
    ],
)

動作

「エアコンの使い方」と入力しました。
すると、最初にエージェントはこのテキストがどのカテゴリに属するかを分析し、"INQUIRY" と出力しています。
その後、エージェント が出力した "INQUIRY" という文字列が、router 関数(ルーターノード)に渡され、Event(route="ROUTE_INQUIRY") が選択されます。
そして、該当のハンドラー(inquiry_handler)が実行され、最終的に【一般サポート】お問い合わせありがとうございます。お調べいたします。と出力されます。

image.png

グラフも表示され、コードを読まなくてもグラフを見るだけでフロー全体が一瞬で把握でき、説明コストが下がりそうだと感じました。

他のルーティングの動作

"ROUTE_COMPLAINT"

image.png

"ROUTE_OTHER"

image.png

まとめ

今回は、新しく発表された ADK 2.0 Beta の「グラフベースのエージェントワークフロー」を実際に試し、基本構文から条件分岐を用いた簡易的なカスタマーサポートのルーティングまでを実装してみました。

これまでのすべてをプロンプトで制御するアプローチとは異なり、ワークフロー全体の流れや確実に行いたい処理を コード(決定論的) で制御し、高度な文脈理解が必要な部分だけを AI(非決定論的) に任せて信頼性を高めることができます。

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?