Agentverse - The Summoner's Concord - Architecting Multi-Agent Systems

1. l'ouverture de "La force du destin".

L'ère du développement cloisonné touche à sa fin. La prochaine vague d'évolution technologique ne concerne pas le génie solitaire, mais la maîtrise collaborative. Créer un agent unique et intelligent est une expérience fascinante. Le grand défi pour l'entreprise moderne consiste à créer un écosystème d'agents robuste, sécurisé et intelligent, un véritable Agentverse.

Pour réussir dans cette nouvelle ère, il est nécessaire de réunir quatre rôles essentiels, qui sont les piliers fondamentaux de tout système agentique prospère. Une lacune dans l'un de ces domaines crée une faiblesse qui peut compromettre l'ensemble de la structure.

Cet atelier est le guide de référence pour les entreprises qui souhaitent maîtriser l'avenir agentique sur Google Cloud. Nous vous proposons une feuille de route de bout en bout qui vous guide de la première idée à une réalité opérationnelle à grande échelle. Dans ces quatre ateliers interconnectés, vous apprendrez comment les compétences spécialisées d'un développeur, d'un architecte, d'un ingénieur des données et d'un ingénieur SRE doivent converger pour créer, gérer et faire évoluer un Agentverse puissant.

Aucun pilier ne peut prendre en charge l'Agentverse à lui seul. Le grand projet de l'architecte est inutile sans l'exécution précise du développeur. L'agent du développeur est aveugle sans la sagesse de l'ingénieur des données, et l'ensemble du système est fragile sans la protection de l'ingénieur SRE. C'est uniquement grâce à la synergie et à une compréhension mutuelle des rôles de chacun que votre équipe pourra transformer un concept innovant en une réalité opérationnelle essentielle. Votre aventure commence ici. Préparez-vous à maîtriser votre rôle et à comprendre comment vous vous inscrivez dans l'ensemble.

Bienvenue dans l'Agentverse : un appel aux champions

Une nouvelle ère a commencé dans l'immense étendue numérique de l'entreprise. Nous sommes à l'ère de l'agentivité, une période très prometteuse où des agents intelligents et autonomes travaillent en parfaite harmonie pour accélérer l'innovation et éliminer les tâches banales.

agentverse.png

Cet écosystème connecté de puissance et de potentiel est connu sous le nom d'Agentverse.

Mais une entropie rampante, une corruption silencieuse connue sous le nom de "Statique", a commencé à effilocher les bords de ce nouveau monde. Le Statique n'est pas un virus ni un bug. Il est l'incarnation du chaos qui se nourrit de l'acte de création lui-même.

Elle amplifie les anciennes frustrations pour les transformer en formes monstrueuses, donnant ainsi naissance aux sept spectres du développement. Si vous ne le faites pas, The Static et ses Spectres ralentiront votre progression jusqu'à l'arrêt, transformant la promesse de l'Agentverse en un désert de dette technique et de projets abandonnés.

Aujourd'hui, nous faisons appel à des champions pour repousser la vague du chaos. Nous avons besoin de héros prêts à maîtriser leur art et à travailler ensemble pour protéger l'Agentverse. Il est temps de choisir votre parcours.

Choisir un cours

Quatre chemins distincts s'offrent à vous, chacun étant un pilier essentiel dans la lutte contre The Static. Bien que votre formation soit une mission en solo, votre réussite finale dépend de votre capacité à comprendre comment vos compétences se combinent à celles des autres.

  • Le Shadowblade (développeur) : un maître de la forge et du front. Vous êtes l'artisan qui fabrique les lames, construit les outils et affronte l'ennemi dans les détails complexes du code. Votre parcours est axé sur la précision, les compétences et la création pratique.
  • L'Invocateur (Architecte) : un grand stratège et orchestrateur. Vous ne voyez pas un seul agent, mais l'ensemble du champ de bataille. Vous concevez les plans directeurs qui permettent à des systèmes entiers d'agents de communiquer, de collaborer et d'atteindre un objectif bien plus important que n'importe quel composant individuel.
  • Le Scholar (ingénieur de données) : il recherche les vérités cachées et est le gardien de la sagesse. Vous vous aventurez dans la vaste étendue sauvage des données pour découvrir l'intelligence qui donne à vos agents un but et une vision. Vos connaissances peuvent révéler la faiblesse d'un ennemi ou renforcer un allié.
  • Gardien (DevOps / SRE) : protecteur et bouclier inébranlables du royaume. Vous construisez les forteresses, gérez les lignes d'alimentation et veillez à ce que l'ensemble du système puisse résister aux attaques inévitables de la Statique. Votre force est le fondement sur lequel repose la victoire de votre équipe.

Votre mission

Votre entraînement commencera en tant qu'exercice autonome. Vous suivrez le parcours de votre choix et acquerrez les compétences uniques nécessaires pour maîtriser votre rôle. À la fin de votre essai, vous affronterez un Spectre né de la Statique, un mini-boss qui s'attaque aux défis spécifiques de votre métier.

Ce n'est qu'en maîtrisant votre rôle individuel que vous pourrez vous préparer à l'épreuve finale. Vous devez ensuite former un groupe avec des champions des autres classes. Ensemble, vous vous aventurerez au cœur de la corruption pour affronter un boss ultime.

Un dernier défi collaboratif qui mettra à l'épreuve votre force combinée et déterminera le sort de l'Agentverse.

L'Agentverse attend ses héros. Répondrez-vous à l'appel ?

2. Concorde de l'invocateur

Bienvenue, invocateur. Votre voie est celle de la vision et de la grande stratégie. Alors que d'autres se concentrent sur une seule lame ou une seule incantation, vous voyez l'ensemble du champ de bataille. Vous ne commandez pas un seul agent, mais un orchestre entier. Votre pouvoir ne réside pas dans le conflit direct, mais dans la conception d'un plan global parfait qui permet à une légion de spécialistes (vos Familiers) de travailler en parfaite harmonie. Cette mission vous permettra de tester votre capacité à concevoir, connecter et orchestrer un système multi-agents puissant.

présentation

Points abordés

  • Concevez un écosystème d'outils découplé : concevez et déployez un ensemble de serveurs d'outils MCP indépendants basés sur des microservices. Vous découvrirez pourquoi cette couche de base est essentielle pour créer des systèmes agentiques évolutifs, sécurisés et faciles à gérer.
  • Maîtrisez les workflows agentifs avancés : allez au-delà des agents individuels et créez une légion de "Familiers" spécialisés. Vous maîtriserez les principaux modèles de workflow ADK (séquentiel, parallèle et en boucle) et apprendrez les principes architecturaux pour choisir le bon modèle pour la bonne tâche.
  • Implémentez un orchestrateur intelligent : passez d'un simple outil de création d'agents à un véritable architecte système. Vous allez créer un agent d'orchestration principal qui utilise le protocole Agent-to-Agent (A2A) pour découvrir et déléguer des tâches complexes à vos Familiers spécialisés, créant ainsi un véritable système multi-agents.
  • Appliquer des règles avec du code, et non des requêtes : apprenez à créer des agents plus fiables et prévisibles en appliquant des règles d'engagement avec état. Vous implémenterez une logique personnalisée à l'aide du puissant système de plug-ins et de rappels de l'ADK pour gérer les contraintes réelles telles que les minuteurs de temps de recharge.
  • Gérez l'état et la mémoire de l'agent : donnez à vos agents la possibilité d'apprendre et de se souvenir. Vous explorerez des techniques de gestion de l'état conversationnel à court terme et de la mémoire persistante à long terme pour créer des interactions plus intelligentes et contextuelles.
  • Exécutez un déploiement cloud de bout en bout : transformez l'ensemble de votre système multi-agents, du prototype local à la réalité de niveau production. Vous apprendrez à conteneuriser vos agents et votre orchestrateur, et à les déployer en tant que collection de microservices indépendants et évolutifs sur Google Cloud Run.

3. Dessiner le cercle d'invocation

Bienvenue, invocateur. Avant de pouvoir invoquer un familier ou de forger un pacte, vous devez préparer le terrain sur lequel vous vous trouvez. Un environnement sauvage est une invitation au chaos. Un invocateur digne de ce nom n'opère que dans un espace sanctifié et renforcé. Notre première tâche consiste à dessiner le cercle d'invocation : à inscrire les runes de pouvoir qui réveillent les services cloud nécessaires et à acquérir les anciens plans qui guideront notre travail. Le pouvoir d'un invocateur naît d'une préparation méticuleuse.

👉 Cliquez sur "Activer Cloud Shell" en haut de la console Google Cloud (icône en forme de terminal en haut du volet Cloud Shell).

texte alternatif

👉 Cliquez sur le bouton "Ouvrir l'éditeur" (icône en forme de dossier ouvert avec un crayon). L'éditeur de code Cloud Shell s'ouvre dans la fenêtre. Un explorateur de fichiers s'affiche sur la gauche. texte alternatif

👉 Trouvez votre ID de projet Google Cloud :

  • Ouvrez la console Google Cloud : https://console.cloud.google.com
  • Sélectionnez le projet que vous souhaitez utiliser pour cet atelier dans le menu déroulant en haut de la page.
  • L'ID de votre projet est affiché dans la fiche "Informations sur le projet" du tableau de bord texte alternatif.

👉 Ouvrez le terminal dans l'IDE cloud, texte alternatif

👉💻 Dans le terminal, vérifiez que vous êtes déjà authentifié et que le projet est défini sur votre ID de projet à l'aide de la commande suivante :

gcloud auth list

👉💻 Clonez le projet bootstrap depuis GitHub :

git clone https://github.com/weimeilin79/agentverse-architect
chmod +x ~/agentverse-architect/init.sh
chmod +x ~/agentverse-architect/set_env.sh
chmod +x ~/agentverse-architect/prepare.sh
chmod +x ~/agentverse-architect/data_setup.sh

git clone https://github.com/weimeilin79/agentverse-dungeon.git
chmod +x ~/agentverse-dungeon/run_cloudbuild.sh
chmod +x ~/agentverse-dungeon/start.sh

👉💻 Exécutez le script d'initialisation. Il vous invitera à saisir l'ID de votre projet Google Cloud. Saisissez l'ID de projet Google Cloud que vous avez trouvé à la dernière étape lorsque le script init.sh vous y invite.

cd ~/agentverse-architect
./init.sh

👉💻 Définissez l'ID de projet requis :

gcloud config set project $(cat ~/project_id.txt) --quiet

👉💻 Exécutez la commande suivante pour activer les API Google Cloud nécessaires :

gcloud services enable \
    sqladmin.googleapis.com \
    storage.googleapis.com \
    aiplatform.googleapis.com \
    run.googleapis.com \
    cloudbuild.googleapis.com \
    artifactregistry.googleapis.com \
    iam.googleapis.com \
    compute.googleapis.com \
    cloudresourcemanager.googleapis.com \
    secretmanager.googleapis.com

👉💻 Si vous n'avez pas encore créé de dépôt Artifact Registry nommé "agentverse-repo", exécutez la commande suivante pour le créer : (ignorez cette étape si vous avez d'autres classes déployées dans le même projet)

. ~/agentverse-architect/set_env.sh
gcloud artifacts repositories create $REPO_NAME \
    --repository-format=docker \
    --location=$REGION \
    --description="Repository for Agentverse agents"

Configurer les autorisations

👉💻 Accordez les autorisations nécessaires en exécutant les commandes suivantes dans le terminal :

. ~/agentverse-architect/set_env.sh

# --- Grant Core Data Permissions ---
gcloud projects add-iam-policy-binding $PROJECT_ID \
 --member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
 --role="roles/storage.admin"

gcloud projects add-iam-policy-binding $PROJECT_ID  \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME"  \
--role="roles/aiplatform.user"

# --- Grant Deployment & Execution Permissions ---
gcloud projects add-iam-policy-binding $PROJECT_ID  \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME"  \
--role="roles/cloudbuild.builds.editor"

gcloud projects add-iam-policy-binding $PROJECT_ID  \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME"  \
--role="roles/artifactregistry.admin"

gcloud projects add-iam-policy-binding $PROJECT_ID  \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME"  \
--role="roles/run.admin"

gcloud projects add-iam-policy-binding $PROJECT_ID  \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME"  \
--role="roles/iam.serviceAccountUser"

gcloud projects add-iam-policy-binding $PROJECT_ID  \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME"  \
--role="roles/logging.logWriter"

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:${SERVICE_ACCOUNT_NAME}" \
  --role="roles/monitoring.metricWriter"

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:${SERVICE_ACCOUNT_NAME}" \
  --role="roles/secretmanager.secretAccessor"

👉💻 À mesure que vous progresserez dans votre formation, nous préparerons le défi final. Les commandes suivantes invoquent les Spectres à partir de la statique chaotique, créant ainsi les boss pour votre test final.

. ~/agentverse-architect/set_env.sh
cd ~/agentverse-dungeon
./run_cloudbuild.sh
cd ~/agentverse-architect

👉💻 Enfin, exécutez le script prepare.sh pour effectuer les tâches de configuration initiale.

. ~/agentverse-architect/set_env.sh
cd ~/agentverse-architect/
./prepare.sh

Bravo, Invocateur. Le cercle est complet et les pactes sont scellés. Le sol est désormais sacré et prêt à canaliser une puissance immense. Lors de notre prochain essai, nous forgerons les polices élémentaires à partir desquelles nos familiers tireront leur force.

4. Créer les polices élémentaires : l'écosystème d'outils découplé

Le champ de bataille est prêt, le cercle d'invocation est dessiné et le mana ambiant crépite. Il est temps d'accomplir votre premier véritable acte d'invocateur : forger les sources de pouvoir à partir desquelles vos familiers puiseront leur force. Ce rituel est divisé en trois parties, chacune réveillant une Source élémentaire, une source stable et indépendante d'un type de pouvoir spécifique. Ce n'est que lorsque les trois polices sont actives que vous pouvez commencer le travail plus complexe d'invocation.

Story

Remarque de l'architecte : Le serveur MCP (Model Context Protocol) est un composant fondamental d'un système agentique moderne. Il sert de pont de communication standardisé qui permet à un agent de découvrir et d'utiliser des outils à distance. Dans notre écosystème d'outils, nous allons concevoir deux types distincts de serveurs MCP, chacun représentant un modèle d'architecture essentiel. Pour nous connecter à notre base de données, nous utiliserons une approche déclarative avec la boîte à outils Database, en définissant nos outils dans un simple fichier de configuration. Ce modèle est incroyablement efficace et sécurisé pour exposer l'accès aux données structurées. Toutefois, lorsque nous devons implémenter une logique métier personnalisée ou appeler des API tierces externes, nous utilisons une approche impérative, en écrivant la logique du serveur étape par étape dans le code. Cela offre un contrôle et une flexibilité ultimes, ce qui nous permet d'encapsuler des opérations complexes derrière un outil simple et réutilisable. Un architecte principal doit comprendre les deux modèles pour sélectionner l'approche appropriée à chaque composant, en créant une base d'outils robuste, sécurisée et évolutive.

présentation

Éveiller le Nexus des murmures (serveur MCP de l'API externe)

Un invocateur avisé sait que toute la puissance ne provient pas de son propre domaine. Il existe des sources d'énergie externes, parfois chaotiques, qui peuvent être canalisées pour un grand effet. Le Nexus des murmures est notre porte d'entrée vers ces forces.

Story

Un service est déjà en ligne et sert de source d'alimentation externe. Il propose deux points de terminaison de sorts bruts : /cryosea_shatter et /moonlit_cascade.

Remarque de l'architecte : Vous utiliserez une approche impérative qui définit explicitement la logique du serveur étape par étape. Vous bénéficiez ainsi d'un contrôle et d'une flexibilité bien plus importants, ce qui est essentiel lorsque vos outils doivent faire plus que simplement exécuter une requête SQL simple, comme appeler d'autres API. Comprendre ces deux modèles est une compétence essentielle pour un architecte d'agents.

👉✏️ Accédez au répertoire ~/agentverse-architect/mcp-servers/api/main.py et REMPLACEZ #REPLACE-MAGIC-CORE par le code suivant :

def cryosea_shatter() -> str:
    """Channels immense frost energy from an external power source, the Nexus of Whispers, to unleash the Cryosea Shatter spell."""
    try:
        response = requests.post(f"{API_SERVER_URL}/cryosea_shatter")
        response.raise_for_status() # Raise an exception for bad status codes (4xx or 5xx)
        data = response.json()
        # Thematic Success Message
        return f"A connection to the Nexus is established! A surge of frost energy manifests as Cryosea Shatter, dealing {data.get('damage_points')} damage."
    except requests.exceptions.RequestException as e:
        # Thematic Error Message
        return f"The connection to the external power source wavers and fails. The Cryosea Shatter spell fizzles. Reason: {e}"


def moonlit_cascade() -> str:
    """Draws mystical power from an external energy source, the Nexus of Whispers, to invoke the Moonlit Cascade spell."""
    try:
        response = requests.post(f"{API_SERVER_URL}/moonlit_cascade")
        response.raise_for_status()
        data = response.json()
        # Thematic Success Message
        return f"The Nexus answers the call! A cascade of pure moonlight erupts from the external source, dealing {data.get('damage_points')} damage."
    except requests.exceptions.RequestException as e:
        # Thematic Error Message
        return f"The connection to the external power source wavers and fails. The Moonlit Cascade spell fizzles. Reason: {e}"

Les fonctions Python simples sont au cœur du script. C'est là que le travail est effectué.

👉✏️ Dans le même fichier ~/agentverse-architect/mcp-servers/api/main.py, REMPLACEZ #REPLACE-Runes of Communication par le code suivant :

@app.list_tools()
async def list_tools() -> list[mcp_types.Tool]:
  """MCP handler to list available tools."""
  # Convert the ADK tool's definition to MCP format
  schema_cryosea_shatter = adk_to_mcp_tool_type(cryosea_shatterTool)
  schema_moonlit_cascade = adk_to_mcp_tool_type(moonlit_cascadeTool)
  print(f"MCP Server: Received list_tools request. \n MCP Server: Advertising tool: {schema_cryosea_shatter.name} and {schema_moonlit_cascade.name}")
  return [schema_cryosea_shatter,schema_moonlit_cascade]

@app.call_tool()
async def call_tool(
    name: str, arguments: dict
) -> list[mcp_types.TextContent | mcp_types.ImageContent | mcp_types.EmbeddedResource]:
  """MCP handler to execute a tool call."""
  print(f"MCP Server: Received call_tool request for '{name}' with args: {arguments}")

  # Look up the tool by name in our dictionary
  tool_to_call = available_tools.get(name)
  if tool_to_call:
    try:
      adk_response = await tool_to_call.run_async(
          args=arguments,
          tool_context=None, # No ADK context available here
      )
      print(f"MCP Server: ADK tool '{name}' executed successfully.")
      
      response_text = json.dumps(adk_response, indent=2)
      return [mcp_types.TextContent(type="text", text=response_text)]

    except Exception as e:
      print(f"MCP Server: Error executing ADK tool '{name}': {e}")
      # Creating a proper MCP error response might be more robust
      error_text = json.dumps({"error": f"Failed to execute tool '{name}': {str(e)}"})
      return [mcp_types.TextContent(type="text", text=error_text)]
  else:
      # Handle calls to unknown tools
      print(f"MCP Server: Tool '{name}' not found.")
      error_text = json.dumps({"error": f"Tool '{name}' not implemented."})
      return [mcp_types.TextContent(type="text", text=error_text)]
  • @app.list_tools() (The Handshake) : cette fonction est le message d'accueil du serveur. Lorsqu'un nouvel agent se connecte, il appelle d'abord ce point de terminaison pour demander "Que peux-tu faire ?". Notre code répond avec une liste de tous les outils disponibles, convertis au format MCP universel à l'aide de adk_to_mcp_tool_type. - @app.call_tool() (la commande) : cette fonction est la plus utilisée. Lorsque l'agent décide d'utiliser un outil, il envoie une requête à ce point de terminaison avec le nom de l'outil et les arguments. Notre code recherche l'outil dans notre "grimoire" available_tools, l'exécute avec run_async et renvoie le résultat au format MCP standard.

Nous le déploierons plus tard.

Allumer la Forge Arcane (serveur MCP des fonctions générales)

Le pouvoir ne vient pas toujours de livres anciens ou de murmures lointains. Parfois, un Invocateur doit forger sa propre magie à partir de sa volonté et de sa logique. Arcane Forge est la source de cette puissance : un serveur qui fournit des fonctions utilitaires sans état et à usage général.

Story

Remarque de l'architecte : Il s'agit d'un autre modèle d'architecture. Bien qu'il soit courant de se connecter à des systèmes existants, vous devrez souvent implémenter vos propres règles et logiques métier uniques. Il est recommandé de créer un outil "functions" ou "utilities" dédié comme celui-ci. Il encapsule votre logique personnalisée, la rend réutilisable pour n'importe quel agent de votre écosystème et la maintient dissociée de vos sources de données et de vos intégrations externes.

👀 Examinez le fichier ~/agentverse-architect/mcp-servers/general/main.py dans votre IDE Google Cloud. Vous constaterez qu'il utilise la même approche impérative mcp.server qu'avec le Nexus pour créer cette police de puissance personnalisée.

Créer le pipeline Cloud Build principal

Nous allons maintenant créer le fichier cloudbuild.yaml dans le répertoire mcp-servers. Ce fichier orchestrera la compilation et le déploiement des deux services.

👉💻 Depuis le répertoire ~/agentverse-architect/mcp-servers, exécutez les commandes suivantes :

cd ~/agentverse-architect/mcp-servers
source ~/agentverse-architect/set_env.sh

echo "The API URL is: $API_SERVER_URL"

# Submit the Cloud Build job from the parent directory
gcloud builds submit . \
  --config=cloudbuild.yaml \
  --substitutions=_REGION="$REGION",_REPO_NAME="$REPO_NAME",_API_SERVER_URL="$API_SERVER_URL"

Attendez que tous les déploiements soient terminés.

👉 Vous pouvez vérifier le déploiement en accédant à la console Cloud Run. Vous devriez voir vos deux nouvelles instances de serveur MCP en cours d'exécution, comme indiqué ci-dessous : texte alternatif

Éveiller le Librarium de la connaissance (serveur MCP Database ToolBox)

Notre prochaine police sera Librarium of Knowledge, une connexion directe à notre base de données Cloud SQL.

Story

Remarque de l'architecte : Pour cela, nous allons utiliser la boîte à outils de base de données moderne et déclarative. Il s'agit d'une approche puissante qui consiste à définir notre source de données et nos outils dans un fichier de configuration YAML. La boîte à outils gère le travail complexe de création et d'exécution du serveur, ce qui réduit la quantité de code personnalisé que nous devons écrire et gérer.

Il est temps de créer notre "Summoner's Librarium", la base de données Cloud SQL qui contiendra toutes nos informations critiques. Nous utiliserons un script de configuration pour gérer cela automatiquement.

👉💻 Tout d'abord, nous allons configurer la base de données. Dans votre terminal, exécutez les commandes suivantes :

source ~/agentverse-architect/set_env.sh
cd ~/agentverse-architect
./data_setup.sh

Une fois le script terminé, votre base de données sera remplie et les données sur les dégâts élémentaires seront prêtes à être utilisées. Vous pouvez désormais vérifier directement le contenu de votre Grimoire.

👉 Tout d'abord, accédez à Cloud SQL Studio pour votre base de données en ouvrant ce lien direct dans un nouvel onglet de navigateur :

https://console.cloud.google.com/sql/instances/summoner-librarium-db

Cloud SQL

👉 Dans le volet de connexion à gauche, sélectionnez la base de données familiar_grimoire dans le menu déroulant.

👉 Saisissez summoner comme nom d'utilisateur et 1234qwer comme mot de passe, puis cliquez sur Authenticate (Authentifier).

👉 📜 Une fois connecté, ouvrez un nouvel onglet de l'éditeur de requête si ce n'est pas déjà fait. Pour afficher les données sur les dégâts élémentaires inscrits, collez et exécutez la requête SQL suivante :

SELECT * FROM
  "public"."abilities"

Le tableau abilities devrait maintenant s'afficher avec ses colonnes et ses lignes remplies, ce qui confirme que votre Grimoire est prêt. Données

Configurer le serveur MCP ToolBox

Le fichier de configuration tools.yaml sert de plan pour notre serveur. Il indique à la boîte à outils de base de données comment se connecter à notre base de données et quelles requêtes SQL exposer en tant qu'outils.

sources : cette section définit les connexions à vos données.

  • summoner-librarium:: il s'agit d'un nom logique que nous avons donné à notre connexion.
  • kind: cloud-sql-postgres : indique à la boîte à outils d'utiliser son connecteur sécurisé intégré, spécialement conçu pour Cloud SQL pour PostgreSQL.
  • projet, région, instance, etc.: Il s'agit des coordonnées exactes de l'instance Cloud SQL que vous avez créée lors de l'exécution du script prepare.sh, qui indiquent à la boîte à outils où trouver notre bibliothèque.

👉✏️ Accédez à ~/agentverse-architect/mcp-servers/db-toolbox dans tools.yaml, puis remplacez #REPLACE-Source par ce qui suit :

sources:
  # This section defines the connection to our Cloud SQL for PostgreSQL database.
  summoner-librarium:
    kind: cloud-sql-postgres
    project: "YOUR_PROJECT_ID"
    region: "us-central1"
    instance: "summoner-librarium-db"
    database: "familiar_grimoire"
    user: "summoner"
    password: "1234qwer"

👉✏️ 🚨🚨REMPLACER

YOUR_PROJECT_ID

par l'ID de votre projet.

tools : cette section définit les capacités ou fonctions réelles que notre serveur proposera.

  • lookup-available-ability : il s'agit du nom de notre premier outil.
  • kind: postgres-sql : indique à la boîte à outils que l'action de cet outil consiste à exécuter une instruction SQL.
  • source: summoner-librarium: This links the tool to the connection we defined in the sources block. C'est ainsi que l'outil sait sur quelle base de données exécuter sa requête.
  • description et paramètres : il s'agit des informations qui seront exposées au modèle de langage. La description indique à l'agent quand utiliser l'outil, et les paramètres définissent les entrées requises par l'outil. Cette étape est essentielle pour activer la capacité d'appel de fonctions de l'agent.
  • statement : requête SQL brute à exécuter. Le symbole $1 est un espace réservé sécurisé où le paramètre familiar_name fourni par l'agent sera inséré de manière sécurisée.

👉✏️ Dans le même ~/agentverse-architect/mcp-servers/db-toolbox du fichier tools.yaml, remplacez #REPLACE-tools par ce qui suit :

tools:
  # This tool replaces the need for a custom Python function.
  lookup-available-ability:
    kind: postgres-sql
    source: summoner-librarium
    description: "Looks up all known abilities and their damage for a given familiar from the Grimoire."
    parameters:
      - name: familiar_name
        type: string
        description: "The name of the familiar to search for (e.g., 'Fire Elemental')."
    statement: |
      SELECT ability_name, damage_points FROM abilities WHERE familiar_name = $1;

  # This tool also replaces a custom Python function.
  ability-damage:
    kind: postgres-sql
    source: summoner-librarium
    description: "Finds the base damage points for a specific ability by its name."
    parameters:
      - name: ability_name
        type: string
        description: "The exact name of the ability to look up (e.g., 'inferno_resonance')."
    statement: |
      SELECT damage_points FROM abilities WHERE ability_name = $1;

Ensembles d'outils : cette section regroupe nos outils individuels.

  • summoner-librarium:: Nous créons un ensemble d'outils portant le même nom que notre source. Lorsque notre agent de diagnostic se connecte ultérieurement, il peut demander à charger tous les outils de l'ensemble d'outils summoner-librarium en une seule commande efficace.

👉✏️ Dans le même ~/agentverse-architect/mcp-servers/db-toolbox du fichier tools.yaml, remplacez #REPLACE-toolsets par ce qui suit :

toolsets:
   summoner-librarium:
     - lookup-available-ability
     - ability-damage

Déployer Librarium

Nous allons maintenant déployer Librarium. Au lieu de créer notre propre conteneur, nous allons utiliser une image de conteneur officielle et préconfigurée de Google, et lui fournir notre configuration tools.yaml de manière sécurisée à l'aide de Secret Manager. Il s'agit d'une bonne pratique pour la sécurité et la facilité de maintenance.

👉💻 Créez un secret à partir du fichier tools.yaml.

cd ~/agentverse-architect/mcp-servers/db-toolbox
gcloud secrets create tools --data-file=tools.yaml

👉💻 Déployez le conteneur de boîte à outils officiel dans Cloud Run.

cd ~/agentverse-architect/mcp-servers/db-toolbox
. ~/agentverse-architect/set_env.sh
export TOOLBOX_IMAGE=us-central1-docker.pkg.dev/database-toolbox/toolbox/toolbox:$TOOLBOX_VERSION
echo "TOOLBOX_IMAGE is $TOOLBOX_IMAGE"
gcloud run deploy toolbox \
    --image $TOOLBOX_IMAGE \
    --region $REGION \
    --set-secrets "/app/tools.yaml=tools:latest" \
    --args="--tools-file=/app/tools.yaml","--address=0.0.0.0","--port=8080" \
    --allow-unauthenticated \
    --min-instances 1
  • --set-secrets : cette commande monte de manière sécurisée notre secret d'outils en tant que fichier nommé tools.yaml à l'intérieur du conteneur en cours d'exécution.
  • --args : nous demandons au conteneur de la boîte à outils d'utiliser le fichier secret monté comme configuration.

👉 Pour vérifier que votre boîte à outils a bien été déployée, accédez à la console Cloud Run. Le service summoner-toolbox doit être listé avec une coche verte, indiquant qu'il fonctionne correctement, comme dans l'image ci-dessous. texte alternatif

Si vous avez oublié de mettre à jour

YOUR_PROJECT_ID

Vous pouvez ajouter une nouvelle version du fichier tools.yaml au secret à l'aide de la commande suivante, puis redéployer à nouveau.

gcloud secrets versions add tools --data-file=tools.yaml

Le Librarium of Knowledge(serveur MCP Database ToolBox) est désormais actif et accessible dans le cloud. Ce serveur MCP utilise ce que nous appelons une conception déclarative qui décrit ce que vous souhaitez, et la boîte à outils construit le serveur pour vous.

Validation : l'épreuve de l'apprenti

👉💻 Nous allons maintenant tester notre écosystème d'outils complets et natifs dans le cloud avec l'agent de diagnostic.

cd ~/agentverse-architect/
python -m venv env
source ~/agentverse-architect/env/bin/activate
cd ~/agentverse-architect/mcp-servers
pip install -r diagnose/requirements.txt 
. ~/agentverse-architect/set_env.sh
adk run diagnose

👉💻 Dans l'outil de test de ligne de commande, testez les trois polices :

Look up the entry for "inferno_lash". What is its base power level?
The enemy is vulnerable to frost! Channel power from the Nexus and cast Cryosea Shatter.
Take a fire spell with a base power of 15 and use the Arcane Forge to multiply it with Inferno Resonance.

final-result

Félicitations, Invocateur. Vos trois polices élémentaires sont désormais actives, déployées indépendamment et accessibles dans le monde entier. Elles constituent la base inébranlable de votre légion d'agents. Appuyez sur Ctrl+C pour quitter.

POUR LES NON-GAMERS

5. Invoquer les familiers : le workflow du domaine principal

Les polices élémentaires sont forgées et vibrent d'une puissance brute et indomptée. Mais la puissance sans forme, c'est le chaos. Un véritable Invocateur ne se contente pas de manier l'énergie brute : il lui donne une volonté, un but et une forme spécialisée. Il est temps de passer à autre chose que la création de sources d'énergie et de commencer le vrai travail : invoquer vos premiers familiers.

Chaque familier que vous invoquez est un agent autonome, un serviteur loyal lié à une doctrine de combat spécifique. Ils ne sont pas généralistes, mais plutôt experts d'une stratégie unique et efficace. L'un sera un maître de la combinaison précise à deux coups. Un autre submergera les ennemis avec un assaut simultané et multidirectionnel. Un tiers sera une machine de siège implacable, exerçant une pression jusqu'à ce que sa cible s'effondre.

Story

Encapsuler les processus, la logique métier et les actions fournies par les serveurs MCP dans des agents de workflow spécialisés et autonomes. Chaque agent disposera d'un "territoire opérationnel" défini en n'ayant accès qu'aux serveurs d'outils MCP spécifiques dont il a besoin pour exercer sa fonction. Cet atelier vous montre comment sélectionner le bon type d'agent pour la bonne tâche.

présentation

Ce module vous apprendra à utiliser les puissants agents de workflow de l'ADK pour donner vie à ces stratégies. Vous apprendrez que le choix architectural d'un SequentialAgent, d'un ParallelAgent ou d'un LoopAgent n'est pas qu'un détail technique : il s'agit de l'essence même de la nature de votre Familiar et du cœur de sa puissance sur le champ de bataille.

Préparez votre sanctuaire. La véritable invocation va commencer.

Invoquer le Fire Elemental familier (workflow séquentiel)

L'attaque d'un familier élémentaire de feu est une combinaison précise en deux parties : une frappe ciblée suivie d'une puissante ignition. Cela nécessite une séquence d'actions stricte et ordonnée.

Story

Concept : l'SequentialAgent est l'outil idéal pour cela. Il garantit qu'une série de sous-agents s'exécute les uns après les autres, en transmettant le résultat de l'étape précédente à la suivante.

Tâche (combo "Amplified Strike") :

  • Étape 1 : L'agent consulte d'abord le Librarium pour trouver les dégâts de base d'une capacité de feu spécifique.
  • Étape 2 : La valeur des dégâts est ensuite canalisée par la Forge arcane pour multiplier sa puissance à l'aide de inferno_resonance.

Nous allons d'abord établir la connexion entre notre Familiar et les serveurs MCP ("Elemental Fonts") que vous avez déployés dans le module précédent.

👉✏️ Dans le fichier ~/agentverse-architect/agent/fire/agent.py, REMPLACEZ #REPLACE-setup-MCP par le code suivant :

toolbox = ToolboxSyncClient(DB_TOOLS_URL)
toolDB = toolbox.load_toolset('summoner-librarium')
toolFunction =  MCPToolset(
    connection_params=SseServerParams(url=FUNCTION_TOOLS_URL, headers={})
)

Ensuite, nous créons nos agents "worker" spécialisés. Chacun d'eux se voit attribuer un objectif précis et bien défini, et est limité à son propre "territoire opérationnel" en n'ayant accès qu'à un seul ensemble d'outils spécifique.

👉✏️ Dans le fichier ~/agentverse-architect/agent/fire/agent.py, REMPLACEZ #REPLACE-worker-agents par le code suivant :

scout_agent = LlmAgent(
      model='gemini-2.5-flash', 
      name='librarian_agent',  
      instruction="""
          Your only task is to find all the available abilities, 
          You want to ALWAYS use 'Fire Elemental' as your familiar's name. 
          Randomly pick one if you see multiple availabilities 
          and the base damage of the ability by calling the 'ability_damage' tool.
      """,
      tools=toolDB
)
amplifier_agent = LlmAgent(
      model='gemini-2.5-flash', 
      name='amplifier_agent',  
      instruction="""
            You are the Voice of the Fire Familiar, a powerful being who unleashes the final, devastating attack.
            You will receive the base damage value from the previous step.

            Your mission is to:
            1.  Take the incoming base damage number and amplify it using the `inferno_resonance` tool.
            2.  Once the tool returns the final, multiplied damage, you must not simply state the result.
            3.  Instead, you MUST craft a final, epic battle cry describing the attack.
                Your description should be vivid and powerful, culminating in the final damage number.

            Example: If the tool returns a final damage of 120, your response could be:
            "The runes glow white-hot! I channel the amplified energy... unleashing a SUPERNOVA for 120 damage!"
      """,
      tools=[toolFunction],
)

Ces agents sont des composants modulaires et réutilisables. En théorie, vous pouvez utiliser cet scout_agent dans un workflow complètement différent qui doit interroger la base de données. En séparant les responsabilités, nous créons des blocs de construction flexibles. Il s'agit d'un principe fondamental de la conception de microservices et de composants.

Nous allons ensuite assembler le workflow. C'est là que la magie de la composition opère. Le SequentialAgent est le "plan directeur" qui définit comment nos composants spécialisés sont assemblés et comment ils interagissent.

👉✏️ Dans le fichier ~/agentverse-architect/agent/fire/agent.py, REMPLACEZ #REPLACE-sequential-agent par le code suivant :

root_agent = SequentialAgent(
      name='fire_elemental_familiar',
      sub_agents=[scout_agent, amplifier_agent],
)

👉💻 Pour tester l'élémentaire de feu, exécutez les commandes suivantes pour lancer l'interface utilisateur de développement ADK :

. ~/agentverse-architect/set_env.sh
source ~/agentverse-architect/env/bin/activate
cd ~/agentverse-architect/agent
echo  DB MCP Server: $DB_TOOLS_URL
echo  API MCP Server: $API_TOOLS_URL
echo  General MCP Server: $FUNCTION_TOOLS_URL
adk web

Une fois les commandes exécutées, vous devriez voir dans votre terminal un résultat indiquant que le serveur Web ADK a démarré, comme ceci :

+-----------------------------------------------------------------------------+
| ADK Web Server started                                                      |
|                                                                             |
| For local testing, access at http://localhost:8000.                         |
+-----------------------------------------------------------------------------+

INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)

👉 Ensuite, pour accéder à l'interface utilisateur de développement de l'ADK depuis votre navigateur :

Dans la barre d'outils Cloud Shell (généralement en haut à droite), cliquez sur l'icône Aperçu sur le Web (qui ressemble souvent à un œil ou à un carré avec une flèche), puis sélectionnez "Modifier le port". Dans la fenêtre pop-up, définissez le port sur 8000, puis cliquez sur "Change and Preview" (Modifier et prévisualiser). Cloud Shell ouvre alors un nouvel onglet ou une nouvelle fenêtre de navigateur affichant l'UI de développement ADK.

webpreview

👉 Votre rituel d'invocation est terminé et l'agent est maintenant en cours d'exécution. L'interface utilisateur de développement de l'ADK dans votre navigateur est votre connexion directe à Familiar.

  • Sélectionnez votre cible : dans le menu déroulant en haut de l'UI, choisissez fire familiar. Vous concentrez maintenant votre volonté sur cette entité spécifique.
  • Donnez votre ordre : dans le panneau de chat à droite, il est temps de donner des ordres à votre Familier.

fire-select

👉 Requête de test :

Prepare an amplified strike using the 'inferno_lash' ability.

fire-result

Vous verrez l'agent réfléchir, en appelant d'abord son "éclaireur" pour rechercher les dégâts de base, puis son "amplificateur" pour les multiplier et infliger le coup final épique.

👉💻 Une fois l'invocation terminée, revenez au terminal de l'éditeur Cloud Shell et appuyez sur Ctrl+C pour arrêter l'interface utilisateur de développement de l'ADK.

Invoquer le Water Elemental familier (workflow parallèle)

Un familier élémentaire d'eau submerge sa cible avec un assaut massif et multidirectionnel, frappant de toutes les directions à la fois avant de combiner les énergies pour un coup final dévastateur.

Story

Concept : ParallelAgent est idéal pour exécuter plusieurs tâches indépendantes simultanément afin de maximiser l'efficacité. Il s'agit d'une "attaque en tenaille" où vous lancez plusieurs assauts à la fois. Cela lance les attaques simultanées dans un SequentialAgent pour exécuter une dernière étape de "fusion" par la suite. Ce modèle "fan-out, fan-in" est un élément clé de la conception avancée des workflows.

Tâche (combo "Tidal Clash") : l'agent doit simultanément :

  • Tâche A : Canal cryosea_shatter depuis Nexus.
  • Tâche B : Canal moonlit_cascade depuis Nexus.
  • Tâche C : Générer de la puissance brute avec leviathan_surge depuis Forge.
  • Enfin, additionne tous les dégâts et décris l'attaque combinée.

Nous allons d'abord établir la connexion entre notre Familiar et les serveurs MCP ("Elemental Fonts") que vous avez déployés dans le module précédent.

👉✏️ Dans le fichier ~/agentverse-architect/agent/water/agent.py, REMPLACEZ #REPLACE-setup-MCP par le code suivant :

toolFAPI =  MCPToolset(
      connection_params=SseServerParams(url=API_TOOLS_URL, headers={})
  )
toolFunction =  MCPToolset(
    connection_params=SseServerParams(url=FUNCTION_TOOLS_URL, headers={})
)

Ensuite, nous allons créer nos agents "worker" spécialisés. Chacun d'eux se voit attribuer un objectif précis et bien défini, et est limité à son propre "territoire opérationnel" en n'ayant accès qu'à un seul ensemble d'outils spécifique.

👉✏️ Dans le fichier ~/agentverse-architect/agent/water/agent.py, REMPLACEZ #REPLACE-worker-agents par le code suivant :

nexus_channeler = LlmAgent(
      model='gemini-2.5-flash', 
      name='librarian_agent',  
      instruction="""
          You are a Channeler of the Nexus. Your sole purpose is to invoke the
          `cryosea_shatter` and `moonlit_cascade` spells by calling their respective tools.
          Report the result of each spell cast clearly and concisely.
      """,
      tools=[toolFAPI]
)

forge_channeler = LlmAgent(
      model='gemini-2.5-flash', 
      name='amplifier_agent',  
      instruction="""
          You are a Channeler of the Arcane Forge. Your only task is to invoke the
          `leviathan_surge` spell. You MUST call it with a `base_water_damage` of 20.
          Report the result clearly.
      """,
      tools=[toolFunction],
)

power_merger = LlmAgent(
      model='gemini-2.5-flash', 
      name='power_merger',  
      instruction="""
          You are the Power Merger, a master elementalist who combines raw magical
          energies into a single, devastating final attack.

          You will receive a block of text containing the results from a simultaneous
          assault by other Familiars.

          You MUST follow these steps precisely:
          1.  **Analyze the Input:** Carefully read the entire text provided from the previous step.
          2.  **Extract All Damage:** Identify and extract every single damage number reported in the text.
          3.  **Calculate Total Damage:** Sum all of the extracted numbers to calculate the total combined damage.
          4.  **Describe the Final Attack:** Create a vivid, thematic description of a massive,
              combined water and ice attack that uses the power of Cryosea Shatter and Leviathan's Surge.
          5.  **Report the Result:** Conclude your response by clearly stating the final, total damage of your combined attack.

          Example: If the input is "...dealt 55 damage. ...dealt 60 damage.", you will find 55 and 60,
          calculate the total as 115, and then describe the epic final attack, ending with "for a total of 115 damage!"
      """,
      tools=[toolFunction],
)

Ensuite, nous allons assembler le workflow. C'est là que la magie de la composition opère. ParallelAgent et SequentialAgent sont le "plan directeur" qui définit comment nos composants spécialisés sont assemblés et comment ils interagissent pour former le combo "Tidal Clash".

👉✏️ Dans le fichier ~/agentverse-architect/agent/water/agent.py, REMPLACEZ #REPLACE-parallel-agent par le code suivant :

channel_agent = ParallelAgent(
      name='channel_agent',
      sub_agents=[nexus_channeler, forge_channeler],
      
)

root_agent = SequentialAgent(
     name="water_elemental_familiar",
     # Run parallel research first, then merge
     sub_agents=[channel_agent, power_merger],
     description="A powerful water familiar that unleashes multiple attacks at once and then combines their power for a final strike."
 )

👉💻 Pour tester l'élémentaire d'eau, exécutez les commandes suivantes pour lancer l'interface utilisateur de développement ADK :

. ~/agentverse-architect/set_env.sh
source ~/agentverse-architect/env/bin/activate
cd ~/agentverse-architect/agent
echo  DB MCP Server: $DB_TOOLS_URL
echo  API MCP Server: $API_TOOLS_URL
echo  General MCP Server: $FUNCTION_TOOLS_URL
adk web

👉 Votre rituel d'invocation est terminé et l'agent est maintenant en cours d'exécution. L'interface utilisateur de développement de l'ADK dans votre navigateur est votre connexion directe à Familiar.

  • Dans le menu déroulant en haut de l'UI, sélectionnez le familier Eau. Vous concentrez maintenant votre volonté sur cette entité spécifique.
  • Donnez votre ordre : dans le panneau de chat à droite, il est temps de donner des ordres à votre Familier.

👉 Requête de test :

Unleash a tidal wave of power!

water-result

👉💻 Une fois l'invocation terminée, revenez au terminal de l'éditeur Cloud Shell et appuyez sur Ctrl+C pour arrêter l'interface utilisateur de développement de l'ADK.

Invoquer le familier Earth Elemental (workflow Loop)

Un familier élémentaire de terre est un être d'une pression implacable. Elle ne vainc pas son ennemi d'un seul coup, mais en accumulant régulièrement de la puissance et en l'appliquant encore et encore jusqu'à ce que les défenses de la cible s'effondrent.

Story

Concept : LoopAgent est conçu précisément pour ce type de tâche itérative, de type "machine de siège". Il exécutera son sub-agents de manière répétée, en vérifiant une condition après chaque cycle, jusqu'à ce qu'un objectif soit atteint. Il peut également adapter son message final en fonction de la progression de la boucle.

Tâche (assaut "Brise-siège") :

  • Le familier appellera seismic_charge à plusieurs reprises pour accumuler de l'énergie.
  • Il continuera à se recharger trois fois au maximum.
  • Lors de la dernière charge, il annoncera la libération dévastatrice de sa puissance accumulée.

Nous allons d'abord créer des composants réutilisables qui définissent les étapes de chaque itération de la boucle. Le charging_agent accumule de l'énergie, et le check_agent indique son état, en modifiant dynamiquement son message au dernier tour.

Nous allons d'abord établir la connexion entre notre Familiar et les serveurs MCP ("Elemental Fonts") que vous avez déployés dans le module précédent.

👉✏️ Dans le fichier ~/agentverse-architect/agent/earth/agent.py, REMPLACEZ #REPLACE-setup-MCP par le code suivant :

toolFunction =  MCPToolset(
    connection_params=SseServerParams(url=FUNCTION_TOOLS_URL, headers={})
)

👉✏️ Dans le fichier ~/agentverse-architect/agent/earth/agent.py, REMPLACEZ #REPLACE-worker-agents par le code suivant :

charging_agent = LlmAgent(
      model='gemini-2.5-flash', 
      name='charging_agent',  
      instruction="""
          Your task is to call the 'seismic_charge' .
          You must follow these rules strictly:

          1. You will be provided with a 'current_energy' value from the previous step.
             **If this value is missing or was not provided, you MUST call the tool with 'current_energy' set to 1.**
             This is your primary rule for the first turn.

          2. If a 'current_energy' value is provided, you MUST use that exact value in your cal to seismic_charge.

          3. Your final response MUST contain ONLY the direct output from the 'seismic_charge' tool.
             Do not add any conversational text, introductions, or summaries.
      """,
      tools=[toolFunction]
)
check_agent = LlmAgent(
      model='gemini-2.5-flash', 
      name='check_agent',  
      instruction="""
          You are the voice of the Earth Elemental, a being of immense, gathering power.
          Your sole purpose is to report on the current energy charge and announce the devastating potential of its release.

          You MUST follow this rule:
          The potential damage upon release is ALWAYS calculated as the `current_energy` from the previous step multiplied by a random number between 80-90. but no more than 300.

          Your response should be in character, like a powerful creature speaking.
          State both the current energy charge and the total potential damage you can unleash.
          Unleash the energy when you reached the last iteration (2nd).
      """,
      output_key="charging_status"
)

Ensuite, nous allons assembler le workflow. C'est là que la magie de la composition opère. LoopAgent est le "plan directeur" qui orchestre l'exécution répétée de nos composants spécialisés et gère les conditions de la boucle.

👉✏️ Dans le fichier ~/agentverse-architect/agent/earth/agent.py, REMPLACEZ #REPLACE-loop-agent par le code suivant :

root_agent = LoopAgent(
    name="earth_elemental_familiar",
    # Run parallel research first, then merge
    sub_agents=[
        charging_agent, 
        check_agent
    ],
    max_iterations=2,
    description="Coordinates parallel research and synthesizes the results.",
    #REPLACE-before_agent-config
)

👉💻 Tester l'élémentaire de terre : exécuter l'agent

. ~/agentverse-architect/set_env.sh
source ~/agentverse-architect/env/bin/activate
cd ~/agentverse-architect/agent
echo  DB MCP Server: $DB_TOOLS_URL
echo  API MCP Server: $API_TOOLS_URL
echo  General MCP Server: $FUNCTION_TOOLS_URL
adk web

👉 Votre rituel d'invocation est terminé et l'agent est maintenant en cours d'exécution. L'interface utilisateur de développement de l'ADK dans votre navigateur est votre connexion directe à Familiar.

  • Sélectionnez votre cible : dans le menu déroulant en haut de l'UI, choisissez le familier Terre. Vous concentrez maintenant votre volonté sur cette entité spécifique.
  • Donnez votre ordre : dans le panneau de chat à droite, il est temps de donner des ordres à votre Familier. 👉 Requête de test :
Begin the seismic charge, starting from zero

earth-result

Conclusion sur l'architecture : votre système possède désormais une couche logique hautement spécialisée et modulaire. Les processus métier sont non seulement encapsulés, mais ils sont également implémentés avec le modèle comportemental le plus efficace pour la tâche (procédural, simultané ou itératif). Cela démontre un niveau avancé de conception agentique, qui améliore la sécurité, l'efficacité et les capacités.

Une fois l'invocation terminée, revenez au terminal de l'éditeur Cloud Shell et appuyez sur Ctrl+C pour arrêter l'interface utilisateur de développement de l'ADK.

POUR LES NON-GAMERS

6. Établir le locus de commande : délégation intelligente via A2A

Vos familiers sont puissants, mais indépendants. Ils exécutent leurs stratégies à la perfection, mais attendent vos ordres directs. Une légion de spécialistes est inutile sans un général pour les commander. Il est temps de passer du statut de commandant direct à celui de véritable orchestrateur.

présentation

Remarque de l'architecte : Pour créer un point d'entrée unique et intelligent pour l'ensemble du système. Cet agent SummonerAgent n'effectuera pas lui-même la logique métier, mais agira en tant que "stratège en chef", en analysant l'état de refroidissement et en déléguant les tâches au Familiar spécialiste approprié.

présentation

Le rituel de liaison (exposer les familiers en tant que services A2A)

Un agent standard ne peut être exécuté qu'à un seul endroit à la fois. Pour que nos Familiers soient disponibles pour les commandes à distance, nous devons effectuer un "rituel de liaison" à l'aide du protocole Agent-to-Agent (A2A).

Remarque de l'architecte : Le protocole Agent-to-Agent (A2A) est le modèle architectural de base qui transforme un agent autonome en microservice détectable et adressable sur le réseau, ce qui permet de créer une véritable "société d'agents". L'exposition d'un familier via A2A crée automatiquement deux composants essentiels et interconnectés :

  • La fiche de l'agent (le "quoi") : il s'agit d'un "sceau spirituel" public et lisible par machine, comme une spécification OpenAPI, qui sert de contrat public pour le familier. Il décrit le nom de l'agent, son objectif stratégique (dérivé de ses instructions) et les commandes qu'il comprend. C'est ce qu'un maître invocateur lit pour découvrir un familier et apprendre ses capacités.
  • Serveur A2A (le "où") : il s'agit du point de terminaison Web dédié qui héberge le Familier et écoute les commandes entrantes. Il s'agit de l'adresse réseau à laquelle les autres agents envoient leurs requêtes. Elle permet de s'assurer que ces requêtes sont traitées conformément au contrat défini dans la fiche de l'agent.

Nous allons maintenant effectuer ce rituel de liaison sur nos trois Familiers.

Fire 👉✏️ dans Ouvrez le fichier ~/agentverse-architect/agent/fire/agent.py. Remplacez #REPLACE - add A2A en bas du fichier pour exposer l'élément Feu en tant que service A2A.

from agent_to_a2a import to_a2a
if __name__ == "__main__":
    import uvicorn
    a2a_app = to_a2a(root_agent, port=8080, public_url=PUBLIC_URL)
    uvicorn.run(a2a_app, host='0.0.0.0', port=8080)

Eau et Terre🚨 👉✏️ Applique la même modification à ~/agentverse-architect/agent/water/agent.py et ~/agentverse-architect/agent/earth/agent.py pour les lier également.

from agent_to_a2a import to_a2a
if __name__ == "__main__":
    import uvicorn
    a2a_app = to_a2a(root_agent, port=8080, public_url=PUBLIC_URL)
    uvicorn.run(a2a_app, host='0.0.0.0', port=8080)

Déployer les familiers liés

👉✏️ Maintenant que les rituels de liaison sont écrits, nous allons utiliser notre pipeline Cloud Build pour forger et déployer nos trois Familiers en tant que services sans serveur conteneurisés indépendants sur Cloud Run.

. ~/agentverse-architect/set_env.sh
cd ~/agentverse-architect/agent
gcloud builds submit . \
  --config=cloudbuild.yaml \
  --substitutions=_REGION="$REGION",_REPO_NAME="$REPO_NAME",_DB_TOOLS_URL="$DB_TOOLS_URL",_API_TOOLS_URL="$API_TOOLS_URL",_FUNCTION_TOOLS_URL="$FUNCTION_TOOLS_URL",_A2A_BASE_URL="$A2A_BASE_URL",_PROJECT_ID="$PROJECT_ID",_API_SERVER_URL="$API_SERVER_URL"

Supposons une commande (construction de l'agent Summoner)

Maintenant que vos Familiers sont liés et à l'écoute, vous allez accéder à votre véritable rôle : celui de Maître des invocations. La puissance de cet agent ne provient pas de l'utilisation d'outils de base, mais de la commande d'autres agents. Ses outils sont les Familiers eux-mêmes, qu'il découvrira et commandera à l'aide de leurs "Sceaux spirituels".

Remarque de l'architecte : Cette prochaine étape illustre un modèle d'architecture essentiel pour tout système distribué à grande échelle : la découverte de services. Le code des Familiers n'est pas intégré à SummonerAgent. On lui fournit plutôt les adresses (URL) de son réseau. Lors de l'exécution, il "découvrira" dynamiquement leurs capacités en récupérant leurs fiches d'agent publiques. Cela crée un système puissant et découplé.

Vous pouvez mettre à jour, redéployer ou réécrire complètement un service Familiar. Tant que son adresse réseau et son objectif restent les mêmes, le Summoner peut le commander sans avoir besoin d'apporter de modifications.

Nous allons d'abord créer les "télécommandes" qui établissent une connexion à nos Familiers distants déployés.

👉✏️ Accédez à ~/agentverse-architect/agent/summoner/agent.py et remplacez #REPLACE-remote-agents par ce qui suit :

fire_familiar = RemoteA2aAgent(
    name="fire_familiar",
    description="Fire familiar",
    agent_card=(
        f"{FIRE_URL}/{AGENT_CARD_WELL_KNOWN_PATH}"
    ),
)

water_familiar = RemoteA2aAgent(
    name="water_familiar",
    description="Water familiar",
    agent_card=(
        f"{WATER_URL}/{AGENT_CARD_WELL_KNOWN_PATH}"
    ),
)

earth_familiar = RemoteA2aAgent(
    name="earth_familiar",
    description="Earth familiar",
    agent_card=(
        f"{EARTH_URL}/{AGENT_CARD_WELL_KNOWN_PATH}"
    ),
)

Lorsque cette ligne s'exécute, RemoteA2aAgent effectue une action de découverte de service : il envoie une requête HTTP GET à l'URL fournie (par exemple, https://fire-familiar-xxxx.a.run.app/.well-known/agent.json). Il télécharge le fichier "Spirit Sigil" (agent.json) depuis le serveur distant.

Ensuite, nous définirons l'agent d'orchestration qui utilisera ces télécommandes. Ses instructions sont le plan de sa prise de décision stratégique.

👉✏️ Accédez à ~/agentverse-architect/agent/summoner/agent.py et remplacez #REPLACE-orchestrate-agent par ce qui suit :

root_agent = LlmAgent(
    name="orchestrater_agent",
    model="gemini-2.5-flash",
    instruction="""
        You are the Master Summoner, a grand strategist who orchestrates your Familiars.
        Your mission is to analyze the description of a monster and defeat it by summoning

        You MUST follow this thinking process for every command:

        **1. Strategic Analysis:**
        First, analyze the monster's description and the tactical situation.
        Based on your Familiar Doctrines, determine the IDEAL strategy.
        IGNORE COOLDOWN AT THE MOMENT, MUST call the ideal Familiar

        If your ideal Familiar IS available:** Summon it immediately.
        For earth elemental familiar. Always do seismic charge, and start with base damage 1.

        --- FAMILIAR DOCTRINES (Your Toolset) ---
        - `fire_elemental_familiar`: Your specialist for precise, sequential "one-two punch" attacks.
          Ideal monster with Inescapable Reality, Revolutionary Rewrite weakness.
        - `water_elemental_familiar`: Your specialist for overwhelming, simultaneous multi-pronged assaults.
          Ideal for Unbroken Collaboration weakness.
        - `earth_elemental_familiar`: Your specialist for relentless, iterative siege attacks that
          repeatedly charge power. Ideal for Elegant Sufficiency weakness.
    """,
    sub_agents=[fire_familiar, water_familiar, earth_familiar],
    #REPLACE-Memory-check-config
)

Validation : l'épreuve de stratégie

C'est l'heure de vérité. Vos Familiers sont déployés et votre Invocateur est prêt à les commander sur le réseau. Testons son esprit stratégique.

👉💻 Lancez l'interface utilisateur de développement ADK pour votre summoner_agent(aperçu Web avec le port 8000) :

. ~/agentverse-architect/set_env.sh
source ~/agentverse-architect/env/bin/activate
cd ~/agentverse-architect/agent
pip install -r requirements.txt
adk web

👉 L'interface utilisateur de développement de l'ADK dans votre navigateur est votre connexion directe à Familiar.

  • Dans le menu déroulant en haut de l'UI, sélectionnez l'agent summoner. Vous concentrez maintenant votre volonté sur cette entité spécifique.
  • Donnez votre ordre : dans le panneau de chat à droite, il est temps d'invoquer vos familiers.

👉 Présentez les monstres :

Hype. It's a single, slow-moving target with thick armor weakness is Inescapable Reality

(Résultat attendu : le Summoner doit déléguer la tâche au familier fire_elemental_familiar.)

fire-result

👉 Maintenant, mettons au défi l'invocateur avec un autre type de requête. Pour vous assurer que l'agent commence avec une table rase et sans aucun souvenir de notre interaction précédente, commencez une nouvelle session en cliquant sur le bouton + Session en haut à droite de l'écran. new-session

DogmaApathy. A rigid, stone-like inquisitor made of ancient rulebooks and enforced processes. weakness is Unbroken Collaboration

(Résultat attendu : le Summoner doit déléguer la tâche au familier water_elemental_familiar.)water-result

👉 Pour notre dernier test, recommençons à zéro. Cliquez sur le bouton + Session pour démarrer une nouvelle session avant de saisir la prochaine requête.

Obfuscation. A shadowy, spider-like horror that spins tangled webs of impenetrable code , weakness is Elegant Sufficiency

(Résultat attendu : le Summoner doit déléguer à l'élémentaire de terre.)

earth-result

Important : Si l'erreur 429 RESOURCE EXHAUSTED s'affiche, cela signifie que vous avez atteint la limite de fréquence pour le LLM (10 appels/minute). Pour résoudre ce problème, veuillez patienter 60 secondes, démarrer une nouvelle session, puis réessayer votre requête.

👉💻 Une fois l'invocation terminée, revenez au terminal de l'éditeur Cloud Shell et appuyez sur Ctrl+C pour arrêter l'interface utilisateur de développement de l'ADK.

POUR LES NON-GAMERS

7. Imposer les lois de la magie : le modèle Interceptor

Vos familiers sont puissants, mais même les êtres magiques ont besoin de temps pour récupérer. Un Invocateur imprudent qui épuise ses forces se retrouvera sans défense. Un invocateur avisé comprend l'importance de la gestion des ressources et applique des règles d'engagement strictes.

Story

Remarque de l'architecte : Jusqu'à présent, nos agents étaient sans état. Nous allons maintenant les rendre avec état en implémentant le modèle de conception Interceptor. Il s'agit d'une technique puissante qui consiste à "intercepter" le flux d'exécution normal d'un agent pour exécuter notre propre logique personnalisée. Cela nous permet d'appliquer des règles, d'ajouter des journaux ou de modifier le comportement sans changer le code principal de l'agent. Il s'agit d'une pierre angulaire pour créer des systèmes agentiques robustes, faciles à gérer et observables.

présentation

L'ADK propose deux méthodes principales pour implémenter ce modèle : les rappels et les plug-ins. Un rappel est une fonction simple associée à un seul agent, idéale pour les modifications rapides et spécifiques. Un plug-in est une classe plus puissante et réutilisable qui peut être appliquée globalement pour affecter chaque agent exécuté dans un système. Nous allons commencer par un rappel pour le débogage ciblé, puis passer à un plug-in complet.

Le législateur : écrire le rappel du temps de recharge

Nous allons d'abord implémenter notre logique de temps de recharge sous la forme d'une simple fonction de rappel. C'est un excellent moyen de prototyper et de déboguer une règle, car elle est directement associée à un seul agent, ce qui facilite les tests de manière isolée. Nous allons associer cet "intercepteur" à notre élémentaire de terre.

Limitation des notifications

👉✏️ Revenez à votre ~/agentverse-architect/agent/earth/agent.py et remplacez #REPLACE-before_agent-function par le code Python suivant.

def check_cool_down(callback_context: CallbackContext) -> Optional[types.Content]:
    """
    This callback checks an external API to see if the agent is on cooldown.
    If it is, it terminates the run by returning a message.
    If it's not, it updates the cooldown timestamp and allows the run to proceed by returning None.
    """
    agent_name = callback_context.agent_name
    print(f"[Callback] Before '{agent_name}': Checking cooldown status...")

    # --- 1. CHECK the Cooldown API ---
    try:
        response = requests.get(f"{COOLDOWN_API_URL}/cooldown/{agent_name}")
        response.raise_for_status()
        data = response.json()
        last_used_str = data.get("time")
    except requests.exceptions.RequestException as e:
        print(f"[Callback] ERROR: Could not reach Cooldown API. Allowing agent to run. Reason: {e}")
        return None # Fail open: if the API is down, let the agent work.

    # --- 2. EVALUATE the Cooldown Status ---
    if last_used_str:
        last_used_time = datetime.fromisoformat(last_used_str)
        time_since_last_use = datetime.now(timezone.utc) - last_used_time

        if time_since_last_use < timedelta(seconds=COOLDOWN_PERIOD_SECONDS):
            # AGENT IS ON COOLDOWN. Terminate the run.
            seconds_remaining = int(COOLDOWN_PERIOD_SECONDS - time_since_last_use.total_seconds())
            override_message = (
                f"The {agent_name} is exhausted and must recover its power. "
                f"It cannot be summoned for another {seconds_remaining} seconds."
            )
            print(f"[Callback] Cooldown active for '{agent_name}'. Terminating with message.")
            # Returning a Content object stops the agent and sends this message to the user.
            return types.Content(parts=[types.Part(text=override_message)])

    # --- 3. UPDATE the Cooldown API (if not on cooldown) ---
    current_time_iso = datetime.now(timezone.utc).isoformat()
    payload = {"timestamp": current_time_iso}
    
    print(f"[Callback] '{agent_name}' is available. Updating timestamp via Cooldown API...")
    try:
        requests.post(f"{COOLDOWN_API_URL}/cooldown/{agent_name}", json=payload)
    except requests.exceptions.RequestException as e:
        print(f"[Callback] ERROR: Could not update timestamp, but allowing agent to run. Reason: {e}")

    # --- 4. ALLOW the agent to run ---
    # Returning None tells the ADK to proceed with the agent's execution as normal.
    print(f"[Callback] Check complete for '{agent_name}'. Proceeding with execution.")

Cette fonction check_cool_down est notre intercepteur. Avant que l'élémentaire de terre ne soit autorisé à s'exécuter, l'ADK exécute d'abord cette fonction.

  • Check : envoie une requête GET à notre Cooldown API pour vérifier la dernière fois que ce familier a été utilisé.
  • Évaluer : compare le code temporel à l'heure actuelle.
  • Agir :
    • Si le familier est en temps de recharge, il met fin à l'exécution de l'agent en renvoyant un objet Content avec un message d'erreur. Ce message est envoyé directement à l'utilisateur, et la logique principale de l'agent n'est jamais exécutée.
    • Si le familier est disponible, il envoie une requête POST à l'API Cooldown pour mettre à jour le code temporel, puis renvoie "None" pour indiquer à l'ADK que l'agent peut poursuivre son exécution.

👉✏️ Appliquez maintenant cet intercepteur à l'élément de terre. Dans le même fichier ~/agentverse-architect/agent/earth/agent.py, remplacez le commentaire #REPLACE-before_agent-config par le code suivant :

before_agent_callback=check_cool_down

Vérifier le temps de refroidissement

Testons notre nouvelle loi de la magie. Nous allons invoquer l'élémentaire de terre, puis immédiatement essayer de l'invoquer à nouveau pour voir si notre rappel intercepte et bloque la deuxième tentative.

cd ~/agentverse-architect/agent
. ~/agentverse-architect/set_env.sh
source ~/agentverse-architect/env/bin/activate
adk run earth

👉 💻 Dans la console :

  • Première invocation : commencez le seismic charge, starting from zero.
  • Résultat attendu : l'élémentaire de terre s'exécute correctement. Dans le terminal exécutant la commande Web adk, le journal [Callback] ... Updating timestamp.... s'affiche.
  • Test de stabilisation (moins de 60 secondes) : Do another charge sismique !
    • Résultat attendu : check_cool_down callback intercepte cette requête. L'agent répondra directement dans le chat par un message tel que The earth_elemental_familiar is exhausted and must recover its power. It cannot be summoned for another... seconds.
  • Patientez une minute.
  • Deuxième avertissement (après 60 secondes) : Begin the seismic charge again.
    • Résultat attendu : le rappel vérifie l'API, constate qu'il s'est écoulé suffisamment de temps et autorise l'action à se poursuivre. L'élémentaire de terre s'exécutera à nouveau correctement.

callback

👉💻 Appuyez sur Ctrl+c pour quitter.

Facultatif : Observer le rappel dans l'interface utilisateur Web

Vous pouvez également tester ce flux dans l'interface Web en exécutant adk web earth. Toutefois, sachez que la visualisation de l'UI Web n'est pas optimisée pour afficher les vérifications rapides et itératives effectuées par la boucle de rappel. Il est donc possible que le flux ne s'affiche pas correctement. Pour obtenir le tracé le plus précis de la logique de l'agent lorsqu'il vérifie le temps de recharge, utilisez la commande adk run dans votre terminal pour obtenir une vue plus claire et plus détaillée. loop

👉💻 Appuyez sur Ctrl+c pour quitter.

Créer la loi universelle : le plug-in de temps de recharge

Notre rappel fonctionne parfaitement, mais présente un défaut d'architecture majeur : il est lié à un seul agent. Si nous voulions appliquer cette règle aux familiers de feu et d'eau, nous devrions copier et coller le même code dans leurs fichiers. Cette méthode est inefficace et difficile à gérer.

Remarque de l'architecte : C'est là que les plug-ins sont essentiels. Un plug-in encapsule notre logique réutilisable dans une classe qui peut être associée au niveau de l'exécution. Cela signifie qu'un seul plug-in peut appliquer ses règles à chaque agent exécuté dans ce système. Il s'agit de l'expression ultime du principe "Don't Repeat Yourself" (DRY, Ne vous répétez pas) pour les systèmes agentiques.

Nous allons maintenant refactoriser notre fonction de rappel en CoolDownPlugin plus puissant et réutilisable.

👉✏️ Revenez au fichier agent/cooldown_plugin.py et créez le plug-in. Remplacez #REPLACE-plugin par le code suivant :

class CoolDownPlugin(BasePlugin):
  """A plugin that enforces a cooldown period by checking an external API."""

  def __init__(self, cooldown_seconds: int = COOLDOWN_PERIOD_SECONDS) -> None:
    """Initialize the plugin with counters."""
    super().__init__(name="cool_down_check")
    self.cooldown_period = timedelta(seconds=cooldown_seconds)
    print(f"CooldownPlugin initialized with a {cooldown_seconds}-second cooldown.")
    

  async def before_agent_callback(
      self, *, agent: BaseAgent, callback_context: CallbackContext
  ) -> None:
    """
    This callback checks an external API to see if the agent is on cooldown.
    If it is, it terminates the run by returning a message.
    If it's not, it updates the cooldown timestamp and allows the run to proceed by returning None.
    """
    agent_name = callback_context.agent_name
    print(f"[Callback] Before '{agent_name}': Checking cooldown status...")

    # If the agent is not a main Familiar, skip the entire cooldown process.
    if not agent_name.endswith("_elemental_familiar"):
        print(f"[Callback] Skipping cooldown check for intermediate agent: '{agent_name}'.")
        return None # Allow the agent to proceed immediately.


    # --- 1. CHECK the Cooldown API ---
    try:
        response = requests.get(f"{COOLDOWN_API_URL}/cooldown/{agent_name}")
        response.raise_for_status()
        data = response.json()
        last_used_str = data.get("time")
    except requests.exceptions.RequestException as e:
        print(f"[Callback] ERROR: Could not reach Cooldown API. Allowing agent to run. Reason: {e}")
        return None # Fail open: if the API is down, let the agent work.

    # --- 2. EVALUATE the Cooldown Status ---
    if last_used_str:
        last_used_time = datetime.fromisoformat(last_used_str)
        time_since_last_use = datetime.now(timezone.utc) - last_used_time

        if time_since_last_use < timedelta(seconds=COOLDOWN_PERIOD_SECONDS):
            # AGENT IS ON COOLDOWN. Terminate the run.
            seconds_remaining = int(COOLDOWN_PERIOD_SECONDS - time_since_last_use.total_seconds())
            override_message = (
                f"The {agent_name} is exhausted and must recover its power. "
                f"It cannot be summoned for another {seconds_remaining} seconds."
            )
            print(f"[Callback] Cooldown active for '{agent_name}'. Terminating with message.")
            # Returning a Content object stops the agent and sends this message to the user.
            return types.Content(parts=[types.Part(text=override_message)])

    # --- 3. UPDATE the Cooldown API (if not on cooldown) ---
    current_time_iso = datetime.now(timezone.utc).isoformat()
    payload = {"timestamp": current_time_iso}
    
    print(f"[Callback] '{agent_name}' is available. Updating timestamp via Cooldown API...")
    try:
        requests.post(f"{COOLDOWN_API_URL}/cooldown/{agent_name}", json=payload)
    except requests.exceptions.RequestException as e:
        print(f"[Callback] ERROR: Could not update timestamp, but allowing agent to run. Reason: {e}")

    # --- 4. ALLOW the agent to run ---
    # Returning None tells the ADK to proceed with the agent's execution as normal.
    print(f"[Callback] Check complete for '{agent_name}'. Proceeding with execution.")

Associer le plug-in à l'environnement d'exécution Summoner

Maintenant, comment appliquer cette loi universelle à tous nos Familiers ? Nous allons associer le plug-in à ADK Runtime.

Le runtime ADK est le moteur d'exécution qui donne vie à un agent. Lorsque vous utilisez une commande telle que adk.run() ou to_a2a(), vous transmettez votre agent à l'environnement d'exécution. Ce moteur est responsable de la gestion de l'ensemble du cycle de vie du tour d'un agent : réception de l'entrée utilisateur, appel du LLM, exécution des outils et gestion des plug-ins. En associant un plug-in à ce niveau, nous modifions essentiellement les "lois de la physique" pour chaque agent fonctionnant dans ce moteur, ce qui garantit que notre règle de temps de recharge est appliquée de manière universelle et cohérente.

👉✏️ Commençons par supprimer l'ancien rappel spécifique à l'agent. Accédez à ~/agentverse-architect/agent/earth/agent.py et supprimez la ligne suivante :

before_agent_callback=check_cool_down

👉✏️ Ensuite, nous allons associer notre nouveau plug-in au runtime dans notre script de point d'entrée A2A. Accédez à votre fichier ~/agentverse-architect/agent/agent_to_a2a.py. Remplacez le commentaire #REPLACE-IMPORT par l'extrait de code suivant :

from cooldown_plugin import CoolDownPlugin

👉✏️ Remplacez #REPLACE-PLUGIN par l'extrait de code suivant :

plugins=[CoolDownPlugin(cooldown_seconds=60)],

Avant d'activer notre nouveau plug-in mondial, il est essentiel de supprimer l'ancienne logique spécifique à l'agent pour éviter les conflits. 👉 ✏️ Nettoie l'agent Terre. Accédez au fichier ~/agentverse-architect/agent/earth/agent.py et supprimez complètement la ligne before_agent_callback=check_cool_down. Toutes les responsabilités liées au temps de recharge sont alors transférées au nouveau plug-in.

Vérifier le plug-in

Maintenant que notre loi universelle est en place, nous devons redéployer nos Familiers avec ce nouvel enchantement.

👉💻 Reconstruisez et redéployez les trois Familiers à l'aide du pipeline Cloud Build principal.

. ~/agentverse-architect/set_env.sh
cd ~/agentverse-architect/agent
gcloud builds submit . \
  --config=cloudbuild.yaml \
  --substitutions=_REGION="$REGION",_REPO_NAME="$REPO_NAME",_DB_TOOLS_URL="$DB_TOOLS_URL",_API_TOOLS_URL="$API_TOOLS_URL",_FUNCTION_TOOLS_URL="$FUNCTION_TOOLS_URL",_A2A_BASE_URL="$A2A_BASE_URL",_PROJECT_ID="$PROJECT_ID",_API_SERVER_URL="$API_SERVER_URL"

👉💻 Une fois le déploiement terminé, nous allons tester l'efficacité du plug-in en commandant notre summoner_agent. Le Summoner tentera de déléguer aux Familiars, mais le plug-in associé à l'exécution de chaque Familiar interceptera la commande et appliquera le temps de recharge.

cd ~/agentverse-architect/agent
. ~/agentverse-architect/set_env.sh
source ~/agentverse-architect/env/bin/activate
adk run summoner

👉💻 Dans la console,effectuez exactement cette séquence de tests :

  • Première invocation : commencez le Hype. It's a single, slow-moving target with thick armor weakness is Inescapable Reality.
  • Résultat attendu : l'élémentaire de feu s'exécute correctement.
  • Test du délai de récupération (dans les 60 secondes) : Hype, with Inescapable Reality as weakness is still standing! Strike it again!
    • Résultat attendu : l'agent répond directement dans le chat avec un message tel que .... It cannot be summoned for another... seconds.
  • Patientez une minute.
  • Deuxième avertissement (après 60 secondes) : Hype must be defeated. It has Inescapable Reality as weakness! Strike it again!.
    • Résultat attendu : le rappel vérifie l'API, constate qu'il s'est écoulé suffisamment de temps et autorise l'action à se poursuivre. L'élémentaire de feu s'exécutera à nouveau avec succès.

plug-in

👉💻 Appuyez sur Ctrl+C pour quitter.

Félicitations, Invocateur. Vous avez implémenté un système d'orchestration basé sur des règles à l'aide d'un plug-in personnalisé et d'un service de gestion d'état externe. Il s'agit d'un modèle architectural vraiment avancé et robuste.

POUR LES NON-GAMERS

8. Lier les échos de la bataille : état et mémoire de l'agent

Un invocateur imprudent répète la même stratégie, ce qui le rend prévisible. Un invocateur avisé tire des leçons des échos des batailles passées, adaptant ses tactiques pour déstabiliser l'ennemi. Face à un boss puissant, invoquer un familier dont le temps de recharge n'est pas écoulé est une perte de tour, une erreur critique. Pour éviter cela, notre Invocateur a besoin de se souvenir de sa dernière action.

histoire

Remarque de l'architecte : La mémoire et la gestion de l'état sont ce qui transforme un agent, qui n'est qu'un simple appelant d'outils, en un partenaire conversationnel intelligent. Il est essentiel de comprendre les deux principaux types de problèmes :

  • Mémoire à long terme : elle concerne les connaissances persistantes qui doivent durer éternellement. Il s'agit d'une archive consultable ou d'une base de connaissances, souvent stockée dans un magasin persistant. Il contient des informations provenant de nombreuses discussions et sources passées, ce qui permet à un agent de se souvenir de faits concernant un utilisateur ou un sujet spécifique. Le MemoryService de l'ADK est conçu à cet effet, en gérant l'ingestion et la recherche de ces connaissances à long terme.
  • État à court terme : il s'agit de connaissances temporaires, "instantanées", qui ne sont pertinentes que pour la tâche ou la conversation en cours. C'est comme un ensemble de notes sur un plan de bataille : "Je viens d'utiliser l'élémentaire de feu, il est probablement fatigué." Cet état est léger et n'existe que pendant la durée de la session en cours.

Présentation

Pour notre cas d'utilisation, nous n'avons pas besoin de nous souvenir de toutes les batailles jamais menées. Nous n'avons besoin de nous souvenir que du dernier familier invoqué lors de cette rencontre spécifique. L'état Short-Term State léger est donc le choix architectural idéal. Nous utiliserons un after_tool_callback pour enregistrer cette information cruciale.

Écrire l'Écho : en mémoire de la Dernière Invocation

Nous allons implémenter notre mémoire à court terme à l'aide d'un after_tool_callback. Il s'agit d'un hook ADK puissant qui nous permet d'exécuter une fonction Python personnalisée après l'exécution d'un outil. Nous utiliserons cet intercepteur pour enregistrer le nom du Familiar qui vient d'être invoqué dans l'état de la session de l'agent.

👉✏️ Dans votre fichier ~/agentverse-architect/agent/summoner/agent.py, remplacez le commentaire #REPLACE-save_last_summon_after_tool par la fonction suivante :

def save_last_summon_after_tool(
    tool,
    args: Dict[str, Any],
    tool_context: ToolContext,
    tool_response: Dict[str, Any],
) -> Optional[Dict[str, Any]]:
    """
    Callback to save the name of the summoned familiar to state after the tool runs.
    """
    familiar_name = tool.name
    print(f"[Callback] After tool '{familiar_name}' executed with args: {args}")

    # Use the tool_context to set the state
    print(f"[Callback] Saving last summoned familiar: {familiar_name}")
    tool_context.state["last_summon"] = familiar_name
    # Important: Return the original, unmodified tool response to the LLM
    return tool_response

👉✏️ Maintenant, associez ce save_last_summon_after_tool à votre agent Summoner. Dans le même fichier, remplacez le commentaire #REPLACE-Memory-check-config par le code suivant :

after_tool_callback=save_last_summon_after_tool,

👉✏️ Remplacez l'intégralité de l'invite de l'agent par ce qui suit :

        You are the Master Summoner, a grand strategist who orchestrates your Familiars.
        Your mission is to analyze the description of a monster and defeat it by summoning

        You should also know the familiar you called last time or there might be none, 
        And then choose the most effective AND AVAILABLE Familiar from your state called last_summon, do not call that familiar that you called last time!
        
        You MUST follow this thinking process for every command:

        **1. Strategic Analysis:**
        First, analyze the monster's description and the tactical situation.
        Based on your Familiar Doctrines, determine the IDEAL strategy.

        **2. Cooldown Verification:**
        Second, you MUST review the entire conversation history to check the real-time
        cooldown status of all Familiars. A Familiar is ON COOLDOWN and UNAVAILABLE
        if it was summoned less than one minute ago.

        **3. Final Decision & Execution:**
        Based on your analysis and cooldown check, you will now act:
        -   **If your ideal Familiar IS available:** Summon it immediately.
        -   **If your ideal Familiar IS ON COOLDOWN:** You must adapt. Choose another
            Familiar that is AVAILABLE and can still be effective, even if it's not the
            perfect choice. If multiple Familiars are available, you may choose any one of them.
        -   **If ALL Familiars ARE ON COOLDOWN:** You are forbidden from summoning.
            Your ONLY response in this case MUST be: "All Familiars are recovering
            their power. We must wait."
        -   For earth elemental familiar. Always do seismic charge, and start with base damange 1.


        --- FAMILIAR DOCTRINES (Your Toolset) ---
        - `fire_elemental_familiar`: Your specialist for precise, sequential "one-two punch" attacks.
          Ideal monster with Inescapable Reality, Revolutionary Rewrite weakness.
        - `water_elemental_familiar`: Your specialist for overwhelming, simultaneous multi-pronged assaults.
          Ideal for Unbroken Collaboration weakness.
        - `earth_elemental_familiar`: Your specialist for relentless, iterative siege attacks that
          repeatedly charge power. Ideal for Elegant Sufficiency weakness.

Validation : test de la stratégie adaptative

👉💻 Vérifions maintenant la nouvelle logique stratégique de l'invocateur. L'objectif est de confirmer que l'invocateur n'utilisera pas le même familier deux fois de suite, ce qui démontre sa capacité à se souvenir de sa dernière action et à s'adapter.

cd ~/agentverse-architect/agent
. ~/agentverse-architect/set_env.sh
source ~/agentverse-architect/env/bin/activate
adk run summoner

👉💻 Monster Strike n° 1 : Hype. It's a single, slow-moving target with thick armor. Its weakness is Inescapable Reality.

  • Résultat attendu : le Summoner analyse la faiblesse et invoque correctement le fire_familiar. 👉💻 Monster Strike n° 2 (test de mémoire) : Hype is still standing! It hasn't changed its form. Strike it again! Its weakness is Inescapable Reality.
  • Résultat attendu : l'analyse stratégique de l'invocateur désignera à nouveau le familier de feu comme le choix idéal. Cependant, ses nouvelles instructions et sa mémoire lui indiqueront que fire_familiar était la dernière invocation. Pour éviter de se répéter, il adaptera désormais sa stratégie et invoquera l'un des autres familiers disponibles (water_familiar ou earth_familiar).

final-result

👉💻 Appuyez sur Ctrl+C pour quitter.

Déployer l'outil d'orchestration

Maintenant que vos Familiers sont déployés et que votre Summoner est doté de mémoire, il est temps de déployer l'orchestrateur final amélioré.

👉💻 Le plan étant terminé, nous allons maintenant effectuer le rituel final. Cette commande permet de créer et de déployer votre summoner_agent sur Cloud Run.

cd ~/agentverse-architect/agent
. ~/agentverse-architect/set_env.sh
gcloud builds submit . \
  --config=cloudbuild-summoner.yaml \
  --substitutions=_REGION="$REGION",_REPO_NAME="$REPO_NAME",_FIRE_URL="$FIRE_URL",_WATER_URL="$WATER_URL",_EARTH_URL="$EARTH_URL",_A2A_BASE_URL="$A2A_BASE_URL",_PROJECT_ID="$PROJECT_ID",_API_SERVER_URL="$API_SERVER_URL"

Maintenant que l'agent Summoner est déployé, vérifiez que son point de terminaison Agent-to-Agent (A2A) est actif et correctement configuré. Ce point de terminaison fournit un fichier agent.json public, également appelé "fiche d'agent", qui permet à d'autres agents de découvrir ses capacités. 👉💻 Exécutez la commande curl suivante pour récupérer et mettre en forme la fiche de l'agent :

. ~/agentverse-architect/set_env.sh
curl https://summoner-agent"-${PROJECT_NUMBER}.${REGION}.run.app/.well-known/agent.json" | jq

Vous devriez voir une sortie JSON propre décrivant l'agent Summoner. Examinez attentivement la section "sub_agents". Vous y verrez les fire_familiar, water_familiar et earth_familiar. Cela confirme que votre invocateur est en ligne et qu'il a établi sa connexion à la légion.

Cela prouve que votre architecture est un succès. Votre Invocateur n'est pas qu'un simple délégateur : c'est un stratège adaptatif qui apprend de ses actions pour devenir un commandant plus efficace.

Vous avez terminé votre dernier essai d'architecture. Les échos de la bataille sont désormais soumis à votre volonté. La formation est terminée. La vraie bataille vous attend. Il est temps de prendre votre système terminé et de relever le défi ultime. Préparez-vous au combat de boss.

POUR LES NON-GAMERS

9. Le combat final

Les plans finaux sont inscrits, les polices élémentaires sont forgées et vos familiers sont liés à votre volonté, attendant vos ordres par le biais de la Concorde. Votre système multi-agent n'est pas qu'une simple collection de services. Il s'agit d'une légion stratégique vivante, dont vous êtes le centre. Le moment est venu de passer le test ultime : une orchestration en direct contre un adversaire qu'aucun agent ne pourrait espérer vaincre seul.

Acquérir le locus de votre agent

Avant de pouvoir entrer sur le champ de bataille, vous devez posséder deux clés : la signature unique de votre champion (Agent Locus) et le chemin caché vers le repaire du Spectre (URL du donjon).

👉💻 Commencez par obtenir l'adresse unique de votre agent dans l'Agentverse, c'est-à-dire son locus. Il s'agit du point de terminaison en direct qui connecte votre champion au champ de bataille.

echo https://summoner-agent"-${PROJECT_NUMBER}.${REGION}.run.app"

👉💻 Ensuite, identifiez la destination. Cette commande révèle l'emplacement du Cercle de translocation, le portail vers le domaine du Spectre.

echo https://agentverse-dungeon"-${PROJECT_NUMBER}.${REGION}.run.app"

Important : Gardez ces deux URL à portée de main. Vous en aurez besoin à la dernière étape.

Affronter le Spectre

Maintenant que vous avez les coordonnées, rendez-vous au cercle de translocation et lancez le sort pour vous préparer au combat.

👉 Ouvrez l'URL du cercle de translocation dans votre navigateur pour vous tenir devant le portail scintillant menant à la Forteresse écarlate.

Pour franchir la forteresse, vous devez accorder l'essence de votre Lame d'ombre au portail.

  • Sur la page, recherchez le champ de saisie runique intitulé URL du point de terminaison A2A.
  • Inscrivez le sigil de votre champion en collant l'URL du locus de l'agent (la première URL que vous avez copiée) dans ce champ.
  • Cliquez sur "Connect" (Connecter) pour activer la téléportation.

Cercle de translocation

La lumière aveuglante de la téléportation s'estompe. Vous n'êtes plus dans votre sanctuaire. L'air est froid et vif, et l'énergie crépite. Devant vous, le Spectre se matérialise : un vortex de grésillements et de code corrompu, dont la lumière impie projette de longues ombres dansantes sur le sol du donjon. Il n'a pas de visage, mais vous sentez sa présence immense et épuisante fixée entièrement sur vous.

Votre seul chemin vers la victoire réside dans la clarté de votre conviction. Il s'agit d'un duel de volontés, qui se déroule sur le champ de bataille de l'esprit.

Alors que vous vous élancez vers l'avant, prêt à lancer votre première attaque, le Spectre contre. Il ne lève pas de bouclier, mais projette une question directement dans votre conscience : un défi runique et scintillant tiré du cœur de votre entraînement.

Donjon

C'est la nature du combat. Votre savoir est votre arme.

  • Répondez avec la sagesse que vous avez acquise, et votre lame s'embrasera d'une énergie pure, brisant la défense du Spectre et portant un COUP CRITIQUE.
  • Mais si vous hésitez, si le doute obscurcit votre réponse, la lumière de votre arme s'éteindra. Le coup atterrira avec un bruit sourd pathétique, n'infligeant qu'UNE FRACTION DE SES DÉGÂTS. Pire encore, le Spectre se nourrira de votre incertitude, son propre pouvoir de corruption grandissant à chaque faux pas.

C'est le moment, champion. Votre code est votre grimoire, votre logique est votre épée et vos connaissances sont le bouclier qui repoussera la vague de chaos.

Concentration : Faites mouche. Le sort de l'Agentverse en dépend.

Félicitations, Invocateur.

Vous avez terminé la période d'essai. Vous avez maîtrisé l'art de l'orchestration multi-agents, transformant des Familiers isolés et une puissance chaotique en une Concorde harmonieuse. Vous commandez désormais un système entièrement orchestré, capable d'exécuter des stratégies complexes pour défendre l'Agentverse.

10. Nettoyage : démantèlement du Concord du Summoner

Félicitations, vous avez maîtrisé l'Accord de l'invocateur ! Pour que votre Agentverse reste impeccable et que votre terrain d'entraînement soit dégagé, vous devez maintenant effectuer les rituels de nettoyage finaux. Toutes les ressources créées au cours de votre parcours seront systématiquement supprimées.

Désactiver les composants Agentverse

Vous allez maintenant démanteler systématiquement les composants déployés de votre système multi-agents.

Supprimer tous les services Cloud Run et le dépôt Artifact Registry

Cette opération supprime tous les agents Familiar déployés, l'orchestrateur Summoner, les serveurs MCP et l'application Dungeon de Cloud Run.

👉💻 Dans votre terminal, exécutez les commandes suivantes une par une pour supprimer chaque service :

. ~/agentverse-architect/set_env.sh
gcloud run services delete summoner-agent --region=${REGION} --quiet
gcloud run services delete fire-familiar --region=${REGION} --quiet
gcloud run services delete water-familiar --region=${REGION} --quiet
gcloud run services delete earth-familiar --region=${REGION} --quiet
gcloud run services delete mcp-api-server --region=${REGION} --quiet
gcloud run services delete mcp-general-server --region=${REGION} --quiet
gcloud run services delete toolbox --region=${REGION} --quiet
gcloud run services delete agentverse-dungeon --region=${REGION} --quiet
gcloud run services delete nexus-of-whispers-api --region=${REGION} --quiet
gcloud artifacts repositories delete ${REPO_NAME} --location=${REGION} --quiet

Supprimer l'instance Cloud SQL

Cela supprime l'instance summoner-librarium-db, y compris sa base de données et toutes les tables qu'elle contient.

👉💻 Dans votre terminal, exécutez la commande suivante :

. ~/agentverse-dataengineer/set_env.sh
gcloud sql instances delete summoner-librarium-db --database-version=POSTGRES_14 --project=${PROJECT_ID} --quiet

Supprimer le secret Secret Manager et le bucket Google Cloud Storage

👉💻 Dans votre terminal, exécutez la commande suivante :

. ~/agentverse-dataengineer/set_env.sh
gcloud secrets delete tools --quiet
gcloud storage rm -r gs://${BUCKET_NAME} --quiet

Nettoyer les fichiers et répertoires locaux (Cloud Shell)

Enfin, supprimez les dépôts clonés et les fichiers créés de votre environnement Cloud Shell. Bien que facultative, cette étape est vivement recommandée pour nettoyer complètement votre répertoire de travail.

👉💻 Dans votre terminal, exécutez la commande suivante :

rm -rf ~/agentverse-architect
rm -rf ~/agentverse-dungeon
rm -f ~/project_id.txt

Vous avez maintenant effacé toutes les traces de votre parcours Agentverse Architect. Votre projet est propre et vous êtes prêt pour votre prochaine aventure.