コンテンツにスキップ

シーケンシャルエージェント

ADKでサポートPython v0.1.0Go v0.1.0Java v0.2.0

SequentialAgent は、サブエージェントをリストで指定された順序で実行するワークフローエージェントです。 実行を固定的で厳密な順序で行いたい場合に SequentialAgent を使用します。

  • Get Page ContentsSummarize Page という2つのツールを使用して、任意のウェブページを要約できるエージェントを構築したいとします。エージェントは常に Summarize Page を呼び出す前に Get Page Contents を呼び出す必要があるため(何もない状態からは要約できないため!)、SequentialAgent を使用してエージェントを構築すべきです。

他のワークフローエージェントと同様に、SequentialAgentはLLMによって駆動されないため、その実行方法は決定論的(deterministic)です。ただし、ワークフローエージェントが関与するのはその実行(つまりシーケンス)のみであり、内部ロジックではありません。ワークフローエージェントのツールやサブエージェントは、LLMを利用する場合もあれば、しない場合もあります。

仕組み

SequentialAgentRun Async メソッドが呼び出されると、以下の処理を実行します。

  1. イテレーション(Iteration): 提供された順序でサブエージェントのリストを反復処理します。
  2. サブエージェントの実行(Sub-Agent Execution): リスト内の各サブエージェントに対して、そのサブエージェントの Run Async メソッドを呼び出します。

Sequential Agent

完全な例:コード開発パイプライン

簡略化されたコード開発パイプラインを考えてみましょう。

  • コードライターエージェント (Code Writer Agent): 仕様に基づいて初期コードを生成するLLMエージェントです。
  • コードレビューアーエージェント (Code Reviewer Agent): 生成されたコードのエラー、スタイル上の問題、ベストプラクティスへの準拠などをレビューするLLMエージェントです。コードライターエージェントの出力を受け取ります。
  • コードリファクターエージェント (Code Refactorer Agent): レビューされたコード(とレビュー担当者のコメント)を受け取り、品質を向上させ問題を修正するためにリファクタリングするLLMエージェントです。

このような場合に SequentialAgent は最適です。

SequentialAgent(sub_agents=[CodeWriterAgent, CodeReviewerAgent, CodeRefactorerAgent])

これにより、コードが記述され、次にレビューされ、最後にリファクタリングされるという、厳密で信頼性の高い順序が保証されます。各サブエージェントからの出力は、出力キー (Output Key) を介して状態 (state) に保存され、次のエージェントに渡されます。

共有のInvocationContext

SequentialAgentは、各サブエージェントに同じ InvocationContext を渡します。これは、すべてのサブエージェントが一時的な (temp:) 名前空間を含む同じセッション状態を共有することを意味し、単一のターン内でステップ間のデータ受け渡しを容易にします。

コード
# Part of agent.py --> Follow https://google.github.io/adk-docs/get-started/quickstart/ to learn the setup

# --- 1. Define Sub-Agents for Each Pipeline Stage ---

# Code Writer Agent
# Takes the initial specification (from user query) and writes code.
code_writer_agent = LlmAgent(
    name="CodeWriterAgent",
    model=GEMINI_MODEL,
    # Change 3: Improved instruction
    instruction="""You are a Python Code Generator.
Based *only* on the user's request, write Python code that fulfills the requirement.
Output *only* the complete Python code block, enclosed in triple backticks (```python ... ```). 
Do not add any other text before or after the code block.
""",
    description="Writes initial Python code based on a specification.",
    output_key="generated_code" # Stores output in state['generated_code']
)

# Code Reviewer Agent
# Takes the code generated by the previous agent (read from state) and provides feedback.
code_reviewer_agent = LlmAgent(
    name="CodeReviewerAgent",
    model=GEMINI_MODEL,
    # Change 3: Improved instruction, correctly using state key injection
    instruction="""You are an expert Python Code Reviewer. 
    Your task is to provide constructive feedback on the provided code.

    **Code to Review:**
    ```python
    {generated_code}
    ```

**Review Criteria:**
1.  **Correctness:** Does the code work as intended? Are there logic errors?
2.  **Readability:** Is the code clear and easy to understand? Follows PEP 8 style guidelines?
3.  **Efficiency:** Is the code reasonably efficient? Any obvious performance bottlenecks?
4.  **Edge Cases:** Does the code handle potential edge cases or invalid inputs gracefully?
5.  **Best Practices:** Does the code follow common Python best practices?

**Output:**
Provide your feedback as a concise, bulleted list. Focus on the most important points for improvement.
If the code is excellent and requires no changes, simply state: "No major issues found."
Output *only* the review comments or the "No major issues" statement.
""",
    description="Reviews code and provides feedback.",
    output_key="review_comments", # Stores output in state['review_comments']
)


# Code Refactorer Agent
# Takes the original code and the review comments (read from state) and refactors the code.
code_refactorer_agent = LlmAgent(
    name="CodeRefactorerAgent",
    model=GEMINI_MODEL,
    # Change 3: Improved instruction, correctly using state key injection
    instruction="""You are a Python Code Refactoring AI.
Your goal is to improve the given Python code based on the provided review comments.

  **Original Code:**
  ```python
  {generated_code}
  ```

  **Review Comments:**
  {review_comments}

**Task:**
Carefully apply the suggestions from the review comments to refactor the original code.
If the review comments state "No major issues found," return the original code unchanged.
Ensure the final code is complete, functional, and includes necessary imports and docstrings.

**Output:**
Output *only* the final, refactored Python code block, enclosed in triple backticks (```python ... ```). 
Do not add any other text before or after the code block.
""",
    description="Refactors code based on review comments.",
    output_key="refactored_code", # Stores output in state['refactored_code']
)


# --- 2. Create the SequentialAgent ---
# This agent orchestrates the pipeline by running the sub_agents in order.
code_pipeline_agent = SequentialAgent(
    name="CodePipelineAgent",
    sub_agents=[code_writer_agent, code_reviewer_agent, code_refactorer_agent],
    description="Executes a sequence of code writing, reviewing, and refactoring.",
    # The agents will run in the order provided: Writer -> Reviewer -> Refactorer
)

# For ADK tools compatibility, the root agent must be named `root_agent`
root_agent = code_pipeline_agent
    model, err := gemini.NewModel(ctx, modelName, &genai.ClientConfig{})
    if err != nil {
        return fmt.Errorf("failed to create model: %v", err)
    }

    codeWriterAgent, err := llmagent.New(llmagent.Config{
        Name:        "CodeWriterAgent",
        Model:       model,
        Description: "Writes initial Go code based on a specification.",
        Instruction: `You are a Go Code Generator.
Based *only* on the user's request, write Go code that fulfills the requirement.
Output *only* the complete Go code block, enclosed in triple backticks ('''go ... ''').
Do not add any other text before or after the code block.`,
        OutputKey: "generated_code",
    })
    if err != nil {
        return fmt.Errorf("failed to create code writer agent: %v", err)
    }

    codeReviewerAgent, err := llmagent.New(llmagent.Config{
        Name:        "CodeReviewerAgent",
        Model:       model,
        Description: "Reviews code and provides feedback.",
        Instruction: `You are an expert Go Code Reviewer.
Your task is to provide constructive feedback on the provided code.

**Code to Review:**
'''go
{generated_code}
'''

**Review Criteria:**
1.  **Correctness:** Does the code work as intended? Are there logic errors?
2.  **Readability:** Is the code clear and easy to understand? Follows Go style guidelines?
3.  **Idiomatic Go:** Does the code use Go's features in a natural and standard way?
4.  **Edge Cases:** Does the code handle potential edge cases or invalid inputs gracefully?
5.  **Best Practices:** Does the code follow common Go best practices?

**Output:**
Provide your feedback as a concise, bulleted list. Focus on the most important points for improvement.
If the code is excellent and requires no changes, simply state: "No major issues found."
Output *only* the review comments or the "No major issues" statement.`,
        OutputKey: "review_comments",
    })
    if err != nil {
        return fmt.Errorf("failed to create code reviewer agent: %v", err)
    }

    codeRefactorerAgent, err := llmagent.New(llmagent.Config{
        Name:        "CodeRefactorerAgent",
        Model:       model,
        Description: "Refactors code based on review comments.",
        Instruction: `You are a Go Code Refactoring AI.
Your goal is to improve the given Go code based on the provided review comments.

**Original Code:**
'''go
{generated_code}
'''

**Review Comments:**
{review_comments}

**Task:**
Carefully apply the suggestions from the review comments to refactor the original code.
If the review comments state "No major issues found," return the original code unchanged.
Ensure the final code is complete, functional, and includes necessary imports.

**Output:**
Output *only* the final, refactored Go code block, enclosed in triple backticks ('''go ... ''').
Do not add any other text before or after the code block.`,
        OutputKey: "refactored_code",
    })
    if err != nil {
        return fmt.Errorf("failed to create code refactorer agent: %v", err)
    }

    codePipelineAgent, err := sequentialagent.New(sequentialagent.Config{
        AgentConfig: agent.Config{
            Name:        appName,
            Description: "Executes a sequence of code writing, reviewing, and refactoring.",
            SubAgents: []agent.Agent{
                codeWriterAgent,
                codeReviewerAgent,
                codeRefactorerAgent,
            },
        },
    })
    if err != nil {
        return fmt.Errorf("failed to create sequential agent: %v", err)
    }
import com.google.adk.agents.LlmAgent;
import com.google.adk.agents.SequentialAgent;
import com.google.adk.events.Event;
import com.google.adk.runner.InMemoryRunner;
import com.google.adk.sessions.Session;
import com.google.genai.types.Content;
import com.google.genai.types.Part;
import io.reactivex.rxjava3.core.Flowable;

public class SequentialAgentExample {

  private static final String APP_NAME = "CodePipelineAgent";
  private static final String USER_ID = "test_user_456";
  private static final String MODEL_NAME = "gemini-2.0-flash";

  public static void main(String[] args) {
    SequentialAgentExample sequentialAgentExample = new SequentialAgentExample();
    sequentialAgentExample.runAgent(
        "Write a Java function to calculate the factorial of a number.");
  }

  public void runAgent(String prompt) {

    LlmAgent codeWriterAgent =
        LlmAgent.builder()
            .model(MODEL_NAME)
            .name("CodeWriterAgent")
            .description("Writes initial Java code based on a specification.")
            .instruction(
                """
                You are a Java Code Generator.
                Based *only* on the user's request, write Java code that fulfills the requirement.
                Output *only* the complete Java code block, enclosed in triple backticks (```java ... ```).
                Do not add any other text before or after the code block.
                """)
            .outputKey("generated_code")
            .build();

    LlmAgent codeReviewerAgent =
        LlmAgent.builder()
            .model(MODEL_NAME)
            .name("CodeReviewerAgent")
            .description("Reviews code and provides feedback.")
            .instruction(
                """
                    You are an expert Java Code Reviewer.
                    Your task is to provide constructive feedback on the provided code.

                    **Code to Review:**
                    ```java
                    {generated_code}
                    ```

                    **Review Criteria:**
                    1.  **Correctness:** Does the code work as intended? Are there logic errors?
                    2.  **Readability:** Is the code clear and easy to understand? Follows Java style guidelines?
                    3.  **Efficiency:** Is the code reasonably efficient? Any obvious performance bottlenecks?
                    4.  **Edge Cases:** Does the code handle potential edge cases or invalid inputs gracefully?
                    5.  **Best Practices:** Does the code follow common Java best practices?

                    **Output:**
                    Provide your feedback as a concise, bulleted list. Focus on the most important points for improvement.
                    If the code is excellent and requires no changes, simply state: "No major issues found."
                    Output *only* the review comments or the "No major issues" statement.
                """)
            .outputKey("review_comments")
            .build();

    LlmAgent codeRefactorerAgent =
        LlmAgent.builder()
            .model(MODEL_NAME)
            .name("CodeRefactorerAgent")
            .description("Refactors code based on review comments.")
            .instruction(
                """
                You are a Java Code Refactoring AI.
                Your goal is to improve the given Java code based on the provided review comments.

                  **Original Code:**
                  ```java
                  {generated_code}
                  ```

                  **Review Comments:**
                  {review_comments}

                **Task:**
                Carefully apply the suggestions from the review comments to refactor the original code.
                If the review comments state "No major issues found," return the original code unchanged.
                Ensure the final code is complete, functional, and includes necessary imports and docstrings.

                **Output:**
                Output *only* the final, refactored Java code block, enclosed in triple backticks (```java ... ```).
                Do not add any other text before or after the code block.
                """)
            .outputKey("refactored_code")
            .build();

    SequentialAgent codePipelineAgent =
        SequentialAgent.builder()
            .name(APP_NAME)
            .description("Executes a sequence of code writing, reviewing, and refactoring.")
            // The agents will run in the order provided: Writer -> Reviewer -> Refactorer
            .subAgents(codeWriterAgent, codeReviewerAgent, codeRefactorerAgent)
            .build();

    // Create an InMemoryRunner
    InMemoryRunner runner = new InMemoryRunner(codePipelineAgent, APP_NAME);
    // InMemoryRunner automatically creates a session service. Create a session using the service
    Session session = runner.sessionService().createSession(APP_NAME, USER_ID).blockingGet();
    Content userMessage = Content.fromParts(Part.fromText(prompt));

    // Run the agent
    Flowable<Event> eventStream = runner.runAsync(USER_ID, session.id(), userMessage);

    // Stream event response
    eventStream.blockingForEach(
        event -> {
          if (event.finalResponse()) {
            System.out.println(event.stringifyContent());
          }
        });
  }
}