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

1. Força do Destino,

A era do desenvolvimento isolado está chegando ao fim. A próxima onda da evolução tecnológica não se trata de genialidade solitária, mas sim de domínio colaborativo. Construir um único agente inteligente é uma experiência fascinante. Construir um ecossistema de agentes robusto, seguro e inteligente — um verdadeiro Agentverse — é o grande desafio para a empresa moderna.

Para ter sucesso nessa nova era, é preciso que quatro funções essenciais, os pilares fundamentais que sustentam qualquer sistema de agente próspero, trabalhem juntas. Uma deficiência em qualquer área cria uma fragilidade que pode comprometer toda a estrutura.

Este workshop é o guia definitivo para empresas que desejam dominar o futuro da computação autônoma no Google Cloud. Oferecemos um roteiro completo que o guia desde a primeira ideia até a sua implementação em larga escala. Ao longo desses quatro laboratórios interconectados, você aprenderá como as habilidades especializadas de um desenvolvedor, arquiteto, engenheiro de dados e SRE devem convergir para criar, gerenciar e dimensionar um Agentverse poderoso.

Nenhum pilar isolado consegue sustentar o Agentverse sozinho. O projeto grandioso do arquiteto é inútil sem a execução precisa do incorporador. O agente do desenvolvedor fica cego sem a sabedoria do engenheiro de dados, e todo o sistema é frágil sem a proteção do SRE. Somente por meio da sinergia e de uma compreensão compartilhada dos papéis de cada um é que sua equipe poderá transformar um conceito inovador em uma realidade operacional de missão crítica. Sua jornada começa aqui. Prepare-se para dominar seu papel e aprender como você se encaixa no todo.

Bem-vindos ao Agentverse: Um Chamado aos Campeões

Na vasta extensão digital da empresa, uma nova era surgiu. É a era agêntica, um momento de imensa promessa, em que agentes inteligentes e autônomos trabalham em perfeita harmonia para acelerar a inovação e eliminar o que é comum.

agentverse.png

Esse ecossistema conectado de poder e potencial é conhecido como Agentverse.

Mas uma entropia crescente, uma corrupção silenciosa conhecida como Estática, começou a desgastar as bordas desse novo mundo. O Estático não é um vírus ou um bug; é a personificação do caos que se alimenta do próprio ato da criação.

Ele amplia frustrações antigas em formas monstruosas, origem aos Sete Espectros do Desenvolvimento. Se não for marcada, "The Static and its Spectres" vai interromper o progresso, transformando a promessa do Agentverse em um terreno baldio de dívidas técnicas e projetos abandonados.

Hoje, pedimos que os campeões combatam essa onda de caos. Precisamos de heróis dispostos a dominar suas habilidades e trabalhar juntos para proteger o Agentverso. Chegou a hora de escolher seu caminho.

Escolha sua turma

Quatro caminhos distintos se abrem diante de você, cada um um pilar crítico na luta contra The Static. Embora seu treinamento seja uma missão individual, seu sucesso final depende de entender como suas habilidades se combinam com as dos outros.

  • O Lâmina de Sombra (Desenvolvedor): um mestre da forja e da linha de frente. Você é o artesão que cria as lâminas, constrói as ferramentas e enfrenta o inimigo nos detalhes intrincados do código. Seu caminho é de precisão, habilidade e criação prática.
  • O Invocador (arquiteto): um grande estrategista e orquestrador. Você não vê um único agente, mas todo o campo de batalha. Você cria os projetos principais que permitem que sistemas inteiros de agentes se comuniquem, colaborem e alcancem um objetivo muito maior do que qualquer componente individual.
  • O Estudioso (engenheiro de dados): um buscador de verdades ocultas e guardião da sabedoria. Você se aventura na vasta e indomável natureza selvagem de dados para descobrir a inteligência que dá propósito e visão aos seus agentes. Seu conhecimento pode revelar a fraqueza de um inimigo ou fortalecer um aliado.
  • O Guardião (DevOps / SRE): o protetor e escudo constante do reino. Você constrói as fortalezas, gerencia as linhas de suprimento de energia e garante que todo o sistema possa resistir aos ataques inevitáveis de The Static. Sua força é a base da vitória da equipe.

Sua missão

Seu treinamento vai começar como um exercício independente. Você vai seguir o programa escolhido e aprender as habilidades exclusivas necessárias para dominar sua função. No final do teste, você vai enfrentar um Spectre nascido de The Static, um mini-chefe que se alimenta dos desafios específicos da sua profissão.

Só é possível se preparar para o teste final dominando sua função individual. Em seguida, forme um grupo com campeões das outras classes. Juntos, vocês vão se aventurar no coração da corrupção para enfrentar um chefe final.

Um desafio final e colaborativo que vai testar sua força combinada e determinar o destino do Agentverse.

O Agentverse espera por seus heróis. Você vai atender ao chamado?

2. A Concordância do Invocador

Olá, invocador. Seu caminho é de visão e grande estratégia. Enquanto outros se concentram em uma única lâmina ou em um único encantamento, você vê todo o campo de batalha. Você não comanda um único agente, mas sim uma orquestra inteira deles. Seu poder não está no conflito direto, mas em criar o projeto perfeito e abrangente que permite que uma legião de especialistas (seus Familiares) trabalhe em perfeita harmonia. Esta missão vai testar sua capacidade de projetar, conectar e orquestrar um sistema multiagente eficiente.

visão geral

O que você vai aprender

  • Projete um ecossistema de ferramentas dissociadas:crie e implante um conjunto de servidores de ferramentas MCP independentes baseados em microsserviços. Você vai aprender por que essa camada fundamental é essencial para criar sistemas de agentes escalonáveis, fáceis de manter e seguros.
  • Domine fluxos de trabalho avançados com agentes:vá além dos agentes únicos e crie uma legião de "Familiares" especialistas. Você dominará os principais padrões de fluxo de trabalho do ADK — Sequencial, Paralelo e em Loop — e aprenderá os princípios arquitetônicos para escolher o padrão certo para a tarefa certa.
  • Implemente um orquestrador inteligente: Evolua de um simples construtor de agentes para um verdadeiro arquiteto de sistemas. Você construirá um Agente de Orquestração mestre que utiliza o protocolo Agente-para-Agente (A2A) para descobrir e delegar tarefas complexas aos seus Familiares especialistas, criando um verdadeiro sistema multiagente.
  • Aplicar regras com código, não comandos:aprenda a criar agentes mais confiáveis e previsíveis aplicando regras de engajamento com estado. Você vai implementar uma lógica personalizada usando o poderoso sistema de plug-ins e callbacks do ADK para gerenciar restrições do mundo real, como timers de espera.
  • Gerenciar o estado e a memória do agente:dê aos seus agentes a capacidade de aprender e lembrar. Você vai conhecer técnicas para gerenciar o estado de conversação de curto prazo e a memória persistente de longo prazo para criar interações mais inteligentes e contextualizadas.
  • Execute uma implantação de nuvem de ponta a ponta: Leve todo o seu sistema multiagente de um protótipo local para uma realidade de nível de produção. Você vai aprender a colocar seus agentes e orquestrador em contêineres e implantá-los como uma coleção de microsserviços escalonáveis e independentes no Google Cloud Run.

3. Desenhar o círculo de invocação

Olá, invocador. Antes que um Familiar possa ser invocado, antes que qualquer pacto possa ser forjado, o próprio terreno em que você está precisa ser preparado. Um ambiente indomado é um convite ao caos; um invocador adequado opera apenas em um espaço santificado e fortalecido. Nossa primeira tarefa é desenhar o círculo de invocação: inscrever as runas de poder que despertam os serviços de nuvem necessários e adquirir os projetos antigos que vão orientar nosso trabalho. O poder de um Invocador nasce de uma preparação meticulosa.

👉 Clique em "Ativar o Cloud Shell" na parte de cima do console do Google Cloud. É o ícone em forma de terminal na parte de cima do painel do Cloud Shell.

texto alternativo

👉 Clique no botão "Abrir editor" (parece uma pasta aberta com um lápis). Isso vai abrir o editor de código do Cloud Shell na janela. Um explorador de arquivos vai aparecer à esquerda. texto alternativo

👉Abra o terminal no IDE da nuvem, texto alternativo

👉💻 No terminal, verifique se você já está autenticado e se o projeto está configurado com o seu ID de projeto usando o seguinte comando:

gcloud auth list

👉💻 Clone o projeto Bootstrap do 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

👉💻 Execute o script de configuração no diretório do projeto.

⚠️ Observação sobre o ID do projeto:o script vai sugerir um ID do projeto padrão gerado aleatoriamente. Pressione Enter para aceitar esse padrão.

No entanto, se você preferir criar um novo projeto específico, digite o ID do projeto desejado quando o script solicitar.

cd ~/agentverse-architect
./init.sh

O script vai processar o restante da configuração automaticamente.

👉 Etapa importante após a conclusão: Assim que o script terminar, você deve garantir que seu Console do Google Cloud esteja exibindo o projeto correto:

  1. Acesse console.cloud.google.com.
  2. Clique no menu suspenso do seletor de projetos na parte superior da página.
  3. Clique na guia Todos, já que o novo projeto ainda não aparece em "Recentes".
  4. Selecione o ID do projeto que você acabou de configurar na etapa init.sh.

03-05-project-all.png

👉💻 Defina o ID do projeto necessário:

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

👉💻 Execute o comando a seguir para ativar as APIs do Google Cloud necessárias:

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 você ainda não criou um repositório do Artifact Registry chamado agentverse-repo, execute o seguinte comando para criá-lo: pule esta etapa se você tiver outras classes implantadas no mesmo projeto

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

Configurar permissão

👉💻 Conceda as permissões necessárias executando os seguintes comandos no terminal:

. ~/agentverse-architect/set_env.sh

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

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

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

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

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

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

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

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

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

👉💻 Enquanto você começa o treinamento, vamos preparar o desafio final. Os comandos a seguir vão invocar os Espectros do caos estático, criando os chefes para seu teste final.

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

👉💻 Por fim, execute o script prepare.sh para realizar as tarefas de configuração inicial.

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

Excelente trabalho, Invocador. O círculo está completo e os pactos estão selados. O chão agora está consagrado, pronto para canalizar um poder imenso. No próximo teste, vamos forjar as fontes elementais de que nossos familiares vão extrair a força.

4. Forjando as Fontes Elementares: O Ecossistema de Ferramentas Desacopladas

O campo de batalha está preparado, o círculo de invocação está desenhado e a mana ambiente está crepitando. É hora de realizar seu primeiro ato como um Invocador: forjar as fontes de poder de onde seus Familiares vão extrair a força. Esse ritual é dividido em três partes, cada uma despertando uma Fonte Elemental, uma fonte estável e independente de um tipo específico de poder. Só quando as três fontes estiverem ativas você poderá começar o trabalho mais complexo de invocação.

História

Observação do arquiteto:o servidor do Protocolo de Contexto de Modelo (MCP) é um componente fundamental em um sistema de agentes moderno, atuando como uma ponte de comunicação padronizada que permite que um agente descubra e use ferramentas remotas. No nosso ecossistema de ferramentas, vamos arquitetar dois tipos distintos de servidores MCP, cada um representando um padrão arquitetônico crítico. Para se conectar ao nosso banco de dados, vamos usar uma abordagem declarativa com a Database Toolbox, definindo nossas ferramentas em um arquivo de configuração simples. Esse padrão é incrivelmente eficiente e seguro para expor o acesso a dados estruturados. No entanto, quando precisamos implementar uma lógica de negócios personalizada ou chamar APIs externas de terceiros, usamos uma abordagem imperativa, escrevendo a lógica do servidor etapa por etapa no código. Isso oferece controle e flexibilidade máximos, permitindo encapsular operações complexas em uma ferramenta simples e reutilizável. Um arquiteto principal precisa entender os dois padrões para selecionar a abordagem certa para cada componente, criando uma base de ferramentas robusta, segura e escalonável.

visão geral

Despertar do Nexus dos Sussurros (servidor MCP da API externa)

Um invocador sábio sabe que nem todo poder se origina do próprio domínio. Há fontes externas, às vezes caóticas, de energia que podem ser canalizadas com grande efeito. O Nexus of Whispers é nosso portal para essas forças.

História

Já existe um serviço ativo que funciona como nossa fonte de energia externa, oferecendo dois endpoints de feitiço brutos: /cryosea_shatter e /moonlit_cascade.

Observação do arquiteto:você vai usar uma abordagem imperativa que define explicitamente a lógica do servidor etapa por etapa. Isso oferece muito mais controle e flexibilidade, o que é essencial quando suas ferramentas precisam fazer mais do que apenas executar uma consulta SQL simples, como chamar outras APIs. Entender os dois padrões é uma habilidade essencial para um arquiteto de agentes.

👉✏️ Navegue até o diretório ~/agentverse-architect/mcp-servers/api/main.py e SUBSTITUA #REPLACE-MAGIC-CORE pelo seguinte código:

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

No centro do script estão as funções simples do Python. É aqui que o trabalho de verdade acontece.

👉✏️ No mesmo arquivo ~/agentverse-architect/mcp-servers/api/main.py SUBSTITUA #REPLACE-Runes of Communication pelo seguinte código:

@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() (O handshake): essa função é a saudação do servidor. Quando um novo agente se conecta, ele primeiro chama esse endpoint para perguntar: "O que você pode fazer?" Nosso código responde com uma lista de todas as ferramentas disponíveis, convertidas para o formato universal do MCP usando adk_to_mcp_tool_type. - @app.call_tool() (o comando): essa função é a mais importante. Quando o agente decide usar uma ferramenta, ele envia uma solicitação para esse endpoint com o nome e os argumentos da ferramenta. Nosso código procura a ferramenta no "livro de feitiços" available_tools, executa com run_async e retorna o resultado no formato MCP padrão.

Vamos implantar isso mais tarde.

Ativar a Forja Arcana (servidor MCP de funções gerais)

Nem todo poder vem de livros antigos ou sussurros distantes. Às vezes, um Invocador precisa forjar a própria magia com vontade bruta e lógica pura. A Arcane Forge é essa fonte de poder: um servidor que fornece funções de utilidade sem estado e de uso geral.

História

Observação do arquiteto: este é outro padrão de arquitetura. Embora seja comum se conectar a sistemas atuais, muitas vezes é necessário implementar suas próprias regras e lógica de negócios exclusivas. Criar uma ferramenta dedicada de "funções" ou "utilitários" como essa é uma prática recomendada. Ele encapsula sua lógica personalizada, tornando-a reutilizável para qualquer agente no seu ecossistema e mantendo-a separada das suas fontes de dados e integrações externas.

👀 Dê uma olhada no arquivo ~/agentverse-architect/mcp-servers/general/main.py no seu Google Cloud IDE. Você verá que ele usa a mesma abordagem imperativa, mcp.server, que o Nexus para construir esta Fonte de Poder personalizada.

Criar o Pipeline de Construção Mestre na Nuvem

Agora, vamos criar o arquivo cloudbuild.yaml dentro do diretório mcp-servers. Este arquivo irá orquestrar a construção e a implantação de ambos os serviços.

👉💻 No diretório ~/agentverse-architect/mcp-servers, execute os seguintes comandos:

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"

Aguarde até que todas as implantações sejam concluídas.

👉 Para verificar a implantação, navegue até o console do Cloud Run. As duas novas instâncias do servidor MCP vão estar em execução, conforme mostrado abaixo: texto alternativo

Despertando o Librarium of Knowledge (servidor MCP da Database ToolBox)

Nossa próxima fonte será a Librarium of Knowledge, uma conexão direta com nosso banco de dados do Cloud SQL.

História

Nota do arquiteto: Para isso, usaremos a moderna e declarativa Database Toolbox. Essa é uma abordagem poderosa na qual definimos nossa fonte de dados e ferramentas em um arquivo de configuração YAML. A caixa de ferramentas lida com o trabalho complexo de criar e executar o servidor, reduzindo a quantidade de código personalizado que precisamos escrever e manter.

É hora de criar nosso "Summoner's Librarium", o banco de dados do Cloud SQL que vai armazenar todas as nossas informações importantes. Vamos usar um script de configuração para lidar com isso automaticamente.

👉💻 Primeiro, vamos configurar o banco de dados. No seu terminal, execute os seguintes comandos:

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

Depois que o script terminar, o banco de dados será preenchido e os dados de dano elemental estarão prontos para uso. Agora você pode verificar o conteúdo do seu Grimório diretamente.

👉 Primeiro, acesse o Cloud SQL Studio do seu banco de dados abrindo este link direto em uma nova guia do navegador:

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

Cloud SQL

👉 No painel de login à esquerda, selecione o banco de dados familiar_grimoire no menu suspenso.

👉 Insira summoner como usuário e 1234qwer como senha e clique em Autenticar.

👉📜 Depois de conectar, abra uma nova aba do editor de consultas, caso ainda não haja uma aberta. Para visualizar os dados de dano elemental inscritos, cole e execute a seguinte consulta SQL:

SELECT * FROM
  "public"."abilities"

Agora você vai ver a tabela abilities com as colunas e linhas preenchidas, confirmando que o Grimoire está pronto. Dados

Configurar o servidor ToolBox MCP

O arquivo de configuração tools.yaml funciona como o projeto do nosso servidor, informando à caixa de ferramentas de banco de dados exatamente como se conectar ao banco de dados e quais consultas SQL expor como ferramentas.

sources: Esta seção define as conexões com seus dados.

  • summoner-librario:: Este é um nome lógico que demos à nossa conexão.
  • kind: cloud-sql-postgres: informa à caixa de ferramentas para usar o conector seguro e integrado projetado especificamente para o Cloud SQL para PostgreSQL.
  • projeto, região, instância, etc.: Essas são as coordenadas exatas da instância do Cloud SQL que você criou durante o script prepare.sh, informando à caixa de ferramentas onde encontrar o Librarium.

👉✏️ Acesse ~/agentverse-architect/mcp-servers/db-toolbox em tools.yaml e substitua #REPLACE-Source pelo seguinte:

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"

👉✏️ 🚨🚨SUBSTITUIR

YOUR_PROJECT_ID

com o ID do projeto.

tools:esta seção define as habilidades ou funções reais que nosso servidor vai oferecer.

  • lookup-available-ability:: Este é o nome da nossa primeira ferramenta.
  • kind: postgres-sql: Isso indica ao Toolbox que a ação desta ferramenta é executar uma instrução SQL.
  • Fonte: summoner-librarian: Isso vincula a ferramenta à conexão que definimos no bloco de fontes. É assim que a ferramenta sabe em qual banco de dados executar a consulta.
  • Descrição e parâmetros: Estas são as informações que serão expostas ao Modelo de Linguagem. A descrição informa ao agente quando usar a ferramenta, e os parâmetros definem as entradas necessárias. Isso é fundamental para habilitar a capacidade do agente de invocar funções.
  • statement: esta é a consulta SQL bruta a ser executada. $1 é um marcador de posição seguro em que o parâmetro familiar_name fornecido pelo agente será inserido com segurança.

👉✏️ No mesmo ~/agentverse-architect/mcp-servers/db-toolbox no arquivo tools.yaml, substitua #REPLACE-tools pelo seguinte

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;

Conjuntos de ferramentas:esta seção agrupa nossas ferramentas individuais.

  • summoner-librarium:: Estamos criando um conjunto de ferramentas com o mesmo nome da nossa fonte. Quando nosso agente de diagnóstico se conecta mais tarde, ele pode pedir para carregar todas as ferramentas do conjunto de ferramentas summoner-librarium em um único comando eficiente.

👉✏️ No mesmo ~/agentverse-architect/mcp-servers/db-toolbox do arquivo tools.yaml, substitua #REPLACE-toolsets pelo seguinte:

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

Como implantar o Librarium

Agora vamos implantar o Librarium. Em vez de criar nosso próprio contêiner, vamos usar uma imagem de contêiner oficial e pré-criada do Google e fornecer nossa configuração tools.yaml a ela de maneira segura usando o Secret Manager. Essa é uma prática recomendada para segurança e capacidade de manutenção.

👉💻 Criar um secret com o arquivo tools.yaml

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

👉💻 Implante o contêiner oficial da caixa de ferramentas no 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: esse comando monta com segurança o secret das nossas ferramentas como um arquivo chamado tools.yaml dentro do contêiner em execução.
  • --args: Instruímos o contêiner da caixa de ferramentas a usar o arquivo secreto montado como sua configuração.

👉 Para confirmar se sua caixa de ferramentas foi implantada com sucesso, navegue atéConsole do Cloud Run. O serviço summoner-toolbox vai aparecer com uma marca de seleção verde, indicando que está funcionando corretamente, como na imagem abaixo. texto alternativo

Se você esqueceu de atualizar

YOUR_PROJECT_ID

adicione uma nova versão do tools.yaml ao secret usando o comando a seguir e faça a nova implantação.

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

O Librarium of Knowledge(servidor MCP da caixa de ferramentas de banco de dados) agora está ativo e acessível na nuvem. Esse servidor do MCP usa o que chamamos de design declarativo, que descreve o que você quer, e a caixa de ferramentas cria o servidor para você.

Verificação: O Julgamento do Aprendiz

👉💻 Agora vamos testar nosso ecossistema completo de ferramentas nativas da nuvem com o Agente de diagnóstico.

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

👉💻 Na ferramenta de teste da linha de comando, teste todas as três fontes:

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.

resultado final

Parabéns, invocador. Suas três fontes elementais agora estão ativas, implantadas de forma independente e acessíveis globalmente, formando a base inabalável para sua legião de agentes. Pressione Ctrl+C para sair.

PARA QUEM NÃO JOGA

5. Convocando os familiares: o fluxo de trabalho do domínio principal

As fontes elementais são forjadas, vibrando com poder bruto e indomável. Mas poder sem forma é caos. Um verdadeiro Invocador não apenas usa energia bruta, mas também dá a ela vontade, propósito e uma forma especializada. É hora de deixar de lado a criação de fontes de energia e começar o trabalho de verdade: invocar seus primeiros familiares.

Cada Familiar que você invocar será um agente autônomo, um servo leal vinculado a uma doutrina de combate específica. Eles não são generalistas, mas mestres de uma única estratégia poderosa. Um será mestre do combo preciso de um-dois. Outro vai dominar os inimigos com um ataque simultâneo e multifacetado. Um terceiro será uma máquina de cerco implacável, aplicando pressão até que o alvo desmorone.

História

Encapsular processos, lógica de negócios e ações fornecidas pelos servidores MCP em agentes de fluxo de trabalho especializados e autônomos. Cada agente terá um "território operacional" definido, já que terá acesso apenas aos servidores de ferramentas do MCP específicos de que precisa para realizar a função. Este laboratório mostra como selecionar o tipo de agente certo para o trabalho certo.

visão geral

Neste módulo, você vai aprender a usar os agentes de fluxo de trabalho eficientes do ADK para dar vida a essas estratégias. Você vai aprender que a escolha arquitetônica de um SequentialAgent, ParallelAgent ou LoopAgent não é apenas um detalhe técnico. Ela é a essência da natureza do seu Familiar e o núcleo do poder dele no campo de batalha.

Prepare seu santuário. A verdadeira convocação está prestes a começar.

Invocar o Fire Elemental Familiar (Fluxo de Trabalho Sequencial)

O ataque de um Familiar Elemental de Fogo é uma combinação precisa de duas partes: um golpe direcionado seguido por uma poderosa ignição. Isso requer uma sequência de ações rigorosa e ordenada.

História

Conceito: O SequentialAgent é a ferramenta perfeita para isso. Isso garante que uma série de subagentes sejam executados um após o outro, passando o resultado da etapa anterior para a próxima.

Tarefa (combo "Aviso amplificado"):

  • Etapa 1: o agente consulta o Librarium para encontrar o dano básico de uma habilidade de fogo específica.
  • Passo 2: Em seguida, o valor do dano será canalizado através da Forja Arcana para multiplicar seu poder usando a ressonância inferno.

Primeiro, vamos estabelecer a conexão entre o nosso Familiar e os servidores MCP (as "Fontes Elementares") que você implantou no módulo anterior.

👉✏️ No arquivo ~/agentverse-architect/agent/fire/agent.py SUBSTITUA #REPLACE-setup-MCP pelo seguinte código:

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

Em seguida, criamos nossos agentes "trabalhadores" especializados. Cada um tem uma finalidade restrita e bem definida e fica limitado ao próprio "território operacional" ao receber acesso a apenas um conjunto de ferramentas específico.

👉✏️ No arquivo ~/agentverse-architect/agent/fire/agent.py, REPLACE #REPLACE-worker-agents com o seguinte código:

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

Esses agentes são componentes modulares e reutilizáveis. Em teoria, é possível usar esse scout_agent em um fluxo de trabalho completamente diferente que precisa consultar o banco de dados. Ao manter as responsabilidades separadas, criamos elementos básicos flexíveis. Esse é um princípio fundamental do design baseado em microsserviços e componentes.

Em seguida, vamos montar o fluxo de trabalho, que é onde a mágica da composição acontece. O SequentialAgent é o "plano principal" que define como nossos componentes especializados são montados e como eles interagem.

👉✏️ No arquivo ~/agentverse-architect/agent/fire/agent.py, REPLACE #REPLACE-sequential-agent com o seguinte código:

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

👉💻 Para testar o Elemental de Fogo, execute os seguintes comandos para iniciar a interface de desenvolvedor do 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

Depois de executar os comandos, você vai ver uma saída no terminal indicando que o servidor da Web do ADK foi iniciado, semelhante a esta:

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

👉 Em seguida, para acessar a interface de desenvolvimento do ADK no navegador:

No ícone de visualização da Web (geralmente um olho ou um quadrado com uma seta) na barra de ferramentas do Cloud Shell (geralmente no canto superior direito), selecione "Alterar porta". Na janela pop-up, defina a porta como 8000 e clique em "Alterar e visualizar". O Cloud Shell vai abrir uma nova guia ou janela do navegador mostrando a interface de desenvolvimento do ADK.

pré-visualização da web

👉 Seu ritual de invocação foi concluído, e o agente está em execução. A interface de desenvolvimento do ADK no navegador é sua conexão direta com o Familiar.

  • Selecione seu destino: no menu suspenso na parte de cima da interface, escolha o fire familiar. Agora você está concentrando sua vontade nessa entidade específica.
  • Dê seu comando: no painel de chat à direita, chegou a hora de dar ordens ao Familiar.

fire-select

👉 Comando de teste:

Prepare an amplified strike using the 'inferno_lash' ability.

fire-result

Você vai ver o agente pensar, primeiro chamando o "scout" para pesquisar o dano básico e depois o "amplificador" para multiplicá-lo e dar o golpe final e épico.

👉💻 Quando terminar de invocar, volte ao terminal do editor do Cloud Shell e pressione Ctrl+C para interromper a interface de desenvolvimento do ADK.

Chamar o Water Elemental Familiar (fluxo de trabalho paralelo)

Um familiar elemental de água ataca o alvo com um assalto massivo e multifacetado, atingindo de todas as direções ao mesmo tempo antes de combinar as energias para um golpe final e devastador.

História

Conceito:o ParallelAgent é ideal para executar várias tarefas independentes simultaneamente e maximizar a eficiência. É um "ataque em pinça", em que você lança vários ataques de uma só vez. Isso inicia os ataques simultâneos em um SequentialAgent para executar uma etapa final de "fusão" depois. Esse padrão "fan-out, fan-in" é fundamental para o design avançado de fluxos de trabalho.

Tarefa (combo "Tidal Clash"): o agente vai:

  • Tarefa A: canal cryosea_shatter do Nexus.
  • Tarefa B: canal moonlit_cascade do Nexus.
  • Tarefa C: gere energia bruta com leviathan_surge da Forja.
  • Por fim, some todos os danos e descreva o ataque combinado.

Primeiro, vamos estabelecer a conexão entre o Familiar e os servidores MCP (as "Fontes elementais") que você implantou no módulo anterior.

👉✏️ No arquivo ~/agentverse-architect/agent/water/agent.py, SUBSTITUA #REPLACE-setup-MCP pelo seguinte código:

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

Em seguida, vamos criar nossos agentes "trabalhadores" especializados. Cada um tem uma finalidade restrita e bem definida e fica limitado ao próprio "território operacional" ao receber acesso a apenas um conjunto de ferramentas específico.

👉✏️ No arquivo ~/agentverse-architect/agent/water/agent.py, SUBSTITUA #REPLACE-worker-agents pelo seguinte código:

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

Em seguida, vamos montar o fluxo de trabalho. É aqui que a mágica da composição acontece. O ParallelAgent e o SequentialAgent são o "plano principal" que define como nossos componentes especializados são montados e como eles interagem para formar o combo "Tidal Clash".

👉✏️ No arquivo ~/agentverse-architect/agent/water/agent.py, SUBSTITUA #REPLACE-parallel-agent pelo seguinte código:

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

👉💻 Para testar o Elemental da Água, execute os seguintes comandos para iniciar a interface de desenvolvedor do 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

👉 Seu ritual de invocação foi concluído, e o agente está em execução. A interface de desenvolvimento do ADK no navegador é sua conexão direta com o Familiar.

  • No menu suspenso na parte de cima da interface, escolha o familiar água. Agora você está concentrando sua vontade nessa entidade específica.
  • Dê seu comando: no painel de chat à direita, chegou a hora de dar ordens ao Familiar.

👉 Prompt de teste:

Unleash a tidal wave of power!

resultado da água

👉💻 Depois de concluir a invocação, retorne ao terminal do Cloud Shell Editor e pressione Ctrl+C para interromper a interface de desenvolvimento do ADK.

Invocar o Familiar Earth Elemental (Fluxo de Trabalho em Loop)

Um familiar elemental da terra é um ser de pressão implacável. Ele não derrota o inimigo com um único golpe, mas acumulando poder e aplicando-o repetidamente até que as defesas do alvo desmoronem.

História

Conceito:o LoopAgent foi projetado exatamente para esse tipo de tarefa iterativa, como um "engenho de cerco". Ele vai executar repetidamente o sub-agents, verificando uma condição após cada ciclo, até que uma meta seja atingida. Ela também pode adaptar a mensagem final com base no progresso do loop.

Tarefa (assalto "Siegebreaker"):

  • O Familiar vai chamar seismic_charge repetidamente para acumular energia.
  • O carregamento continuará por um máximo de 3 vezes.
  • Na carga final, ele vai anunciar a liberação devastadora do poder acumulado.

Primeiro, vamos criar componentes reutilizáveis que definem as etapas em cada iteração do loop. O charging_agent acumulará energia e o check_agent relatará seu status, alterando dinamicamente sua mensagem no turno final.

Primeiro, vamos estabelecer a conexão entre o nosso Familiar e os servidores MCP (as "Fontes Elementares") que você implantou no módulo anterior.

👉✏️ No arquivo ~/agentverse-architect/agent/earth/agent.py, SUBSTITUA #REPLACE-setup-MCP pelo seguinte código:

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

👉✏️ No arquivo ~/agentverse-architect/agent/earth/agent.py, SUBSTITUA #REPLACE-worker-agents pelo seguinte código:

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

Em seguida, vamos montar o fluxo de trabalho. É aqui que a magia da composição acontece. O LoopAgent é o "plano mestre" que orquestra a execução repetida de nossos componentes especializados e gerencia as condições do loop.

👉✏️ No arquivo ~/agentverse-architect/agent/earth/agent.py SUBSTITUA #REPLACE-loop-agent pelo seguinte código:

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
)

👉💻 Teste o Elemental da Terra: Execute o 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

👉 Seu ritual de invocação foi concluído e o agente já está em execução. A interface de desenvolvimento do ADK no seu navegador é a sua conexão direta com o Familiar.

  • Selecione seu alvo: No menu suspenso na parte superior da interface do usuário, escolha o familiar earth. Agora você está concentrando sua vontade nessa entidade específica.
  • Dê sua ordem: No painel de bate-papo à direita, é hora de dar ordens ao Familiar. 👉 Prompt de teste:
Begin the seismic charge, starting from zero

resultado da terra

Conclusão arquitetônica: Seu sistema agora possui uma camada lógica altamente especializada e modular. Os processos de negócio não são apenas encapsulados, mas também implementados com o padrão de comportamento mais eficiente para a tarefa (procedimental, concorrente ou iterativo). Isso demonstra um nível avançado de design de agentes, aprimorando a segurança, a eficiência e a capacidade.

Após concluir a invocação, retorne ao terminal do Cloud Shell Editor e pressione Ctrl+C para interromper a interface de desenvolvimento do ADK.

PARA NÃO JOGADORES

6. Como estabelecer o locus de comando: delegação inteligente via A2A

Seus familiares são poderosos, mas independentes. Elas executam as estratégias com perfeição, mas aguardam seu comando direto. Uma legião de especialistas é inútil sem um general para comandá-los. É hora de passar de um comandante direto para um verdadeiro orquestrador.

visão geral

Observação do arquiteto:para criar um único ponto de entrada inteligente para todo o sistema. Esse SummonerAgent não vai executar a lógica de negócios, mas vai atuar como um "estrategista principal", analisando o status de resfriamento e delegando tarefas ao Familiar especialista adequado.

visão geral

O ritual de vinculação (como expor familiares como serviços A2A)

Um agente padrão só pode ser executado em um lugar por vez. Para disponibilizar nossos Familiars para comando remoto, precisamos realizar um "ritual de vinculação" usando o protocolo agente para agente (A2A).

Observação do arquiteto:o protocolo Agent-to-Agent (A2A) é o padrão arquitetônico principal que eleva um agente independente a um microsserviço detectável e endereçável pela rede, permitindo uma verdadeira "sociedade de agentes". Expor um Familiar via A2A cria automaticamente dois componentes essenciais e interconectados:

  • O cartão do agente (o "o quê"): é um "sigilo espiritual" público e legível por máquina, como uma especificação OpenAPI, que funciona como o contrato público do Familiar. Ele descreve o nome do agente, o propósito estratégico (derivado das instruções) e os comandos que ele entende. É assim que um mestre invocador lê para descobrir um familiar e aprender as habilidades dele.
  • O servidor A2A (o "Onde"): é o endpoint da Web dedicado que hospeda o Familiar e aguarda comandos recebidos. É o endereço de rede para onde outros agentes enviam suas solicitações e garante que essas solicitações sejam tratadas de acordo com o contrato definido no Cartão do Agente.

Realizaremos agora este ritual de ligação em todos os três de nossos Familiares.

Fogo 👉✏️ em Abra o arquivo ~/agentverse-architect/agent/fire/agent.py. Substitua o #REPLACE - add A2A na parte inferior do arquivo para expor o Elemental de Fogo como um serviço 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)

Água e Terra🚨 👉✏️ Aplique a mesma alteração a ~/agentverse-architect/agent/water/agent.py e ~/agentverse-architect/agent/earth/agent.py para vinculá-los também.

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)

Implantando os Familiares Vinculados

👉✏️ Com os rituais de vinculação escritos, vamos usar nosso pipeline do Cloud Build para criar e implantar nossos três Familiares como um serviço independente, conteinerizado e sem servidor no 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"

Assumindo o Comando (Construindo o Agente Invocador)

Agora que seus Familiares estão vinculados e ouvindo, você vai ascender ao seu verdadeiro papel: o Mestre Invocador. O poder desse agente não vem do uso de ferramentas básicas, mas do comando de outros agentes. As ferramentas são os próprios Familiares, que ele descobre e comanda usando os "Selos espirituais".

Nota do arquiteto: Esta próxima etapa demonstra um padrão arquitetônico crítico para qualquer sistema distribuído de grande escala: Descoberta de serviço. O SummonerAgent não possui o código dos Familiars embutido. Em vez disso, são fornecidos os seus endereços de rede (URLs). Em tempo de execução, ele "descobrirá" dinamicamente suas capacidades buscando seus Agent Cards públicos. Isso cria um sistema independente e eficiente.

Você pode atualizar, reimplantar ou reescrever completamente um serviço Familiar e, contanto que seu endereço de rede e sua finalidade permaneçam os mesmos, o Invocador poderá comandá-lo sem precisar fazer nenhuma alteração.

Primeiro, vamos forjar os "controles remotos" que estabelecem uma conexão com nossos Familiares remotos implantados.

👉✏️ Acesse ~/agentverse-architect/agent/summoner/agent.py e substitua #REPLACE-remote-agents pelo seguinte:

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 essa linha é executada, o RemoteA2aAgent realiza uma ação de descoberta de serviços: ele faz uma solicitação HTTP GET para o URL fornecido (por exemplo, https://fire-familiar-xxxx.a.run.app/.well-known/agent.json). Ele baixa o "Spirit Sigil" (arquivo agent.json) do servidor remoto.

Em segundo lugar, vamos definir o agente orquestrador que vai usar esses controles remotos. As instruções são o projeto para a tomada de decisões estratégicas.

👉✏️ Acesse ~/agentverse-architect/agent/summoner/agent.py e substitua #REPLACE-orchestrate-agent pelo seguinte:

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ção: o teste da estratégia

Chegou a hora da verdade. Seus familiares estão implantados, e seu invocador está pronto para comandá-los na rede. Vamos testar a mente estratégica dele.

👉💻 Inicie a interface de desenvolvimento do ADK para seu summoner_agent(visualização na Web com a porta 8000):

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

👉 A interface de desenvolvimento do ADK no navegador é sua conexão direta com o Familiar.

  • No menu suspenso na parte de cima da interface, escolha o agente convocador. Agora você está concentrando sua vontade nessa entidade específica.
  • Emita seu comando: no painel de chat à direita, é hora de convocar seus familiares.

👉 Apresente os monstros:

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

(Esperado: o invocador deve delegar ao familiar elemental de fogo.)

resultado-de-fogo

👉 Agora, vamos desafiar o Summoner com um tipo diferente de solicitação. Para garantir que o agente comece do zero e não se lembre da nossa interação anterior, clique no botão + Sessão no canto superior direito da tela para iniciar uma nova sessão. new-session

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

(Esperado: O Invocador deve delegar ao familiar_elemental_da_água.)resultado da água

👉 Para nosso teste final, vamos começar de novo. Clique no botão + Sessão para iniciar uma nova sessão antes de inserir o próximo comando.

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

(Esperado: o invocador deve delegar ao familiar elemental da terra.)

earth-result

Importante:se você encontrar um erro 429 RESOURCE EXHAUSTED, atingiu o limite de taxa do LLM (10 chamadas/minuto). Para corrigir isso, aguarde 60 segundos, inicie uma + Nova sessão e tente de novo.

👉💻 Quando terminar de invocar, volte ao terminal do editor do Cloud Shell e pressione Ctrl+C para interromper a interface de desenvolvimento do ADK.

PARA QUEM NÃO JOGA

7. Imposing the Laws of Magic – The Interceptor Pattern

Seus familiares são poderosos, mas até mesmo seres mágicos precisam de tempo para se recuperar. Um Invocador imprudente que esgota as próprias forças fica indefeso. Um invocador sábio entende a importância do gerenciamento de recursos e impõe regras de combate estritas.

História

Observação do arquiteto: até agora, nossos agentes não têm estado. Agora, vamos torná-los com estado implementando o padrão de design de interceptor. Essa é uma técnica eficiente em que "interceptamos" o fluxo de execução normal de um agente para executar nossa própria lógica personalizada. Isso permite aplicar regras, adicionar registros ou modificar o comportamento sem mudar o código principal do agente. É uma pedra angular na criação de sistemas de agentes robustos, fáceis de manter e observáveis.

visão geral

O ADK oferece duas maneiras principais de implementar esse padrão: callbacks e plug-ins. Um callback é uma função simples anexada a um único agente, perfeita para modificações rápidas e específicas. Um plug-in é uma classe mais poderosa e reutilizável que pode ser aplicada globalmente para afetar todos os agentes em execução em um sistema. Vamos começar com um callback para depuração focada e depois passar para um plug-in completo.

The Law Giver – Scribing the Cooldown callback

Primeiro, vamos implementar nossa lógica de redução como uma função de callback simples. Essa é uma excelente maneira de criar protótipos e depurar uma regra, porque ela é anexada diretamente a um único agente, facilitando o teste isolado. Vamos anexar esse "interceptador" ao nosso Elemental da Terra.

Período de espera

👉✏️ Volte para ~/agentverse-architect/agent/earth/agent.py e substitua #REPLACE-before_agent-function pelo seguinte código 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.")

Essa função check_cool_down é nosso interceptor. Antes de o Elemental da Terra ser executado, o ADK vai executar essa função.

  • Verificação: Faz uma solicitação GET ao nosso Cooldown API para verificar a última vez que este Familiar foi usado.
  • Avaliar: Compara o registro de data e hora com a hora atual.
  • Ação:
    • Se o Familiar estiver em espera, ele encerrará a execução do agente retornando um objeto Content com uma mensagem de erro. Essa mensagem é enviada diretamente ao usuário, e a lógica principal do agente nunca é executada.
    • Se o Familiar estiver disponível, ele fará uma solicitação POST para a API Cooldown para atualizar o carimbo de data/hora e retornará "None", sinalizando para o ADK que o agente pode continuar a execução.

👉✏️ Agora, aplique esse interceptor ao Elemental da Terra. No mesmo arquivo ~/agentverse-architect/agent/earth/agent.py, substitua o comentário #REPLACE-before_agent-config pelo seguinte:

before_agent_callback=check_cool_down

Verificando o tempo de espera

Vamos testar nossa nova lei da magia. Vamos invocar o Elemental da Terra e tentar invocar de novo imediatamente para ver se nosso callback intercepta e bloqueia a segunda tentativa.

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

👉💻 No console:

  • Primeira citação: inicie o seismic charge, starting from zero.
  • Esperado: o Elemental da Terra será executado com sucesso. No terminal que executa o comando adk web, você vai ver o registro [Callback] ... Atualizando o carimbo de data/hora....
  • Teste de Resfriamento (dentro de 60 segundos): Do another carga sísmica`!
    • Esperado: O check_cool_down callback irá interceptar isto. O agente responderá diretamente no chat com uma mensagem como: The earth_elemental_familiar is exhausted and must recover its power. It cannot be summoned for another... seconds.
  • Aguarde um minuto.
  • Segunda Invocação (após 60 segundos): Begin the seismic charge again.
    • Esperado: o callback vai verificar a API, ver que já passou tempo suficiente e permitir que a ação continue. O Elemental da Terra vai funcionar novamente.

callback

👉💻 Pressione Ctrl+c para sair.

Opcional: observar o callback na interface da Web

Como alternativa, você também pode testar esse fluxo na interface da Web executando adk web earth. No entanto, a visualização da interface da Web não é otimizada para mostrar as verificações rápidas e iterativas realizadas pelo loop de callback. Por isso, ela pode não renderizar o fluxo com precisão. Para ver o rastreamento mais preciso e detalhado da lógica do agente enquanto ele verifica o período de espera, use o comando adk run no terminal. loop

👉💻 Pressione Ctrl+c para sair.

Criando a Lei Universal – O Plugin de Tempo de Resfriamento

Nosso callback funciona perfeitamente, mas tem uma falha arquitetônica grave: ele está vinculado a um único agente. Se quisermos aplicar essa regra aos familiares de fogo e água, teremos que copiar e colar o mesmo código nos arquivos deles. Isso é ineficiente e difícil de manter.

Nota do arquiteto: É aqui que os plugins são essenciais. Um plugin encapsula nossa lógica reutilizável em uma classe que pode ser anexada em tempo de execução. Isso significa que um único plugin pode aplicar suas regras a todos os agentes que são executados dentro desse sistema. É a expressão máxima do princípio "Não se repita" (Don't Repeat Yourself - DRY) para sistemas agentivos.

Agora vamos refatorar nossa função de callback em um CoolDownPlugin mais eficiente e reutilizável.

👉✏️ Navegue de volta ao arquivo agent/cooldown_plugin.py e crie o plug-in. Substitua #REPLACE-plugin pelo seguinte código:

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

Como anexar o plug-in ao ambiente de execução do Summoner

Agora, como aplicamos essa lei universal a todos os nossos familiares? Vamos anexar o plug-in ao ADK Runtime.

O ambiente de execução do ADK é o mecanismo de execução que dá vida a um agente. Quando você usa um comando como adk.run() ou to_a2a(), está entregando o agente ao ambiente de execução. Esse mecanismo é responsável por gerenciar todo o ciclo de vida de uma interação do agente: receber a entrada do usuário, chamar o LLM, executar ferramentas e processar plug-ins. Ao anexar um plug-in nesse nível, modificamos essencialmente as "leis da física" para todos os agentes que operam nesse mecanismo, garantindo que nossa regra de tempo de espera seja aplicada de forma universal e consistente.

👉✏️ Primeiro, vamos remover o callback antigo específico do agente. Acesse ~/agentverse-architect/agent/earth/agent.py e exclua toda a linha que diz:

before_agent_callback=check_cool_down

👉✏️ Em seguida, vamos anexar nosso novo plug-in ao ambiente de execução no script do ponto de entrada A2A. Navegue até o arquivo ~/agentverse-architect/agent/agent_to_a2a.py. Substitua o comentário #REPLACE-IMPORT pelo seguinte snippet de código:

from cooldown_plugin import CoolDownPlugin

👉✏️ Substitua #REPLACE-PLUGIN pelo seguinte snippet de código:

plugins=[CoolDownPlugin(cooldown_seconds=60)],

Antes de ativar nosso novo plug-in global, é fundamental remover a lógica antiga e específica do agente para evitar conflitos. 👉✏️ Limpe o agente da Terra. Acesse o arquivo ~/agentverse-architect/agent/earth/agent.py e exclua completamente a linha before_agent_callback=check_cool_down. Isso transfere todas as responsabilidades de resfriamento para o novo plug-in.

Como verificar o plug-in

Agora que nossa lei universal está em vigor, precisamos reimplantar nossos familiares com esse novo encanto.

👉💻 Recompile e reimplante todos os três Familiars usando o pipeline principal do 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"

👉💻 Depois que a implantação for concluída, vamos testar a eficácia do plug-in comandando nosso summoner_agent. O Summoner vai tentar delegar aos Familiars, mas o plug-in anexado ao tempo de execução de cada Familiar vai interceptar o comando e aplicar o tempo de espera.

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

👉💻 No console,execute exatamente esta sequência de testes::

  • Primeira Invocação: Comece o Hype. It's a single, slow-moving target with thick armor weakness is Inescapable Reality.
  • Esperado: o Elemental de Fogo será executado com sucesso.
  • Teste de Resfriamento (em até 60 segundos): Hype, with Inescapable Reality as weakness is still standing! Strike it again!
    • Esperado: O agente responderá diretamente no chat com uma mensagem como: .... It cannot be summoned for another... seconds.
  • Aguarde um minuto.
  • Segunda convocação (após 60 segundos): Hype must be defeated. It has Inescapable Reality as weakness! Strike it again!.
    • Esperado: o callback vai verificar a API, ver que já passou tempo suficiente e permitir que a ação continue. O Elemental de Fogo vai funcionar novamente.

plug-in

👉💻 Pressione Ctrl+C para sair.

Parabéns, Invocador. Você implementou com sucesso um sistema de orquestração baseado em regras usando um plugin personalizado e um serviço externo de gerenciamento de estado — um padrão arquitetural verdadeiramente avançado e robusto.

PARA QUEM NÃO JOGA

8. Unindo os Ecos da Batalha - Estado e Memória do Agente

Um Invocador imprudente repete a mesma estratégia, tornando-se previsível. Um invocador sábio aprende com os ecos de batalhas passadas, adaptando suas táticas para manter o inimigo em desvantagem. Ao enfrentar um chefe poderoso, invocar um Familiar que está em tempo de recarga é um turno desperdiçado — um erro crítico. Para evitar isso, nosso Invocador precisa se lembrar de sua última ação.

story

Nota do arquiteto: O gerenciamento de memória e estado é o que eleva um agente de um simples chamador de ferramentas a um parceiro conversacional inteligente. É crucial entender os dois tipos principais:

  • Memória de Longo Prazo: Isso é para conhecimento persistente que deve durar para sempre. Pense nisso como um arquivo pesquisável ou uma base de conhecimento, geralmente armazenada em um repositório permanente. Contém informações de vários chats e fontes anteriores, permitindo que um agente se lembre de fatos sobre um usuário ou tópico específico. O MemoryService do ADK foi projetado para isso, gerenciando a ingestão e a busca desse conhecimento de longo prazo.
  • Estado de curto prazo: para conhecimento temporário, "no momento", que é relevante apenas para a tarefa ou conversa atual. É como um conjunto de observações em um plano de batalha: "Acabei de usar o Elemental de Fogo, então ele provavelmente está cansado". Esse estado é leve e existe apenas durante a sessão atual.

Visão geral

Para o nosso caso específico, não precisamos nos lembrar de todas as batalhas já travadas; precisamos apenas nos lembrar do último Familiar invocado nesse encontro em particular. Portanto, o estado de curto prazo leve Short-Term State é a escolha arquitetônica perfeita. Usaremos um after_tool_callback para salvar esta informação crucial.

Escrevendo o Eco: Recordando a Última Convocação

Vamos implementar nossa memória de curto prazo usando um after_tool_callback. Esse é um hook ADK avançado que permite executar uma função personalizada do Python depois que uma ferramenta é executada com sucesso. Vamos usar esse interceptador para registrar o nome do Familiar que acabou de ser invocado no estado da sessão do agente.

👉✏️ No seu arquivo ~/agentverse-architect/agent/summoner/agent.py, substitua o comentário #REPLACE-save_last_summon_after_tool pela seguinte função:

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

👉✏️ Agora, anexe esse save_last_summon_after_tool ao seu agente Summoner. No mesmo arquivo, substitua o comentário #REPLACE-Memory-check-config pelo seguinte:

after_tool_callback=save_last_summon_after_tool,

👉✏️ Substitua todo o comando do agente pelo seguinte:

        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ção: o teste da estratégia adaptativa

👉💻 Agora, vamos verificar a nova lógica estratégica do Summoner. O objetivo é confirmar que o Invocador não vai usar o mesmo Familiar duas vezes seguidas, demonstrando a capacidade de lembrar da última ação e se adaptar.

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.

  • Esperado: o Summoner vai analisar a fraqueza e invocar corretamente o fire_familiar.

👉💻 Monster Strike #2 (The Memory Test): Hype is still standing! It hasn't changed its form. Strike it again! Its weakness is Inescapable Reality.

  • Expectativa: A análise estratégica do Invocador apontará novamente para o Familiar de Fogo como a escolha ideal. No entanto, suas novas instruções e memória lhe dirão que fire_familiar foi a última invocação. Para evitar repetir o mesmo erro, agora adaptará sua estratégia e invocará um dos outros Familiares disponíveis (familiar_da_água ou familiar_da_terra).

resultado final

👉💻 Pressione Ctrl+C para sair.

Implantação do Orchestrator

Com seus Familiares posicionados e seu Invocador agora imbuído de memória, é hora de implantar o orquestrador final e aprimorado.

👉💻 Com o projeto concluído, vamos realizar o ritual final. Esse comando vai criar e implantar o summoner_agent no 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"

Agora que o agente Summoner foi implantado, verifique se o endpoint de agente para agente (A2A) está ativo e configurado corretamente. Esse endpoint veicula um arquivo public agent.json, também conhecido como card do agente, que permite que outros agentes descubram os recursos dele. 👉💻 Execute o comando curl a seguir para buscar e formatar o card do agente:

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

Você vai ver uma saída JSON limpa descrevendo o agente de invocação. Observe atentamente a seção "sub_agents". Ela lista fire_familiar, water_familiar e earth_familiar. Isso confirma que seu invocador está ativo e estabeleceu uma conexão com a legião.

Isso comprova que sua arquitetura é um sucesso. Seu Invocador não é apenas um delegador; ele é um estrategista adaptativo que aprende com suas ações para se tornar um comandante mais eficaz.

Você concluiu seu último teste de arquitetura. Os ecos da batalha agora estão atrelados à sua vontade. O treinamento acabou. A verdadeira batalha espera por você. Chegou a hora de pegar seu sistema finalizado e encarar o desafio definitivo. Prepare-se para a Luta contra o Chefe.

PARA QUEM NÃO JOGA

9. A luta contra o chefe

Os projetos finais estão inscritos, as fontes elementais estão forjadas e seus familiares estão vinculados à sua vontade, aguardando seu comando pelo Concord. Seu sistema multiagente não é apenas uma coleção de serviços, mas uma legião estratégica viva, com você como o centro. Chegou a hora do teste final: uma orquestração em tempo real contra um adversário que nenhum agente conseguiria derrotar sozinho.

Adquira a localização do seu agente.

Antes de entrar no campo de batalha, você precisa ter duas chaves: a assinatura exclusiva do seu campeão (Agent Locus) e o caminho oculto para o covil do Spectre (URL da masmorra).

👉💻 Primeiro, obtenha o endereço exclusivo do seu agente no Agentverse — seu Locus. Este é o ponto de extremidade em tempo real que conecta seu campeão ao campo de batalha.

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

👉💻 Em seguida, marque o destino. Esse comando revela a localização do Círculo de Translocação, o portal para o domínio do Spectre.

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

Importante: Mantenha ambos os URLs à mão. Você precisará deles na etapa final.

Confrontando o Espectro

Com as coordenadas em mãos, você agora navegará até o Círculo de Translocação e lançará o feitiço para entrar em batalha.

👉 Abra o link do Círculo de Translocação no seu navegador para ficar diante do portal cintilante da Fortaleza Carmesim.

Para invadir a fortaleza, você deve sintonizar a essência de sua Lâmina Sombria com o portal.

  • Na página, encontre o campo de entrada rúnico rotulado como A2A Endpoint URL.
  • Inscreva o sigilo do seu campeão colando o URL do seu Agent Locus (o primeiro URL que você copiou) neste campo.
  • Clique em Conectar para liberar a magia do teletransporte.

Círculo de translocação

A luz ofuscante do teletransporte desaparece. Você não está mais no seu sanctum. O ar estala com energia, frio e cortante. Antes de você, o Spectre se materializa: um vórtice de estática sibilante e código corrompido, cuja luz profana projeta sombras longas e dançantes no chão da masmorra. Ele não tem rosto, mas você sente a presença imensa e exaustiva fixada totalmente em você.

Seu único caminho para a vitória está na clareza da sua convicção. É um duelo de vontades, travado no campo de batalha da mente.

Ao avançar, pronto para desferir seu primeiro ataque, o Espectro contra-ataca. Não ergue um escudo, mas projeta uma pergunta diretamente em sua consciência — um desafio rúnico cintilante, extraído do âmago do seu treinamento.

Masmorra

Essa é a natureza da luta. Seu conhecimento é sua arma.

  • Responda com a sabedoria que você adquiriu, e sua lâmina se inflamará com energia pura, destruindo a defesa do Espectro e desferindo um GOLPE CRÍTICO.
  • Mas se você vacilar, se a dúvida nublar sua resposta, a luz da sua arma se apagará. O golpe será desferido com um baque patético, causando apenas uma FRAÇÃO DO DANO. Pior ainda, o Espectro se alimentará da sua incerteza, e seu poder corruptor crescerá a cada passo em falso.

É isso, campeão. Seu código é seu grimório, sua lógica é sua espada e seu conhecimento é o escudo que vai conter a maré do caos.

Foco. Acertar. O destino do Agentverse depende disso.

Parabéns, invocador.

Você concluiu o teste. Você dominou a arte da orquestração multiagente, transformando Familiars isolados e poder caótico em uma Concord harmoniosa. Agora você comanda um sistema totalmente orquestrado, capaz de executar estratégias complexas para defender o Agentverse.

10. Limpeza: desmantelando a Concordância do Invocador

Parabéns por dominar a Concordância do Invocador! Para garantir que o Agentverse permaneça intacto e que os locais de treinamento sejam limpos, agora você precisa realizar os rituais de limpeza finais. Isso vai remover sistematicamente todos os recursos criados durante sua jornada.

Desativar os componentes do Agentverse

Agora você irá desmontar sistematicamente os componentes implantados do seu sistema multiagente.

Excluir todos os serviços do Cloud Run e o repositório do Artifact Registry

Isso remove todos os agentes Familiar implantados, o Summoner Orchestrator, os servidores MCP e o aplicativo Dungeon do Cloud Run.

👉💻 No seu terminal, execute os seguintes comandos um por um para excluir cada serviço:

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

Exclua a instância do Cloud SQL

Isso remove a instância summoner-librarium-db, incluindo seu banco de dados e todas as tabelas dentro dela.

👉💻 No seu terminal, execute:

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

Exclua o secret do Secret Manager e o bucket do Google Cloud Storage

👉💻 No seu terminal, execute:

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

Limpar arquivos e diretórios locais (Cloud Shell)

Por fim, limpe seu ambiente Cloud Shell dos repositórios clonados e dos arquivos criados. Esta etapa é opcional, mas altamente recomendada para uma limpeza completa do seu diretório de trabalho.

👉💻 No terminal, execute:

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

Você agora concluiu com sucesso todos os vestígios de sua jornada como Arquiteto do Agentverse. Seu projeto está limpo, e você está pronto para sua próxima aventura.