マルチエージェント システムの構築

1. はじめに

概要

このラボでは、単純なチャットボットにとどまらず、分散マルチエージェント システム を構築します。

単一の LLM で質問に回答できますが、現実世界の複雑さには、多くの場合、専門的な役割が必要です。バックエンド エンジニアに UI の設計を依頼したり、デザイナーにデータベース クエリの最適化を依頼したりすることはありません。同様に、1 つのタスクに焦点を当て、互いに連携して複雑な問題を解決する専門の AI エージェントを作成できます。

次の要素で構成されるコース作成システム を構築します。

  1. リサーチャー エージェント: google_search を使用して最新情報を検索します。
  2. ジャッジ エージェント: 調査の品質と完全性を評価します。
  3. コンテンツ ビルダー エージェント: 調査結果を構造化されたコースに変換します。
  4. オーケストレーター エージェント: これらのスペシャリスト間のワークフローと通信を管理します。

前提条件

  • Python の基本的な知識。
  • Google Cloud コンソールに関する知識。

演習内容

  • ウェブを検索できるツール使用エージェント(researcher)を定義します。
  • judge に Pydantic を使用して構造化出力を実装します。
  • Agent-to-Agent(A2A) プロトコルを使用してリモート エージェントに接続します。
  • LoopAgent を構築して、リサーチャーとジャッジの間にフィードバック ループを作成します。
  • ADK を使用して、分散システムをローカルで実行します。
  • マルチエージェント システムを Google Cloud Run にデプロイします。

アーキテクチャとオーケストレーションの原則

コードを記述する前に、これらのエージェントがどのように連携するかを理解しましょう。コース作成パイプライン を構築します。

システム設計

アーキテクチャ図

エージェントによるオーケストレーション

標準エージェント(リサーチャーなど)は作業を行います。オーケストレーター エージェントLoopAgentSequentialAgent など)は他のエージェントを管理します。独自のツールはありません。ツールは委任です。

  1. LoopAgent: コードの while ループのように動作します。条件が満たされる(または最大イテレーション回数に達する)まで、エージェントのシーケンスを繰り返し実行します。これはリサーチ ループに使用します。
    • リサーチャーが情報を検索します。
    • ジャッジがそれを評価します。
    • ジャッジが「不合格」と判断した場合、EscalationChecker はループを続行します。
    • ジャッジが「合格」と判断した場合、EscalationChecker はループを終了します。
  2. SequentialAgent: 標準のスクリプト実行のように動作します。エージェントを順番に実行します。これはハイレベル パイプラインに使用します。
    • まず、リサーチ ループを実行します(適切なデータで終了するまで)。
    • 次に、コンテンツ ビルダーを実行します(コースを作成するため)。

これらを組み合わせることで、最終的な出力を生成する前に自己修正できる堅牢なシステムを作成します。

2. セットアップ

環境設定

  1. Cloud Shell を開く: Google Cloud コンソールの右上にある [Cloud Shell をアクティブにする] アイコンをクリックします。

スターター コードを取得する

  1. スターター リポジトリのクローンをホーム ディレクトリに作成します。
    cd ~
    git clone --depth 1 --filter=blob:none --sparse https://github.com/GoogleCloudPlatform/devrel-demos.git temp-repo && cd temp-repo && git sparse-checkout set agents/build-with-ai/production-ready-ai/prai-roadshow-lab-1-starter && cd .. && mv temp-repo/agents/build-with-ai/production-ready-ai/prai-roadshow-lab-1-starter . && rm -rf temp-repo
    cd prai-roadshow-lab-1-starter
    
  2. API を有効にする: 次のコマンドを実行して、必要な Google Cloud サービスを有効にします。
    gcloud services enable \
        run.googleapis.com \
        artifactregistry.googleapis.com \
        cloudbuild.googleapis.com \
        aiplatform.googleapis.com \
        compute.googleapis.com
    
  3. エディタでこのフォルダを開きます。

依存関係のインストール

依存関係の管理には uv を使用します。

  1. プロジェクトの依存関係をインストールします。
    # Ensure you have uv installed: pip install uv
    uv sync
    
  2. 環境変数を設定します。
    • ヒント: プロジェクト ID は、Cloud Console ダッシュボードで確認できます。または、gcloud config get-value project を実行して確認することもできます。
    これらの変数を保存する .env ファイルを作成します。これにより、セッションが切断された場合に簡単に再読み込みできます。
    cat <<EOF > .env
    export GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project)
    export GOOGLE_CLOUD_LOCATION=us-central1
    export GOOGLE_GENAI_USE_VERTEXAI=true
    EOF
    
  3. 環境変数をソースにします。
    source .env
    
    警告: 環境変数は、新しいターミナル セッション間で保持されません 。新しいターミナルタブを開いた場合は、source .env を実行して復元します。

3. 🕵️ リサーチャー エージェント

リサーチャー エージェント

リサーチャー はスペシャリストです。唯一の仕事は情報を見つけることです。これを行うには、ツール(Google 検索)にアクセスする必要があります。

リサーチャーを分離する理由

詳細: 1 つのエージェントですべてを行うのはなぜですか?

小規模で集中的なエージェントは、評価デバッグ が容易です。調査が不適切な場合は、リサーチャーのプロンプトを反復処理します。コースのフォーマットが不適切な場合は、コンテンツ ビルダーを反復処理します。モノリシックな「すべてを行う」プロンプトでは、1 つのものを修正すると別のものが壊れることがよくあります。

  1. Cloud Shell で作業している場合は、次のコマンドを実行して Cloud Shell エディタを開きます。
    cloudshell workspace .
    
    ローカル環境で作業している場合は、お好みの IDE を開きます。
  2. agents/researcher/agent.py を開きます。
  3. TODO を含むスケルトンが表示されます。
  4. 次のコードを追加して、researcher エージェントを定義します。
    # ... existing imports ...
    
    # Define the Researcher Agent
    researcher = Agent(
        name="researcher",
        model=MODEL,
        description="Gathers information on a topic using Google Search.",
        instruction="""
        You are an expert researcher. Your goal is to find comprehensive and accurate information on the user's topic.
        Use the `google_search` tool to find relevant information.
        Summarize your findings clearly.
        If you receive feedback that your research is insufficient, use the feedback to refine your next search.
        """,
        tools=[google_search],
    )
    
    root_agent = researcher
    

重要なコンセプト: ツールの使用

tools=[google_search] を渡していることに注意してください。ADK は、このツールを LLM に記述する複雑さを処理します。モデルが情報が必要だと判断すると、構造化されたツール呼び出しが生成され、ADK が Python 関数 google_search を実行し、結果をモデルにフィードバックします。

4. ⚖️ ジャッジ エージェント

Judge エージェント

リサーチャーは懸命に働きますが、LLM は怠け者になる可能性があります。作業をレビューするジャッジ が必要です。ジャッジは調査を受け入れ、構造化された合格/不合格の評価を返します。

構造化出力

詳細: ワークフローを自動化するには、予測可能 な出力が必要です。長文のテキスト レビューは、プログラムで解析するのが困難です。JSON スキーマ(Pydantic を使用)を適用することで、ジャッジがブール値 pass または fail を返すようにします。これにより、コードで確実に処理できます。

  1. agents/judge/agent.py を開きます。
  2. JudgeFeedback スキーマと judge エージェントを定義します。
    # 1. Define the Schema
    class JudgeFeedback(BaseModel):
        """Structured feedback from the Judge agent."""
        status: Literal["pass", "fail"] = Field(
            description="Whether the research is sufficient ('pass') or needs more work ('fail')."
        )
        feedback: str = Field(
            description="Detailed feedback on what is missing. If 'pass', a brief confirmation."
        )
    
    # 2. Define the Agent
    judge = Agent(
        name="judge",
        model=MODEL,
        description="Evaluates research findings for completeness and accuracy.",
        instruction="""
        You are a strict editor.
        Evaluate the 'research_findings' against the user's original request.
        If the findings are missing key info, return status='fail'.
        If they are comprehensive, return status='pass'.
        """,
        output_schema=JudgeFeedback,
        # Disallow delegation because it should only output the schema
        disallow_transfer_to_parent=True,
        disallow_transfer_to_peers=True,
    )
    
    root_agent = judge
    

重要なコンセプト: エージェントの動作の制限

disallow_transfer_to_parent=Truedisallow_transfer_to_peers=True を設定します。これにより、ジャッジは構造化された JudgeFeedback のみを返すようになります。 ユーザーと「チャット」したり、別のエージェントに委任したりすることはできません。これにより、ロジックフローの決定論的コンポーネントになります。

5. 🧪 単独でのテスト

接続する前に、各エージェントが動作することを確認できます。ADK を使用すると、エージェントを個別に実行できます。

重要なコンセプト: インタラクティブ ランタイム

adk run は、ユーザーが「ユーザー」となる軽量環境を起動します。これにより、エージェントの指示とツールの使用状況を個別にテストできます。エージェントがここで失敗した場合(Google 検索を使用できないなど)、オーケストレーションで確実に失敗します。

  1. リサーチャーをインタラクティブに実行します。特定のエージェント ディレクトリを指定していることに注意してください。
    # This runs the researcher agent in interactive mode
    uv run adk run agents/researcher
    
  2. チャット プロンプトに次のように入力します。
    Find the population of Tokyo in 2020
    
    Google 検索ツールを使用して回答を返す必要があります。注: プロジェクト、ロケーション、Vertex の使用が設定されていないことを示すエラーが表示された場合は、プロジェクト ID が設定されていることを確認し、次のコマンドを実行します。
    export GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project)
    export GOOGLE_CLOUD_LOCATION=us-central1
    export GOOGLE_GENAI_USE_VERTEXAI=true
    
  3. チャットを終了します(Ctrl+C)。
  4. ジャッジをインタラクティブに実行します。
    uv run adk run agents/judge
    
  5. チャット プロンプトで、次のように入力をシミュレートします。
    Topic: Tokyo. Findings: Tokyo is a city.
    
    調査結果が短すぎるため、status='fail'`status='fail'` を返す必要があります。

6. ✍️ コンテンツ ビルダー エージェント

Content Builder

コンテンツ ビルダー はクリエイティブ ライターです。承認された調査結果をコースに変換します。

  1. agents/content_builder/agent.py を開きます。
  2. content_builder エージェントを定義します。
    content_builder = Agent(
        name="content_builder",
        model=MODEL,
        description="Transforms research findings into a structured course.",
        instruction="""
        You are an expert course creator.
        Take the approved 'research_findings' and transform them into a well-structured, engaging course module.
    
        **Formatting Rules:**
        1. Start with a main title using a single `#` (H1).
        2. Use `##` (H2) for main section headings.
        3. Use bullet points and clear paragraphs.
        4. Maintain a professional but engaging tone.
    
        Ensure the content directly addresses the user's original request.
        """,
    )
    root_agent = content_builder
    

重要なコンセプト: コンテキストの伝播

「コンテンツ ビルダーはリサーチャーが見つけたものをどのように知るのですか?」と思われるかもしれません。ADK では、パイプライン内のエージェントが session.state を共有します。後で、オーケストレーターで、リサーチャーとジャッジが出力をこの共有状態に保存するように構成します。コンテンツ ビルダーのプロンプトは、この履歴に効果的にアクセスできます。

7. 🎻 オーケストレーター

オーケストレーター エージェント

オーケストレーター は、マルチエージェント チームのマネージャーです。特定のタスクを実行するスペシャリスト エージェント(リサーチャー、ジャッジ、コンテンツ ビルダー)とは異なり、オーケストレーターの仕事はワークフローを調整し、それらの間で情報が正しく流れるようにすることです。

🌐 アーキテクチャ: Agent-to-Agent(A2A)

A2A アーキテクチャ

このラボでは、分散システム を構築します。すべてのエージェントを単一の Python プロセスで実行するのではなく、独立したマイクロサービスとしてデプロイします。これにより、各エージェントは個別にスケーリングでき、システム全体をクラッシュさせることなく失敗できます。

これを実現するために、Agent-to-Agent(A2A) プロトコルを使用します。

A2A プロトコル

詳細: 本番環境システムでは、エージェントは異なるサーバー(または異なるクラウド)で実行されます。A2A プロトコル は、HTTP 経由で互いを検出して通信するための標準的な方法を作成します。RemoteA2aAgent は、このプロトコルの ADK クライアントです。

  1. agents/orchestrator/agent.py を開きます。
  2. コメント # TODO: Define connections to remote agents またはリモート エージェント定義のセクションを見つけます。
  3. 次のコードを追加して、接続を定義します。インポートの 、他のエージェント定義の に配置してください。
    # ... existing code ...
    
    # Connect to the Researcher (Localhost port 8001)
    researcher_url = os.environ.get("RESEARCHER_AGENT_CARD_URL", "http://localhost:8001/a2a/agent/.well-known/agent-card.json")
    researcher = RemoteA2aAgent(
        name="researcher",
        agent_card=researcher_url,
        description="Gathers information using Google Search.",
        # IMPORTANT: Save the output to state for the Judge to see
        after_agent_callback=create_save_output_callback("research_findings"),
        # IMPORTANT: Use authenticated client for communication
        httpx_client=create_authenticated_client(researcher_url)
    )
    
    # Connect to the Judge (Localhost port 8002)
    judge_url = os.environ.get("JUDGE_AGENT_CARD_URL", "http://localhost:8002/a2a/agent/.well-known/agent-card.json")
    judge = RemoteA2aAgent(
        name="judge",
        agent_card=judge_url,
        description="Evaluates research.",
        after_agent_callback=create_save_output_callback("judge_feedback"),
        httpx_client=create_authenticated_client(judge_url)
    )
    
    # Content Builder (Localhost port 8003)
    content_builder_url = os.environ.get("CONTENT_BUILDER_AGENT_CARD_URL", "http://localhost:8003/a2a/agent/.well-known/agent-card.json")
    content_builder = RemoteA2aAgent(
        name="content_builder",
        agent_card=content_builder_url,
        description="Builds the course.",
        httpx_client=create_authenticated_client(content_builder_url)
    )
    

8. 🛑 エスカレーション チェッカー

ループを停止する方法が必要です。ジャッジが「合格」と判断した場合は、すぐにループを終了してコンテンツ ビルダーに移動します。

BaseAgent を使用したカスタム ロジック

詳細: すべてのエージェントが LLM を使用するわけではありません。単純な Python ロジックが必要になることもあります。BaseAgent を使用すると、コードを実行するだけのエージェントを定義できます。この場合、セッションの状態を確認し、EventActions(escalate=True) を使用して LoopAgent に停止を通知します。

  1. agents/orchestrator/agent.py に移動します。
  2. EscalationChecker TODO プレースホルダを見つけます。
  3. 次の実装に置き換えます
    class EscalationChecker(BaseAgent):
        """Checks the judge's feedback and escalates (breaks the loop) if it passed."""
    
        async def _run_async_impl(
            self, ctx: InvocationContext
        ) -> AsyncGenerator[Event, None]:
            # Retrieve the feedback saved by the Judge
            feedback = ctx.session.state.get("judge_feedback")
            print(f"[EscalationChecker] Feedback: {feedback}")
    
            # Check for 'pass' status
            is_pass = False
            if isinstance(feedback, dict) and feedback.get("status") == "pass":
                is_pass = True
            # Handle string fallback if JSON parsing failed
            elif isinstance(feedback, str) and '"status": "pass"' in feedback:
                is_pass = True
    
            if is_pass:
                # 'escalate=True' tells the parent LoopAgent to stop looping
                yield Event(author=self.name, actions=EventActions(escalate=True))
            else:
                # Continue the loop
                yield Event(author=self.name)
    
    escalation_checker = EscalationChecker(name="escalation_checker")
    

重要なコンセプト: イベントによる制御フロー

エージェントはテキストだけでなく、イベント とも通信します。escalate=True でイベントを生成することで、このエージェントは親(LoopAgent)にシグナルを送信します。LoopAgent は、このシグナルをキャッチしてループを終了するようにプログラムされています。

9. 🔁 リサーチ ループ

リサーチ ループ

フィードバック ループが必要です。リサーチ -> ジャッジ ->(不合格)-> リサーチ -> ...

  1. agents/orchestrator/agent.py に移動します。
  2. research_loop 定義を追加します。EscalationChecker クラスと escalation_checker インスタンスの に配置します。
    research_loop = LoopAgent(
        name="research_loop",
        description="Iteratively researches and judges until quality standards are met.",
        sub_agents=[researcher, judge, escalation_checker],
        max_iterations=3,
    )
    

重要なコンセプト: LoopAgent

LoopAgent は、sub_agents を順番に処理します。

  1. researcher: データを検索します。
  2. judge: データを評価します。
  3. escalation_checker: yield Event(escalate=True) を生成するかどうかを決定します。escalate=True が発生すると、ループは早期に終了します。それ以外の場合は、リサーチャーから再開します(max_iterations まで)。

10. 🔗 最終パイプライン

最終パイプライン

最後に、すべてをまとめます。

  1. agents/orchestrator/agent.py に移動します。
  2. ファイルの下部に root_agent を定義します。既存の root_agent = None プレースホルダを置き換えます。
    root_agent = SequentialAgent(
        name="course_creation_pipeline",
        description="A pipeline that researches a topic and then builds a course from it.",
        sub_agents=[research_loop, content_builder],
    )
    

重要なコンセプト: 階層型構成

research_loop はエージェント(LoopAgent)です。SequentialAgent の他のサブエージェントと同様に扱います。この構成可能性により、単純なパターン(シーケンス内のループ、ルーター内のシーケンスなど)をネストして複雑なロジックを構築できます。

11. 💻 ローカルで実行する

すべてを実行する前に、ADK が分散環境をローカルでシミュレートする方法を確認しましょう。

詳細: ローカル開発の仕組み

マイクロサービス アーキテクチャでは、すべてのエージェントが独自のサーバーとして実行されます。デプロイすると、4 つの異なる Cloud Run サービスが作成されます。4 つのターミナルタブを開いて 4 つのコマンドを実行する必要がある場合、ローカルでのシミュレーションは面倒です。

このスクリプトは、リサーチャー(ポート 8001)、ジャッジ(8002)、コンテンツ ビルダー(8003)の uvicorn プロセスを開始します。RESEARCHER_AGENT_CARD_URL などの環境変数を設定し、オーケストレーター(ポート 8004)に渡します。これは、後でクラウドで構成する方法とまったく同じです。

アプリの実行

  1. オーケストレーション スクリプトを実行します。
    ./run_local.sh
    
    これにより、4 つの個別のプロセスが開始されます。
  2. テスト:
    • Cloud Shell を使用している場合: [ウェブでプレビュー] ボタン(ターミナルの右上)-> [ポート 8080 でプレビュー] -> [ポートを変更] を 8000 にクリックします。
    • ローカルで実行している場合: ブラウザで http://localhost:8000 を開きます。
    • プロンプト: "コーヒーの歴史に関するコースを作成してください。"
    • 観察: オーケストレーターがリサーチャーを呼び出します。出力はジャッジに送られます。ジャッジが失敗した場合、ループは続行されます。
    トラブルシューティング:
    • 「Internal Server Error」 / 認証エラー: 認証エラー(google-auth 関連など)が表示された場合は、ローカル マシンで実行している場合は gcloud auth application-default login を実行していることを確認してください。Cloud Shell で、GOOGLE_CLOUD_PROJECT 環境変数が正しく設定されていることを確認します。
    • ターミナル エラー: 新しいターミナル ウィンドウでコマンドが失敗した場合は、環境変数(GOOGLE_CLOUD_PROJECT など)を再エクスポートしてください。
  3. エージェントの単独テスト: システム全体が実行されている場合でも、ポートを直接ターゲットにすることで、特定のエージェントをテストできます。これは、チェーン全体をトリガーせずに特定のコンポーネントをデバッグする場合に便利です。注: これらはウェブページではなく API エンドポイントです。ブラウザからアクセスすることはできません。代わりに、curl を使用して実行されていることを確認します(エージェント カードを取得するなど)。
    • リサーチャーのみ(ポート 8001):
      • ステータスを確認します(url エンドポイントを見つけます)。
        curl http://localhost:8001/a2a/agent/.well-known/agent-card.json
        
      • クエリを送信します(A2A JSON-RPC プロトコルを使用)。
        curl -X POST http://localhost:8001/a2a/agent \
          -H "Content-Type: application/json" \
          -d '{
            "jsonrpc": "2.0",
            "method": "message/send",
            "id": 1,
            "params": {
              "message": {
                "message_id": "test-1",
                "role": "user",
                "parts": [
                  {
                    "text": "What is the capital of France?",
                    "kind": "text"
                  }
                ]
              }
            }
          }'
        
    • ジャッジのみ(ポート 8002):
      • ステータスを確認します。
        curl http://localhost:8002/a2a/agent/.well-known/agent-card.json
        
      • クエリを送信します。
        curl -X POST http://localhost:8002/a2a/agent \
          -H "Content-Type: application/json" \
          -d '{
            "jsonrpc": "2.0",
            "method": "message/send",
            "id": 1,
            "params": {
              "message": {
                "message_id": "test-2",
                "role": "user",
                "parts": [
                  {
                    "text": "Topic: Tokyo. Findings: Tokyo is the capital of Japan.",
                    "kind": "text"
                  }
                ]
              }
            }
          }'
        
    • コンテンツ ビルダーのみ(ポート 8003):
      curl http://localhost:8003/a2a/agent/.well-known/agent-card.json
      
    • オーケストレーター(ポート 8004):
      curl http://localhost:8004/a2a/agent/.well-known/agent-card.json
      

12. 🚀 Cloud Run にデプロイする

最終的な検証はクラウドで実行されます。各エージェントを個別のサービスとしてデプロイします。

デプロイ構成について

エージェントを Cloud Run にデプロイするときに、動作と接続を構成するためにいくつかの環境変数を渡します。

  • GOOGLE_CLOUD_PROJECT: エージェントがロギングと Vertex AI の呼び出しに正しい Google Cloud プロジェクトを使用するようにします。
  • GOOGLE_GENAI_USE_VERTEXAI: Gemini API を直接呼び出すのではなく、モデル推論に Vertex AI を使用するようにエージェント フレームワーク(ADK)に指示します。
  • [AGENT]_AGENT_CARD_URL: これはオーケストレーターにとって重要です。オーケストレーターにリモート エージェントの場所を伝えます。 これをデプロイされた Cloud Run URL(特にエージェント カードのパス)に設定することで、オーケストレーターはインターネット経由でリサーチャー、ジャッジ、コンテンツ ビルダーを検出して通信できます。
  1. サブエージェントをデプロイする(並列):時間を節約するため、リサーチャー、ジャッジ、コンテンツ ビルダーを同時にデプロイします。3 つの新しいターミナルタブを開きます。 新しいタブで、次のコマンドを実行して環境を設定します。
    cd ~/prai-roadshow-lab-1-starter
    source .env
    
    タブ 1: リサーチャーのデプロイを実行します。
    gcloud run deploy researcher \
      --source agents/researcher/ \
      --region us-central1 \
      --allow-unauthenticated \
      --labels dev-tutorial=prod-ready-1 \
      --set-env-vars GOOGLE_CLOUD_PROJECT=$GOOGLE_CLOUD_PROJECT \
      --set-env-vars GOOGLE_GENAI_USE_VERTEXAI="true"
    
    タブ 2: ジャッジのデプロイを実行します。
    gcloud run deploy judge \
      --source agents/judge/ \
      --region us-central1 \
      --allow-unauthenticated \
      --labels dev-tutorial=prod-ready-1 \
      --set-env-vars GOOGLE_CLOUD_PROJECT=$GOOGLE_CLOUD_PROJECT \
      --set-env-vars GOOGLE_GENAI_USE_VERTEXAI="true"
    
    タブ 3: コンテンツ ビルダーのデプロイを実行します。
    gcloud run deploy content-builder \
      --source agents/content_builder/ \
      --region us-central1 \
      --allow-unauthenticated \
      --labels dev-tutorial=prod-ready-1 \
      --set-env-vars GOOGLE_CLOUD_PROJECT=$GOOGLE_CLOUD_PROJECT \
      --set-env-vars GOOGLE_GENAI_USE_VERTEXAI="true"
    
  2. URL をキャプチャする:3 つのデプロイがすべて完了したら、元のターミナル (オーケストレーターをデプロイする場所)に戻ります。次のコマンドを実行して、サービス URL をキャプチャします。
    RESEARCHER_URL=$(gcloud run services describe researcher --region us-central1 --format='value(status.url)')
    JUDGE_URL=$(gcloud run services describe judge --region us-central1 --format='value(status.url)')
    CONTENT_BUILDER_URL=$(gcloud run services describe content-builder --region us-central1 --format='value(status.url)')
    
    echo "Researcher: $RESEARCHER_URL"
    echo "Judge: $JUDGE_URL"
    echo "Content Builder: $CONTENT_BUILDER_URL"
    
  3. オーケストレーターをデプロイする: キャプチャした環境変数を使用して、オーケストレーターを構成します。
    gcloud run deploy orchestrator \
      --source agents/orchestrator/ \
      --region us-central1 \
      --allow-unauthenticated \
      --labels dev-tutorial=prod-ready-1 \
      --set-env-vars RESEARCHER_AGENT_CARD_URL=$RESEARCHER_URL/a2a/agent/.well-known/agent-card.json \
      --set-env-vars JUDGE_AGENT_CARD_URL=$JUDGE_URL/a2a/agent/.well-known/agent-card.json \
      --set-env-vars CONTENT_BUILDER_AGENT_CARD_URL=$CONTENT_BUILDER_URL/a2a/agent/.well-known/agent-card.json \
      --set-env-vars GOOGLE_CLOUD_PROJECT=$GOOGLE_CLOUD_PROJECT \
      --set-env-vars GOOGLE_GENAI_USE_VERTEXAI="true"
    
    URL をキャプチャします。
    ORCHESTRATOR_URL=$(gcloud run services describe orchestrator --region us-central1 --format='value(status.url)')
    echo $ORCHESTRATOR_URL
    
  4. フロントエンドをデプロイする:
    gcloud run deploy course-creator \
        --source app \
        --region us-central1 \
        --allow-unauthenticated \
        --labels dev-tutorial=prod-ready-1 \
        --set-env-vars AGENT_SERVER_URL=$ORCHESTRATOR_URL \
        --set-env-vars GOOGLE_CLOUD_PROJECT=$GOOGLE_CLOUD_PROJECT
    
  5. リモート デプロイをテストする: デプロイしたオーケストレーターの URL を開きます。Google のサーバーレス インフラストラクチャを利用してエージェントをスケーリングし、完全にクラウドで実行されるようになりました。ヒント: すべてのマイクロサービスとその URL は、Cloud Run インターフェースにあります。

13. まとめ

おめでとうございます!プロダクション レディな分散マルチエージェント システムを構築してデプロイできました。

達成したこと

  • 複雑なタスクを分解した: 1 つの巨大なプロンプトではなく、作業を専門の役割(リサーチャー、ジャッジ、コンテンツ ビルダー)に分割しました。
  • 品質検証(QC)を実装した: LoopAgent と構造化された Judge を使用して、高品質の情報のみが最終ステップに到達するようにしました。
  • 本番環境向けに構築した: Agent-to-Agent(A2A) プロトコルと Cloud Run を使用して、各エージェントが独立したスケーラブルなマイクロサービスであるシステムを作成しました。これは、すべてを単一の Python スクリプトで実行するよりもはるかに堅牢です。
  • オーケストレーション: SequentialAgentLoopAgent を使用して、明確な制御フロー パターンを定義しました。

次のステップ

これで基盤ができたので、このシステムを拡張できます。

  • ツールを追加する: リサーチャーに内部ドキュメントまたは API へのアクセス権を付与します。
  • ジャッジを改善する: より具体的な条件や「Human in the Loop」ステップを追加します。
  • モデルを切り替える: エージェントごとに異なるモデルを使用してみます(ジャッジには高速なモデル、コンテンツ ライターには強力なモデルなど)。

これで、Google Cloud で複雑で信頼性の高いエージェント ワークフローを構築できるようになりました。