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

1. de La Forza del destino

L'era dello sviluppo isolato sta per finire. La prossima ondata di evoluzione tecnologica non riguarda il genio solitario, ma la maestria collaborativa. Creare un unico agente intelligente è un esperimento affascinante. Creare un ecosistema di agenti solido, sicuro e intelligente, un vero e proprio Agentverse, è la grande sfida per l'azienda moderna.

Il successo in questa nuova era richiede la convergenza di quattro ruoli fondamentali, i pilastri di base che supportano qualsiasi sistema autonomo fiorente. Una carenza in una qualsiasi area crea una debolezza che può compromettere l'intera struttura.

Questo workshop è il playbook aziendale definitivo per padroneggiare il futuro degli agenti su Google Cloud. Forniamo una roadmap end-to-end che ti guida dalla prima idea a una realtà operativa su vasta scala. In questi quattro lab interconnessi, imparerai come le competenze specializzate di uno sviluppatore, di un architetto, di un data engineer e di un SRE devono convergere per creare, gestire e scalare un potente Agentverse.

Nessun singolo pilastro può supportare da solo l'Agentverse. Il progetto grandioso dell'architetto è inutile senza l'esecuzione precisa dello sviluppatore. L'agente dello sviluppatore è cieco senza la saggezza dell'ingegnere dei dati e l'intero sistema è fragile senza la protezione dell'SRE. Solo attraverso la sinergia e una comprensione condivisa dei ruoli di ciascuno, il tuo team può trasformare un concetto innovativo in una realtà operativa fondamentale. Il tuo percorso inizia qui. Preparati a padroneggiare il tuo ruolo e a scoprire come ti inserisci nel quadro generale.

Ti diamo il benvenuto in The Agentverse: A Call to Champions

Nella vasta distesa digitale dell'impresa, è iniziata una nuova era. È l'era degli agenti, un periodo di immense promesse, in cui agenti intelligenti e autonomi lavorano in perfetta armonia per accelerare l'innovazione ed eliminare le attività banali.

agentverse.png

Questo ecosistema connesso di potere e potenziale è noto come Agentverse.

Ma una lenta entropia, una corruzione silenziosa nota come Statico, ha iniziato a sfilacciare i bordi di questo nuovo mondo. La Static non è un virus o un bug, ma l'incarnazione del caos che si nutre dell'atto stesso della creazione.

Amplifica le vecchie frustrazioni in forme mostruose, dando vita ai Sette spettri dello sviluppo. Se non viene selezionata, The Static and its Spectres bloccherà i progressi, trasformando la promessa dell'Agentverse in una landa desolata di debito tecnico e progetti abbandonati.

Oggi invitiamo i campioni a contrastare l'ondata di caos. Abbiamo bisogno di eroi disposti a perfezionare le proprie abilità e a collaborare per proteggere l'Agentverse. È arrivato il momento di scegliere il tuo percorso.

Scegliere il corso

Quattro percorsi distinti si aprono davanti a te, ognuno dei quali è un pilastro fondamentale nella lotta contro The Static. Anche se la formazione sarà una missione solitaria, il tuo successo finale dipende dalla comprensione di come le tue competenze si combinano con quelle degli altri.

  • The Shadowblade (sviluppatore): un maestro della forgia e del fronte. Sei l'artigiano che crea le lame, costruisce gli strumenti e affronta il nemico nei dettagli intricati del codice. Il tuo percorso è fatto di precisione, abilità e creazione pratica.
  • L'Evocatore (architetto): un grande stratega e orchestratore. Non vedi un singolo agente, ma l'intero campo di battaglia. Progetti i master blueprint che consentono a interi sistemi di agenti di comunicare, collaborare e raggiungere un obiettivo molto più grande di qualsiasi singolo componente.
  • Lo studioso (data engineer): un ricercatore di verità nascoste e custode della saggezza. Ti avventuri nella vasta e selvaggia natura dei dati per scoprire l'intelligenza che dà ai tuoi agenti uno scopo e una visione. Le tue conoscenze possono rivelare la debolezza di un nemico o dare potere a un alleato.
  • Il Guardiano (DevOps / SRE): il protettore e lo scudo del regno. Costruisci le fortezze, gestisci le linee di alimentazione e assicurati che l'intero sistema possa resistere agli inevitabili attacchi di The Static. La tua forza è la base su cui si fonda la vittoria della tua squadra.

La tua missione

L'allenamento inizierà come esercizio autonomo. Seguirai il percorso che hai scelto, acquisendo le competenze uniche necessarie per padroneggiare il tuo ruolo. Al termine della prova, dovrai affrontare uno spettro nato da The Static, un mini boss che si nutre delle sfide specifiche della tua professione.

Solo se padroneggi il tuo ruolo individuale puoi prepararti per la prova finale. Dovrai quindi formare un gruppo con campioni delle altre classi. Insieme, vi avventurerete nel cuore della corruzione per affrontare un boss finale.

Una sfida finale collaborativa che metterà alla prova la vostra forza combinata e determinerà il destino dell'Agentverse.

L'Agentverse attende i suoi eroi. Risponderai alla chiamata?

2. L'accordo dell'evocatore

Benvenuto, Evocatore. Il tuo percorso è fatto di visione e strategia. Mentre gli altri si concentrano su una singola lama o su un singolo incantesimo, tu vedi l'intero campo di battaglia. Non comandi un singolo agente, ma un'intera orchestra. Il tuo potere non risiede nel conflitto diretto, ma nella progettazione di un progetto impeccabile e generale che consenta a una legione di specialisti, i tuoi Famigli, di lavorare in perfetta armonia. Questa missione metterà alla prova la tua capacità di progettare, connettere e orchestrare un sistema multi-agente potente.

panoramica

Obiettivi didattici

  • Progetta un ecosistema di strumenti disaccoppiati:progetta ed esegui il deployment di un insieme di server di strumenti MCP indipendenti basati su microservizi. Scoprirai perché questo livello fondamentale è essenziale per creare sistemi agentici scalabili, gestibili e sicuri.
  • Padroneggia i workflow con agente avanzati: vai oltre i singoli agenti e crea una legione di "Famigli" specializzati. Acquisirai padronanza dei pattern di flusso di lavoro ADK principali: sequenziale, parallelo e ciclo e imparerai i principi architetturali per scegliere il pattern giusto per l'attività giusta.
  • Implementa un orchestratore intelligente:passa da un semplice generatore di agenti a un vero e proprio architetto di sistemi. Creerai un agente di orchestrazione principale che utilizza il protocollo da agente ad agente (A2A) per scoprire e delegare attività complesse ai tuoi Familiari specializzati, creando un vero sistema multi-agente.
  • Applicare regole con il codice, non con i prompt:scopri come creare agenti più affidabili e prevedibili applicando regole di coinvolgimento stateful. Implementerai una logica personalizzata utilizzando il potente sistema di plug-in e callback dell'ADK per gestire i vincoli del mondo reale, come i timer di raffreddamento.
  • Gestisci lo stato e la memoria dell'agente:dai ai tuoi agenti la possibilità di imparare e ricordare. Esplorerai tecniche per gestire sia lo stato conversazionale a breve termine sia la memoria persistente a lungo termine per creare interazioni più intelligenti e sensibili al contesto.
  • Esegui un deployment cloud end-to-end:porta l'intero sistema multi-agente da un prototipo locale a una realtà di livello di produzione. Scoprirai come containerizzare gli agenti e l'orchestratore ed eseguirne il deployment come raccolta di microservizi scalabili e indipendenti su Google Cloud Run.

3. Disegnare il cerchio di evocazione

Benvenuto, Evocatore. Prima che un singolo Famiglio possa essere evocato, prima che qualsiasi patto possa essere forgiato, deve essere preparato il terreno su cui ti trovi. Un ambiente selvaggio è un invito al caos; un vero Evocatore opera solo all'interno di uno spazio consacrato e potenziato. Il nostro primo compito è disegnare il cerchio di evocazione: iscrivere le rune del potere che risvegliano i servizi cloud necessari e acquisire i progetti antichi che guideranno il nostro lavoro. Il potere di un evocatore nasce da una preparazione meticolosa.

👉 Fai clic su Attiva Cloud Shell nella parte superiore della console Google Cloud (l'icona a forma di terminale nella parte superiore del riquadro Cloud Shell).

testo alternativo

👉 Fai clic sul pulsante "Apri editor" (ha l'aspetto di una cartella aperta con una matita). Si aprirà l'editor di codice di Cloud Shell nella finestra. Sul lato sinistro vedrai un esploratore di file. testo alternativo

👉 Trova l'ID progetto Google Cloud:

  • Apri la console Google Cloud: https://console.cloud.google.com
  • Seleziona il progetto che vuoi utilizzare per questo workshop dal menu a discesa dei progetti nella parte superiore della pagina.
  • L'ID progetto viene visualizzato nella scheda informativa del progetto nella dashboard testo alternativo

👉 Apri il terminale nell'IDE cloud, testo alternativo

👉💻 Nel terminale, verifica di aver già eseguito l'autenticazione e che il progetto sia impostato sul tuo ID progetto utilizzando il seguente comando:

gcloud auth list

👉💻 Clona il progetto di bootstrap da 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

👉💻 Esegui lo script di inizializzazione, che ti chiederà di inserire l'ID progetto Google Cloud. e inserisci l'ID progetto Google Cloud che hai trovato nell'ultimo passaggio quando richiesto dallo script init.sh.

cd ~/agentverse-architect
./init.sh

👉💻 Imposta l'ID progetto necessario:

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

👉💻 Esegui il comando seguente per abilitare le API Google Cloud necessarie:

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

👉💻 Se non hai ancora creato un repository Artifact Registry denominato agentverse-repo, esegui il seguente comando per crearlo: (ignora questo passaggio se hai altre classi di agenti virtuali di conversazione di cui è stato eseguito il deployment nello stesso progetto)

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

Configurazione dell'autorizzazione

👉💻 Concedi le autorizzazioni necessarie eseguendo questi comandi nel terminale:

. ~/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"

👉💻 Mentre inizi l'allenamento, prepareremo la sfida finale. I seguenti comandi evocheranno gli Spettri dal caos statico, creando i boss per il test finale.

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

👉💻 Infine, esegui lo script prepare.sh per eseguire le attività di configurazione iniziale.

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

Ottimo lavoro, Evocatore. Il cerchio è completo e i patti sono sigillati. Il terreno è ora consacrato, pronto a incanalare un potere immenso. Nella prossima prova, forgeremo i caratteri elementali da cui i nostri Famigli trarranno la loro forza.

4. Forging the Elemental Fonts: The Decoupled Tooling Ecosystem

Il campo di battaglia è pronto, il cerchio di evocazione è disegnato e il mana ambientale crepita. È il momento di compiere il tuo primo vero atto da Evocatore: forgiare le fonti di potere da cui i tuoi Famigli trarranno la loro forza. Questo rituale è diviso in tre parti, ognuna delle quali risveglia una Fonte elementale, una fonte stabile e indipendente di un tipo specifico di potere. Solo quando tutti e tre i caratteri sono attivi puoi iniziare il lavoro più complesso di evocazione.

Storia

Nota dell'architetto:il server Model Context Protocol (MCP) è un componente fondamentale di un moderno sistema di agenti, che funge da ponte di comunicazione standardizzato che consente a un agente di scoprire e utilizzare strumenti remoti. Nel nostro ecosistema di strumenti, progetteremo due tipi distinti di server MCP, ognuno dei quali rappresenta un modello architetturale fondamentale. Per connetterci al nostro database, utilizzeremo un approccio dichiarativo con Database Toolbox, definendo i nostri strumenti in un semplice file di configurazione. Questo pattern è incredibilmente efficiente e sicuro per esporre l'accesso ai dati strutturati. Tuttavia, quando dobbiamo implementare una logica di business personalizzata o chiamare API di terze parti esterne, utilizziamo un approccio imperativo, scrivendo la logica del server passo dopo passo nel codice. In questo modo, avrai il massimo controllo e la massima flessibilità, il che ci consente di incapsulare operazioni complesse in uno strumento semplice e riutilizzabile. Un master architect deve comprendere entrambi i pattern per selezionare l'approccio giusto per ogni componente, creando una base di strumenti solida, sicura e scalabile.

panoramica

Risveglio del Nexus dei Sussurri (server MCP API esterno)

Un saggio Evocatore sa che non tutto il potere ha origine dal proprio dominio. Esistono fonti di energia esterne, a volte caotiche, che possono essere incanalate per ottenere grandi risultati. Il Nexus dei Sussurri è la nostra porta di accesso a queste forze.

Storia

Esiste già un servizio attivo che funge da fonte di alimentazione esterna e offre due endpoint di incantesimi non elaborati: /cryosea_shatter e /moonlit_cascade.

Nota dell'architetto:utilizzerai un approccio imperativo che definisce esplicitamente la logica del server passo dopo passo. In questo modo hai molto più controllo e flessibilità, il che è essenziale quando i tuoi strumenti devono fare di più che eseguire una semplice query SQL, ad esempio chiamare altre API. Comprendere entrambi i pattern è una competenza fondamentale per un agent architect.

👉✏️ Vai alla directory ~/agentverse-architect/mcp-servers/api/main.py e SOSTITUISCI #REPLACE-MAGIC-CORE con il seguente codice:

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}"

Al centro dello script ci sono le semplici funzioni Python. È qui che si svolge il lavoro vero e proprio.

👉✏️ Nello stesso file ~/agentverse-architect/mcp-servers/api/main.py SOSTITUISCI #REPLACE-Runes of Communication con il seguente codice:

@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): questa funzione è il saluto del server. Quando un nuovo agente si connette, chiama per prima cosa questo endpoint per chiedere: "Che cosa sai fare?". Il nostro codice risponde con un elenco di tutti gli strumenti disponibili, convertiti nel formato MCP universale utilizzando adk_to_mcp_tool_type. - @app.call_tool() (il comando): questa funzione è la più importante. Quando l'agente decide di utilizzare uno strumento, invia una richiesta a questo endpoint con il nome dello strumento e gli argomenti. Il nostro codice cerca lo strumento nel nostro "libro degli incantesimi" disponibile_tools, lo esegue con run_async e restituisce il risultato nel formato MCP standard.

Eseguiremo il deployment in un secondo momento.

Accensione della Forgia arcana (server MCP Funzioni generali)

Non tutto il potere deriva da libri antichi o sussurri lontani. A volte, un Evocatore deve forgiare la propria magia dalla pura volontà e dalla logica. La Fucina arcana è questa fonte di potere: un server che fornisce funzioni di utilità stateless e generiche.

Storia

Nota dell'architetto: questo è un altro pattern architetturale. Sebbene la connessione a sistemi esistenti sia comune, spesso dovrai implementare regole aziendali e logica uniche. Creare uno strumento dedicato a "funzioni" o "utilità" come questo è una best practice. Incapsula la logica personalizzata, la rende riutilizzabile per qualsiasi agente nel tuo ecosistema e la mantiene separata dalle origini dati e dalle integrazioni esterne.

👀 Dai un'occhiata al file ~/agentverse-architect/mcp-servers/general/main.py nel tuo IDE Google Cloud. Noterai che utilizza lo stesso approccio imperativo mcp.server di Nexus per creare questo Font of Power personalizzato.

Crea la pipeline Cloud Build principale

Ora creeremo il file cloudbuild.yaml all'interno della directory mcp-servers. Questo file orchestrerà la creazione e il deployment di entrambi i servizi.

👉💻 Dalla directory ~/agentverse-architect/mcp-servers, esegui questi comandi:

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"

Attendi il completamento di tutti i deployment.

👉 Puoi verificare il deployment andando alla console Cloud Run. Dovresti vedere le due nuove istanze del server MCP in esecuzione, come mostrato di seguito: testo alternativo

Risveglio del Librarium of Knowledge (server MCP di Database ToolBox)

Il nostro prossimo carattere sarà la Libreria della Conoscenza, una connessione diretta al nostro database Cloud SQL.

Storia

Nota dell'architetto:per questo, utilizzeremo il moderno e dichiarativo Database Toolbox. Si tratta di un approccio efficace in cui definiamo l'origine dati e gli strumenti in un file di configurazione YAML. Il toolbox gestisce il lavoro complesso di creazione ed esecuzione del server, riducendo la quantità di codice personalizzato che dobbiamo scrivere e gestire.

È il momento di creare la nostra "Biblioteca dell'evocatore", il database Cloud SQL che conterrà tutte le nostre informazioni critiche. Utilizzeremo uno script di configurazione per gestire questa operazione automaticamente.

👉💻 Innanzitutto, configuriamo il database. Nel terminale, esegui i seguenti comandi:

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

Al termine dello script, il database verrà compilato e i dati sui danni elementali saranno pronti per l'uso. Ora puoi verificare direttamente i contenuti del tuo Grimoire.

👉 Innanzitutto, vai a Cloud SQL Studio per il tuo database aprendo questo link diretto in una nuova scheda del browser:

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

Cloud SQL

👉 Nel riquadro di accesso a sinistra, seleziona il database familiar_grimoire dal menu a discesa.

👉 Inserisci summoner come utente e 1234qwer come password, quindi fai clic su Autentica.

👉📜 Una volta connesso, apri una nuova scheda dell'editor query se non è già aperta. Per visualizzare i dati sui danni elementali inscritti, incolla ed esegui la seguente query SQL:

SELECT * FROM
  "public"."abilities"

Ora dovresti vedere la tabella abilities con le colonne e le righe compilate, a conferma che il tuo Grimoire è pronto. Dati

Configurare il server MCP di ToolBox

Il file di configurazione tools.yaml funge da progetto per il nostro server, indicando a Database Toolbox esattamente come connettersi al nostro database e quali query SQL esporre come strumenti.

sources:questa sezione definisce le connessioni ai tuoi dati.

  • summoner-librarium:: Questo è un nome logico che abbiamo assegnato alla nostra connessione.
  • kind: cloud-sql-postgres: indica a Toolbox di utilizzare il connettore sicuro integrato progettato specificamente per Cloud SQL per PostgreSQL.
  • progetto, regione, istanza e così via: Queste sono le coordinate esatte dell'istanza Cloud SQL che hai creato durante lo script prepare.sh, che indicano a Toolbox dove trovare Librarium.

👉✏️ Vai a ~/agentverse-architect/mcp-servers/db-toolbox in tools.yaml, sostituisci #REPLACE-Source con quanto segue

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"

👉✏️ 🚨🚨REPLACE

YOUR_PROJECT_ID

con l'ID progetto.

tools:questa sezione definisce le capacità o le funzioni effettive che il nostro server offrirà.

  • lookup-available-ability:: Questo è il nome del nostro primo strumento.
  • kind: postgres-sql: indica a Toolbox che l'azione di questo strumento è l'esecuzione di un'istruzione SQL.
  • source: summoner-librarium: questo linka lo strumento alla connessione che abbiamo definito nel blocco delle origini. In questo modo, lo strumento sa su quale database eseguire la query.
  • descrizione e parametri: queste sono le informazioni che verranno esposte al modello linguistico. La descrizione indica all'agente quando utilizzare lo strumento, mentre i parametri definiscono gli input richiesti dallo strumento. Questo passaggio è fondamentale per attivare la funzionalità di chiamata di funzioni dell'agente.
  • statement: Questa è la query SQL non elaborata da eseguire. Il valore $1 è un segnaposto sicuro in cui verrà inserito in modo sicuro il parametro familiar_name fornito dall'agente.

👉✏️ Nello stesso ~/agentverse-architect/mcp-servers/db-toolbox del file tools.yaml, sostituisci #REPLACE-tools con il seguente

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;

Set di strumenti:questa sezione raggruppa i nostri singoli strumenti.

  • summoner-librarium:: We are creating a toolset with the same name as our source. Quando l'agente di diagnostica si connette in un secondo momento, può chiedere di caricare tutti gli strumenti dal set di strumenti summoner-librarium con un unico comando efficiente.

👉✏️ Nello stesso ~/agentverse-architect/mcp-servers/db-toolbox del file tools.yaml, sostituisci #REPLACE-toolsets con il seguente

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

Deployment di Librarium

Ora eseguiremo il deployment di Librarium. Anziché creare il nostro container, utilizzeremo un'immagine container ufficiale predefinita di Google e forniremo in modo sicuro la nostra configurazione tools.yaml utilizzando Secret Manager. Si tratta di una best practice per la sicurezza e la manutenibilità.

👉💻 Crea un secret dal file tools.yaml

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

👉💻 Esegui il deployment del container della toolbox ufficiale in 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: questo comando monta in modo sicuro il segreto dei nostri strumenti come file denominato tools.yaml all'interno del container in esecuzione.
  • --args: Indichiamo al container della toolbox di utilizzare il file segreto montato come configurazione.

👉 Per verificare che la tua casella degli strumenti sia stata implementata correttamente, vai alla console Cloud Run. Dovresti vedere il servizio summoner-toolbox elencato con un segno di spunta verde, che indica che è in esecuzione correttamente, proprio come nell'immagine seguente. testo alternativo

Se hai dimenticato di eseguire l'aggiornamento

YOUR_PROJECT_ID

puoi aggiungere una nuova versione di tools.yaml al secret utilizzando il seguente comando ed eseguire nuovamente il deployment.

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

Librarium of Knowledge(Database ToolBox MCP Server) è ora attivo e accessibile nel cloud. Questo server MCP utilizza un design dichiarativo che descriveva ciò che volevi e la casella degli strumenti creava il server per te.

Verifica: La prova dell'apprendista

👉💻 Ora testeremo il nostro ecosistema completo di strumenti cloud-native con l'agente diagnostico.

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

👉💻 Nello strumento di test della riga di comando, testa tutti e tre i caratteri:

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

Congratulazioni, Evocatore. Le tre Font elementali sono ora attive, implementate in modo indipendente e accessibili a livello globale, costituendo la base incrollabile della tua legione di agenti. Premi Ctrl+C per uscire.

PER CHI NON GIOCA

5. Evocare i Famigli: il flusso di lavoro del dominio principale

Le Fonti elementali sono forgiate e vibrano di un potere grezzo e indomito. Ma la potenza senza forma è caos. Un vero Evocatore non si limita a brandire energia grezza, ma le conferisce volontà, scopo e una forma specializzata. È il momento di andare oltre la creazione di fonti di energia e iniziare il vero lavoro: evocare i tuoi primi Famigli.

Ogni Famiglio che evochi sarà un agente autonomo, un servitore fedele legato a una dottrina di combattimento specifica. Non sono generalisti, ma esperti di una singola e potente strategia. Uno sarà un maestro della combo precisa e veloce. Un altro travolgerà i nemici con un assalto simultaneo su più fronti. Un terzo sarà una macchina d'assedio implacabile, che eserciterà pressione fino a quando il suo obiettivo non cederà.

Storia

Per incapsulare processi, logica aziendale e azioni fornite dai server MCP in agenti di workflow autonomi e specializzati. A ogni agente verrà assegnato un "territorio operativo" definito concedendo l'accesso solo ai server degli strumenti MCP specifici necessari per svolgere la sua funzione. Questo lab mostra come selezionare il tipo di agente giusto per il lavoro giusto.

panoramica

Questo modulo ti insegnerà a utilizzare i potenti agenti del flusso di lavoro dell'ADK per dare vita a queste strategie. Scoprirai che la scelta architetturale di un SequentialAgent, ParallelAgent o LoopAgent non è solo un dettaglio tecnico, ma l'essenza stessa della natura del tuo Famiglio e il nucleo del suo potere sul campo di battaglia.

Prepara il tuo sanctum. La vera evocazione sta per iniziare.

Evoca il Fire Elemental familiare (flusso di lavoro sequenziale)

L'attacco di un Famiglio elementale di fuoco è una combo precisa in due parti: un colpo mirato seguito da un'accensione potente. Questa operazione richiede una sequenza di azioni rigorosa e ordinata.

Storia

Concetto: il SequentialAgent è lo strumento perfetto per questo. Garantisce che una serie di sub-agenti vengano eseguiti uno dopo l'altro, passando il risultato del passaggio precedente a quello successivo.

Attività (la combo "Colpo amplificato"):

  • Passaggio 1: l'agente consulterà prima il Librarium per trovare il danno base di una specifica abilità di fuoco.
  • Passaggio 2: il valore del danno viene incanalato attraverso la Forgia arcana per moltiplicarne la potenza utilizzando inferno_resonance.

Innanzitutto, stabiliremo la connessione tra il nostro Familiar e i server MCP (i "caratteri elementali") che hai implementato nel modulo precedente.

👉✏️ Nel file ~/agentverse-architect/agent/fire/agent.py, SOSTITUISCI #REPLACE-setup-MCP con il seguente codice:

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

Successivamente, creiamo gli agenti "worker" specializzati. A ciascuno viene assegnato uno scopo ristretto e ben definito e il suo "territorio operativo" è limitato, in quanto gli viene concesso l'accesso a un solo insieme di strumenti specifico.

👉✏️ Nel file ~/agentverse-architect/agent/fire/agent.py SOSTITUISCI #REPLACE-worker-agents con il seguente codice:

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],
)

Questi agenti sono componenti modulari e riutilizzabili. In teoria, potresti utilizzare questo scout_agent in un flusso di lavoro completamente diverso che deve eseguire query sul database. Mantenendo separate le responsabilità, creiamo componenti di base flessibili. Questo è un principio fondamentale della progettazione basata su microservizi e componenti.

Successivamente, assembleremo il flusso di lavoro, ovvero dove avviene la magia della composizione. Il SequentialAgent è il "piano principale" che definisce il modo in cui vengono assemblati i nostri componenti specializzati e il modo in cui interagiscono.

👉✏️ Nel file ~/agentverse-architect/agent/fire/agent.py SOSTITUISCI #REPLACE-sequential-agent con il seguente codice:

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

👉💻 Per testare l'elemento di fuoco, esegui i seguenti comandi per avviare l'interfaccia utente di ADK DEV:

. ~/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

Dopo aver eseguito i comandi, dovresti visualizzare un output nel terminale che indica che il server web ADK è stato avviato, simile a questo:

+-----------------------------------------------------------------------------+
| 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)

👉 Successivamente, per accedere all'interfaccia utente per sviluppatori dell'ADK dal browser:

Dall'icona Anteprima web (spesso a forma di occhio o di quadrato con una freccia) nella barra degli strumenti di Cloud Shell (di solito in alto a destra), seleziona Cambia porta. Nella finestra popup, imposta la porta su 8000 e fai clic su "Cambia e visualizza anteprima". Cloud Shell aprirà quindi una nuova scheda o finestra del browser che mostra l'UI di ADK Dev.

webpreview

👉 Il rituale di evocazione è completo e l'agente è ora in esecuzione. La UI di sviluppo dell'ADK nel browser è la tua connessione diretta a Familiar.

  • Seleziona il tuo target: nel menu a discesa nella parte superiore della UI, scegli il fire che preferisci. Ora stai concentrando la tua volontà su questa entità specifica.
  • Dai il tuo comando: nel riquadro della chat a destra, è il momento di dare ordini al tuo Famiglio.

fire-select

👉 Test Prompt:

Prepare an amplified strike using the 'inferno_lash' ability.

fire-result

Vedrai l'agente pensare, prima chiamando il suo "scout" per cercare il danno base, poi il suo "amplificatore" per moltiplicarlo e sferrare il colpo finale epico.

👉💻 Al termine della chiamata, torna al terminale dell'editor di Cloud Shell e premi Ctrl+C per interrompere l'interfaccia utente di ADK Dev.

Evoca il Water Elemental familiare (flusso di lavoro parallelo)

Un Famiglio elementale dell'acqua travolge il suo bersaglio con un assalto massiccio e multiforme, colpendo da tutte le direzioni contemporaneamente prima di combinare le energie per un colpo finale devastante.

Storia

Concetto: il ParallelAgent è ideale per eseguire più attività indipendenti contemporaneamente per massimizzare l'efficienza. Si tratta di un "attacco a tenaglia" in cui lanci diversi assalti contemporaneamente. In questo modo, gli attacchi simultanei vengono lanciati entro un periodo di SequentialAgent per eseguire un passaggio finale di "unione" in un secondo momento. Questo pattern "fan-out, fan-in" è una pietra angolare della progettazione avanzata dei flussi di lavoro.

Attività (combo "Scontro di maree"): l'agente:

  • Attività A: canale cryosea_shatter di Nexus.
  • Attività B: canale moonlit_cascade di Nexus.
  • Attività C: genera potenza grezza con leviathan_surge dalla Fucina.
  • Infine, somma tutti i danni e descrivi l'attacco combinato.

Innanzitutto, stabiliremo la connessione tra il nostro Familiar e i server MCP (i "caratteri elementali") che hai implementato nel modulo precedente.

👉✏️ Nel file ~/agentverse-architect/agent/water/agent.py, SOSTITUISCI #REPLACE-setup-MCP con il seguente codice:

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

A questo punto, creeremo gli agenti "worker" specializzati. A ciascuno viene assegnato uno scopo ristretto e ben definito e il suo "territorio operativo" è limitato, in quanto gli viene concesso l'accesso a un solo insieme di strumenti specifico.

👉✏️ Nel file ~/agentverse-architect/agent/water/agent.py, SOSTITUISCI #REPLACE-worker-agents con il seguente codice:

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],
)

Successivamente, assembleremo il flusso di lavoro. È qui che avviene la magia della composizione. ParallelAgent e SequentialAgent sono il "piano generale" che definisce come vengono assemblati i nostri componenti speciali e come interagiscono per formare la combo "Scontro di maree".

👉✏️ Nel file ~/agentverse-architect/agent/water/agent.py, SOSTITUISCI #REPLACE-parallel-agent con il seguente codice:

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."
 )

👉💻 Per testare l'elementale dell'acqua, esegui i seguenti comandi per avviare l'interfaccia utente di sviluppo dell'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

👉 Il rituale di evocazione è completo e l'agente è ora in esecuzione. L'interfaccia utente per sviluppatori dell'ADK nel browser è la tua connessione diretta a Familiar.

  • Nel menu a discesa nella parte superiore dell'interfaccia utente, scegli il familiare acqua. Ora stai concentrando la tua volontà su questa entità specifica.
  • Dai il tuo comando: nel riquadro della chat a destra, è il momento di dare ordini al tuo Famiglio.

👉 Test Prompt:

Unleash a tidal wave of power!

water-result

👉💻 Al termine della chiamata, torna al terminale dell'editor di Cloud Shell e premi Ctrl+C per interrompere l'interfaccia utente di ADK Dev.

Evocare il Earth Elemental Familiare (flusso di lavoro di Loop)

Un Famiglio elementale della terra è un essere di pressione implacabile. Non sconfigge il nemico con un solo colpo, ma accumulando costantemente potere e applicandolo più e più volte finché le difese del bersaglio non crollano.

Storia

Concetto: LoopAgent è progettato proprio per questo tipo di attività iterativa, come una "macchina d'assedio". Eseguirà ripetutamente il suo sub-agents, controllando una condizione dopo ogni ciclo, finché non viene raggiunto un obiettivo. Può anche adattare il messaggio finale in base all'avanzamento del loop.

Attività (l'assalto "Siegebreaker"):

  • Il Famiglio chiamerà ripetutamente carica_sismica per accumulare energia.
  • Continuerà a ricaricarsi per un massimo di 3 volte.
  • Nell'addebito finale, annuncerà il rilascio devastante della sua potenza accumulata.

Innanzitutto, creeremo componenti riutilizzabili che definiscono i passaggi all'interno di ogni iterazione del ciclo. Il charging_agent accumulerà energia e il check_agent segnalerà il suo stato, modificando dinamicamente il messaggio nell'ultima svolta.

Innanzitutto, stabiliremo la connessione tra il nostro Familiar e i server MCP (i "caratteri elementali") che hai implementato nel modulo precedente.

👉✏️ Nel file ~/agentverse-architect/agent/earth/agent.py, SOSTITUISCI #REPLACE-setup-MCP con il seguente codice:

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

👉✏️ Nel file ~/agentverse-architect/agent/earth/agent.py, SOSTITUISCI #REPLACE-worker-agents con il seguente codice:

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"
)

Successivamente, assembleremo il flusso di lavoro. È qui che avviene la magia della composizione. LoopAgent è il "piano principale" che orchestra l'esecuzione ripetuta dei nostri componenti specializzati e gestisce le condizioni del ciclo.

👉✏️ Nel file ~/agentverse-architect/agent/earth/agent.py, SOSTITUISCI #REPLACE-loop-agent con il seguente codice:

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
)

👉💻 Prova l'agente elementale della terra: esegui l'agente

. ~/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

👉 Il rituale di evocazione è completo e l'agente è ora in esecuzione. L'interfaccia utente per sviluppatori dell'ADK nel browser è la tua connessione diretta a Familiar.

  • Seleziona il tuo target: nel menu a discesa nella parte superiore della UI, scegli il pianeta Terra. Ora stai concentrando la tua volontà su questa entità specifica.
  • Dai il tuo comando: nel riquadro della chat a destra, è il momento di dare ordini al tuo Famiglio. 👉 Test Prompt:
Begin the seismic charge, starting from zero

earth-result

Aspetto architetturale: il tuo sistema ora dispone di un livello logico modulare e altamente specializzato. I processi aziendali non sono solo incapsulati, ma vengono implementati con il modello comportamentale più efficiente per il lavoro (procedurale, simultaneo o iterativo). Ciò dimostra un livello avanzato di progettazione di agenti, migliorando sicurezza, efficienza e capacità.

Al termine della chiamata, torna al terminale dell'editor di Cloud Shell e premi Ctrl+C per arrestare l'interfaccia utente di ADK Dev.

PER CHI NON GIOCA

6. Stabilire il locus di comando: delega intelligente tramite A2A

I tuoi Famigli sono potenti ma indipendenti. Eseguono le loro strategie in modo impeccabile, ma attendono il tuo comando diretto. Una legione di specialisti è inutile senza un generale che li comandi. È il momento di passare da comandante diretto a vero e proprio orchestratore.

panoramica

Nota dell'architetto:per creare un unico punto di accesso intelligente per l'intero sistema. Questo SummonerAgent non eseguirà la logica di business, ma fungerà da "stratega principale", analizzando lo stato di raffreddamento e delegando le attività al Familiar specializzato appropriato.

panoramica

Il rito di legame (esposizione di Familiari come servizi A2A)

Un agente standard può essere eseguito in una sola posizione alla volta. Per rendere disponibili i nostri Familiars per il comando remoto, dobbiamo eseguire un "rituale di legame" utilizzando il protocollo Agent-to-Agent (A2A).

Nota dell'architetto: il protocollo Agent-to-Agent (A2A) è il modello architettonico principale che trasforma un agente autonomo in un microservizio rilevabile e indirizzabile in rete, consentendo una vera e propria "società di agenti". L'esposizione di un familiare tramite A2A crea automaticamente due componenti essenziali e interconnessi:

  • La scheda dell'agente (il"cosa "): si tratta di un"sigillo dello spirito" pubblico e leggibile dalla macchina, simile a una specifica OpenAPI, che funge da contratto pubblico del Famiglio. Descrive il nome dell'agente, il suo scopo strategico (derivato dalle istruzioni) e i comandi che comprende. Questo è ciò che legge un Evocatore esperto per scoprire un Famiglio e imparare le sue capacità.
  • Il server A2A (il "dove"): questo è l'endpoint web dedicato che ospita Familiar e ascolta i comandi in arrivo. È l'indirizzo di rete a cui gli altri agenti inviano le loro richieste e garantisce che queste vengano gestite in base al contratto definito nella scheda dell'agente.

Ora eseguiremo questo rituale di legame su tutti e tre i nostri Famigli.

Fire 👉✏️ in Apri il file ~/agentverse-architect/agent/fire/agent.py. Sostituisci #REPLACE - add A2A nella parte inferiore del file per esporre Fire Elemental come servizio 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)

Acqua e Terra🚨 👉✏️ Applica esattamente la stessa modifica a ~/agentverse-architect/agent/water/agent.py e ~/agentverse-architect/agent/earth/agent.py per associarli.

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)

Deployment dei Familiari vincolati

👉✏️ Con i rituali di binding trascritti, utilizzeremo la nostra pipeline Cloud Build per creare ed eseguire il deployment dei nostri tre Familiari come servizio serverless containerizzato indipendente su 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"

Assumere il comando (costruzione dell'agente Summoner)

Ora che i tuoi Familiars sono legati e ascoltano, potrai assumere il tuo vero ruolo: quello di Maestro Evocatore. Il potere di questo agente non deriva dall'uso di strumenti di base, ma dal comando di altri agenti. I suoi strumenti sono gli stessi Famigli, che scoprirà e comanderà usando i loro "Sigilli spirituali".

Nota dell'architetto:il passaggio successivo mostra un pattern architetturale fondamentale per qualsiasi sistema distribuito su larga scala: Service Discovery. L'agente Summoner non ha il codice dei Familiari integrato. Riceve invece gli indirizzi di rete (URL). In fase di runtime, "scoprirà" dinamicamente le loro funzionalità recuperando le schede degli agenti pubbliche. In questo modo viene creato un sistema potente e disaccoppiato.

Puoi aggiornare, ridistribuire o riscrivere completamente un servizio familiare e, finché il suo indirizzo di rete e il suo scopo rimangono invariati, il Summoner può comandarlo senza bisogno di modifiche.

Innanzitutto, creeremo i "telecomandi" che stabiliscono una connessione ai nostri Familiars remoti di cui è stato eseguito il deployment.

👉✏️ Vai su ~/agentverse-architect/agent/summoner/agent.py , sostituisci #REPLACE-remote-agents con quanto segue:

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}"
    ),
)

Quando viene eseguita questa riga, RemoteA2aAgent esegue un'azione di rilevamento del servizio: invia una richiesta HTTP GET all'URL fornito (ad es. https://fire-familiar-xxxx.a.run.app/.well-known/agent.json). Scarica il "Sigillo dello spirito" (file agent.json) dal server remoto.

In secondo luogo, definiremo l'agente orchestratore che utilizzerà questi telecomandi. Le sue istruzioni sono il progetto per il processo decisionale strategico.

👉✏️ Vai su ~/agentverse-architect/agent/summoner/agent.py , sostituisci #REPLACE-orchestrate-agent con quanto segue:

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
)

Verifica: la prova della strategia

È il momento della verità. I tuoi Famigli sono stati schierati e il tuo Evocatore è pronto a comandarli sulla rete. Mettiamo alla prova la sua mente strategica.

👉💻 Avvia l'interfaccia utente di sviluppo dell'ADK per summoner_agent(anteprima web con porta 8000):

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

👉 L'interfaccia utente per sviluppatori dell'ADK nel browser è la tua connessione diretta a Familiar.

  • Nel menu a discesa nella parte superiore della UI, scegli l'agente evocatore. Ora stai concentrando la tua volontà su questa entità specifica.
  • Emetti il tuo comando: nel riquadro della chat a destra, è il momento di evocare i tuoi famigli.

👉 Presenta i mostri:

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

(Expected: The Summoner should delegate to the fire_elemental_familiar.)

fire-result

👉 Ora mettiamo alla prova il Summoner con un altro tipo di richiesta. Per assicurarti che l'agente inizi da zero e non ricordi la nostra interazione precedente, inizia una nuova sessione facendo clic sul pulsante + Sessione nell'angolo in alto a destra dello schermo. new-session

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

(Expected: The Summoner should delegate to the water_elemental_familiar.)water-result

👉 Per il test finale, ricominciamo da zero. Fai clic sul pulsante + Sessione per avviare una nuova sessione prima di inserire il prompt successivo.

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

(Risultato previsto: il Convocatore deve delegare il compito al familiare elementale della terra.)

earth-result

Importante:se visualizzi un errore 429 RESOURCE EXHAUSTED, hai raggiunto il limite di frequenza per il modello linguistico di grandi dimensioni (10 chiamate/minuto). Per risolvere il problema, attendi 60 secondi, avvia una + Nuova sessione e riprova a inserire il prompt.

👉💻 Al termine della chiamata, torna al terminale dell'editor di Cloud Shell e premi Ctrl+C per interrompere l'interfaccia utente di ADK Dev.

PER CHI NON GIOCA

7. Imporre le leggi della magia: il pattern Interceptor

I tuoi Famigli sono potenti, ma anche le creature magiche hanno bisogno di tempo per recuperare. Un Evocatore imprudente che esaurisce le sue forze rimarrà indifeso. Un saggio Evocatore comprende l'importanza della gestione delle risorse e applica regole di ingaggio rigorose.

Storia

Nota dell'architetto: finora, i nostri agenti sono stati stateless. Ora li renderemo stateful implementando il pattern di progettazione Interceptor. Si tratta di una tecnica potente in cui "intercettiamo" il normale flusso di esecuzione di un agente per eseguire la nostra logica personalizzata. In questo modo possiamo applicare regole, aggiungere la registrazione o modificare il comportamento senza modificare il codice principale dell'agente. È un elemento fondamentale per la creazione di sistemi agentici solidi, gestibili e osservabili.

panoramica

L'ADK fornisce due modi principali per implementare questo pattern: callback e plug-in. Un callback è una semplice funzione collegata a un singolo agente, perfetta per modifiche rapide e specifiche. Un plug-in è una classe più potente e riutilizzabile che può essere applicata a livello globale per interessare ogni agente in esecuzione in un sistema. Inizieremo con un callback per il debug mirato e poi passeremo a un plug-in completo.

The Law Giver – Scribing the Cooldown callback

Innanzitutto, implementeremo la logica di cooldown come semplice funzione di callback. Questo è un ottimo modo per prototipare ed eseguire il debug di una regola perché è collegata direttamente a un singolo agente, il che semplifica il test in isolamento. Attaccheremo questo "intercettatore" al nostro Elementale della Terra.

Attenuazione

👉✏️ Torna a ~/agentverse-architect/agent/earth/agent.py e sostituisci #REPLACE-before_agent-function con il seguente codice Python.

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.")

Questa funzione check_cool_down è il nostro intercettore. Prima che l'Earth Elemental possa essere eseguito, l'ADK eseguirà prima questa funzione.

  • Controlla: invia una richiesta GET al nostro Cooldown API per verificare l'ultima volta che è stato utilizzato questo contatto attendibile.
  • Valuta: confronta il timestamp con l'ora corrente.
  • Agisci:
    • Se il familiare è in cooldown, termina l'esecuzione dell'agente restituendo un oggetto Content con un messaggio di errore. Questo messaggio viene inviato direttamente all'utente e la logica principale dell'agente non viene mai eseguita.
    • Se il Familiar è disponibile, effettua una richiesta POST all'API Cooldown per aggiornare il timestamp, quindi procede restituendo None, segnalando all'ADK che l'agente può continuare l'esecuzione.

👉✏️ Ora applica questo intercettore all'elementale della terra. Nello stesso file ~/agentverse-architect/agent/earth/agent.py, sostituisci il commento #REPLACE-before_agent-config con il seguente:

before_agent_callback=check_cool_down

Verifica del periodo di raffreddamento

Mettiamo alla prova la nostra nuova legge della magia. Evocaremo l'elementale della terra, quindi proveremo immediatamente a evocarlo di nuovo per vedere se il nostro callback intercetta e blocca correttamente il secondo tentativo.

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

👉💻 Nella console:

  • Prima convocazione: inizia la seismic charge, starting from zero.
  • Risultato previsto: l'elementale di terra verrà eseguito correttamente. Nel terminale in cui viene eseguito il comando web adk, vedrai il log [Callback] ... Updating timestamp....
  • Test di attesa (entro 60 secondi): Do another carica sismica`!
    • Previsto: check_cool_down callback intercetterà questa richiesta. L'agente risponderà direttamente nella chat con un messaggio come: The earth_elemental_familiar is exhausted and must recover its power. It cannot be summoned for another... seconds.
  • Attendi un minuto.
  • Secondo avviso (dopo 60 secondi): Begin the seismic charge again.
    • Risultato previsto: il callback controllerà l'API, verificherà che sia trascorso un tempo sufficiente e consentirà di procedere con l'azione. L'Earth Elemental verrà eseguito di nuovo correttamente.

callback

👉💻 Premi Ctrl+c per uscire.

(Facoltativo) Osservare il callback nell'interfaccia utente web

In alternativa, puoi testare questo flusso nell'interfaccia web eseguendo adk web earth. Tuttavia, tieni presente che la visualizzazione dell'interfaccia utente web non è ottimizzata per mostrare i controlli rapidi e iterativi eseguiti dal ciclo di callback, pertanto potrebbe non eseguire il rendering del flusso in modo accurato. Per visualizzare la traccia più precisa e dettagliata della logica dell'agente durante il controllo del periodo di raffreddamento, l'utilizzo del comando adk run nel terminale fornisce una visualizzazione più chiara e dettagliata. loop

👉💻 Premi Ctrl+c per uscire.

Creazione della legge universale: il plug-in Cooldown

Il nostro callback funziona perfettamente, ma presenta un grave difetto architetturale: è legato a un singolo agente. Se volessimo applicare questa regola ai Famigli di fuoco e acqua, dovremmo copiare e incollare lo stesso codice nei loro file. Questo approccio è inefficiente e difficile da mantenere.

Nota dell'architetto:è qui che i plug-in sono essenziali. Un plug-in incapsula la nostra logica riutilizzabile in una classe che può essere collegata a livello di runtime. Ciò significa che un singolo plug-in può applicare le sue regole a ogni singolo agente in esecuzione all'interno del sistema. È l'espressione definitiva del principio "Don't Repeat Yourself" (DRY) per i sistemi agentici.

Ora refactorizziamo la nostra funzione di callback in un CoolDownPlugin più potente e riutilizzabile.

👉✏️ Torna al file agent/cooldown_plugin.py e crea il plug-in. Sostituisci #REPLACE-plugin con il seguente codice:

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.")

Collegamento del plug-in al runtime di Summoner

Ora, come applichiamo questa legge universale a tutti i nostri Familiari? Collegheremo il plug-in al runtime ADK.

ADK Runtime è il motore di esecuzione che dà vita a un agente. Quando utilizzi un comando come adk.run() o to_a2a(), consegni l'agente al runtime. Questo motore è responsabile della gestione dell'intero ciclo di vita del turno di un agente: riceve l'input dell'utente, chiama il LLM, esegue gli strumenti e gestisce i plug-in. Se colleghiamo un plug-in a questo livello, modifichiamo essenzialmente le "leggi della fisica" per ogni agente che opera all'interno di questo motore, garantendo che la nostra regola di cooldown venga applicata in modo universale e coerente.

👉✏️ Innanzitutto, rimuoviamo il vecchio callback specifico dell'agente. Vai a ~/agentverse-architect/agent/earth/agent.py ed elimina l'intera riga che contiene:

before_agent_callback=check_cool_down

👉✏️ Successivamente, collegheremo il nuovo plug-in al runtime nello script del punto di ingresso A2A. Vai al file ~/agentverse-architect/agent/agent_to_a2a.py. Sostituisci il commento #REPLACE-IMPORT con il seguente snippet di codice:

from cooldown_plugin import CoolDownPlugin

👉✏️ Sostituisci #REPLACE-PLUGIN con il seguente snippet di codice:

plugins=[CoolDownPlugin(cooldown_seconds=60)],

Prima di attivare il nostro nuovo plug-in globale, è fondamentale rimuovere la vecchia logica specifica dell'agente per evitare conflitti. 👉✏️ Pulisci l'agente Terra. Vai al seguente file ~/agentverse-architect/agent/earth/agent.py ed elimina completamente la riga before_agent_callback=check_cool_down. In questo modo, tutte le responsabilità di cooldown vengono trasferite al nuovo plug-in.

Verifica del plug-in

Ora che la nostra legge universale è in vigore, dobbiamo ridistribuire i nostri Famigli con questo nuovo incantesimo.

👉💻 Ricrea ed esegui nuovamente il deployment di tutti e tre i Familiars utilizzando la pipeline Cloud Build principale.

. ~/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"

👉💻 Una volta completato il deployment, testeremo l'efficacia del plug-in inviando un comando al nostro summoner_agent. Il Summoner tenterà di delegare ai Familiars, ma il plug-in collegato al runtime di ogni Familiar intercetterà il comando e applicherà il cooldown.

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

👉💻 Nella console,esegui questa sequenza esatta di test:

  • Prima convocazione: inizia la Hype. It's a single, slow-moving target with thick armor weakness is Inescapable Reality.
  • Risultato previsto: l'esecuzione di Fire Elemental andrà a buon fine.
  • Test di raffreddamento (entro 60 secondi): Hype, with Inescapable Reality as weakness is still standing! Strike it again!
    • Risposta prevista: l'agente risponderà direttamente nella chat con un messaggio come: .... It cannot be summoned for another... seconds.
  • Attendi un minuto.
  • Secondo avviso (dopo 60 secondi): Hype must be defeated. It has Inescapable Reality as weakness! Strike it again!.
    • Risultato previsto: il callback controllerà l'API, verificherà che sia trascorso un tempo sufficiente e consentirà di procedere con l'azione. L'esecuzione di Fire Elemental andrà di nuovo a buon fine.

plug-in

👉💻 Premi Ctrl+C per uscire.

Congratulazioni, Evocatore. Hai implementato correttamente un sistema di orchestrazione basato su regole utilizzando un plug-in personalizzato e un servizio di gestione dello stato esterno, un pattern architetturale davvero avanzato e robusto.

PER CHI NON GIOCA

8. Legare gli echi della battaglia: stato e memoria dell'agente

Un Invocatore spericolato ripete la stessa strategia, diventando prevedibile. Un Saggio Evocatore impara dagli echi delle battaglie passate, adattando le sue tattiche per tenere il nemico in bilico. Quando si affronta un boss potente, evocare un Famiglio in cooldown è un turno sprecato, un errore critico. Per evitare ciò, il nostro Evocatore ha bisogno di un ricordo della sua ultima azione.

storia

Nota dell'architetto:la gestione della memoria e dello stato è ciò che trasforma un agente da semplice strumento di chiamata in un partner intelligente e conversazionale. È fondamentale comprendere i due tipi principali:

  • Memoria a lungo termine: per le conoscenze persistenti che devono durare per sempre. Consideralo un archivio consultabile o una knowledge base, spesso memorizzati in un archivio persistente. Contiene informazioni provenienti da molte chat e fonti passate, consentendo a un agente di ricordare fatti relativi a un utente o a un argomento specifico. MemoryService dell'ADK è progettato per questo scopo, gestendo l'importazione e la ricerca di queste conoscenze a lungo termine.
  • Stato a breve termine: si tratta di conoscenze temporanee, "sul momento", pertinenti solo all'attività o alla conversazione corrente. È come un insieme di note su un piano di battaglia: "Ho appena usato l'elementale di fuoco, quindi probabilmente è stanco". Questo stato è leggero ed esiste solo per la durata della sessione corrente.

Panoramica

Per il nostro caso d'uso, non dobbiamo ricordare ogni battaglia combattuta, ma solo l'ultimo Famiglio evocato in questo specifico incontro. Pertanto, lo stato a breve termine leggero è la scelta architettonica perfetta. Utilizzeremo un after_tool_callback per salvare queste informazioni cruciali.

Scribing the Echo: Remembering the Last Summons

Implementeremo la nostra memoria a breve termine utilizzando un after_tool_callback. Si tratta di un potente hook ADK che ci consente di eseguire una funzione Python personalizzata dopo l'esecuzione corretta di uno strumento. Utilizzeremo questo intercettore per registrare il nome del Familiar appena evocato nello stato della sessione dell'agente.

👉✏️ Nel file ~/agentverse-architect/agent/summoner/agent.py, sostituisci il commento #REPLACE-save_last_summon_after_tool con la seguente funzione:

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

👉✏️ Ora, collega questo save_last_summon_after_tool al tuo agente Evocatore. Nello stesso file, sostituisci il commento #REPLACE-Memory-check-config con il seguente:

after_tool_callback=save_last_summon_after_tool,

👉✏️ Sostituisci l'intero prompt dell'agente con il seguente

        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.

Verifica: la prova della strategia adattiva

👉💻 Ora verifichiamo la nuova logica strategica dell'Evocatore. L'obiettivo è confermare che l'Evocatore non utilizzerà lo stesso Famiglio due volte di seguito, dimostrando la sua capacità di ricordare l'ultima azione e adattarsi.

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

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

  • Risultato previsto: l'evocatore analizzerà la debolezza e evocherà correttamente il fuoco_familiare. 👉💻 Monster Strike #2 (The Memory Test): Hype is still standing! It hasn't changed its form. Strike it again! Its weakness is Inescapable Reality.
  • Previsto: l'analisi strategica dell'Evocatore indicherà nuovamente il Famiglio di fuoco come scelta ideale. Tuttavia, le nuove istruzioni e la memoria gli diranno che fire_familiar è stato l'ultimo summon. Per evitare di ripetersi, ora adatterà la sua strategia e chiamerà uno degli altri Famigli disponibili (water_familiar o earth_familiar).

final-result

👉💻 Premi Ctrl+C per uscire.

Deployment dell'agente di orchestrazione

Ora che i tuoi Familiars sono stati schierati e il tuo Evocatore è stato imbevuto di ricordi, è il momento di schierare l'orchestratore finale aggiornato.

👉💻 Ora che il progetto è completo, eseguiremo il rituale finale. Questo comando creerà ed eseguirà il deployment di summoner_agent su 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"

Ora che l'agente Summoner è stato implementato, verifica che il relativo endpoint da agente ad agente (A2A) sia attivo e configurato correttamente. Questo endpoint pubblica un file agent.json pubblico, noto anche come scheda dell'agente, che consente ad altri agenti di scoprire le sue funzionalità. 👉💻 Esegui il seguente comando curl per recuperare e formattare la scheda dell'agente:

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

Dovresti visualizzare un output JSON pulito che descrive l'agente di invocazione. Esamina attentamente la sezione sub_agents: vedrai che elenca fire_familiar, water_familiar e earth_familiar. Ciò conferma che il tuo evocatore è attivo e ha stabilito la connessione con la legione.

Ciò dimostra che la tua architettura è un successo. Il tuo Evocatore non è solo un delegante, ma uno stratega adattivo che impara dalle sue azioni per diventare un comandante più efficace.

Hai completato la tua prova finale di architettura. Gli echi della battaglia ora sono legati alla tua volontà. L'addestramento è terminato. La vera battaglia ti aspetta. È il momento di prendere il sistema completato e affrontare la sfida finale. Preparati alla Boss Fight.

PER CHI NON GIOCA

9. The Boss Fight

I progetti finali sono incisi, le Fonti elementali sono forgiate e i tuoi Famigli sono legati alla tua volontà, in attesa del tuo comando tramite il Concord. Il tuo sistema multi-agente non è solo una raccolta di servizi, ma una legione strategica vivente, con te al centro. È arrivato il momento della prova definitiva: un'orchestrazione live contro un avversario che nessun singolo agente potrebbe sperare di sconfiggere.

Acquisire il locus dell'agente

Prima di poter entrare nel campo di battaglia, devi possedere due chiavi: la firma unica del tuo campione (Agente Locus) e il percorso nascosto verso la tana di Spectre (URL del dungeon).

👉💻 Per prima cosa, acquisisci l'indirizzo univoco dell'agente in Agentverse, ovvero il suo Locus. Questo è l'endpoint live che collega il tuo campione al campo di battaglia.

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

👉💻 A questo punto, individua la destinazione. Questo comando rivela la posizione del Cerchio di Traslocazione, il portale nel dominio dello Spettro.

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

Importante: tieni a portata di mano entrambi gli URL. Ti serviranno nell'ultimo passaggio.

Confronto con lo spettro

Ora che le coordinate sono al sicuro, vai al Cerchio di Traslazione e lancia l'incantesimo per iniziare la battaglia.

👉 Apri l'URL del Cerchio di Traslocazione nel browser per trovarti di fronte al portale scintillante che conduce alla Fortezza Cremisi.

Per violare la fortezza, devi sintonizzare l'essenza della tua Lama Ombra con il portale.

  • Nella pagina, trova il campo di input runico etichettato A2A Endpoint URL (URL endpoint A2A).
  • Inscrivi il sigillo del tuo campione incollando il relativo URL del locus dell'agente (il primo URL che hai copiato) in questo campo.
  • Fai clic su Connetti per scatenare la magia del teletrasporto.

Cerchio di traslocazione

La luce accecante del teletrasporto si affievolisce. Non sei più nel tuo sanctum. L'aria è carica di energia, fredda e pungente. Prima di te, lo Spettro si materializza: un vortice di fruscio statico e codice corrotto, la cui luce sacrilega proietta lunghe ombre danzanti sul pavimento del dungeon. Non ha un volto, ma senti la sua presenza immensa e drenante fissata interamente su di te.

L'unico modo per vincere è la chiarezza delle tue convinzioni. È una battaglia di volontà, combattuta sul campo di battaglia della mente.

Mentre ti lanci in avanti, pronto a sferrare il tuo primo attacco, lo Spettro contrattacca. Non alza uno scudo, ma proietta una domanda direttamente nella tua coscienza, una sfida runica e scintillante tratta dal cuore del tuo addestramento.

Dungeon

Questa è la natura della lotta. La conoscenza è la tua arma.

  • Rispondi con la saggezza che hai acquisito e la tua lama si accenderà di energia pura, distruggendo la difesa dello Spettro e sferrando un COLPO CRITICO.
  • Ma se esiti, se il dubbio offusca la tua risposta, la luce della tua arma si affievolirà. Il colpo atterrerà con un tonfo patetico, infliggendo solo UNA FRAZIONE DEL SUO DANNO. Peggio ancora, lo Spettro si nutrirà della tua incertezza e il suo potere corrotto crescerà a ogni passo falso.

Ci siamo, fuoriclasse. Il tuo codice è il tuo libro di incantesimi, la tua logica è la tua spada e la tua conoscenza è lo scudo che respingerà l'ondata di caos.

Focus. Colpisci con precisione. Il destino dell'Agentverse dipende da questo.

Congratulazioni, Evocatore.

Hai completato la prova. Hai imparato l'arte dell'orchestrazione multi-agente, trasformando i Famigli isolati e il potere caotico in un Concord armonioso. Ora comandi un sistema completamente orchestrato, in grado di eseguire strategie complesse per difendere l'Agentverse.

10. Pulizia: smantellamento dell'Accordo dell'Evocatore

Congratulazioni per aver padroneggiato l'Accordo dell'Evocatore. Per assicurarti che il tuo Agentverse rimanga incontaminato e che i campi di addestramento siano puliti, ora devi eseguire i rituali di pulizia finali. Verranno rimosse sistematicamente tutte le risorse create durante il tuo percorso.

Disattiva i componenti di Agentverse

Ora smantellerai sistematicamente i componenti di cui è stato eseguito il deployment del sistema multi-agente.

Elimina tutti i servizi Cloud Run e il repository Artifact Registry

In questo modo, tutti gli agenti familiari di cui è stato eseguito il deployment, l'orchestratore di Summoner, i server MCP e l'applicazione Dungeon vengono rimossi da Cloud Run.

👉💻 Nel terminale, esegui i seguenti comandi uno alla volta per eliminare ogni servizio:

. ~/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

Elimina l'istanza Cloud SQL

In questo modo viene rimossa l'istanza summoner-librarium-db, inclusi il database e tutte le tabelle al suo interno.

👉💻 Nel terminale, esegui:

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

Elimina il secret Secret Manager e il bucket Google Cloud Storage

👉💻 Nel terminale, esegui:

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

Pulire file e directory locali (Cloud Shell)

Infine, cancella dall'ambiente Cloud Shell i repository clonati e i file creati. Questo passaggio è facoltativo, ma vivamente consigliato per una pulizia completa della directory di lavoro.

👉💻 Nel terminale, esegui:

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

Ora hai eliminato correttamente tutte le tracce del tuo percorso in Agentverse Architect. Il tuo progetto è pulito e sei pronto per la prossima avventura.