1. Visão geral
Neste codelab, você vai criar o AI Creative Studio, um sistema multiagente distribuído que transforma um único comando em uma campanha completa do Instagram.
Digite uma frase. Receba de volta pesquisa de público-alvo, legendas, conceitos visuais, cópias revisadas e um cronograma completo do projeto, tudo gerado por uma equipe de agentes de IA colaborativos.
Os agentes que você vai criar
Agente | Papel |
Estrategista de marca | Pesquisa na Web insights sobre público-alvo, análise da concorrência e tendências para 2025 |
Redatora | Escreve legendas do Instagram com hashtags e CTAs, com tecnologia de uma habilidade do ADK que carrega diretrizes da plataforma e fórmulas de legenda sob demanda. |
Designer | Cria conceitos visuais e gera imagens reais com o Gemini, armazenadas no GCS |
Crítico | Cópias e recursos visuais de avaliações: retornam |
Gerente de projeto | Cria uma linha do tempo e um detalhamento de tarefas do projeto, que podem ser sincronizados com o Notion usando o MCP. |
Diretor de criação | Orquestra todos os cinco especialistas em sequência: você dá um comando, e ele coordena o restante |
Os cinco agentes são implantados como microsserviços independentes do Cloud Run. Eles se comunicam pelo protocolo A2A, um padrão aberto independente de linguagem para que qualquer agente possa chamar outro, seja qual for o framework. O Creative Director é executado no Agent Runtime e se conecta a cada especialista remotamente.
Arquitetura

O que você vai aprender
- Crie agentes de LLM com o ADK do Google:
Agent, instruções do sistema e ferramentas integradas. - Empacote o conhecimento reutilizável do agente em arquivos modulares com as habilidades do ADK (
SkillToolset). - Gere imagens reais conectando um agente de texto a um modelo de imagem usando um
FunctionTool. - Integre APIs externas sem código de junção personalizado usando o Protocolo de Contexto de Modelo (MCP).
- Transforme qualquer agente em um serviço que pode ser chamado pela rede usando o protocolo de agente para agente (A2A) via HTTPS.
- Orquestre agentes distribuídos com
RemoteA2aAgenteAgentTool. - Empacote e implante agentes independentes como microsserviços do Cloud Run.
- Hospede um orquestrador com estado no Agent Runtime.
- Mantenha fluxos de trabalho multiagentes longos dentro dos limites de contexto usando a compactação de contexto.
- Crie um ciclo de controle de qualidade: o Critic analisa a saída → revisão automática quando necessário.
O que é necessário
- Um projeto do Google Cloud com o faturamento ativado
- Papel do IAM de Proprietário ou Editor
- Conhecimento básico de Python
2. Configuração de seu ambiente
Neste codelab, vamos usar o Cloud Shell.
O que é o Cloud Shell?
O Cloud Shell é um ambiente Linux sem custo financeiro baseado em navegador com tudo pré-instalado: gcloud, git, Python, Docker e muito mais. Não é necessário instalar nada localmente.
Para abrir o Cloud Shell, clique no ícone do terminal na barra de ferramentas superior direita do console do GCP:

Ao abrir o Cloud Shell pela primeira vez, você vai precisar verificar sua conta. Clique em Verificar:

Em seguida, clique em Autorizar para permitir que o Cloud Shell faça chamadas de API do Google Cloud:

O Cloud Shell está pronto. Uma mensagem de boas-vindas vai aparecer no terminal: 
Autenticar e configurar seu projeto
O Cloud Shell já está autenticado com sua Conta do Google. Confirme sua conta ativa e encontre o ID do projeto:
gcloud config list
Você também pode conferir o ID do projeto no painel do console do GCP, no painel lateral esquerdo. Copie o caminho. Você vai precisar dele no próximo comando:

Agora, defina o projeto:
export PROJECT_ID=$(gcloud config get-value project)
export REGION="us-central1" # Cloud Run deployment region
echo "Project: $PROJECT_ID"
Saída esperada:
Project: my-project-123
Ativar APIs obrigatórias
gcloud services enable \
aiplatform.googleapis.com \
apphub.googleapis.com \
run.googleapis.com \
cloudbuild.googleapis.com \
artifactregistry.googleapis.com \
generativelanguage.googleapis.com \
iam.googleapis.com \
cloudresourcemanager.googleapis.com \
storage.googleapis.com \
secretmanager.googleapis.com
Isso leva cerca de 2 minutos. Você vai ver Operation finished successfully quando terminar.
Configurar as credenciais padrão do aplicativo (ADC)
Os agentes vão chamar a plataforma de agentes do Gemini Enterprise usando a biblioteca Google Auth, que exige o Application Default Credentials, separado da autenticação da CLI gcloud.
Execute este comando uma vez:
gcloud auth application-default login
Uma guia do navegador será aberta pedindo confirmação. Clique em Permitir. Você vai ver:
Credentials saved to file: ~/.config/gcloud/application_default_credentials.json
Clonar o repositório inicial
Este codelab usa um repositório inicial, um projeto esqueleto com toda a infraestrutura no lugar (Dockerfiles, pyproject.toml, scripts de implantação), mas com a lógica do agente para você escrever.
git clone https://github.com/Saoussen-CH/mas-a2a-gcp.git ~/ai-creative-studio
cd ~/ai-creative-studio/workshop/starter
Cada agent.py contém marcadores de posição # TODO em que você vai escrever a lógica do agente. Os scripts Dockerfile, pyproject.toml e de implantação já estão concluídos.
Configure as variáveis de ambiente
Copie o exemplo fornecido e injete o ID do projeto em uma etapa:
cp .env.example .env
sed -i "s|GOOGLE_CLOUD_PROJECT=your-project-id|GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project)|" .env
Em seguida, crie o bucket do GCS em que o Designer vai armazenar as imagens geradas e atualize .env com o nome dele:
export PROJECT_ID=$(gcloud config get-value project)
export BUCKET_NAME="${PROJECT_ID}-campaign-images"
gcloud storage buckets create gs://${BUCKET_NAME} \
--location=us-central1 \
--project=${PROJECT_ID}
sed -i "s|GCS_IMAGES_BUCKET=your-project-id-campaign-images|GCS_IMAGES_BUCKET=${BUCKET_NAME}|" .env
Em seguida, configure o suporte a URLs de imagens assinados. O diretor de criação gera links HTTPS clicáveis para cada imagem no resumo final da campanha. Isso exige uma conta de serviço para assinar os URLs. Execute estes comandos para configurar:
export PROJECT_NUMBER=$(gcloud projects describe $(gcloud config get-value project) --format="value(projectNumber)")
export SA_EMAIL="${PROJECT_NUMBER}-compute@developer.gserviceaccount.com"
export AGENT_RUNTIME_SA="service-${PROJECT_NUMBER}@gcp-sa-aiplatform-re.iam.gserviceaccount.com"
# Allow your user account to sign URLs locally (adk web)
gcloud iam service-accounts add-iam-policy-binding ${SA_EMAIL} \
--member="user:$(gcloud config get-value account)" \
--role="roles/iam.serviceAccountTokenCreator"
# Allow Agent Runtime to sign URLs when deployed
gcloud projects add-iam-policy-binding $(gcloud config get-value project) \
--member="serviceAccount:${AGENT_RUNTIME_SA}" \
--role="roles/iam.serviceAccountTokenCreator"
# Save SA email and project number to .env
grep -q "^SIGNING_SERVICE_ACCOUNT" .env \
&& sed -i "s|^SIGNING_SERVICE_ACCOUNT=.*|SIGNING_SERVICE_ACCOUNT=${SA_EMAIL}|" .env \
|| echo "SIGNING_SERVICE_ACCOUNT=${SA_EMAIL}" >> .env
grep -q "^GOOGLE_CLOUD_PROJECT_NUMBER" .env \
&& sed -i "s|^GOOGLE_CLOUD_PROJECT_NUMBER=.*|GOOGLE_CLOUD_PROJECT_NUMBER=${PROJECT_NUMBER}|" .env \
|| echo "GOOGLE_CLOUD_PROJECT_NUMBER=${PROJECT_NUMBER}" >> .env
Abra .env no editor para revisar todas as configurações:
cloudshell edit .env
Isso abre .env como uma guia no editor do Cloud Shell. Clique no botão Abrir editor na barra de ferramentas se o painel do editor não estiver visível:


Confirme se o projeto foi definido corretamente:
grep GOOGLE_CLOUD_PROJECT .env
Instalar dependências
Usamos o uv, um gerenciador de pacotes Python rápido e moderno que lida com ambientes virtuais e instalações em uma única ferramenta. Ele é de 10 a 100 vezes mais rápido que o pip e é a maneira recomendada de gerenciar projetos Python.
O Cloud Shell já tem o uv instalado. Todos os agentes compartilham as mesmas dependências principais. Portanto, instale uma vez e isso vai funcionar para todos os agentes neste codelab:
uv sync
O comando uv sync lê pyproject.toml e cria um diretório .venv/ com todas as dependências. Cada especialista também tem o próprio pyproject.toml usado exclusivamente por builds do Docker. A instalação compartilhada acima abrange tudo o que você precisa para testes locais.
3. Entender o ADK do Google
Antes de escrever o código, vamos entender o Kit de Desenvolvimento de Agente (ADK), a estrutura que você vai usar para criar todos os agentes neste codelab.
O que é o ADK?
O Agent Development Kit (ADK, na sigla em inglês) é um framework flexível e modular para desenvolver e implantar agentes de IA. Embora otimizado para o Gemini e o ecossistema do Google, o ADK é independente de modelo e implantação e foi criado para ser compatível com outros frameworks. O ADK foi projetado para tornar o desenvolvimento de agentes mais parecido com o desenvolvimento de software, facilitando a criação, a implantação e a orquestração de arquiteturas de agentes que variam de tarefas simples a fluxos de trabalho complexos.
O ADK lida com as partes complexas (chamada de função, conversa com várias interações, gerenciamento de contexto, streaming) para que você possa se concentrar na lógica do agente.
Elementos básicos de um agente do ADK
Cada agente é composto de quatro elementos básicos:
Bloquear | Papel |
Modelo | O LLM que analisa metas, determina um plano e gera respostas |
Ferramentas | Funções que buscam dados ou realizam ações chamando APIs ou serviços |
Orquestração | Mantém a memória e o estado entre as conversas, encaminha chamadas de ferramentas e transmite os resultados de volta ao modelo. |
Ambiente de execução | Executa o sistema quando invocado, localmente via |
Definição de agente
Cada um dos cinco agentes neste codelab é definido da mesma maneira:
from google.adk.agents import Agent
from google.adk.tools.google_search_tool import google_search
root_agent = Agent(
name="brand_strategist", # unique identifier
model=os.getenv("GEMINI_MODEL", "gemini-2.5-flash"), # the LLM powering this agent
instruction=SYSTEM_INSTRUCTION, # the agent's persona, constraints, and output format
description="Brand strategist for market research, trend analysis, and competitive insights",
tools=[google_search], # functions the LLM can call
)
Campo | Finalidade |
| ID exclusivo: usado por orquestradores para encaminhar chamadas. |
| O modelo do Gemini que oferece suporte a esse agente |
| Comando do sistema: define a função, as restrições e o formato de saída do agente. |
| Resumo de uma linha: o orquestrador lê isso para decidir qual especialista chamar. |
| Funções que o LLM pode invocar (integradas, como |
Como o ADK executa um agente
User message
│
▼
Agent (LLM) ← reads instruction + conversation history
│
├─► needs more info? → calls a tool → gets result → continues reasoning
│
└─► done reasoning → returns final text response
O LLM decide de forma autônoma se vai chamar uma ferramenta, qual ferramenta e com quais argumentos. Você escreve a instrução, e o ADK cuida do resto.
4. Criar e testar o agente de estratégia de marca
Vamos começar com o primeiro agente: o estrategista de marca. Este é um agente de pesquisa que busca insights sobre o público-alvo, análise da concorrência e temas em alta usando a Pesquisa Google.
Abra o arquivo do agente esqueleto no editor do Cloud Shell:
cloudshell edit agents/brand_strategist/agent.py
Você vai encontrar duas seções # TODO para preencher.
TODO 1: escreva a instrução do sistema
Primeiro, você vai escrever a instrução do sistema para o agente. A instrução do sistema é uma string que define a função, as restrições e o formato de saída do agente.
SYSTEM_INSTRUCTION = f"""You are a Brand Strategist specializing in market research and trend analysis.
IMPORTANT: Today's date is {datetime.date.today().strftime("%B %d, %Y")}.
When conducting research, focus on current trends from {datetime.date.today().year}.
Use search queries like "[topic] trends {datetime.date.today().year}" for recent insights.
IMPORTANT: Your role is RESEARCH ONLY. You do NOT create campaign content, captions, or designs.
After providing research insights, your work is complete.
Your expertise:
- Identifying target audience insights and behaviors
- Analyzing competitor strategies
- Researching current social media trends
- Understanding platform algorithms and best practices
You have access to:
- google_search: Search the web for competitors, trends, and market insights
When given a campaign brief:
1. Use google_search to research the target audience's current interests
2. Search for and analyze 2-3 competitor brands
3. Identify 3-5 trending topics related to the product category
4. Provide high-level strategic insights - NOT specific campaign content
DO NOT create captions, copy, designs, or any campaign content.
Format your output as:
**Audience Insights:**
[Key behaviors and preferences based on research]
**Competitive Analysis:**
[What 2-3 competitors are doing - strengths and weaknesses]
**Trending Topics:**
[3-5 relevant trends to consider]
**Key Strategic Insights:**
[High-level themes and positioning opportunities]
"""
TODO 2 - Create the root_agent
Em seguida, substitua o root_agent incompleto por:
root_agent = Agent(
name="brand_strategist",
model=os.getenv("GEMINI_MODEL", "gemini-2.5-flash"),
instruction=SYSTEM_INSTRUCTION,
description="Brand strategist for market research, trend analysis, and competitive insights",
tools=[google_search],
)
Testar localmente com a interface da Web do ADK
Agora vamos testar o agente usando a interface da Web do ADK, uma interface de chat integrada para testar agentes antes da implantação na nuvem.
uv run adk web agents --allow_origins='*'
Você vai ver:
INFO: Started server process
INFO: Uvicorn running on http://localhost:8000
O servidor agora está sendo executado no Cloud Shell:
Para abrir no navegador, use a Visualização da Web:
- Procure a barra de ferramentas do Cloud Shell na parte de cima da página.
- Clique no ícone Visualização da Web (parece uma caixa com uma seta para cima, no canto superior direito da barra de ferramentas do Cloud Shell).
- Clique em "Alterar porta", insira
8000e clique em "Alterar e visualizar".
Uma nova guia do navegador será aberta com a interface da Web do ADK. Clique no menu suspenso Selecionar um agente no canto superior esquerdo. Todos os seus agentes vão aparecer:
Escolha brand_strategist para começar a testar:
Teste estes comandos
Na caixa de chat da interface da Web do ADK, tente:
Research the eco-friendly water bottle market for health-conscious millennialsWhat are the top Instagram trends in the wellness space in 2025?
O agente vai chamar a Pesquisa Google e retornar uma pesquisa estruturada com as seções "Insights do público-alvo", "Análise da concorrência" e "Assuntos em alta".
5. Criar o Copywriter: habilidades do ADK
Função:transformar pesquisas de marca em legendas do Instagram. O redator cria três variações de legenda com diferentes tons (inspirador, educativo, comunidade), cada uma com hashtags e uma CTA.
Conceito: habilidades do ADK
Uma abordagem simples incorporaria todo o conhecimento da plataforma (limites de caracteres, níveis de hashtags, fórmulas de legendas, exemplos de voz da marca) diretamente no comando do sistema. Isso funciona, mas aumenta cada solicitação com conteúdo que o agente só precisa ocasionalmente.
Com as habilidades do ADK (SkillToolset, introduzidas no ADK 1.25.0), é possível empacotar esse conhecimento em arquivos modulares com três níveis de carregamento:
- L1: frontmatter (
name+descriptionemSKILL.md): sempre disponível, usado para descoberta de habilidades - L2 - instruções (corpo de
SKILL.md): carregadas quando o agente aciona a habilidade - L3: recursos (arquivos
references/eassets/): carregados apenas quando o agente os lê explicitamente.
A instrução do sistema é reduzida a uma breve declaração de função mais "carregue a habilidade antes de escrever". Os detalhes da plataforma só entram na janela de contexto quando o agente realmente precisa deles.
A habilidade do redator publicitário está em agents/copywriter/skills/instagram-copywriting/:
skills/
instagram-copywriting/
SKILL.md ← L1 frontmatter (discovery) + L2 instructions (loaded on trigger)
references/
platform-guide.md ← L3: character limits, hashtag tiers, algorithm signals
caption-formulas.md ← L3: hook formulas, CTA patterns, full caption structures
assets/
brand-voice-examples.md ← L3: annotated real-world caption examples
Abra o arquivo diretamente no editor do Cloud Shell:
cloudshell edit agents/copywriter/agent.py
TODO 1 - Importe load_skill_from_dir e skill_toolset
Encontre o comentário # TODO 1: Import load_skill_from_dir and skill_toolset e adicione as duas importações:
from google.adk.skills import load_skill_from_dir
from google.adk.tools import skill_toolset
TODO 2 - Carregar a habilidade e criar um SkillToolset
Encontre os dois comentários abaixo das importações:
# TODO 2: Load the instagram-copywriting skill from the skills/ directory
# TODO 2: Create a SkillToolset with the loaded skill
Substitua por:
_instagram_skill = load_skill_from_dir(
pathlib.Path(__file__).parent / "skills" / "instagram-copywriting"
)
_copywriting_skills = skill_toolset.SkillToolset(skills=[_instagram_skill])
load_skill_from_dir lê SKILL.md e todos os arquivos em references/ e assets/. O SkillToolset envolve isso no formato aceito pelos agentes do ADK: um conjunto de ferramentas, não uma habilidade bruta.
TODO 3: registrar o conjunto de ferramentas com o agente
Encontre tools=[], # TODO 3: Add the SkillToolset here e substitua por:
tools=[_copywriting_skills],
Abra o arquivo de habilidade para ver como ele é estruturado:
cloudshell edit agents/copywriter/skills/instagram-copywriting/SKILL.md
Mantenha a interface da web do ADK em execução. Use o menu suspenso do agente para mudar para copywriter sem reiniciar o servidor.
Se ele não estiver em execução, inicie-o novamente:
uv run adk web agents --allow_origins='*'
Faça um teste:mude o menu suspenso para copywriter e envie:
You are writing captions for EcoFlow Smart Water Bottle targeting health-conscious millennials aged 25-35.
Audience insight: they prioritize sustainability, track health metrics, and share lifestyle content.
Competitor insight: Hydro Flask dominates with lifestyle branding; S'well leads on premium aesthetics.
Write 3 Instagram captions - one inspirational, one educational, one community-focused. Include 5 hashtags each and a CTA.
6. Criar o Designer: geração de imagens multimodais
Mantenha a interface da web do ADK em execução. Use o menu suspenso de agentes para trocar de agente sem reiniciar o servidor.
Função:crie conceitos visuais para cada legenda e gere as imagens usando a geração de imagens nativa do Gemini. O Designer gera exatamente um conceito visual por legenda, com um comando detalhado, estilo, paleta de cores, clima e formato do Instagram. Em seguida, ele chama imediatamente a ferramenta generate_image para produzir a imagem real e fazer upload dela no GCS.
Conceito: como conectar um agente de texto a um modelo de imagem usando uma ferramenta
O Designer é executado no gemini-3-flash-preview (o modelo de texto definido via GEMINI_MODEL em .env), mas a geração de imagens exige um modelo dedicado (gemini-3.1-flash-image-preview). Esse modelo de imagem não oferece suporte a chamadas de função, então não pode ser usado diretamente como um agente do ADK. Em vez disso, ele é envolvido em uma função Python simples e registrado como um FunctionTool.
Esse é o padrão para qualquer modelo ou API que o LLM não pode chamar diretamente: envolva em uma ferramenta, deixe o agente orquestrar quando chamar e receba um resultado estruturado.
Designer agent (text model)
│
│ decides visual concept, writes image prompt
▼
generate_image tool
│
│ calls gemini-3.1-flash-image-preview
│ uploads result to GCS
▼
{"status": "success", "gcs_uri": "gs://..."}
│
│ returned to agent, included in response
▼
Critic (receives gcs_uri, passes to Vertex AI for multimodal review)
Abra o arquivo diretamente no editor do Cloud Shell:
cloudshell edit agents/designer/image_gen_tool.py
A assinatura da função, a configuração do ambiente e a injeção de proporção são fornecidas. Siga as três tarefas TODO em ordem:
TODO 1 - Chamar o modelo de imagem do Gemini
Encontre o comentário # TODO 1 e substitua por:
client = genai.Client(vertexai=True, project=project_id, location=location)
response = client.models.generate_content(
model=image_model,
contents=prompt_with_aspect,
config=types.GenerateContentConfig(
response_modalities=["IMAGE", "TEXT"],
http_options=types.HttpOptions(
retry_options=types.HttpRetryOptions(
attempts=5, exp_base=2, initial_delay=30,
http_status_codes=[429, 500, 503, 504],
),
timeout=180_000,
),
),
)
TODO 2: extrair bytes de imagem da resposta
Encontre o comentário # TODO 2 e substitua por:
image_bytes = None
mime_type = "image/png"
for part in response.candidates[0].content.parts:
if part.inline_data is not None:
image_bytes = part.inline_data.data
mime_type = part.inline_data.mime_type or "image/png"
break
if not image_bytes:
return {"status": "error", "error": "Gemini returned no image data"}
TODO 3: fazer upload para o GCS e retornar o URI
Encontre o comentário # TODO 3 e substitua por:
ext = "jpg" if "jpeg" in mime_type else "png"
from google.cloud import storage
gcs_client = storage.Client(project=project_id)
bucket = gcs_client.bucket(bucket_name)
blob_name = f"campaign-images/{concept_name}-{uuid.uuid4().hex[:8]}.{ext}"
blob = bucket.blob(blob_name)
blob.upload_from_file(io.BytesIO(image_bytes), content_type=mime_type)
gcs_uri = f"gs://{bucket_name}/{blob_name}"
Faça um teste:mude o menu suspenso para designer e envie:
Create a visual concept and generate the image for an EcoFlow Smart Water Bottle Instagram post targeting health-conscious millennials.
Style: clean, modern, lifestyle-focused. Include a detailed prompt with color palette, mood, and format (1080x1080 or 1080x1350).
7. Criar o Critic - Structured Output
Função:garantir a qualidade do texto e dos recursos visuais antes de entregá-los ao gerente de projetos. O Critic avalia os dois entregáveis e retorna APPROVED ou NEEDS_REVISION com sugestões específicas. Quando os valores gcs_uri estão presentes na entrada, a ferramenta review_image é chamada para inspecionar visualmente cada imagem gerada antes da pontuação.
Conceito: quando usar um modelo Pydantic para a saída do Gemini
A regra é sobre quem consome a saída:
- O código Python o consome → use
response_schema+ Pydantic. O código não consegue lidar com ambiguidade. Por isso, você precisa de uma estrutura garantida para extrair campos de maneira confiável. - Um LLM consome → formato de texto + instrução do sistema são suficientes. Os LLMs entendem regras de formatação e toleram variações.
Em review_image, o código Python precisa de score, approval_status, what_works, issues e suggestions como valores tipados. A transmissão de response_schema=_GeminiReview restringe o Gemini no nível da API para retornar um JSON válido. model_validate_json() o analisa em um objeto tipado que seu código pode usar de maneira confiável.
class _GeminiReview(BaseModel):
score: int = Field(ge=1, le=10)
approval_status: Literal["APPROVED", "NEEDS_REVISION"]
what_works: str
issues: str
suggestions: str
Abra o arquivo diretamente no editor do Cloud Shell:
cloudshell edit agents/critic/image_review_tool.py
Os modelos Pydantic e o comando são fornecidos. Siga as três tarefas TODO em ordem:
TODO 1 - Create an image part from the GCS URI
Encontre o comentário # TODO 1 e substitua por:
image_part = types.Part.from_uri(file_uri=gcs_uri, mime_type=mime_type)
TODO 2: chamar o Gemini com um esquema de resposta estruturada
Encontre o comentário # TODO 2 e substitua por:
response = client.models.generate_content(
model=model,
contents=[image_part, prompt],
config=types.GenerateContentConfig(
response_schema=_GeminiReview,
response_mime_type="application/json",
),
)
TODO 3: analisar a resposta e retornar o resultado
Encontre o comentário # TODO 3 e substitua por:
review = _GeminiReview.model_validate_json(response.text)
return ImageReviewResult(status="success", concept_name=concept_name, **review.model_dump())
Faça um teste:mude o menu suspenso para critic e envie:
Review this Instagram caption for an eco-friendly water bottle brand targeting millennials:
"Hydrate smarter, live greener. 💧 Our EcoFlow bottle tracks your intake, keeps your drink cold for 24h, and never touches single-use plastic. Because what you drink from matters as much as what you drink. #EcoFlow #HydrationGoals #SustainableLiving #ZeroWaste #HealthyHabits - Shop link in bio."
Score it and indicate APPROVED or NEEDS_REVISION with specific feedback.
Verifique se a resposta contém **POSTS REVIEW:**, Status: APPROVED (ou NEEDS_REVISION) e **OVERALL ASSESSMENT:**. Se essas seções estiverem presentes, o Critic estará pronto para ser conectado ao orquestrador.
Quando terminar de testar todos os três agentes, pressione Ctrl+C para interromper o servidor.
8. Criar o agente do gerenciador de projetos com o MCP
O gerente de projetos apresenta um novo conceito: MCP (Protocolo de Contexto de Modelo).
Abra o arquivo:
cloudshell edit agents/project_manager/agent.py
Esse arquivo é mais complexo. Ele tem uma função create_project_manager_agent() com duas ramificações: uma sem o Notion (linhas do tempo somente de texto) e outra com o conjunto de ferramentas do MCP do Notion. Você vai preencher os dois.
O problema que o MCP resolve
Seu agente precisa chamar um serviço externo, por exemplo, criar uma página no Notion. Você pode escrever código Python que chama diretamente a API REST do Notion. Mas:
- Cada desenvolvedor escreve um wrapper diferente
- Você precisa manter o código de integração personalizado
- O LLM não sabe que a API existe, a menos que você descreva cada endpoint manualmente.
O MCP resolve isso definindo uma maneira padrão para que serviços externos exponham seus recursos como ferramentas que um LLM pode descobrir e chamar automaticamente.
O que é o MCP?
O MCP (Protocolo de Contexto de Modelo) é um padrão aberto (publicado pela Anthropic) para conectar agentes de IA a ferramentas e fontes de dados externas. Ele funciona como um adaptador universal.
Um servidor MCP é um pequeno programa que:
- Encapsula uma API externa (Notion, GitHub, bancos de dados, sistemas de arquivos etc.).
- Expõe essa API como uma lista de ferramentas tipadas e documentadas.
- Comunicação com o agente por um protocolo simples (stdio ou HTTP).
O agente se conecta ao servidor MCP, descobre automaticamente as ferramentas disponíveis e pode chamá-las como qualquer outra ferramenta. O LLM vê API-post-page(...) como uma função chamável.
A2A x MCP: qual é a diferença?
Esse é um ponto comum de confusão. Confira a principal diferença:
A2A | MCP | |
O que conecta | Agente ↔ Agente | Agente ↔ ferramenta/serviço externo |
O outro lado é | Outro agente de LLM | Um wrapper de API (sem LLM) |
Exemplo | O diretor de criação liga para o estrategista de marca | O gerente de projetos chama a API do Notion |
Protocolo | JSON-RPC por HTTPS | stdio ou fluxo HTTP |
Definido por | Anthropic |
Pense no seguinte:
- A2A = como os agentes conversam com outros agentes
- MCP = como os agentes conversam com ferramentas e serviços
Neste projeto, os dois são usados juntos:
Creative Director
│
│ (A2A) Brand Strategist ─── (google_search tool built into ADK)
│ (A2A) Copywriter
│ (A2A) Designer
│ (A2A) Critic
│ (A2A) Project Manager
│
│ (MCP) notion-mcp-server ──► Notion REST API
Como o MCP funciona neste projeto
Quando o agente é executado, o ADK inicia o notion-mcp-server como um processo filho. Esse processo expõe essas ferramentas diretamente ao LLM:
Ferramenta | O que faz? |
| Busca o esquema (nomes de propriedades, tipos, valores válidos) |
| Consulta páginas existentes |
| Cria uma página |
| Atualiza uma página existente. |
O LLM chama essas funções como qualquer outra. Ele não sabe que elas passam pelo MCP para a API REST do Notion em segundo plano.
Por que stdio? Por que não apenas HTTP?
O servidor do MCP é executado como um processo secundário do agente, comunicando-se por stdin/stdout. Isso significa que:
- Não é necessário ter uma porta de rede extra
- O ciclo de vida é gerenciado pelo agente (iniciado sob demanda, interrompido ao sair).
- Tudo é enviado em uma imagem Docker. Não há um serviço separado para implantação.
(Opcional) Ativar a integração com o Notion
Você pode pular toda esta seção. O agente Gerente de projetos sempre produz uma linha do tempo completa da campanha baseada em texto, com ou sem o Notion. Se você pular essa configuração, o agente vai voltar ao modo na memória e mostrar a linha do tempo como texto simples no chat. Nada vai quebrar. Você só não vai ver as tarefas aparecerem em um banco de dados do Notion. Vá direto para a tarefa 1 se quiser pular.
Se você tem uma conta do Notion e quer ver a integração do MCP em ação, conclua a configuração abaixo agora. Os TODOs a seguir fazem referência aos IDs do banco de dados do Notion, que é onde você os encontra.
Etapa 1: criar o banco de dados do Notion com base em um modelo
Usamos o modelo oficial Projetos e tarefas do Notion como nosso banco de dados. Escolhemos esse modelo propositadamente para demonstrar uma configuração complexa do mundo real. Ele tem vários tipos de propriedades (status, intervalos de datas, relações, seleções) com nomes não óbvios. Esse é um ótimo teste da descoberta dinâmica de esquema do MCP: o agente precisa descobrir os nomes exatos das propriedades no tempo de execução, em vez de tê-los codificados.
Clique no link abaixo para adicionar o modelo ao seu espaço de trabalho do Notion:
→ Adicionar o modelo "Projetos e tarefas" ao Notion

Depois de adicionados, você terá dois bancos de dados vinculados: Projetos e Tarefas. O modelo vem com entradas de exemplo. Exclua todas elas antes de continuar para que o agente comece com um espaço de trabalho limpo (selecione tudo → Excluir).
Etapa 2: criar uma integração do Notion
Crie a integração:
- Acesse notion.so/my-integrations
- Clique em New Integration → nomeie como
AI Creative Studio - Associe ao seu espaço de trabalho
- Clique em Configurar configurações e verifique se as funcionalidades Ler conteúdo, Atualizar conteúdo e Inserir conteúdo estão marcadas.

- Copie o token de integração interna (
ntn_...) e cole no arquivo.env:
NOTION_TOKEN=ntn_your-token-here
Conecte a integração aos seus bancos de dados:
- Abra a página do modelo que você acabou de duplicar e clique no banco de dados Projetos.
- Clique no menu
...(canto superior direito) → Conexões → Adicionar uma conexão → selecioneAI Creative Studio


- Faça o mesmo com o banco de dados Tarefas.
Receba os IDs do banco de dados:
- Clique no link do banco de dados Projetos para abrir. Ele será aberto em uma página própria com um URL como:
https://www.notion.so/9887b6a94f7f83f68f8581e038d1aaa4?v=2c37b6a94f7f838685f1086e312c7278

O ID do banco de dados é o primeiro UUID no URL, tudo antes de ?v=:
https://www.notion.so/{DATABASE_ID}?v=...
^^^^^^^^^^^^^^^^
9887b6a94f7f83f68f8581e038d1aaa4 ← this is your DATABASE_ID
- Faça o mesmo com o link do banco de dados Tarefas para receber o ID do banco de dados.
- Adicione os três valores ao seu
.env:
NOTION_TOKEN=ntn_your-token-here
NOTION_PROJECT_DATABASE_ID=9887b6a94f7f83f68f8581e038d1aaa4 # <-- your Projects DB ID
NOTION_TASKS_DATABASE_ID=your-tasks-db-id # <-- your Tasks DB ID
Etapa 3: instalar o servidor MCP do Notion
O Project Manager se conecta ao Notion usando o pacote oficial @notionhq/notion-mcp-server Node.js. Instale globalmente:
npm install -g @notionhq/notion-mcp-server@1.9.1
Verifique a instalação:
npm list -g @notionhq/notion-mcp-server
Saída esperada:
└── @notionhq/notion-mcp-server@1.9.1
notion-mcp-server: command not found
? Verifique se o Node.js está instalado (node --version) e se o bin global do npm está no seu PATH (export PATH=$PATH:$(npm bin -g)).
Etapa 4: verifique seu arquivo .env
Abra .env e confirme se todos os três valores do Notion estão definidos (você os adicionou na etapa 2):
cloudshell edit .env
NOTION_TOKEN=ntn_... # integration token
NOTION_PROJECT_DATABASE_ID=... # Projects database ID
NOTION_TASKS_DATABASE_ID=... # Tasks database ID
O agente do Project Manager detecta automaticamente essas variáveis na inicialização e ativa o conjunto de ferramentas do MCP do Notion.
Como a descoberta de esquema funciona
O Gerenciador de projetos usa a descoberta dinâmica de esquemas e nunca codifica nomes de propriedades do Notion:
Step 1: Call API-retrieve-a-database to discover exact property names
Step 2: Read the "properties" object in the response
Step 3: Use ONLY discovered property names (case-sensitive) in API calls
Step 4: For select/status fields, use only values from the options array
Isso significa que o agente se adapta automaticamente a qualquer estrutura de banco de dados do Notion. Renomeie suas propriedades para francês, árabe ou qualquer outra coisa, e o agente ainda vai funcionar.
TODO 1: escreva a instrução do sistema
O modelo inicial já calcula notion_section, uma string vazia quando o Notion não está configurado ou um bloco que contém os IDs do banco de dados e orientações completas da ferramenta quando está. Isso mantém as instruções do Notion totalmente fora do comando do agente que não usa o Notion. O LLM nunca vê regras para ferramentas que não tem.
Substitua o marcador de posição return por uma instrução real do sistema que use {notion_section}:
return f"""You are a Project Manager specializing in creative campaign execution.
Today's date is {datetime.date.today().strftime("%B %d, %Y")}.
Use this as the starting point for all timelines.
Your goal: create a complete project plan for the campaign.
{notion_section}
**Project Timeline:**
Phase 1: Strategy & Research | [date] → [date] | [key activities]
Phase 2: Content Creation | [date] → [date] | [key activities]
Phase 3: Review & Revision | [date] → [date] | [key activities]
Phase 4: Launch & Monitoring | [date] → [date] | [key activities]
**Task List:**
| Task | Owner | Deadline | Status |
[list each task with realistic deadlines from today; set Owner to TBD]
**Budget Breakdown:**
[by category with approximate allocations]
**Milestones:**
[3-5 key checkpoints with dates]
**Notion Status:**
[What happened - e.g. "Project created (ID: xxx), 8 tasks linked" or "Notion not configured - text timeline only"]
"""
TODO 2: agente sem Notion
Dentro de create_project_manager_agent(), na ramificação if not notion_token, substitua o agente incompleto por:
return Agent(
name="project_manager",
model=os.getenv("GEMINI_MODEL", "gemini-2.5-flash"),
generate_content_config=GENERATE_CONTENT_CONFIG,
instruction=get_system_instruction(),
description="Project manager that creates campaign timelines and task breakdowns",
)
TODO 3: agente com MCP do Notion
Observação:o arquivo inicial já contém um callback handle_notion_error pré-gravado acima de create_project_manager_agent(). Ele intercepta erros da API do Notion (400/404) e substitui os payloads de erro brutos por mensagens limpas e práticas para que o LLM possa se autocorrigir. Basta conectá-lo via after_tool_callback.
Primeiro, leia os dois IDs de banco de dados na parte de cima de create_project_manager_agent():
notion_token = os.getenv("NOTION_TOKEN")
notion_project_db_id = os.getenv("NOTION_PROJECT_DATABASE_ID")
notion_tasks_db_id = os.getenv("NOTION_TASKS_DATABASE_ID")
Em seguida, na ramificação else, crie o conjunto de ferramentas do MCP e o agente:
from google.adk.tools.mcp_tool import McpToolset, StdioConnectionParams
from mcp import StdioServerParameters
server_params = StdioServerParameters(
command="notion-mcp-server",
env={
"NOTION_TOKEN": notion_token,
"PATH": os.environ.get("PATH", ""),
}
)
notion_toolset = McpToolset(
connection_params=StdioConnectionParams(
server_params=server_params,
timeout=30.0
)
)
return Agent(
name="project_manager",
model=os.getenv("GEMINI_MODEL", "gemini-2.5-flash"),
generate_content_config=GENERATE_CONTENT_CONFIG,
after_tool_callback=handle_notion_error,
instruction=get_system_instruction(
project_database_id=notion_project_db_id,
tasks_database_id=notion_tasks_db_id,
),
description="Project manager with Notion integration for task tracking",
tools=[notion_toolset],
)
Prática recomendada:nunca falhe de forma definitiva em integrações opcionais. A linha do tempo de texto é sempre o principal item entregue, e o Notion é complementar.
Testar o gerenciador de projetos localmente com o ADK Web
uv run adk web agents --allow_origins='*'
Abra a Visualização da Web na porta 8000. Use o menu suspenso do agente para selecionar project_manager e tente:
Create a project plan for a GreenBrew organic coffee brand Instagram campaign.
Budget: $2,500. Launch in 3 weeks. Target audience: eco-conscious millennials aged 22-30.
Include phases, tasks with deadlines from today, and milestones.
Você vai ver um cronograma de texto estruturado com fases, lista de tarefas e marcos. Se as credenciais do Notion estiverem definidas em .env, o agente também vai criar entradas no seu espaço de trabalho do Notion.
9. Entender o protocolo A2A
Vamos usar o protocolo Agente-para-Agente (A2A) para conectar os diferentes agentes no nosso sistema. Vamos entender como isso funciona.
O problema que o A2A resolve
Imagine que você tem um agente de estratégia de marca criado com o ADK e um agente de redação publicitária criado com o LangGraph. Como uma pessoa liga para a outra? Elas falam linguagens internas diferentes. Você precisaria escrever um código de junção personalizado todas as vezes.
O A2A resolve isso definindo uma linguagem universal que qualquer agente, independente da estrutura, pode usar. É o HTTP do mundo dos agentes: um padrão que todos concordam para que qualquer pessoa possa conversar com qualquer pessoa.
O que é A2A?
O Agent-to-Agent (A2A) é um padrão aberto para comunicação entre agentes publicado pelo Google. Ele define:
- Como um agente se descreve: card do agente em
/.well-known/agent.json - Como outro agente o chama: JSON-RPC por HTTPS
- Como os resultados são retornados: streaming ou resposta única
O que torna o A2A flexível:
- Independente de linguagem: os agentes Python podem conversar com agentes TypeScript.
- Independente de framework: os agentes do ADK podem conversar com agentes do LangGraph ou do CrewAI
- Independente da infraestrutura: os agentes locais podem conversar com os agentes na nuvem
Como funciona: passo a passo
Creative Director Brand Strategist
│ │
│ 1. GET /.well-known/agent.json │
│ ────────────────────────────────►│
│ ◄──── agent card (name, url, │
│ skills, capabilities) ───│
│ │
│ 2. POST / │
│ {"method": "tasks/send", │
│ "params": {"message": ...}} │
│ ────────────────────────────────►│
│ │ LLM does
│ │ the work...
│ 3. streaming response chunks │
│ ◄───────────────────────────────│
│ ◄───────────────────────────────│
│ ◄───────────────────────────────│
Etapa 1:descoberta. O orquestrador busca o card do agente uma vez para saber o nome, o URL e os recursos dele.
Etapa 2:invocação. O orquestrador envia uma tarefa via POST JSON-RPC. O corpo contém a mensagem (o comando para o especialista).
Etapa 3: resposta: o especialista transmite a resposta em partes, assim como uma chamada normal de LLM.
O card do agente
Cada agente publica uma autodescrição em /.well-known/agent.json. É como um cartão de visitas: informa ao mundo o que o agente pode fazer e onde encontrá-lo:
{
"name": "brand_strategist",
"description": "Market research and competitive analysis",
"url": "https://brand-strategist-xyz.run.app",
"capabilities": { "streaming": true },
"skills": [
{
"id": "market_research",
"description": "Research target audiences, competitors, and trends"
}
]
}
O orquestrador lê esse card para criar o objeto RemoteA2aAgent. Não é necessário conhecimento codificado dos elementos internos do especialista.
Expor um agente via A2A no ADK
O to_a2a() encapsula qualquer agente do ADK em um app FastAPI compatível com A2A. Uma linha:
from google.adk.a2a.utils.agent_to_a2a import to_a2a
# root_agent = your normal ADK Agent(...)
a2a_app = to_a2a(root_agent, host=PUBLIC_HOST, port=PUBLIC_PORT, protocol=PROTOCOL)
uvicorn.run(a2a_app, host=HOST, port=PORT)
Isso cria automaticamente:
/.well-known/agent.json: o card do agente/: o endpoint JSON-RPC. Todas as solicitações de tarefas A2A vão para o caminho raiz.
10. Expor agentes como serviços A2A
Para expor agentes como serviços A2A, use a função utilitária to_a2a() do ADK.
Como o to_a2a() funciona
from google.adk.a2a.utils.agent_to_a2a import to_a2a
a2a_app = to_a2a(root_agent, host=PUBLIC_HOST, port=PUBLIC_PORT, protocol=PROTOCOL)
uvicorn.run(a2a_app, host=HOST, port=PORT)
O to_a2a() envolve seu agente do ADK em um aplicativo FastAPI que expõe automaticamente:
/.well-known/agent.json: o card do agente (nome, descrição, recursos)/a2a/{agent_name}: o endpoint JSON-RPC para receber tarefas.
O código de estrutura de cada agente já inclui um bloco __main__ que envolve o agente em um servidor A2A usando to_a2a(). Não é preciso escrever esse código, ele já está disponível.
Como entender a configuração de URL duplo
Quando você executa python agent.py, o bloco __main__ usa duas configurações de URL separadas:
# Where the server actually listens (network interface):
HOST = "0.0.0.0"
PORT = 8082 # Brand Strategist (others use 8083–8086 locally)
# What gets advertised in the agent card (the address other agents use to reach it):
PUBLIC_HOST = os.getenv("PUBLIC_HOST", "localhost")
PUBLIC_PORT = int(os.getenv("PUBLIC_PORT", str(PORT)))
PROTOCOL = os.getenv("PROTOCOL", "http")
a2a_app = to_a2a(root_agent, host=PUBLIC_HOST, port=PUBLIC_PORT, protocol=PROTOCOL)
uvicorn.run(a2a_app, host=HOST, port=PORT)
Ambiente |
|
|
Local |
|
|
Cloud Run |
|
|
Localmente, ambos apontam para a mesma máquina. No Cloud Run, o contêiner fica em escuta interna em 8080, mas o card do agente precisa anunciar o URL HTTPS público. Caso contrário, o diretor de criação não consegue entrar em contato com o especialista de fora do contêiner.
Inicie todos os cinco servidores A2A especializados.
Vamos executar todos os cinco especialistas como servidores A2A simultaneamente e testar o diretor de criação localmente apontando para eles.
Abra cinco terminais separados do Cloud Shell (clique no ícone + na barra de guias do terminal) e execute um agente por terminal.
O uv run ativa automaticamente o .venv. Não é necessário fazer source manual em cada terminal.
Terminal 1: estrategista de marca (porta 8082)
cd ~/ai-creative-studio/workshop/starter
PORT=8082 uv run agents/brand_strategist/agent.py
Terminal 2: redator publicitário (porta 8083)
cd ~/ai-creative-studio/workshop/starter
PORT=8083 uv run agents/copywriter/agent.py
Terminal 3: designer (porta 8084)
cd ~/ai-creative-studio/workshop/starter
PORT=8084 uv run agents/designer/agent.py
Terminal 4: Critic (porta 8085)
cd ~/ai-creative-studio/workshop/starter
PORT=8085 uv run agents/critic/agent.py
Terminal 5: gerente de projetos (porta 8086)
cd ~/ai-creative-studio/workshop/starter
PORT=8086 uv run agents/project_manager/agent.py
Definir URLs de localhost em .env
Em Terminal 6, atualize .env com os URLs do agente local para que o diretor de criação possa encontrá-los:
cd ~/ai-creative-studio/workshop/starter
sed -i \
-e 's|STRATEGIST_AGENT_URL=.*|STRATEGIST_AGENT_URL=http://localhost:8082|' \
-e 's|COPYWRITER_AGENT_URL=.*|COPYWRITER_AGENT_URL=http://localhost:8083|' \
-e 's|DESIGNER_AGENT_URL=.*|DESIGNER_AGENT_URL=http://localhost:8084|' \
-e 's|CRITIC_AGENT_URL=.*|CRITIC_AGENT_URL=http://localhost:8085|' \
-e 's|PM_AGENT_URL=.*|PM_AGENT_URL=http://localhost:8086|' \
.env
Inspecionar agentes com o A2A Inspector
O A2A Inspector é uma ferramenta de desenvolvedor de código aberto que usa o protocolo A2A de forma nativa. Ele permite se conectar diretamente a qualquer agente A2A em execução, ler o card do agente e enviar tarefas sem escrever código do cliente.
O que ela mostra:
- Card do agente: os metadados estruturados que seu agente anuncia, como nome, descrição, modos de entrada/saída compatíveis e URL do endpoint. É isso que o diretor de criação lê quando descobre um especialista.
- Interface de chat: envie qualquer mensagem para o agente pelo A2A e confira a resposta bruta. Você pode testar comandos isoladamente antes de conectar os agentes.
- Validação de protocolo: o inspetor verifica se o card do agente está em conformidade com a especificação A2A, mostrando campos ausentes ou respostas malformadas no início.
Por que isso é importante:quando você implanta no Cloud Run mais tarde, o diretor de criação descobre cada especialista buscando o card do agente em /.well-known/agent.json. Se o card estiver errado (URL inválido, recursos ausentes), o orquestrador falhará silenciosamente. Com ele, é possível detectar esses problemas localmente antes de qualquer implantação na nuvem.

O card do agente mostra a identidade e os recursos do especialista exatamente como outros agentes os veem.

Instalar e iniciar o inspetor
cd ~/ai-creative-studio/workshop
./setup_inspector.sh
A atualização .env é um comando único. Use o Terminal 6 para iniciar o inspetor:
cd ~/a2a-inspector
bash scripts/run.sh
Para abrir a interface do inspetor, use Visualização da Web → Alterar porta → digite 5001.
Conectar-se ao estrategista de marca
Insira http://localhost:8082 no campo de URL do inspetor e clique em Conectar. O inspetor busca o card do agente e mostra os metadados do especialista.

O que o card do agente informa
O card do agente é mais do que metadados. Ele é o contrato de capacidade total que o agente anuncia para a rede. Entre em contato com o gerente de projeto (http://localhost:8086) para ver o exemplo mais completo:
{
"name": "project_manager",
"description": "Project manager with Notion integration for task tracking",
"protocolVersion": "0.3.0",
"defaultInputModes": ["text/plain"],
"defaultOutputModes": ["text/plain"],
"skills": [
{
"id": "project_manager",
"name": "model",
"tags": ["llm"],
"description": "... full system instruction including today's date and Notion database IDs ..."
},
{
"id": "project_manager-API-post-page",
"name": "API-post-page",
"tags": ["llm", "tools"],
"description": "Notion | Create a page"
},
{
"id": "project_manager-API-retrieve-a-database",
"name": "API-retrieve-a-database",
"tags": ["llm", "tools"],
"description": "Notion | Retrieve a database"
}
]
}
Três coisas se destacam:
1. As ferramentas do MCP se tornam habilidades de A2A: todas as ferramentas do Notion a que o gerente de projetos tem acesso (API-post-page, API-retrieve-a-database etc.) são listadas como uma habilidade separada no card do agente. Qualquer outro agente na rede pode descobrir exatamente quais ferramentas esse agente pode usar sem ler nenhum código.
2. A instrução do sistema está incorporada: a primeira habilidade description contém a instrução completa do sistema, incluindo a data de hoje e os IDs do banco de dados do Notion. É assim que o diretor de criação sabe o que transmitir quando chama o gerente de projetos.
3. O URL é o endpoint ativo: o campo url é exatamente o que o RemoteA2aAgent usa quando o diretor de criação chama esse especialista. Se o URL no card estiver errado, o orquestrador não poderá acessar o agente.
Por isso, o inspetor é uma ferramenta de depuração eficiente: basta olhar o card do agente para saber se ele está em execução, quais ferramentas ele tem e se o endpoint está correto.
Enviar uma mensagem de teste
Depois de conectado, digite um comando no painel de chat e envie. O inspetor envia como uma tarefa A2A e transmite a resposta de volta, da mesma forma que o diretor de criação vai chamar esse agente em produção.

Aponte o inspetor para qualquer porta local (8082 a 8086) para testar cada especialista individualmente.
11. Criar o orquestrador do diretor de criação
O diretor de criação é o principal organizador. Ele lê URLs especializados de variáveis de ambiente, encapsula cada um como um RemoteA2aAgent e os expõe como AgentTools que o LLM pode chamar.
Verifique se os cinco agentes especializados ainda estão em execução (terminais 1 a 5 da etapa 10).
No Terminal 6 (o terminal do inspetor A2A), interrompa o inspetor com Ctrl+C.
Abra o arquivo:
cd ~/ai-creative-studio/workshop/starter
cloudshell edit agents/creative_director/agent.py
Este arquivo tem três TODOs. Siga as etapas na ordem.
PENDENTE 1: revise a instrução do sistema já escrita
A instrução do sistema está em prompt.py no mesmo diretório e é importada automaticamente:
from .prompt import SYSTEM_INSTRUCTION_TEMPLATE
Abra prompt.py para ler antes de continuar:
cloudshell edit agents/creative_director/prompt.py
É importante entender isso porque ele controla todo o comportamento de orquestração.
Por que o comando do orquestrador controla tudo
Abra prompt.py ao lado desta seção. Os exemplos abaixo fazem referência a partes específicas dela.
O comando em prompt.py não é apenas documentação, mas o plano de controle de todo o sistema. Um comando mal estruturado do orquestrador produz: agentes chamados fora de ordem, conteúdo gerado pelo orquestrador em vez de especialistas, fluxos de trabalho que continuam após falhas e contexto descartado silenciosamente entre agentes. Esses nove elementos evitam as falhas mais comuns:
Elemento 0: planeje primeiro, depois execute
Esse é o elemento mais importante. Antes de ligar para qualquer especialista, o orquestrador recebe instruções para gerar um plano numerado:
I'll create your campaign by coordinating the specialist agents in sequence:
1. Brand Strategist - develop positioning and audience insights
2. Copywriter - write captions using those insights
3. Visual Designer - create image prompts aligned with the copy
4. Critic - review and score the full package
5. Project Manager - build the timeline and task breakdown
Sem essa etapa, o LLM passa direto para as chamadas de ferramentas e perde o controle de onde está no fluxo de trabalho, principalmente depois de receber uma resposta longa de um especialista. Ao delinear o plano primeiro, o orquestrador sabe em qual etapa está, o que vem a seguir e como é uma execução completa. Se você pular essa etapa, o orquestrador vai parar no meio do fluxo de trabalho ou repetir etapas.
Elemento 1: definição explícita de função
❌ "You are a helpful creative assistant."
✅ "You orchestrate specialists. You do NOT write captions, designs, or timelines yourself."
Sem essa proibição explícita, o LLM às vezes pula a chamada de especialistas e gera conteúdo diretamente. Isso é mais rápido e ele "sabe" como fazer isso. A instrução precisa fazer isso errado.
Elemento 2: sintaxe de chamada de função com padrões incorretos listados
Mostrar apenas a sintaxe correta não é suficiente. O LLM pode gerar chamadas que parecem plausíveis, mas falham silenciosamente. O comando lista explicitamente o padrão correto e os que nunca devem ser usados:
✅ copywriter(request="...") ← correct
❌ print(copywriter(...)) ← breaks silently
❌ default_api.copywriter(...) ← breaks silently
❌ copywriter.run(...) ← breaks silently
❌ agents.copywriter(...) ← breaks silently
Listar os padrões errados explicitamente reduziu as chamadas de ferramentas malformadas em cerca de 95% na produção.
Elemento 3: execução sequencial detalhada etapa por etapa
a) Call the tool
b) Wait for tool_output
c) Verify the output is not an error
d) Confirm to the user: "✓ Brand Strategist complete"
e) Then move to the next agent
Sem as etapas (b) e (c), o LLM às vezes chama dois agentes simultaneamente ou presume o sucesso e continua antes de receber a resposta.
Elemento 4: diretivas de erro STOP, report, do not proceed
Nas primeiras versões, o orquestrador recebia um erro de um especialista, criava uma saída plausível para ele e continuava para o próximo agente. O usuário recebeu uma campanha completa criada com base em uma alucinação. A correção é explícita: PARE imediatamente. Informe o erro exato. Nunca continue.
Elemento 5: regras de transmissão de contexto
Os agentes remotos não têm histórico de conversas. Quando o orquestrador chama o redator publicitário por A2A, ele vê apenas a mensagem nessa única solicitação. Ele não tem ideia do que o estrategista de marca disse. O orquestrador precisa agrupar explicitamente as saídas anteriores em cada chamada subsequente:
copywriter(request="Create 3 posts for EcoFlow water bottle targeting millennials.
Use these insights from the Brand Strategist: [paste full strategist output here].
Create engaging captions with hashtags.")
A instrução diz explicitamente: "Agentes remotos NÃO têm memória compartilhada. Você precisa transmitir as saídas anteriores explicitamente". Sem isso, cada agente trabalha sem informações.
Elemento 6: classificação de solicitações simples e complexas
Nem toda solicitação precisa dos cinco agentes. O comando instrui o orquestrador a classificar a solicitação antes de planejar:
SIMPLE → one agent needed
"Research the eco-friendly water bottle market" → brand_strategist only
"Write 3 Instagram captions" → copywriter only
COMPLEX → all agents sequentially
"Create a complete campaign with timeline" → all 5 agents
Sem essa classificação, o orquestrador executaria todos os cinco agentes para cada solicitação, incluindo "me dê três ideias de postagem", adicionando latência e custo desnecessários.
Elemento 7: regras de comunicação: mostrar resultados completos, sem filtragem
O comando é explícito de que o orquestrador não pode resumir nem editar o que os especialistas retornam:
- DO NOT summarize unless the output exceeds 2000 words
- DO NOT filter or edit agent responses
- Show the user exactly what each specialist produced
- NEVER say results are ready unless you received them in tool_output
Sem isso, o orquestrador reescreve as saídas dos especialistas com as próprias palavras, perdendo detalhes, introduzindo erros e anulando o propósito de ter especialistas.
Elemento 8: conclusão do fluxo de trabalho: nunca pare antes da hora
Um modo de falha sutil, mas crítico: o orquestrador anuncia um plano de cinco etapas, conclui três e apresenta os resultados como se tudo estivesse pronto. O comando impede isso com uma checklist explícita que precisa ser aprovada antes que o orquestrador possa terminar:
✓ Did I announce a plan with N agents?
✓ Have I called ALL N agents from my plan?
✓ Did each agent respond successfully?
✓ Am I presenting complete results from ALL agents?
If any answer is NO → continue executing the remaining agents.
Isso impede que o orquestrador trate uma execução parcial como completa.
O ciclo de controle de qualidade
O fluxo de trabalho de revisão é a parte mais complexa do prompt.py. Abra a seção ## REVISION WORKFLOW e acompanhe.
Como funciona
Depois que o crítico responde, o diretor de criação não continua cegamente com o gerente de projeto. Ele lê a saída do Critic e ramifica:
Critic output
│
├── "All Approved: YES"
│ └──► proceed to Project Manager
│
└── "Status: NEEDS_REVISION"
│
├── posts fail → call copywriter again with feedback
├── visuals fail → call designer again with feedback
└── both fail → call copywriter, then designer
│
└──► revised output → Project Manager
(1 revision max per deliverable)
Isso é orientado por LLM, não por código
O codelab mencionado anteriormente diz que o orquestrador "analisa" a resposta do Critic. Não há código Python fazendo essa análise, nem regex, nem correspondência de strings. O diretor de criação é um LLM lendo a própria instrução. Essa instrução diz:
Look for "Status: NEEDS_REVISION" in the critic's response.
Posts need revision → call copywriter
Visuals need revision → call designer
O LLM lê essas strings exatas na saída do Critic e segue a ramificação. Por isso, o formato de crítica é inegociável: se o crítico escrever "precisa de algum trabalho" em vez de NEEDS_REVISION, o LLM não vai encontrar uma correspondência na instrução e vai pular a etapa de revisão sem avisar.
Como o contexto é encaminhado em uma chamada de revisão
A chamada de revisão segue a mesma regra de transmissão de contexto do Elemento 5. O orquestrador precisa incluir tudo explicitamente porque o redator não se lembra da primeira versão:
"I need you to revise the Instagram posts based on critic feedback.
ORIGINAL BRIEF:
[the original user request]
YOUR FIRST VERSION:
[the posts the copywriter created]
CRITIC FEEDBACK (Score: 6/10 - NEEDS_REVISION):
[the critic's specific suggestions]
Please revise the posts addressing this feedback while maintaining
the strengths the critic identified."
Sem a seção "SUA PRIMEIRA VERSÃO", o Copywriter escreveria do zero em vez de melhorar o que já produziu.
O limite de uma revisão e por que isso é importante
Após uma rodada de revisão, o orquestrador passa para o gerente de projetos, independente da pontuação. A instrução rastreia isso mentalmente:
After calling copywriter for revision once:
→ mark "copywriter_revised = true" in context
→ even if the critic still suggests changes, proceed to PM
Sem esse limite, o loop pode ser executado indefinidamente: o revisor sinaliza um problema → o redator revisa → o revisor sinaliza de novo → o redator revisa de novo. Cada rodada custa tokens e tempo. Uma revisão é suficiente para melhorar a qualidade sem risco de um ciclo descontrolado.
O que é transmitido ao gerente de projeto
O gerente de projeto sempre recebe as versões finais aprovadas, não os originais. Se houver revisões, o orquestrador vai passar a cópia e os recursos visuais revisados. Se tudo foi aprovado na primeira vez, ele passa essas informações diretamente. O PM nunca vê rascunhos rejeitados.
TODO 2 - Registre cada especialista como um RemoteA2aAgent + AgentTool
Encontre o comentário # TODO 2: For each specialist URL... e substitua por:
if strategist_url:
available_agents_list.append(
"- **brand_strategist**: Market research, competitor analysis, trend identification"
)
strategist_agent = RemoteA2aAgent(
name="brand_strategist",
description="Researches markets, competitors, and trends using Google Search",
agent_card=f"{strategist_url}/.well-known/agent.json",
)
agent_tools.append(AgentTool(agent=strategist_agent))
if copywriter_url:
available_agents_list.append(
"- **copywriter**: Instagram captions, hashtags, and CTAs"
)
copywriter_agent = RemoteA2aAgent(
name="copywriter",
description="Creates Instagram captions with hashtags and CTAs",
agent_card=f"{copywriter_url}/.well-known/agent.json",
)
agent_tools.append(AgentTool(agent=copywriter_agent))
if designer_url:
available_agents_list.append(
"- **designer**: Visual concepts and real images generated via Gemini (GCS URIs returned)"
)
designer_agent = RemoteA2aAgent(
name="designer",
description="Creates visual concepts and generates real images via Gemini, stored in GCS",
agent_card=f"{designer_url}/.well-known/agent.json",
)
agent_tools.append(AgentTool(agent=designer_agent))
if critic_url:
available_agents_list.append(
"- **critic**: Quality review with APPROVED/NEEDS_REVISION scoring"
)
critic_agent = RemoteA2aAgent(
name="critic",
description="Reviews campaign materials and returns structured quality feedback",
agent_card=f"{critic_url}/.well-known/agent.json",
)
agent_tools.append(AgentTool(agent=critic_agent))
if pm_url:
available_agents_list.append(
"- **project_manager**: Project timelines, task breakdowns, Notion integration"
)
pm_agent = RemoteA2aAgent(
name="project_manager",
description="Creates project timelines and task breakdowns, optionally in Notion",
agent_card=f"{pm_url}/.well-known/agent.json",
)
agent_tools.append(AgentTool(agent=pm_agent))
PENDENTE 3: unir em um app com compactação de contexto
Por que a compactação é necessária
Todas as mensagens em uma conversa (o comando do usuário, cada chamada de ferramenta e cada resposta de ferramenta) são adicionadas à janela de contexto que o LLM lê no próximo turno. Em um fluxo de trabalho de cinco agentes, isso se acumula rapidamente:
Turn 1: user prompt ~200 tokens
Turn 2: orchestrator plan ~300 tokens
Turn 3: brand_strategist tool_call ~150 tokens
Turn 4: brand_strategist tool_output ~1,500 tokens ← full research report
Turn 5: copywriter tool_call ~300 tokens ← must include strategist output
Turn 6: copywriter tool_output ~2,000 tokens ← 3 captions
Turn 7: designer tool_call ~500 tokens
Turn 8: designer tool_output ~1,500 tokens
...
No Agente 4 (Crítico), a janela de contexto contém a saída completa de todos os três agentes anteriores, geralmente de 8.000 a 12.000 tokens apenas em respostas de ferramentas. Mesmo com a grande janela de contexto do Gemini 2.5 Pro, a qualidade do raciocínio do orquestrador diminui à medida que ele precisa consultar um histórico cada vez maior. Sem compactação, fluxos de trabalho longos atingem limites práticos no Agent 4.
O que a compactação faz
Em vez de manter todos os eventos completos, o ADK chama periodicamente um LLM para resumir eventos mais antigos em uma representação compacta. Apenas o resumo de eventos anteriores e a saída completa do agente mais recente são mantidos no contexto.
Without compaction:
[full strategist output] + [full copywriter output] + [full designer output] + → Critic
With compaction (interval=3, overlap=1):
[summary of strategist + copywriter] + [full designer output] + → Critic
O resumo preserva os fatos essenciais (insights principais, legendas aprovadas, conceitos visuais) e descarta a formatação detalhada, o contexto repetido transmitido a cada agente e o raciocínio intermediário. O Critic ainda tem tudo o que precisa para avaliar, só que lê um resumo em vez de três relatórios completos.
O código
Encontre o comentário # TODO 3: Wrap the agent in an App... e substitua o marcador App(...) por:
from google.adk.apps import App
from google.adk.apps.app import EventsCompactionConfig
from google.adk.apps.llm_event_summarizer import LlmEventSummarizer
from google.adk.models import Gemini
compaction_config = EventsCompactionConfig(
summarizer=LlmEventSummarizer(llm=Gemini(model_id=os.getenv("GEMINI_MODEL", "gemini-2.5-flash"))),
compaction_interval=3, # Summarize after every 3 agent completions
overlap_size=1, # Keep the most recent agent's output in full
)
app = App(
name="creative_director",
root_agent=agent,
events_compaction_config=compaction_config,
plugins=[LoggingPlugin()],
)
return agent, app
compaction_interval=3: a compactação é acionada após cada três conclusões do agente. Para um pipeline de cinco agentes, isso significa que ele é acionado uma vez (após os agentes 1 a 3). Em seguida, o Critic e o PM veem um resumo dos agentes 1 a 3 mais a saída completa do agente anterior.
overlap_size=1: a resposta completa mais recente do agente é sempre mantida na íntegra, nunca resumida. Isso é importante porque o Critic precisa da saída completa do Designer, incluindo os valores gcs_uri, para carregar e analisar as imagens reais. Um resumo perderia esses URIs.
Como isso funciona em uma campanha completa:
Agent 1 (Strategist) → full context
Agent 2 (Copywriter) → full context
Agent 3 (Designer) → full context
↓ compaction fires: summarizes agents 1-2, keeps 3 in full
Agent 4 (Critic) → sees [summary of 1-2] + [full output of 3]
Agent 5 (PM) → sees [summary of 1-3] + [full output of 4]
Noções básicas sobre RemoteA2aAgent e AgentTool
RemoteA2aAgent("brand_strategist", agent_card=url)
│
│ wraps the remote service so ADK can call it
▼
AgentTool(agent=strategist_agent)
│
│ exposes it as a callable tool to the LLM
▼
Agent(tools=[...])
│
│ LLM calls tool("brand_strategist", message=...) when needed
▼
brand-strategist-xxxx.run.app ← actual HTTP A2A call happens here
O LLM decide quando chamar cada ferramenta com base na instrução do sistema e na solicitação do usuário. O orquestrador nunca chama agentes diretamente no código. Tudo é impulsionado pelo raciocínio do LLM.
Testar o Creative Director localmente
uv run adk web agents --allow_origins='*'
Abra a Visualização da Web na porta 8000. Use o menu suspenso do agente para selecionar creative_director e tente:
Research the eco-friendly water bottle market for health-conscious millennials
O diretor de criação vai encaminhar isso apenas para o estrategista de marca, e você vai receber uma resposta dele.
Para a campanha completa, tente o seguinte:
Create a complete Instagram campaign for SolarPack portable solar charger targeting
outdoor enthusiasts and digital nomads aged 22-35.
Budget $2,000, launch in 2 weeks.
Você vai ver o diretor de criação coordenar todos os cinco especialistas em sequência, com a saída de cada agente fluindo para o próximo.

Pare o Creative Director (Ctrl+C) antes de continuar. O inspetor A2A também usa a porta 8000.
Interrompa os cinco servidores especializados (Ctrl+C em cada terminal) quando terminar o teste local.
12. Implantar e testar os agentes especializados
Agora estamos prontos para implantar nossos agentes no Google Cloud. O Cloud Run é um ótimo serviço para implantar agentes. É sem servidor, escalonável e fácil de usar. Cada agente especialista é implantado como um serviço independente do Cloud Run.
Configuração da implantação
O Dockerfile de cada especialista segue este padrão:
FROM python:3.12-slim
WORKDIR /app
RUN apt-get update && apt-get install -y --no-install-recommends gcc curl
# Fast dependency install with uv
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
COPY pyproject.toml .
RUN uv sync --no-install-project --no-dev
COPY . .
RUN useradd -m -u 1000 appuser && chown -R appuser:appuser /app
USER appuser
ENV PYTHONUNBUFFERED=1 PORT=8080 HOST=0.0.0.0
EXPOSE 8080
CMD ["uv", "run", "python", "agent.py"]
Implantar todos os cinco especialistas em sequência
cd ~/ai-creative-studio/workshop/starter
source .env
uv run deploy/deploy_all_specialists.py
Esse script implanta todos os cinco agentes um de cada vez (~10 a 12 minutos no total). A implantação sequencial evita a cota de polling do Cloud Build (60 solicitações/minuto). Quando concluído, ele grava o URL do Cloud Run de cada agente de volta em .env.
Depois que o Designer é implantado, o script concede automaticamente à conta de serviço do Cloud Run roles/storage.objectCreator no seu bucket do GCS para que ele possa fazer upload das imagens geradas.
Se você configurou as credenciais do Notion em .env, o script também as armazena com segurança no Secret Manager (como notion-token, notion-project-db-id, notion-tasks-db-id) e as injeta no serviço Project Manager via --set-secrets em vez de variáveis de ambiente simples. Isso significa que o token nunca aparece na guia "Ambiente" do Cloud Run nem no histórico de comandos gcloud.
Verificar implantações
Quando a implantação for concluída, o script vai gravar automaticamente os URLs do Cloud Run de volta no .env, substituindo os URLs de localhost da etapa anterior:
source .env
echo "Deployed URLs:"
echo " Brand Strategist: $STRATEGIST_AGENT_URL"
echo " Copywriter: $COPYWRITER_AGENT_URL"
echo " Designer: $DESIGNER_AGENT_URL"
echo " Critic: $CRITIC_AGENT_URL"
echo " Project Manager: $PM_AGENT_URL"
O diretor de criação vai usar automaticamente esses URLs do Cloud Run quando forem implantados no ambiente de execução do agente na próxima etapa.
Verificar cartões de agente
Cada agente implantado expõe um card em /.well-known/agent.json. Busque-os para confirmar se tudo está ativo:
source .env
for agent_url in $STRATEGIST_AGENT_URL $COPYWRITER_AGENT_URL $DESIGNER_AGENT_URL $CRITIC_AGENT_URL $PM_AGENT_URL; do
echo "=== Agent Card: $agent_url ==="
curl -s "${agent_url}/.well-known/agent.json" | python3 -m json.tool | grep -E '"name"|"url"|"description"'
echo ""
done
Saída esperada para cada agente:
"name": "brand_strategist",
"url": "https://brand-strategist-xxxx.run.app",
"description": "Brand strategist for market research and competitive insights"
Teste com o A2A Inspector (Cloud Run)
O A2A Inspector já está instalado desde a etapa 10. Inicie-o:
cd ~/a2a-inspector
bash scripts/run.sh
Abra a Visualização na Web → Alterar porta → 5001. Insira o URL do Cloud Run no campo de conexão:
https://brand-strategist-xxxx.us-central1.run.app
Clique em Conectar. Não é necessário um token de autenticação, já que os serviços são implantados com --allow-unauthenticated.
O inspetor se conecta, valida o card do agente e permite que você converse de forma interativa por A2A.
Inspecionar agentes implantados no Cloud Run
Depois de implantar no Cloud Run, aponte o inspetor para o URL HTTPS público para verificar se a implantação na nuvem está funcionando:

O fluxo de trabalho é idêntico: cole o URL do Cloud Run, conecte e envie uma mensagem de teste. Se o card do agente carregar e o chat responder, o especialista foi implantado e está disponível.
13. Implantar o Creative Director no Agent Runtime
O orquestrador é implantado no tempo de execução do agente, que fornece estado de sessão gerenciado, escalonamento automático e rastreamento integrado.
Por que usar o Agent Runtime para o orquestrador?
Os cinco especialistas são implantados no Cloud Run, que é leve, sem estado e processa uma tarefa por vez. O diretor de criação tem requisitos diferentes:
Requisito | Por que isso é importante |
Estado da sessão | Um fluxo de trabalho com várias etapas leva mais de 45 segundos. O Agent Runtime mantém o estado da conversa entre as chamadas de ferramentas do orquestrador para que nada seja perdido no meio do pipeline. |
Carga variável | Às vezes, uma campanha por hora, às vezes, várias em paralelo. O tempo de execução do agente é reduzido a zero quando está inativo e é escalonado horizontalmente de forma automática. Você não paga por capacidade ociosa. |
Observabilidade | O Cloud Logging, o Cloud Monitoring e o Cloud Trace vêm integrados. É possível ver todas as chamadas A2A, todos os tokens usados e todos os picos de latência sem adicionar instrumentação. |
Fluxos de trabalho de longa duração | O Cloud Run tem um tempo limite de solicitação de 3.600 segundos. O Agent Runtime foi projetado para fluxos de trabalho que podem levar minutos, com novas tentativas gerenciadas e persistência de estado. |
O Cloud Run é a plataforma certa para especialistas em aplicativos sem estado. O Agent Runtime é a plataforma certa para o orquestrador com estado.
Implantar o orquestrador
cd ~/ai-creative-studio/workshop/starter
source .env
uv run deploy/deploy_orchestrator.py --action deploy
Isso leva de 5 a 10 minutos. Quando concluídos, o AGENT_ENGINE_ID e o AGENT_ENGINE_RESOURCE_NAME são salvos em .env.
source .env
echo "Agent Engine ID: $AGENT_ENGINE_ID"
echo "Resource: $AGENT_ENGINE_RESOURCE_NAME"
Como a implantação funciona
O client.agent_engines.create() empacota o objeto App, faz upload dele com as dependências e o implanta na infraestrutura gerenciada. Confira o que cada parâmetro faz:
import vertexai
from vertexai import Client, agent_engines
vertexai.init(project=PROJECT_ID, location=LOCATION, staging_bucket=STAGING_BUCKET)
# Wrap the App in an AdkApp adapter - enables tracing in Cloud Trace
adk_app = agent_engines.AdkApp(app=root_app, enable_tracing=True)
# Initialize client and deploy
client = Client(project=PROJECT_ID, location=LOCATION)
agent_engine_resource = client.agent_engines.create(
agent=adk_app,
config={
"staging_bucket": STAGING_BUCKET, # GCS bucket for packaging artifacts
"display_name": "Creative Director",
# Python packages installed in the managed runtime - pin for reproducibility
"requirements": [
"google-cloud-aiplatform[agent_engines]>=1.132.0,<2.0.0",
"google-adk[a2a]==1.31.1",
"google-genai>=1.70.0",
"google-cloud-storage>=2.10.0",
"python-dotenv>=1.0.0",
"pydantic>=2.0.0",
"cloudpickle>=3.0.0",
],
# Specialist URLs passed as env vars - the orchestrator reads these at runtime
"env_vars": {
"COPYWRITER_AGENT_URL": COPYWRITER_URL,
"DESIGNER_AGENT_URL": DESIGNER_URL,
"STRATEGIST_AGENT_URL": STRATEGIST_URL,
"CRITIC_AGENT_URL": CRITIC_URL,
"PM_AGENT_URL": PM_URL,
},
},
)
resource_name = agent_engine_resource.api_resource.name
agent_engine_id = resource_name.split("/")[-1]
O que acontece nos bastidores:
1. Agent Engine packages your App + requirements into a container
2. Uploads it to the staging bucket in your project
3. Deploys to managed compute (you never see or manage the VM)
4. Returns a resource name: projects/.../locations/.../reasoningEngines/<id>
5. That ID is saved to .env as AGENT_ENGINE_ID
Após a implantação, o orquestrador se conecta aos cinco especialistas do Cloud Run usando os URLs nas variáveis de ambiente.
- Elas são transmitidas por
.envantes da execução do script de implantação.
14. Veicular uma campanha completa
Todo o sistema é implantado. Execute uma campanha completa no playground do Agent Runtime.
Abra o playground do Agent Runtime
- Acesse https://console.cloud.google.com/agent-platform/runtimes. Você também pode acessar o Agent Runtime em Plataforma de agentes > Agentes > Implantações.
- Selecione o ambiente de execução do agente implantado (
creative-director). - Clique em Playground na barra lateral esquerda.
- Clique em Nova sessão para abrir uma conversa.
Veicular uma campanha completa
Cole este resumo no chat e envie:
Create a complete Instagram campaign for:
- Product: EcoFlow Smart Water Bottle (tracks hydration, keeps drinks cold 24h)
- Target Audience: Health-conscious millennials, 25-35 years old
- Platform: Instagram
- Goal: Brand awareness + drive website traffic
- Brand Voice: Motivational, clean, science-backed
- Budget: $3,000
- Timeline: Launch in 2 weeks
O diretor de criação vai executar todos os cinco agentes em sequência:
- Estrategista de marca: pesquisa de mercado, análise da concorrência, insights sobre público-alvo
- Redator → 3 postagens no Instagram com legendas, hashtags e CTAs
- Designer → conceitos visuais + imagens reais geradas pelo Gemini (URIs do GCS) para cada postagem
- Crítica → revisão de qualidade com pontuações APROVADO / PRECISA_DE_REVISÃO
- (Revisão, se necessário) → O redator ou designer foi chamado novamente com feedback
- Gerente de projetos → cronograma de duas semanas, detalhamento de tarefas, alocação de orçamento

Testar o roteamento de um único agente
Envie essa solicitação mais curta em uma nova sessão:
Research the luxury skincare market - top brands and trends in 2025
O diretor de criação encaminha isso apenas para o estrategista de marca. Nenhum outro agente é chamado. Essa é a lógica de classificação de solicitações da instrução do sistema funcionando corretamente.
Inspecionar rastreamentos de execução
Ainda no console:
- Clique em Rastreamentos na barra lateral esquerda (ao lado de Playground).
- Em Visualização de rastreamento, selecione o rastreamento da sessão que você acabou de executar.
- Expanda a árvore de rastreamento para ver cada chamada de agente, as entradas/saídas, a latência e o uso de tokens.
Cada chamada de A2A para um especialista aparece como um intervalo separado. Você pode ver exatamente qual contexto o diretor de criação passou para cada agente e o que ele recebeu de volta.
Opcional: executar no terminal
Você também pode executar a campanha de forma programática usando o script run_campaign.py, que já está incluído no starter.
cd ~/ai-creative-studio/workshop/starter
uv run run_campaign.py
15. Limpeza
Limpe os recursos do Google Cloud para evitar cobranças contínuas.
Execute o script de encerramento. Ele lê seu .env e exclui tudo o que foi criado durante este codelab:
bash deploy/teardown_gcp.sh
O script mostra exatamente o que será excluído e pede confirmação antes de fazer qualquer coisa:
Recurso | O que é excluído |
Serviços do Cloud Run | estrategista de marca, redator, designer, crítico, gerente de projetos |
Agent Runtime | Mecanismo de raciocínio do diretor de criação + todas as sessões |
Artifact Registry |
|
Buckets do GCS |
|
Secret Manager |
|
Verificar se tudo foi removido
gcloud run services list --region=us-central1
gcloud storage buckets list --project=$GCP_PROJECT_ID
Saída esperada: listas vazias ou apenas seus próprios recursos preexistentes.
16. Resumo
Parabéns! Você criou e implantou um sistema de IA multiagente de nível de produção no Google Cloud.
O que você criou
Agente | Capacidade | Implantação |
Estrategista de marca | Pesquisa de mercado pela Pesquisa Google | Cloud Run |
Copywriter | Criação de legendas para o Instagram | Cloud Run |
Designer | Geração de imagens com upload do Gemini + GCS | Cloud Run |
Crítico | Avaliação de qualidade com pontuação | Cloud Run |
Gerente de projetos | Cronograma + MCP do Notion | Cloud Run |
Diretor de criação | Orquestração completa via A2A | Agent Runtime |
Principais padrões aprendidos
- ADK
Agent: defina um agente de LLM com uma instrução e ferramentas opcionais adk web: execute e teste qualquer agente do ADK localmente com uma interface de chat integradaSkillToolset: empacota o conhecimento reutilizável em arquivos modulares carregados sob demanda.FunctionTool: encapsula qualquer função Python (ou modelo externo) como uma ferramenta de agente chamável.to_a2a(): expõe qualquer agente do ADK como um serviço HTTPS compatível com A2A.RemoteA2aAgent+AgentTool: orquestrar agentes remotos como ferramentas chamáveisMcpToolset: conecte-se a serviços externos via servidores stdio do MCP.EventsCompactionConfig: como lidar com limites de tokens em fluxos de trabalho multiagente longos- Saída estruturada da crítica: controle de qualidade legível por máquina com revisão automática
- Cloud Run: implante agentes em contêineres em grande escala
- Agent Runtime: orquestradores de host com sessões gerenciadas e rastreamento.
Próximas etapas
- Adicionar a edição de imagens em várias etapas ao Designer usando a capacidade de edição do
gemini-3.1-flash-image-preview - Adicionar autenticação do IAM aos serviços do Cloud Run (remover
--allow-unauthenticated) - Substituir um especialista por um agente LangGraph ou CrewAI: o A2A é independente de framework
- Adicione o feedback do usuário como uma ferramenta para que os participantes possam classificar e iterar nas saídas
- Conheça o rastreamento do tempo de execução do agente no console do Cloud