1. はじめに
概要
このラボでは、シンプルな chatbot を超えて、分散型マルチエージェント システム を構築します。
1 つの LLM で質問に回答できますが、現実世界の複雑さには、多くの場合、専門的な役割が必要です。バックエンド エンジニアに UI の設計を依頼したり、デザイナーにデータベース クエリの最適化を依頼したりすることはありません。同様に、1 つのタスクに焦点を当て、互いに連携して複雑な問題を解決する専門の AI エージェントを作成できます。
次の要素で構成されるコース作成システム を構築します。
- リサーチャー エージェント:
google_searchを使用して最新情報を検索します。 - ジャッジ エージェント: 調査の品質と完全性を評価します。
- コンテンツ ビルダー エージェント: 調査結果を構造化されたコースに変換します。
- オーケストレーター エージェント: これらのスペシャリスト間のワークフローと通信を管理します。
前提条件
- Python の基礎知識。
- Google Cloud コンソールに関する知識。
演習内容
- ウェブを検索できるツール使用エージェント(
researcher)を定義します。 judgeに Pydantic を使用して構造化出力を実装します。- Agent-to-Agent(A2A) プロトコルを使用してリモート エージェントに接続します。
LoopAgentを構築して、リサーチャーとジャッジの間にフィードバック ループを作成します。- ADK を使用して、分散システムをローカルで実行します。
- マルチエージェント システムを Google Cloud Run にデプロイします。
アーキテクチャとオーケストレーションの原則
コードを記述する前に、これらのエージェントがどのように連携するかを理解しましょう。コース作成パイプライン を構築します。
システム設計

エージェントによるオーケストレーション
標準エージェント(リサーチャーなど)は作業を行います。オーケストレーター エージェント (LoopAgent や SequentialAgent など)は他のエージェントを管理します。独自のツールはありません。ツールは委任です。
LoopAgent: コードのwhileループのように動作します。条件が満たされる(または最大イテレーション回数に達する)まで、エージェントのシーケンスを繰り返し実行します。これはリサーチ ループに使用します。- リサーチャー が情報を検索します。
- ジャッジ が評価します。
- ジャッジ が「不合格」と判断した場合、エスカレーション チェッカー はループを続行します。
- ジャッジ が「合格」と判断した場合、エスカレーション チェッカー はループを終了します。
SequentialAgent: 標準のスクリプト実行のように動作します。エージェントを順番に実行します。これはハイレベル パイプラインに使用します。- まず、リサーチ ループ を実行します(適切なデータで終了するまで)。
- 次に、コンテンツ ビルダー を実行します(コースを作成するため)。
これらを組み合わせることで、最終的な出力を生成する前に自己修正できる堅牢なシステムを作成します。
2. セットアップ
環境設定
- Cloud Shell を開く: Google Cloud コンソールの右上にある [Cloud Shell をアクティブにする] アイコンをクリックします。
スターター コードを取得する
- スターター リポジトリのクローンをホーム ディレクトリに作成します。
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 - API を有効にする: 次のコマンドを実行して、必要な Google Cloud サービスを有効にします。
gcloud services enable \ run.googleapis.com \ artifactregistry.googleapis.com \ cloudbuild.googleapis.com \ aiplatform.googleapis.com \ compute.googleapis.com - エディタでこのフォルダを開きます。
依存関係のインストール
依存関係の管理には uv を使用します。
- プロジェクトの依存関係をインストールします。
# Ensure you have uv installed: pip install uv uv sync - 環境変数を設定します。
- ヒント: プロジェクト 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=global export GOOGLE_GENAI_USE_VERTEXAI=true EOF - ヒント: プロジェクト ID は、Cloud Console ダッシュボードで確認できます。または、
- 環境変数をソースにします。
警告: 環境変数は、新しいターミナル セッション間で維持されません。新しいターミナルタブを開いた場合は、source .envsource .envを実行して復元します。
3. 🕵️ リサーチャー エージェント

リサーチャー はスペシャリストです。唯一の仕事は情報を見つけることです。これを行うには、Google 検索というツールにアクセスする必要があります。
リサーチャーを分離する理由
詳細: 1 つのエージェントですべてを行うのはなぜですか?
小規模で集中的なエージェントは、評価 とデバッグ が容易です。調査が不適切な場合は、リサーチャーのプロンプトを反復処理します。コースの書式設定が不適切な場合は、コンテンツ ビルダーを反復処理します。モノリシックな「すべてを行う」プロンプトでは、1 つのものを修正すると別のものが壊れることがよくあります。
- Cloud Shell で作業している場合は、次のコマンドを実行して Cloud Shell エディタを開きます。
ローカル環境で作業している場合は、お好みの IDE を開きます。cloudshell workspace . agents/researcher/agent.pyを開きます。- TODO を含むスケルトンが表示されます。
- 次のコードを追加して、
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. Summarize your findings clearly. If you receive feedback that your research is insufficient, use the feedback to refine your next search. DO NOT output any function calls. Provide your research directly as text. """, ) root_agent = researcher
重要なコンセプト: ツールの使用
Gemini 3 を使用する場合、Google 検索ツールは自動的に利用可能になります。Gemini 2.5 などの別のモデルを使用している場合は、tools=[google_search] を追加のパラメータとして Agent() コンストラクタに渡す必要があります。ADK は、このツールを LLM に記述する複雑さを処理します。モデルが情報が必要だと判断すると、構造化されたツール呼び出しが生成され、ADK が Python 関数 google_search を実行し、結果をモデルにフィードバックします。
4. ⚖️ ジャッジ エージェント

リサーチャーは熱心に働きますが、LLM は怠け者になる可能性があります。作業をレビューするジャッジ が必要です。ジャッジは調査を受け入れ、構造化された合格/不合格の評価を返します。
構造化出力
詳細: ワークフローを自動化するには、予測可能 な出力が必要です。長文のテキスト レビューはプログラムで解析するのが困難です。JSON スキーマ(Pydantic を使用)を適用することで、ジャッジがブール値 pass または fail を返すようにします。これにより、コードで確実に処理できます。
agents/judge/agent.pyを開きます。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=True と disallow_transfer_to_peers=True を設定します。これにより、ジャッジは構造化された JudgeFeedback のみを返すようになります。 ユーザーと「チャット」したり、別のエージェントに委任したりすることはできません。これにより、ロジックフローの決定論的コンポーネントになります。
5. 🧪 単独でのテスト
接続する前に、各エージェントが動作することを確認できます。ADK を使用すると、エージェントを個別に実行できます。
重要なコンセプト: インタラクティブ ランタイム
adk run は、ユーザーが「ユーザー」となる軽量環境を起動します。これにより、エージェントの指示とツールの使用状況を個別にテストできます。エージェントがここで失敗した場合(Google 検索を使用できないなど)、オーケストレーションで確実に失敗します。
- リサーチャーをインタラクティブに実行します。特定のエージェント ディレクトリを指定します。
# This runs the researcher agent in interactive mode uv run adk run agents/researcher - チャット プロンプトに次のように入力します。
Google 検索ツールを使用して回答を返す必要があります。注: プロジェクト、ロケーション、Vertex の使用が設定されていないことを示すエラーが表示された場合は、プロジェクト ID が設定されていることを確認し、次のコマンドを実行します。Find the population of Tokyo in 2020export GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project) export GOOGLE_CLOUD_LOCATION=global export GOOGLE_GENAI_USE_VERTEXAI=true - チャットを終了します(Ctrl+C)。
- ジャッジをインタラクティブに実行します。
uv run adk run agents/judge - チャット プロンプトで、次のように入力をシミュレートします。
調査結果が短すぎるため、Topic: Tokyo. Findings: Tokyo is a city.status='fail'が返されます。
6. ✍️ コンテンツ ビルダー エージェント

コンテンツ ビルダー はクリエイティブ ライターです。承認された調査結果をコースに変換します。
agents/content_builder/agent.pyを開きます。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)

このラボでは、分散システム を構築します。すべてのエージェントを 1 つの Python プロセスで実行するのではなく、独立したマイクロサービスとしてデプロイします。これにより、各エージェントは個別にスケーリングでき、システム全体をクラッシュさせることなく失敗できます。
これを実現するために、Agent-to-Agent(A2A) プロトコルを使用します。
A2A プロトコル
詳細: 本番環境システムでは、エージェントは異なるサーバー(または異なるクラウド)で実行されます。A2A プロトコル は、HTTP 経由で互いを検出して通信するための標準的な方法を作成します。RemoteA2aAgent は、このプロトコルの ADK クライアントです。
agents/orchestrator/agent.pyを開きます。- コメント
# TODO: Define connections to remote agentsまたはリモート エージェント定義のセクションを見つけます。 - 次のコードを追加して、接続を定義します。インポートの後 、他のエージェント定義の前 に配置してください。
# ... 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 に停止を通知します。
agents/orchestrator/agent.pyに移動します。EscalationCheckerTODO プレースホルダを見つけます。- 次の実装に置き換えます 。
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. 🔁 リサーチ ループ

フィードバック ループが必要です。リサーチ -> ジャッジ ->(不合格)-> リサーチ -> ...
agents/orchestrator/agent.pyに移動します。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 を順番に処理します。
researcher: データを検索します。judge: データを評価します。escalation_checker:yield Event(escalate=True)を実行するかどうかを決定します。escalate=Trueが発生すると、ループは早期に終了します。それ以外の場合は、リサーチャーで再起動します(max_iterationsまで)。
10. 🔗 最終パイプライン

最後に、すべてをまとめます。
agents/orchestrator/agent.pyに移動します。- ファイルの下部に
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)に渡します。これは、後でクラウドで構成する方法とまったく同じです。

- オーケストレーション スクリプトを実行します。
これにより、4 つの個別のプロセスが開始されます。perl -pi -e 's/us-central1/global/g' run_local.sh ./run_local.sh - テスト:
- Cloud Shell を使用している場合: [ウェブでプレビュー] ボタン(ターミナルの右上)-> [ポート 8080 でプレビュー] -> [ポートを変更] を
8000にクリックします。 - ローカルで実行している場合: ブラウザで
http://localhost:8000を開きます。 - プロンプト: "コーヒーの歴史に関するコースを作成してください。"
- 観察: オーケストレーターがリサーチャーを呼び出します。出力はジャッジに送られます。ジャッジが失敗した場合、ループは続行されます。
- 「内部サーバー エラー」 / 認証エラー: 認証エラー(
google-auth関連など)が表示された場合は、ローカル マシンで実行している場合はgcloud auth application-default loginを実行していることを確認してください。Cloud Shell で、GOOGLE_CLOUD_PROJECT環境変数が正しく設定されていることを確認します。 - ターミナル エラー: 新しいターミナル ウィンドウでコマンドが失敗した場合は、環境変数(
GOOGLE_CLOUD_PROJECTなど)を再エクスポートしてください。
- Cloud Shell を使用している場合: [ウェブでプレビュー] ボタン(ターミナルの右上)-> [ポート 8080 でプレビュー] -> [ポートを変更] を
- エージェントの単独テスト: システム全体が実行されている場合でも、ポートを直接ターゲットにすることで特定のエージェントをテストできます。これは、チェーン全体をトリガーせずに特定のコンポーネントをデバッグする場合に便利です。注: これらはウェブページではなく 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
- リサーチャーのみ(ポート 8001):
12. 🚀 Cloud Run にデプロイする
最終的な検証はクラウドで実行されます。各エージェントを個別のサービスとしてデプロイします。
デプロイ構成について
エージェントを Cloud Run にデプロイするときに、動作と接続を構成するためにいくつかの環境変数を渡します。
GOOGLE_CLOUD_PROJECT: エージェントがロギングと Vertex AI の呼び出しに正しい Google Cloud プロジェクトを使用するようにします。GOOGLE_GENAI_USE_VERTEXAI: Gemini API を直接呼び出すのではなく、モデル推論に Vertex AI を使用するようにエージェント フレームワーク(ADK)に指示します。GOOGLE_CLOUD_LOCATION: 使用するエンドポイントをエージェント フレームワーク(ADK)に指示します。[AGENT]_AGENT_CARD_URL: これはオーケストレーターにとって重要です。オーケストレーターにリモート エージェントの場所を伝えます。 これをデプロイされた Cloud Run URL(特にエージェント カードのパス)に設定することで、オーケストレーターはインターネット経由でリサーチャー、ジャッジ、コンテンツ ビルダーを検出して通信できます。
- サブエージェントをデプロイする(並列):時間を節約するため、リサーチャー、ジャッジ、コンテンツ ビルダーを同時にデプロイします。3 つの新しいターミナルタブを開きます。各 新しいタブで、次のコマンドを実行して環境を設定します。
タブ 1: リサーチャーのデプロイを実行します。cd ~/prai-roadshow-lab-1-starter source .env タブ 2: ジャッジのデプロイを実行します。gcloud run deploy researcher \ --source agents/researcher/ \ --region us-west1 \ --allow-unauthenticated \ --labels dev-tutorial=prod-ready-1 \ --set-env-vars GOOGLE_CLOUD_PROJECT=$GOOGLE_CLOUD_PROJECT \ --set-env-vars GOOGLE_CLOUD_LOCATION=$GOOGLE_CLOUD_LOCATION \ --set-env-vars GOOGLE_GENAI_USE_VERTEXAI="true" タブ 3: コンテンツ ビルダーのデプロイを実行します。gcloud run deploy judge \ --source agents/judge/ \ --region us-west1 \ --allow-unauthenticated \ --labels dev-tutorial=prod-ready-1 \ --set-env-vars GOOGLE_CLOUD_PROJECT=$GOOGLE_CLOUD_PROJECT \ --set-env-vars GOOGLE_CLOUD_LOCATION=$GOOGLE_CLOUD_LOCATION \ --set-env-vars GOOGLE_GENAI_USE_VERTEXAI="true"gcloud run deploy content-builder \ --source agents/content_builder/ \ --region us-west1 \ --allow-unauthenticated \ --labels dev-tutorial=prod-ready-1 \ --set-env-vars GOOGLE_CLOUD_PROJECT=$GOOGLE_CLOUD_PROJECT \ --set-env-vars GOOGLE_CLOUD_LOCATION=$GOOGLE_CLOUD_LOCATION \ --set-env-vars GOOGLE_GENAI_USE_VERTEXAI="true" - URL をキャプチャする:3 つのデプロイがすべて完了したら、元のターミナル (オーケストレーターをデプロイする場所)に戻ります。次のコマンドを実行して、サービス URL をキャプチャします。
RESEARCHER_URL=$(gcloud run services describe researcher --region us-west1 --format='value(status.url)') JUDGE_URL=$(gcloud run services describe judge --region us-west1 --format='value(status.url)') CONTENT_BUILDER_URL=$(gcloud run services describe content-builder --region us-west1 --format='value(status.url)') echo "Researcher: $RESEARCHER_URL" echo "Judge: $JUDGE_URL" echo "Content Builder: $CONTENT_BUILDER_URL" - オーケストレーターをデプロイする: キャプチャした環境変数を使用して、オーケストレーターを構成します。
URL をキャプチャします。gcloud run deploy orchestrator \ --source agents/orchestrator/ \ --region us-west1 \ --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_CLOUD_LOCATION=$GOOGLE_CLOUD_LOCATION \ --set-env-vars GOOGLE_GENAI_USE_VERTEXAI="true"ORCHESTRATOR_URL=$(gcloud run services describe orchestrator --region us-west1 --format='value(status.url)') echo $ORCHESTRATOR_URL - フロントエンドをデプロイする:
gcloud run deploy course-creator \ --source app \ --region us-west1 \ --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 - リモート デプロイをテストする: デプロイしたオーケストレーターの URL を開きます。Google のサーバーレス インフラストラクチャを利用してエージェントをスケーリングし、完全にクラウドで実行されるようになりました。ヒント: すべてのマイクロサービスとその URL は、Cloud Run インターフェースにあります。
13. まとめ
おめでとうございます!プロダクション レディな分散型マルチエージェント システムを構築してデプロイできました。
達成したこと
- 複雑なタスクを分解: 1 つの巨大なプロンプトではなく、作業を専門の役割(リサーチャー、ジャッジ、コンテンツ ビルダー)に分割しました。
- 品質検証(QC)を実装:
LoopAgentと構造化されたJudgeを使用して、高品質の情報のみが最終ステップに到達するようにしました。 - 本番環境向けに構築: Agent-to-Agent(A2A) プロトコルと Cloud Run を使用して、各エージェントが独立したスケーラブルなマイクロサービスであるシステムを作成しました。これは、1 つの Python スクリプトですべてを実行するよりもはるかに堅牢です。
- オーケストレーション:
SequentialAgentとLoopAgentを使用して、明確な制御フロー パターンを定義しました。
次のステップ
これで基盤ができたので、このシステムを拡張できます。
- ツールを追加: リサーチャーに内部ドキュメントや API へのアクセス権を付与します。
- ジャッジを改善: より具体的な条件や「Human in the Loop」ステップを追加します。
- モデルを切り替える: エージェントごとに異なるモデルを使用してみます(ジャッジには高速なモデル、コンテンツ ライターには強力なモデルなど)。
これで、Google Cloud で複雑で信頼性の高いエージェント ワークフローを構築できるようになりました。