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

1. Overture

L'era dello sviluppo isolato sta per finire. La prossima ondata di evoluzione tecnologica non si baserà sul genio solitario, ma sulla 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, un architetto, un data engineer e 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 del Data Engineer 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 dilagante estensione digitale dell'impresa è iniziata una nuova era. È l'era degli agenti, un'epoca di immense promesse, in cui agenti intelligenti e autonomi lavorano in perfetta armonia per accelerare l'innovazione e spazzare via ciò che è banale.

agentverse.png

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

Ma una lenta entropia, una corruzione silenziosa nota come Static, ha iniziato a sfilacciare i bordi di questo nuovo mondo. 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 controllato, Static e i suoi spettri bloccherà i progressi, trasformando la promessa dell'Agentverse in una terra desolata di debito tecnico e progetti abbandonati.

Oggi lanciamo un appello ai campioni affinché respingano l'ondata di caos. Abbiamo bisogno di eroi disposti a padroneggiare la loro arte e a collaborare per proteggere l'Agentverse. È giunto il momento di scegliere la tua strada.

Scegli il corso

Quattro percorsi distinti si aprono davanti a te, ognuno dei quali è un pilastro fondamentale nella lotta contro 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.

  • La Lama d'Ombra (sviluppatore): un maestro della forgia e della prima linea. 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 progetti principali che consentono a interi sistemi di agenti di comunicare, collaborare e raggiungere un obiettivo molto più grande di quello di un 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 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 Static, un mini boss che si nutre delle sfide specifiche della tua professione.

Solo se padroneggerai il tuo ruolo individuale potrai 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 e 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

Ti diamo il benvenuto, Evocatore. Il tuo percorso è fatto di visione e strategia generale. Mentre gli altri si concentrano su una singola lama o 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 Familiari, di lavorare in perfetta armonia. Questa missione metterà alla prova la tua capacità di progettare, connettere e orchestrare un potente sistema multi-agente.

panoramica

Obiettivi didattici

  • Progetta un ecosistema di strumenti disaccoppiati: progetta e distribuisci un set di server di strumenti MCP indipendenti basati su microservizi. Imparerai perché questo livello fondamentale è fondamentale per creare sistemi agenti scalabili, manutenibili e sicuri.
  • Padroneggia flussi di lavoro agentici avanzati: vai oltre i singoli agenti e crea una schiera di "Familiari" specializzati. Imparerai a padroneggiare i principali modelli di flusso di lavoro ADK (sequenziale, parallelo e ciclico) e apprenderai i principi architettonici per scegliere il modello giusto per ogni attività.
  • Implementare un orchestratore intelligente: passare da un semplice generatore di agenti a un vero e proprio architetto di sistemi. Costruirai un agente di orchestrazione master che utilizza il protocollo Agent-to-Agent (A2A) per scoprire e delegare attività complesse ai tuoi Familiar specializzati, creando un vero e proprio sistema multi-agente.
  • Applica le regole con il codice, non con i prompt: impara a creare agenti più affidabili e prevedibili applicando regole di interazione con stato. Implementerai una logica personalizzata utilizzando il potente sistema di plugin e callback dell'ADK per gestire vincoli reali come i timer di raffreddamento.
  • Gestisci lo stato e la memoria degli agenti: 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 consapevoli del 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

Ti diamo il benvenuto, Evocatore. Prima che possa essere evocato un solo Famiglio, prima che possano essere stretti patti, il terreno stesso su cui ti trovi deve essere preparato. 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: incidere 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" (sembra una cartella aperta con una matita). Verrà aperto l'editor di codice di Cloud Shell nella finestra. Vedrai un file explorer sul lato sinistro. testo alternativo

👉Apri il terminale nell'IDE cloud, testo alternativo

👉💻 Nel terminale, verifica di essere già autenticato 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 configurazione dalla directory del progetto.

⚠️ Nota sull'ID progetto: lo script suggerirà un ID progetto predefinito generato in modo casuale. Puoi premere Invio per accettare questo valore predefinito.

Tuttavia, se preferisci creare un nuovo progetto specifico, puoi digitare l'ID progetto desiderato quando richiesto dallo script.

cd ~/agentverse-architect
./init.sh

Lo script gestirà automaticamente il resto della procedura di configurazione.

👉 Passaggio importante dopo il completamento: una volta completato lo script, devi assicurarti che Google Cloud Console stia visualizzando il progetto corretto:

  1. Vai su console.cloud.google.com.
  2. Fare clic sul menu a discesa del selettore di progetto nella parte superiore della pagina.
  3. Fai clic sulla scheda "Tutti" (poiché il nuovo progetto potrebbe non essere ancora visualizzato in "Recenti").
  4. Seleziona l'ID progetto appena configurato nel passaggio init.sh.

03-05-project-all.png

👉💻 Imposta l'ID progetto necessario:

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

👉💻 Esegui il seguente comando 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: (Salta questo passaggio se hai altre classi distribuite nello stesso progetto)

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

Configura l'autorizzazione

👉💻 Concedi le autorizzazioni necessarie eseguendo i seguenti 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"

👉💻 All'inizio dell'allenamento, prepareremo la sfida finale. I seguenti comandi evocheranno gli Spettri dal caos statico, creando i boss per la prova 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 siglati. 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. Forgiare i caratteri elementari: l'ecosistema degli utensili disaccoppiati

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. Ciò offre il massimo controllo e flessibilità, consentendoci di incapsulare operazioni complesse dietro 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 con grande efficacia. Il Nexus of Whispers è la nostra porta d'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. Ciò ti offre molto più controllo e flessibilità, essenziali quando i tuoi strumenti devono fare più che eseguire una semplice query SQL, come chiamare altre API. Per un architetto di agenti è fondamentale comprendere entrambi i modelli.

👉✏️ 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}"

Il cuore dello script sono le semplici funzioni Python. È qui che avviene il vero lavoro.

👉✏️ 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 puoi 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.

Lo implementeremo più tardi.

Accensione della Forgia Arcana (Server MCP Funzioni Generali)

Non tutto il potere proviene da libri antichi o da sussurri lontani. A volte, un Evocatore deve forgiare la propria magia partendo dalla pura volontà e dalla pura 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. La creazione di 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 Google Cloud IDE. Scoprirai che utilizza lo stesso approccio imperativo mcp.server del Nexus per creare questa Fonte di Potere personalizzata.

Creare la pipeline di compilazione del cloud master

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 i seguenti 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 tutte le distribuzioni.

👉 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 font sarà la Biblioteca 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 complesso lavoro 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 effettuata la connessione, apri una nuova scheda dell'editor di query, se non ne hai già aperta una. Per visualizzare i dati sui danni elementari inscritti, incollare ed eseguire 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 ToolBox MCP

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

fonti: questa sezione definisce le connessioni ai tuoi dati.

  • summoner-librarium:: Questo è il nome logico che abbiamo dato 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, ecc.: Queste sono le coordinate esatte dell'istanza Cloud SQL creata durante lo script prepare.sh, che indicano alla Toolbox dove trovare il nostro Librarium.

👉✏️ Vai su ~/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"

👉✏️ 🚨🚨SOSTITUISCI

YOUR_PROJECT_ID

con l'ID progetto.

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

  • lookup-available-ability:: Questo è il nome del nostro primo strumento.
  • tipo: postgres-sql: indica alla Toolbox che l'azione di questo strumento è quella di eseguire un'istruzione SQL.
  • source: summoner-librarium: questo collega lo strumento alla connessione definita 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 è fondamentale per abilitare la funzionalità di chiamata di funzioni dell'agente.
  • istruzione: questa è la query SQL grezza da eseguire. $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 nel file tools.yaml, sostituisci #REPLACE-tools con quanto segue

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:: Stiamo creando un set di strumenti con lo stesso nome della nostra sorgente. Quando il nostro agente diagnostico si connetterà in seguito, potrà 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 segreto 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" \
    --labels="dev-tutorial-codelab=agentverse" \
    --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 contenitore in esecuzione.
  • --args: istruiamo il contenitore della casella degli strumenti a utilizzare il file segreto montato come configurazione.

👉 Per verificare che il toolbox sia stato implementato correttamente, vai alla console Cloud Run. Dovresti vedere il servizio summoner-toolbox elencato con un segno di spunta verde, a indicare che funziona correttamente, proprio come nell'immagine qui sotto. 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 quello che abbiamo chiamato progettazione dichiarativa, che descriveva ciò che volevi, e la casella degli strumenti ha creato 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 font:

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. I tuoi tre Font Elementali sono ora attivi, distribuiti in modo indipendente e accessibili a livello globale, costituendo la base incrollabile della tua legione agentica. Premere Ctrl+C per uscire.

PER I NON GIOCATORI

5. Evocazione dei familiari: 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à un ariete 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 di workflow 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 familiare Fire Elemental (flusso di lavoro sequenziale)

L'attacco di un Famiglio Elementale del Fuoco è una precisa combo in due parti: un colpo mirato seguito da una potente accensione. Ciò richiede una sequenza di azioni rigorosa e ordinata.

Storia

Concetto: SequentialAgent è lo strumento perfetto per questo scopo. 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"):

  • Fase 1: L'agente consulterà prima il Librarium per scoprire il danno base di una specifica abilità di fuoco.
  • Fase 2: Prenderà quindi quel valore di danno e lo incanalerà attraverso la Forgia Arcana per moltiplicare il suo potere usando inferno_resonance.

Per prima cosa, stabiliremo la connessione tra il nostro Familiar e i server MCP (i "Font Elementari") che hai distribuito 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 di essi viene assegnato uno scopo ristretto e ben definito e viene limitato al proprio "territorio operativo", potendo accedere a un solo set di strumenti specifico.

👉✏️ Nel file ~/agentverse-architect/agent/fire/agent.py REPLACE #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 richiede di interrogare il database. Mantenendo separate le loro responsabilità, creiamo elementi costitutivi flessibili. Questo è un principio fondamentale della progettazione basata su microservizi e componenti.

Successivamente assembleremo il flusso di lavoro: è qui che avviene la magia della composizione. SequentialAgent è il "piano generale" che definisce come vengono assemblati i nostri componenti specialistici e come 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 vedere 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 di ADK Dev dal tuo browser:

Dall'icona di anteprima Web (spesso somiglia a un occhio o a un quadrato con una freccia) nella barra degli strumenti di Cloud Shell (solitamente 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 visualizzerà l'interfaccia utente di ADK Dev.

anteprima web

👉 Il rituale di evocazione è completato e l'agente è ora in esecuzione. L'interfaccia utente di ADK Dev nel tuo browser è la tua connessione diretta a Familiar.

  • Seleziona il tuo target: nel menu a discesa nella parte superiore dell'interfaccia utente, scegli il famiglio fire. Ora stai concentrando la tua volontà su questa specifica entità.
  • Dai il tuo comando: nel pannello della chat sulla destra, è il momento di impartire ordini al Famiglio.

fire-select

👉 Richiesta di prova:

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.

👉💻 Una volta terminata l'evocazione, torna al terminale di Cloud Shell Editor e premi Ctrl+C per interrompere l'interfaccia utente di ADK Dev.

Evoca il familiare Water Elemental (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 workflow.

Attività (la combinazione "Tidal Clash"): l'agente dovrà contemporaneamente:

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

Per prima cosa, stabiliremo la connessione tra il nostro Familiar e i server MCP (i "Font Elementari") che hai distribuito 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 principale" 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 d'Acqua, esegui i seguenti comandi per avviare l'interfaccia utente di sviluppo 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, seleziona il famiglio acqua. Ora stai concentrando la tua volontà su questa specifica entità.
  • 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!

risultato dell'acqua

👉💻 Una volta terminata l'evocazione, torna al terminale di Cloud Shell Editor e premi Ctrl+C per interrompere l'interfaccia utente di ADK Dev.

Evoca il famiglio Earth Elemental (flusso di lavoro ciclico)

Un Famiglio Elementale della Terra è un essere sottoposto a una pressione incessante. Non sconfigge il nemico con un singolo colpo, ma accumulando costantemente potere e applicandolo ripetutamente 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.

Compito (l'assalto "Spezza-assedio"):

  • Il Familiar chiamerà ripetutamente seismic_charge per accumulare energia.
  • Continuerà a caricarsi per un massimo di 3 volte.
  • Con la carica finale, annuncerà il devastante rilascio del suo potere accumulato.

Per prima cosa creeremo componenti riutilizzabili che definiranno 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 suo messaggio nell'ultimo turno.

Per prima cosa, stabiliremo la connessione tra il nostro Familiar e i server MCP (i "Font Elementari") che hai distribuito 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 generale" che orchestra l'esecuzione ripetuta dei nostri componenti specialistici e gestisce le condizioni del loop.

👉✏️ 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 Earth Elemental

. ~/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 è completato e l'agente è ora in esecuzione. L'interfaccia utente ADK Dev nel tuo browser è la tua connessione diretta a Familiar.

  • Seleziona il tuo obiettivo: nel menu a discesa nella parte superiore dell'interfaccia utente, scegli il famiglio terra. Ora stai concentrando la tua volontà su questa specifica entità.
  • Dai il tuo comando: nel pannello della chat sulla destra, è il momento di impartire ordini al Famiglio. 👉 Richiesta di prova:
Begin the seismic charge, starting from zero

risultato terrestre

Considerazioni architettoniche: il tuo sistema ora possiede un livello logico altamente specializzato e modulare. 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 agentica, che migliora la sicurezza, l'efficienza e la capacità.

Una volta terminata l'evocazione, torna al terminale di Cloud Shell Editor e premi Ctrl+C per arrestare l'interfaccia utente di ADK Dev.

PER I NON GIOCATORI

6. Stabilire il luogo 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 rituale vincolante (smascherare i familiari come servizi A2A)

Un agente standard può essere eseguito solo in un posto alla volta. Per rendere i nostri Familiari disponibili al comando remoto, dobbiamo eseguire un "rituale di associazione" utilizzando il protocollo Agente-Agente (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 altri agenti inviano le loro richieste e garantisce che tali richieste vengano gestite secondo il contratto definito nella Scheda Agente.

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

Fuoco 👉✏️ in Apri il file ~/agentverse-architect/agent/fire/agent.py. Sostituisci #REPLACE - add A2A in fondo al 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)

Dispiegamento dei familiari vincolati

👉✏️ Una volta definiti i rituali di binding, utilizzeremo la nostra pipeline Cloud Build per creare e distribuire i nostri tre Familiar come servizio serverless containerizzato e 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 Familiari sono vincolati e ti ascoltano, potrai assumere il tuo vero ruolo: il 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 i Familiari stessi, che scoprirà e comanderà tramite 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 Evocatore non ha il codice dei Famigli integrato. Vengono invece forniti 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.

È possibile aggiornare, ridistribuire o riscrivere completamente un servizio Familiar e, finché il suo indirizzo di rete e il suo scopo rimangono gli stessi, l'Evocatore può comandarlo senza dover apportare alcuna modifica.

Per prima cosa, creeremo i "telecomandi" che stabiliranno una connessione con i nostri Familiari remoti e schierati.

👉✏️ 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 file "Spirit Sigil" (agent.json) dal server remoto.

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

👉✏️ Vai su ~/agentverse-architect/agent/summoner/agent.py e 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 Familiari sono schierati e il tuo Evocatore è pronto a comandarli attraverso la rete. Mettiamo alla prova la sua mentalità 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 ADK Dev nel tuo browser è la tua connessione diretta con Familiar.

  • Nel menu a discesa nella parte superiore dell'interfaccia utente, seleziona l'agente summoner. Ora stai concentrando la tua volontà su questa specifica entità.
  • Dai il tuo comando: nel pannello della chat sulla 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

(Previsto: l'evocatore dovrebbe delegare al famiglio elementale del fuoco.)

risultato del fuoco

👉 Ora sfidiamo l'Evocatore con un tipo di richiesta diverso. Per assicurarti che l'agente inizi con una tabula rasa e senza alcun ricordo della nostra precedente interazione, avvia una nuova sessione cliccando sul pulsante + Sessione nell'angolo in alto a destra dello schermo. nuova sessione

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

(Previsto: l'evocatore dovrebbe delegare al famiglio dell'elemento acqua.)water-result

👉 Per il nostro test finale, ripartiamo ancora una volta da zero. Fare clic sul pulsante + Sessione per avviare una nuova sessione prima di accedere al prompt successivo.

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

(Previsto: l'evocatore dovrebbe delegare al famiglio elementale della terra.)

risultato terrestre

Importante: se visualizzi un errore 429 RESOURCE EXHAUSTED, hai raggiunto il limite di velocità per LLM (10 chiamate/minuto). Per risolvere il problema, attendi 60 secondi, avvia una + Nuova sessione e riprova a rispondere al prompt.

👉💻 Una volta terminata l'evocazione, torna al terminale di Cloud Shell Editor e premi Ctrl+C per interrompere l'interfaccia utente di ADK Dev.

PER I NON GIOCATORI

7. Imporre le leggi della magia – Il modello Interceptor

I tuoi Famigli sono potenti, ma anche gli esseri magici 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 senza stato. Ora li renderemo con stato 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. Ciò ci consente di applicare regole, aggiungere registrazioni o modificare il comportamento senza modificare il codice principale dell'agente. È un elemento fondamentale per la creazione di sistemi agenti robusti, manutenibili 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

Per prima cosa implementeremo la nostra logica di raffreddamento come una semplice funzione di callback. Si tratta di un modo eccellente per creare un prototipo e sottoporre a debug una regola, perché è collegata direttamente a un singolo agente, rendendola facile da testare in modo isolato. Attaccheremo questo "intercettore" 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'Elementale della Terra possa funzionare, l'ADK eseguirà questa funzione.

  • Controllo: invia una richiesta GET al nostro Cooldown API per verificare l'ultima volta che questo Familiar è stato utilizzato.
  • Valuta: confronta il timestamp con l'ora corrente.
  • Atto:
    • 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 Familiar è disponibile, invia 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 quanto segue:

before_agent_callback=check_cool_down

Verifica del periodo di raffreddamento

Mettiamo alla prova la nostra nuova legge della magia. Evocheremo l'elementale della terra, poi proveremo subito 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 raffreddamento (entro 60 secondi): Do another carica sismica!
    • Previsto: check_cool_down callback intercetterà questo. L'agente risponderà direttamente nella chat con un messaggio del tipo: The earth_elemental_familiar is exhausted and must recover its power. It cannot be summoned for another... seconds.
  • Attendi un minuto.
  • Seconda evocazione (dopo 60 secondi): Begin the seismic charge again.
    • Risultato previsto: il callback controllerà l'API, vedrà che è trascorso abbastanza tempo e consentirà di procedere con l'azione. L'Earth Elemental verrà eseguito di nuovo correttamente.

callback

👉💻 Premi Ctrl+c per uscire.

Facoltativo: osservazione del callback nell'interfaccia utente Web

In alternativa, puoi anche testare questo flusso nell'interfaccia web eseguendo adk web earth. Tuttavia, tieni presente che la visualizzazione dell'interfaccia utente Web non è ottimizzata per la visualizzazione dei controlli rapidi e iterativi eseguiti dal ciclo di callback, quindi potrebbe non riprodurre il 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.

Creare la legge universale – Il plugin Cooldown

Il nostro callback funziona perfettamente, ma presenta un grave difetto architettonico: è 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 riorganizzeremo la nostra funzione di callback in un CoolDownPlugin più potente e riutilizzabile.

👉✏️ Torna al file agent/cooldown_plugin.py e crea il plugin. 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 plugin al runtime del Summoner

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

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: ricezione dell'input dell'utente, chiamata del LLM, esecuzione degli strumenti e gestione dei 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 regola di cooldown venga applicata in modo universale e coerente.

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

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 frammento 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à relative al cooldown vengono trasferite al nuovo plug-in.

Verifica del plugin

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

👉💻 Ricostruisci e ridistribuisci tutti e tre i Familiar utilizzando la pipeline master Cloud Build.

. ~/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. L'evocatore tenterà di delegare ai Familiari, ma il plugin collegato al runtime di ciascun Familiare 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 esatta sequenza di test:

  • Prima convocazione: inizia il Hype. It's a single, slow-moving target with thick armor weakness is Inescapable Reality.
  • Previsto: l'Elementale del Fuoco verrà eseguito correttamente.
  • Test di raffreddamento (entro 60 secondi): Hype, with Inescapable Reality as weakness is still standing! Strike it again!
    • Risultato previsto: l'agente risponderà direttamente nella chat con un messaggio come: .... It cannot be summoned for another... seconds.
  • Aspetta che passi 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, vedrà che è trascorso abbastanza tempo e consentirà di procedere con l'azione. L'elementale di fuoco verrà eseguito di nuovo correttamente.

plug-in

👉💻 Premi Ctrl+C per uscire.

Congratulazioni, Evocatore. Hai implementato con successo un sistema di orchestrazione basato su regole utilizzando un plugin personalizzato e un servizio di gestione dello stato esterno: un modello architettonico davvero avanzato e robusto.

PER CHI NON GIOCA

8. Legare gli echi della battaglia - Stato dell'agente e memoria

Un Evocatore spericolato ripete la stessa strategia, diventando prevedibile. Un Svocatore saggio impara dagli echi delle battaglie passate, adattando le sue tattiche per tenere in scacco il nemico. 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 le due tipologie 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, acquisite "al momento", rilevanti solo per l'attività o la conversazione in corso. È 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

Nel nostro caso d'uso, non abbiamo bisogno di ricordare ogni battaglia combattuta; dobbiamo solo ricordare 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 questa informazione fondamentale.

Scrivere l'eco: ricordare l'ultima convocazione

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 Familiare appena evocato nello stato di sessione dell'agente.

👉✏️ Nel tuo 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, allega questo save_last_summon_after_tool al tuo agente evocatore. Nello stesso file, sostituisci il commento #REPLACE-Memory-check-config con quanto segue:

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

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

  • Previsto: l'evocatore analizzerà la debolezza ed evocherà correttamente il famiglio del fuoco.

👉💻 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 indicheranno 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).

risultato finale

👉💻 Premi Ctrl+C per uscire.

Distribuzione dell'orchestratore

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

👉💻 Una volta completato il progetto, eseguiremo il rituale finale. Questo comando creerà e distribuirà il tuo 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 delegatore; è uno stratega adattabile 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 allo Scontro con il boss.

PER I NON GIOCATORI

9. Lo scontro con il boss

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 per la tana dello Spettro (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"

👉💻 Ora, individua la destinazione. Questo comando rivela la posizione del Cerchio di Traslocazione, il portale che conduce al dominio di Spectre.

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

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

Affrontare lo spettro

Una volta ottenute le coordinate, potrai raggiungere il Cerchio di Traslocazione e lanciare l'incantesimo per lanciarti in battaglia.

👉 Apri l'URL del Cerchio di Traslocazione nel tuo browser per trovarti di fronte al portale scintillante per The Crimson Keep.

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

  • Nella pagina, trova il campo di input runico etichettato A2A Endpoint URL.
  • 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'unica via per la vittoria risiede nella chiarezza delle tue convinzioni. Si tratta di un duello di volontà, combattuto 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 che trae origine dal nucleo del tuo addestramento.

Dungeon

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

  • Rispondi con la saggezza che hai acquisito e la tua lama si accenderà di pura energia, mandando in frantumi la difesa dello Spettro e infliggendo un COLPO CRITICO.
  • Ma se esiti, se il dubbio offusca la tua risposta, la luce della tua arma si affievolirà. Il colpo arriverà con un tonfo patetico, provocando solo una FRAZIONE DEL SUO DANNO. Quel che è peggio è che lo Spettro si nutrirà della tua incertezza e il suo potere corruttivo crescerà a ogni passo falso.

Ci siamo, Campione. Il tuo codice è il tuo libro degli incantesimi, la tua logica è la tua spada e la tua conoscenza è lo scudo che respingerà l'ondata del 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 il Concordo 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.

Disattivare i componenti 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 vengono rimossi da Cloud Run tutti gli agenti Familiar distribuiti, Summoner Orchestrator, i server MCP e l'applicazione Dungeon.

👉💻 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 di Cloud SQL

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

👉💻 Nel terminale, esegui:

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

Elimina il segreto di Secret Manager e il bucket di Google Cloud Storage

👉💻 Nel terminale, esegui:

. ~/agentverse-architect/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 altamente 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 di Agentverse Architect. Il tuo progetto è pulito e sei pronto per la prossima avventura.