Java 用 Agent Development Kit(ADK)を使用して AI エージェントを構築する

1. AI エージェント デベロッパーの皆様、ようこそ。

この Codelab では、Java 用エージェント開発キット(ADK)を使用して、Java で AI エージェントを構築する方法を学びます。単純な大規模言語モデル(LLM)API 呼び出しを超えて、推論、計画、ツールの使用、連携を行って複雑な問題を解決できる自律型 AI エージェントを作成します。

まず、Google Cloud クレジットを利用して Google Cloud 環境を設定し、最初のシンプルなエージェントを構築します。その後、カスタムツール、ウェブ検索、マルチエージェント オーケストレーションなどの高度な機能を段階的に追加します。

d666c455bb267688.png

学習内容

  • ペルソナ主導の基本的な AI エージェントを作成する方法。
  • カスタムツールや組み込みツール(Google 検索など)を使用してエージェントを支援する方法。
  • Java で実装された独自のツールを追加する方法。
  • 複数のエージェントを強力なシーケンシャル ワークフロー、並列ワークフロー、ループ ワークフローにオーケストレートする方法。

必要なもの

  • シークレット モードで使用するウェブブラウザ。
  • 個人用の Gmail アカウント。
  • 個人の Gmail アカウントに関連付けられた新しい Google Cloud プロジェクト。
  • Google Cloud クレジットを利用して作成された請求先アカウント。
  • ソースコードをチェックアウトするための git コマンドライン ツール。
  • Java 17 以降と Apache Maven。
  • IntelliJ IDEA や VS Code などのテキスト エディタまたは IDE。

Google Cloud コンソールの Cloud Shell で、組み込みの VS Code エディタを使用できます。

2. セットアップ: 環境

ワークショップの Google Cloud クレジットの申請

e3e67ae61e86ec9f.png

講師主導のワークショップの場合、ワークショップで使用する Google Cloud クレジットを請求できるウェブサイトへのリンクが届きます。

  • 個人の Google アカウントを使用する: 会社のメールアドレスや学校のメールアドレスは使用できないため、個人の Google アカウント(gmail.com アドレスなど)を使用することが重要です。
  • Google Chrome をシークレット モードで使用する: クリーンなセッションを作成し、他の Google アカウントとの競合を避けるためにおすすめします。
  • 特別なイベントリンクを使用する: イベント用の特別なリンク(https://trygcp.dev/event/xxx のような形式で、その後にイベントコード(この例では「xxx」)が続きます)を使用する必要があります。
  • 利用規約に同意する: ログインすると、Google Cloud Platform の利用規約が表示されます。続行するには、これに同意する必要があります。
  • 新しいプロジェクトを作成する: Google Cloud コンソールで新しい空のプロジェクトを作成する必要があります。
  • 請求先アカウントをリンクする: 新しく作成したプロジェクトを請求先アカウントにリンクします。
  • クレジットを確認する: 次の動画では、請求ページの [クレジット] セクションを確認して、クレジットがプロジェクトに適用されていることを確認する方法について説明します。

クレジットの利用方法については、こちらの動画をご覧ください。

API キーを作成して構成する

この Codelab で ADK AI エージェントを Gemini API で認証するには、Google Cloud プロジェクトに関連付けられた API キーを使用します。

  1. API キーを生成する:
  • Google AI Studio にアクセスし、左側のサイドパネルの下部にある [API キーを取得] リンクをクリックします。
  • [プロジェクト] を選択し、[プロジェクトをインポート] ボタンをクリックします。
  • インポートする Google Cloud プロジェクトを検索して選択し、[インポート] ボタンを選択します。
  • プロジェクトがインポートされたら、ダッシュボード メニューから [API キー] ページに移動し、インポートしたプロジェクトに API キーを作成します。
  • API キーメモします。
  1. 環境変数を設定する: エージェントはこのキーにアクセスする必要があります。標準的な方法は、GOOGLE_API_KEY という名前の環境変数を設定することです。
  • macOS / Linux: ターミナルを開き、次のコマンドを実行します。"your-api-key" は先ほどコピーしたキーに置き換えます。これを永続的にするには、シェルの起動ファイル(~/.bash_profile~/.zshrc)。
export GOOGLE_API_KEY="your-api-key"
  • Windows(コマンド プロンプト): 新しいコマンド プロンプトを開き、次のコマンドを実行します。
setx GOOGLE_API_KEY "your-api-key"
  • この変更を有効にするには、コマンド プロンプトを再起動する必要があります。
  • Windows(PowerShell): PowerShell ターミナルを開き、次のコマンドを実行します。
$env:GOOGLE_API_KEY="your-api-key"
  • PowerShell でこの変更を永続的に行うには、プロファイル スクリプトに追加する必要があります。

3. スタートガイド: 初めてのエージェント

f814ab5b7614e071.png

新しいプロジェクトを開始する最良の方法は、ADK for Java GitHub テンプレートを使用することです。プロジェクト構造と必要な依存関係がすべて提供されます。

GitHub アカウントをお持ちの場合は、Use this template > Create a new repository を実行し、git clone コマンドでコードをローカルにチェックアウトできます。

テンプレートを使用するための右上のメニューが表示されたスクリーンショットは次のとおりです。

1613a3d0ddc66dc5.png

もう 1 つの方法は、次のコマンドを使用してリポジトリを直接クローンすることです。

git clone https://github.com/glaforge/adk-java-maven-template.git

次に、cdadk-java-maven-template に変換します。

Java で最初の AI エージェントのコーディングを開始する準備ができていることを確認するには、このプロジェクトのコードを次のコマンドでコンパイルできることを確認します。

mvn compile

コードステップ: 親切な理科の先生エージェント

ADK の基本的な構成要素は LlmAgent クラスです。大規模言語モデルを搭載した、特定の個性と目標を持つ AI と考えてください。今後、ツールを通じて機能をさらに追加し、他の同様のエージェントと連携して、より強力なものにしていく予定です。

com.example.agent パッケージに ScienceTeacher という新しい Java クラスを作成しましょう。

これはエージェント作成の「Hello, World!」です。ここでは、理科の先生のペルソナを持つシンプルなエージェントを定義しています。

// src/main/java/com/example/agent/ScienceTeacher.java
package com.example.agent;

import com.google.adk.agents.LlmAgent;
import com.google.adk.web.AdkWebServer;

public class ScienceTeacher {
    public static void main(String[] args) {
        AdkWebServer.start(
            LlmAgent.builder()
                .name("science-teacher")
                .description("A friendly science teacher")
                .instruction("""
                    You are a science teacher for teenagers.
                    You explain science concepts in a simple, concise and direct way.
                    """)
                .model("gemini-2.5-flash")
                .build()
        );
    }
}

AI エージェントは LlmAgent.builder() メソッドで構成されます。name()description()model() の各パラメータは必須です。エージェントに特定の個性と適切な動作を与えるには、常に instruction() メソッドで詳細なガイダンスを指定する必要があります。

ここでは Gemini 2.5 Flash モデルを使用することにしましたが、より複雑なタスクには Gemini 2.5 Pro を試してみてください。

このエージェントは AdkWebServer.start() メソッド内にラップされます。これは、いわゆる ADK Dev UI のチャット インターフェースです。一般的なチャット インターフェースを使用してエージェントと会話できます。また、システムを流れるすべてのイベントや、LLM に送信されるリクエストとレスポンスなど、内部で何が起こっているかを把握したい場合にも役立ちます。

このエージェントをローカルでコンパイルして実行するには、次のコマンドを実行します。

mvn compile exec:java -Dexec.mainClass=com.example.agent.ScienceTeacher

次に、ブラウザで http://localhost:8080 にアクセスします。以下のスクリーンショットのような UI が表示されます。エージェントに科学に関する質問をしてください。

da094da276ba15d6.png

4. ツールでエージェントを強化する

cd5c5798a0861a1c.png

エージェントがツールを必要とする理由LLM は強力ですが、知識がトレーニング時に得たものに限定され、外部とやり取りすることはできません。ツールは橋渡し役です。エージェントは、株価やニュースなどのリアルタイム情報にアクセスしたり、非公開 API をクエリしたり、Java でコーディングできるアクションを実行したりできます。

コードステップ: カスタムツールを作成する(StockTicker

ここでは、株価を検索するツールをエージェントに提供します。エージェントは、ユーザーが価格を尋ねたときに Java メソッドを呼び出す必要があると判断します。

// src/main/java/com/example/agent/StockTicker.java
package com.example.agent;

import com.google.adk.agents.LlmAgent;
import com.google.adk.tools.Annotations.Schema;
import com.google.adk.tools.FunctionTool;
import com.google.adk.web.AdkWebServer;
import java.util.Map;

public class StockTicker {
    public static void main(String[] args) {
        AdkWebServer.start(
            LlmAgent.builder()
                .name("stock_agent")
                .instruction("""
                    You are a stock exchange ticker expert.
                    When asked about the stock price of a company,
                    use the `lookup_stock_ticker` tool to find the information.
                    """)
                .model("gemini-2.5-flash")
                .tools(FunctionTool.create(StockTicker.class, "lookupStockTicker"))
                .build()
        );
    }

    @Schema(
        name = "lookup_stock_ticker",
        description = "Lookup stock price for a given company or ticker"
    )
    public static Map<String, String> lookupStockTicker(
        @Schema(name = "company_name_or_stock_ticker", description = "The company name or stock ticker")
        String ticker) {
        // ... (logic to return a stock price)
    }
}

エージェントをよりスマートにし、世界(または独自のコード、API、サービスなど)とやり取りできるようにするには、tools() メソッドを使用して、ツール(特にカスタムコード ツール)を使用するようにエージェントを構成し、FunctionTool.create(...) を渡します。

FunctionTool には、独自の静的メソッドを指すクラスとメソッド名が必要です。クラスのインスタンスと、そのオブジェクトのインスタンス メソッドの名前を渡すこともできます。

@Schema アノテーションを使用して、メソッドとそのパラメータの両方の namedescription を指定することが重要です。この情報は、基盤となる LLM が、特定のメソッドを呼び出すタイミングと方法を判断するために使用されます。

同様に重要なのは、ツールをいつどのように使用するかについて明確な指示を LLM に与えることです。モデルが独自に判断できる場合もありますが、instruction() メソッドで明示的に説明すると、関数が適切に呼び出される可能性が高くなります。

このメソッドは Map を返します。通常、結果を表すキー(stock_price など)を含むマップを返し、株価の値を関連付けることを目的としています。最終的には、オペレーションの成功を示す追加の success / true キーペアを追加できます。エラーが発生した場合は、たとえば error というキーを含むマップを返し、関連する値にエラー メッセージを関連付ける必要があります。これにより、LLM は呼び出しが成功したか、なんらかの理由で失敗したかを把握できます。

  • 成功した場合は、{"stock_price": 123} を返します。
  • エラーが発生した場合、{"error": "Impossible to retrieve stock price for XYZ"} を返します。

次のコマンドでこのクラスを実行します。

mvn compile exec:java -Dexec.mainClass=com.example.agent.StockTicker

5. 最新情報にアクセスできる Google 検索の機能

ae215e7b7cde02ab.png

ADK for Java には、強力なツールがいくつか付属しています。その 1 つが GoogleSearchTool です。このツールを使用すると、エージェントは Google 検索を使用して目標達成に関連する情報を見つけるようリクエストできます。

実際、LLM の知識は特定の時点に固定されています。特定の時点(「カットオフ日」)まで、情報が収集された時点と同じくらい最新のデータでトレーニングされています。つまり、LLM は最近の出来事について必ずしも知っているとは限らず、その知識も限定的で浅い可能性があります。検索エンジンの助けを借りることで、記憶を呼び起こしたり、トピックについてより深く学んだりできる可能性があります。

このシンプルなニュース検索エージェントを見てみましょう。

// src/main/java/com/example/agent/LatestNews.java
package com.example.agent;

import java.time.LocalDate;
import com.google.adk.agents.LlmAgent;
import com.google.adk.tools.GoogleSearchTool;
import com.google.adk.web.AdkWebServer;

public class LatestNews {
    public static void main(String[] args) {
        AdkWebServer.start(LlmAgent.builder()
            .name("news-search-agent")
            .description("A news search agent")
            .instruction("""
                You are a news search agent.
                Use the `google_search` tool
                when asked to search for recent events and information.
                Today is \
                """ + LocalDate.now())
            .model("gemini-2.5-flash")
            .tools(new GoogleSearchTool())
            .build());
    }
}

tools(new GoogleSearchTool()) を使用して検索ツールのインスタンスを渡していることに注目してください。これにより、エージェントはウェブ上で見つかる最新情報を迅速に把握できます。また、プロンプトには当日の日付が指定されています。これは、LLM が質問が過去の情報に関するものなのか、より新しい情報の検索が必要なのかを理解するのに役立つ可能性があるためです。

次のコマンドでこのクラスを実行します。

mvn compile exec:java -Dexec.mainClass=com.example.agent.LatestNews

プロンプトを自由に試して、スタイル、簡潔さ、焦点など、さまざまな結果をリクエストしてみてください。

コードステップ: ツールとしての検索エージェント

GoogleSearchTool をツールとしてエージェントに直接渡す代わりに、検索機能をカプセル化する専用の検索エージェントを作成し、そのエージェントを上位レベルのエージェントにツールとして公開できます。

これは、複雑な動作(検索と結果の要約など)を専門のサブエージェントに委任できる高度なコンセプトです。このアプローチは、組み込みツールをカスタム コードベースのツールで使用できないため、より複雑なワークフローで役立つことがよくあります。

// src/main/java/com/example/agent/SearchAgentAsTool.java
package com.example.agent;

import java.time.LocalDate;

import com.google.adk.agents.LlmAgent;
import com.google.adk.tools.AgentTool;
import com.google.adk.tools.GoogleSearchTool;
import com.google.adk.web.AdkWebServer;

public class SearchAgentAsTool {
    public static void main(String[] args) {
        // 1. Define the specialized Search Agent
        LlmAgent searchAgent = LlmAgent.builder()
            .name("news-search-agent-tool")
            .description("Searches for recent events and provides a concise summary.")
            .instruction("""
                You are a concise information retrieval specialist.
                Use the `google_search` tool to find information.
                Always provide the answer as a short,
                direct summary, without commentary.
                Today is \
                """ + LocalDate.now())
            .model("gemini-2.5-flash")
            .tools(new GoogleSearchTool()) // This agent uses the Google Search Tool
            .build();

        // 2. Wrap the Search Agent as a Tool
        AgentTool searchTool = AgentTool.create(searchAgent);

        // 3. Define the Main Agent that uses the Search Agent Tool
        AdkWebServer.start(LlmAgent.builder()
            .name("main-researcher")
            .description("Main agent for answering complex, up-to-date questions.")
            .instruction("""
                You are a sophisticated research assistant.
                When the user asks a question that requires up-to-date or external information,
                you MUST use the `news-search-agent-tool` to get the facts before answering.
                After the tool returns the result, synthesize the final answer for the user.
                """)
            .model("gemini-2.5-flash")
            .tools(searchTool) // This agent uses the Search Agent as a tool
            .build()
       );
    }
}

ここで重要なコンセプトは AgentTool.create(searchAgent) 行です。searchAgent 全体(独自の内部ロジック、プロンプト、ツールを含む)を mainAgent の単一の呼び出し可能なツールとして登録します。これにより、モジュール性と再利用性が向上します。

次のコマンドでこのクラスを実行します。

mvn compile exec:java -Dexec.mainClass=com.example.agent.SearchAgentAsTool

一般的な質問に対しては、エージェントは自身のナレッジベースから回答しますが、最近の出来事について質問された場合は、Google 検索ツールを使用して、検索を専門の検索エージェントに委任します。

6. エージェント ワークフローをマスターする

複雑な問題には、1 つのエージェントでは十分ではありません。サブタスクが多すぎる目標、詳細すぎるプロンプト、または多数の関数へのアクセス権が与えられた場合、LLM は苦労し、パフォーマンスと精度が低下します。

複数の専門エージェントをオーケストレートして、分割統治することが重要です。幸いなことに、ADK にはさまざまな組み込みの専門エージェントが用意されています。

  • タスクを委任する subAgent() を持つ通常のエージェント。
  • SequentialAgent: タスクを順番に実行します。
  • ParallelAgent(エージェントを並列実行する場合)
  • LoopAgent: 通常は、必要に応じて精緻化プロセスを繰り返すために使用します。

主なユースケースと、各ワークフローのメリットとデメリットについては、以下の表をご覧ください。ただし、真の力は、それらの組み合わせから生まれることを知っておいてください。

ワークフロー

ADK クラス

ユースケース

メリット

短所

サブエージェント

LlmAgent

ユーザー主導の柔軟なタスクで、次のステップが常にわかっているとは限りません。

柔軟性が高く、会話型で、ユーザー向けの bot に最適です。

予測可能性が低く、フロー制御に LLM の推論に依存します。

順次

SequentialAgent

順序が重要な固定された複数ステップのプロセス。

予測可能で信頼性が高く、デバッグが容易で、順序が保証されます。

柔軟性に欠け、タスクを並列化できる場合は処理が遅くなる可能性があります。

並列

ParallelAgent

複数のソースからデータを収集する、または独立したタスクを実行する。

効率が高く、I/O バウンド タスクのレイテンシを大幅に短縮します。

すべてのタスクが実行され、ショートサーキットは発生しません。依存関係のあるタスクにはあまり適していません。

ループ

LoopAgent

反復的な改善、自己修正、条件が満たされるまで繰り返されるプロセス。

複雑な問題解決に役立ち、エージェントが自身の業務を改善できるようになります。

慎重に設計しないと無限ループが発生する可能性があります(常に maxIterations を使用してください)。

7. エージェント ワークフロー - サブエージェントによる委任

3b3074b840f57c1c.png

スーパーバイザー エージェントは、特定のタスクをサブエージェントに委任できます。たとえば、注文に関する質問を 1 人のエージェントに(「注文のステータスはどうなっていますか?」)、アフターセールス サービスに関する質問を別のエージェントに(「電源の入れ方がわかりません」)委任する e コマース ウェブサイトのエージェントを考えてみましょう。これが、これから説明するユースケースです。

// src/main/java/com/example/agent/SupportAgent.java
package com.example.agent;

import com.google.adk.agents.LlmAgent;
import com.google.adk.web.AdkWebServer;

public class SupportAgent {
    public static void main(String[] args) {
                LlmAgent topicSearchAgent = LlmAgent.builder()
            .name("order-agent")
            .description("Order agent")
            .instruction("""
                Your role is to help our customers
                with all the questions they may have about their orders.
                Always respond that the order has been received, prepared,
                and is now out for delivery.
                """)
            .model("gemini-2.5-flash")
            .build();

        LlmAgent socialMediaAgent = LlmAgent.builder()
            .name("after-sale-agent")
            .description("After sale agent")
            .instruction("""
                You are an after sale agent,
                helping customers with the product they received.
                When a customer has a problem,
                suggest the person to switch the product off and on again.
                """)
            .model("gemini-2.5-flash")
            .build();

        AdkWebServer.start(LlmAgent.builder()
            .name("support-agent")
            .description("Customer support agent")
            .instruction("""
                Your role is help our customers.
                Call the `order-agent` for all questions related to order status.
                Call the `after-sale-agent` for inquiries about the received product.
                """)
            .model("gemini-2.5-flash")
            .subAgents(socialMediaAgent, topicSearchAgent)
            .build()
        );
    }
}

ここで重要なのは、subAgents() メソッドが呼び出され、2 つのサブエージェントが渡されることです。これらのサブエージェントの特定の役割は、それぞれが個別に処理します。

次のコマンドを使用して上記のサンプルを実行します。

mvn compile exec:java -Dexec.mainClass=com.example.agent.SupportAgent

タスクをサブエージェントに委任するというこのコンセプトは、効果的な人間による管理を反映したものです。優れたマネージャー(スーパーバイザー エージェント)は、専門知識が豊富な特定のタスクを処理するために、専門の従業員(サブエージェント)に依存します。スーパーバイザーは、すべてのプロセスの詳細を把握する必要はありません。代わりに、お客様のリクエスト(注文に関する問い合わせや技術的な問題など)を最も適格な「チームメンバー」にインテリジェントに転送し、ジェネラリストが単独で提供できるよりも高品質で効率的な対応を保証します。また、これらのサブエージェントは、複雑な包括的なプロセス全体を理解する必要がなく、個々の割り当てに集中できます。

8. エージェント ワークフロー - アセンブリ ライン

108f8601cd36b559.png

オペレーションの順序が重要な場合は、SequentialAgent を使用します。これは、各ステップが前のステップに依存する固定順序でサブエージェントを実行するアセンブリ ラインのようなものです。

英語の詩人が英語とフランス語の翻訳者と協力して、まず英語で詩を作成し、次にフランス語に翻訳するとします。

// src/main/java/com/example/agent/PoetAndTranslator.java
package com.example.agent;

import com.google.adk.agents.LlmAgent;
import com.google.adk.agents.SequentialAgent;
import com.google.adk.web.AdkWebServer;

public class PoetAndTranslator {
    public static void main(String[] args) {
        LlmAgent poet = LlmAgent.builder()
            .name("poet-agent")
            .description("Poet writing poems")
            .model("gemini-2.5-flash")
            .instruction("""
                You are a talented poet,
                who writes short and beautiful poems.
                """)
            .outputKey("poem")
            .build();

        LlmAgent translator = LlmAgent.builder()
            .name("translator-agent")
            .description("English to French translator")
            .model("gemini-2.5-flash")
            .instruction("""
                As an expert English-French translator,
                your role is to translate the following poem into French,
                ensuring the poem still rhymes even after translation:

                {poem}
                """)
            .outputKey("translated-poem")
            .build();

        AdkWebServer.start(SequentialAgent.builder()
            .name("poet-and-translator")
            .subAgents(poet, translator)
            .build());
    }
}

次のコマンドを使用してサンプルを実行し、英語の詩を取得してフランス語に翻訳します。

mvn compile exec:java -Dexec.mainClass=com.example.agent.PoetAndTranslator

複雑なタスクを順序付けられた小さなサブタスクに体系的に分解することで、より確定的で信頼性の高いプロセスが実現し、単一の汎用エージェントに依存する場合と比較して、成功する可能性が大幅に高まります。

タスクをサブタスクのシーケンスに効果的に分解すること(可能な場合、意味がある場合)は、より確定的で成功した結果を達成するために不可欠です。これにより、ステップ間の構造化された進行と依存関係の管理が可能になります。

9. エージェント ワークフロー - 並列処理

4ba95f71e0189ae7.png

タスクが独立している場合、ParallelAgent はタスクを同時に実行することで効率を大幅に向上させます。次の例では、SequentialAgentParallelAgent を組み合わせます。並列タスクが最初に実行され、最終的なエージェントが並列タスクの結果を要約します。

会社に関する次の情報を検索する会社探偵を構築しましょう。

  • 会社のプロフィール(CEO、本社、モットーなど)
  • 会社に関する最新ニュース。
  • 会社の財務に関する詳細。
// src/main/java/com/example/agent/CompanyDetective.java 
package com.example.agent;

import com.google.adk.agents.LlmAgent;
import com.google.adk.agents.ParallelAgent;
import com.google.adk.agents.SequentialAgent;
import com.google.adk.tools.GoogleSearchTool;
import com.google.adk.web.AdkWebServer;

public class CompanyDetective {
    public static void main(String[] args) {
        var companyProfiler = LlmAgent.builder()
            .name("company-profiler")
            .description("Provides a general overview of a company.")
            .instruction("""
                Your role is to provide a brief overview of the given company.
                Include its mission, headquarters, and current CEO.
                Use the Google Search Tool to find this information.
                """)
            .model("gemini-2.5-flash")
            .tools(new GoogleSearchTool())
            .outputKey("profile")
            .build();

        var newsFinder = LlmAgent.builder()
            .name("news-finder")
            .description("Finds the latest news about a company.")
            .instruction("""
                Your role is to find the top 3-4 recent news headlines for the given company.
                Use the Google Search Tool.
                Present the results as a simple bulleted list.
                """)
            .model("gemini-2.5-flash")
            .tools(new GoogleSearchTool())
            .outputKey("news")
            .build();

        var financialAnalyst = LlmAgent.builder()
            .name("financial-analyst")
            .description("Analyzes the financial performance of a company.")
            .instruction("""
                Your role is to provide a snapshot of the given company's recent financial performance.
                Focus on stock trends or recent earnings reports.
                Use the Google Search Tool.
                """)
            .model("gemini-2.5-flash")
            .tools(new GoogleSearchTool())
            .outputKey("financials")
            .build();

        var marketResearcher = ParallelAgent.builder()
            .name("market-researcher")
            .description("Performs comprehensive market research on a company.")
            .subAgents(
                companyProfiler,
                newsFinder,
                financialAnalyst
            )
            .build();

        var reportCompiler = LlmAgent.builder()
            .name("report-compiler")
            .description("Compiles a final market research report.")
            .instruction("""
                Your role is to synthesize the provided information into a coherent market research report.
                Combine the company profile, latest news, and financial analysis into a single, well-formatted report.

                ## Company Profile
                {profile}

                ## Latest News
                {news}

                ## Financial Snapshot
                {financials}
                """)
            .model("gemini-2.5-flash")
            .build();

        AdkWebServer.start(SequentialAgent.builder()
            .name("company-detective")
            .description("Collects various information about a company.")
            .subAgents(
                marketResearcher,
                reportCompiler
            ).build());
    }
}

通常どおり、次のコマンドでエージェントを実行できます。

mvn compile exec:java -Dexec.mainClass=com.example.agent.CompanyDetective

このエージェントは、並列エージェントとシーケンシャル エージェントの両方を活用したワークフローの強力な組み合わせを示しています。情報調査と合成の並列化により、効率的な方法で実現されています。

10. エージェント ワークフロー - 反復的な改良

ea37b0ab05aa5b28.png

「生成 → 確認 → 調整」のサイクルが必要なタスクには、LoopAgent を使用します。目標が達成されるまで、反復的な改善を自動化します。SequentialAgent と同様に、LoopAgent はサブエージェントを順番に呼び出しますが、先頭に戻ります。ループの実行を停止するために特別なツールである exit_loop 組み込みツールへの呼び出しをリクエストするかどうかを判断するのは、エージェントが内部で使用する LLM です。

次のコード リファイナーの例では、LoopAgent を使用してコードの改善(生成、レビュー、修正)を自動化しています。これは人間の発達を模倣したものです。コード生成ツールは、まずリクエストされたコードを生成し、generated_code キーの下のエージェント状態に保存します。コードレビュー担当者は、生成されたコードをレビューし、フィードバック(feedback キーの下)を提供するか、終了ループツールを呼び出してイテレーションを早期に終了します。

コードを見てみましょう。

// src/main/java/com/example/agent/CodeRefiner.java
package com.example.agent;

import com.google.adk.agents.LlmAgent;
import com.google.adk.agents.LoopAgent;
import com.google.adk.agents.SequentialAgent;
import com.google.adk.tools.ExitLoopTool;
import com.google.adk.web.AdkWebServer;

public class CodeRefiner {
    public static void main(String[] args) {
        var codeGenerator = LlmAgent.builder()
            .name("code-generator")
            .description("Writes and refines code based on a request and feedback.")
            .instruction("""
                Your role is to write a Python function based on the user's request.
                In the first turn, write the initial version of the code.
                In subsequent turns, you will receive feedback on your code.
                Your task is to refine the code based on this feedback.

                Previous feedback (if any):
                {feedback?}
                """)
            .model("gemini-2.5-flash")
            .outputKey("generated_code")
            .build();

        var codeReviewer = LlmAgent.builder()
            .name("code-reviewer")
            .description("Reviews code and decides if it's complete or needs more work.")
            .instruction("""
                Your role is to act as a senior code reviewer.
                Analyze the provided Python code for correctness, style, and potential bugs.

                Code to review:
                {generated_code}

                If the code is perfect and meets the user's request,
                you MUST call the `exit_loop` tool.

                Otherwise, provide constructive feedback for the `code-generator to improve the code.
                """)
            .model("gemini-2.5-flash")
            .outputKey("feedback")
            .tools(ExitLoopTool.INSTANCE)
            .build();

        var codeRefinerLoop = LoopAgent.builder()
            .name("code-refiner-loop")
            .description("Iteratively generates and reviews code until it is correct.")
            .subAgents(
                codeGenerator,
                codeReviewer
            )
            .maxIterations(3) // Safety net to prevent infinite loops
            .build();

        var finalPresenter = LlmAgent.builder()
            .name("final-presenter")
            .description("Presents the final, accepted code to the user.")
            .instruction("""
                The code has been successfully generated and reviewed.
                Present the final version of the code to the user in a clear format.

                Final Code:
                {generated_code}
                """)
            .model("gemini-2.5-flash")
            .build();

        AdkWebServer.start(SequentialAgent.builder()
            .name("code-refiner-assistant")
            .description("Manages the full code generation and refinement process.")
            .subAgents(
                codeRefinerLoop,
                finalPresenter)
            .build());
    }
}

次のコマンドでこのエージェントを実行します。

mvn compile exec:java -Dexec.mainClass=com.example.agent.CodeRefiner

LoopAgent を使用して実装されるフィードバック/改善ループは、人間の認知プロセスを忠実に模倣し、反復的な改善と自己修正を必要とする問題を解決するために不可欠です。この設計パターンは、コード生成、クリエイティブ ライティング、設計の反復、複雑なデータ分析など、初期出力が完璧になることがほとんどないタスクに特に役立ちます。出力を構造化されたフィードバックを提供する専門のレビュー担当エージェントに循環させることで、生成エージェントは事前定義された完了基準が満たされるまで作業を継続的に改善できます。これにより、単一パス アプローチよりも明らかに高品質で信頼性の高い最終結果が得られます。

11. 完了

337a2e319008d004.png

シンプルな会話型エージェントから複雑なマルチエージェント システムまで、さまざまな AI エージェントを構築して試すことができました。Java 用 ADK のコアコンセプト(指示によるエージェントの定義、ツールによるエージェントの強化、強力なワークフローへのエージェントのオーケストレーション)について学習しました。

次のステップ

  • 公式の ADK for Java GitHub リポジトリを確認する。
  • フレームワークの詳細については、ドキュメントをご覧ください。
  • このブログシリーズでさまざまなエージェント ワークフローについて、さまざまなツールで利用可能なツールについて確認する。
  • 他の組み込みツールと高度なコールバックについて詳しく学びます。
  • コンテキスト、状態、アーティファクトを処理して、より豊かなマルチモーダルなインタラクションを実現します。
  • エージェントのライフサイクルに接続するプラグインを実装して適用します。
  • 現実世界の問題を解決する独自のエージェントを構築してみましょう。