1. Introdução
Neste laboratório, você vai além dos chatbots simples e cria um sistema multiagente distribuído.
Embora um único LLM possa responder a perguntas, a complexidade do mundo real geralmente exige funções especializadas. Você não pede para o engenheiro de back-end projetar a interface nem para o designer otimizar as consultas de banco de dados. Da mesma forma, podemos criar agentes de IA especializados que se concentram em uma tarefa e se coordenam para resolver problemas complexos.
Você vai criar um sistema de criação de cursos que consiste em:
- Agente de pesquisa: usa o google_search para encontrar informações atualizadas.
- Agente de avaliação: critica a pesquisa em relação à qualidade e integridade.
- Agente do Content Builder: transformar a pesquisa em um curso estruturado.
- Agente de orquestração: gerencia o fluxo de trabalho e a comunicação entre esses especialistas.
O que você vai aprender
- Defina um agente que usa ferramentas (pesquisador) e pode pesquisar na Web.
- Implemente a saída estruturada com Pydantic para o juiz.
- Conecte-se a agentes remotos usando o protocolo Agente-para-Agente (A2A).
- Construa um LoopAgent para criar um ciclo de feedback entre o pesquisador e o juiz.
- Execute o sistema distribuído localmente usando o ADK.
- Implante o sistema multiagente no Google Cloud Run.
- Usar um modelo da Gemma em uma GPU do Cloud Run para o agente do criador de conteúdo.
O que é necessário
- Um navegador da web, como o Chrome
- Tenha um projeto do Google Cloud com o faturamento ativado.
2. Princípios de arquitetura e orquestração
Primeiro, vamos entender como esses agentes trabalham juntos. Estamos criando um pipeline de criação de cursos.
O design do sistema

Orquestração com agentes
Os agentes padrão (como o Pesquisador) fazem o trabalho. Os agentes orquestradores (como LoopAgent ou SequentialAgent) gerenciam outros agentes. Elas não têm ferramentas próprias. A "ferramenta" delas é a delegação.
LoopAgent: funciona como um loopwhileno código. Ele executa uma sequência de agentes repetidamente até que uma condição seja atendida (ou o número máximo de iterações seja alcançado). Usamos isso para o ciclo de pesquisa:- O Pesquisador encontra informações.
- O juiz faz uma crítica.
- Se o Judge disser "Fail", o EscalationChecker vai permitir que o loop continue.
- Se Judge disser "Pass", o EscalationChecker vai interromper o loop.
SequentialAgent: funciona como uma execução de script padrão. Ele executa agentes um após o outro. Usamos isso para o pipeline de alto nível:- Primeiro, execute o Ciclo de pesquisa até que ele termine com bons dados.
- Em seguida, execute o Criador de conteúdo (para escrever o curso).
Ao combinar esses elementos, criamos um sistema robusto que pode se autocorrigir antes de gerar a saída final.
3. Configuração
Configurar o projeto
Criar um projeto do Google Cloud
- No console do Google Cloud, na página do seletor de projetos, selecione ou crie um projeto na nuvem do Google Cloud.
- Verifique se o faturamento está ativado para seu projeto do Cloud. Saiba como verificar se o faturamento está ativado em um projeto.
Iniciar o Cloud Shell
O Cloud Shell é um ambiente de linha de comando executado no Google Cloud que vem pré-carregado com as ferramentas necessárias.
- Clique em Ativar o Cloud Shell na parte de cima do console do Google Cloud.
- Depois de se conectar ao Cloud Shell, verifique sua autenticação:
gcloud auth list - Confirme se o projeto está configurado:
gcloud config get project - Se o projeto não estiver definido como esperado, faça o seguinte:
export PROJECT_ID=<YOUR_PROJECT_ID> gcloud config set project $PROJECT_ID
Configuração do ambiente
- Abra o Cloud Shell: clique no ícone Ativar o Cloud Shell no canto superior direito do console do Google Cloud.
Acessar o código inicial
- Clone o repositório inicial no seu diretório principal:
Clone apenas o código necessário para este codelab na pasta de demonstrações do DevRel do Google Cloud.cd ~ Acesse a pasta que contém o código deste codelab.git clone --depth 1 --filter=blob:none --sparse https://github.com/GoogleCloudPlatform/devrel-demos.git temp-repo && cd temp-repo && git sparse-checkout set agents/multi-agent-system && cd .. && mv temp-repo/agents/multi-agent-system . && rm -rf temp-repocd multi-agent-system - Ativar APIs: execute o seguinte comando para ativar os serviços do Google Cloud necessários:
gcloud services enable \ run.googleapis.com \ artifactregistry.googleapis.com \ cloudbuild.googleapis.com \ aiplatform.googleapis.com \ compute.googleapis.com - Abra essa pasta no editor.
cloudshell edit .
Configurar ambiente
- Configure as variáveis de ambiente.Vamos criar um arquivo
.envpara armazenar essas variáveis e facilitar a recarga delas se a sessão for desconectada.cat <<EOF > .env export GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project) export GOOGLE_CLOUD_LOCATION=europe-west4 export GOOGLE_GENAI_USE_VERTEXAI=true EOF - Extraia as variáveis de ambiente:
source .env
4. 🕵️ O agente de pesquisa

O Pesquisador é um especialista. A única função dele é encontrar informações. Para isso, ele precisa de acesso a uma ferramenta: a Pesquisa Google.
Por que separar o pesquisador?
Análise detalhada:por que não ter apenas um agente para fazer tudo?
Agentes pequenos e focados são mais fáceis de avaliar e depurar. Se a pesquisa for ruim, itere no comando do pesquisador. Se a formatação do curso estiver ruim, faça iterações no Content Builder. Em um comando monolítico "faça tudo", corrigir uma coisa geralmente quebra outra.
- Se você estiver trabalhando no Cloud Shell, execute o seguinte comando para abrir o editor do Cloud Shell:
cloudshell workspace . - Abra
agents/researcher/agent.py. - Analise o código a seguir, que define o agente
researcher:# ... existing imports ... # Define the Researcher Agent researcher = Agent( name="researcher", model=MODEL, description="Gathers information on a topic using Google Search.", instruction=""" You are an expert researcher. Your goal is to find comprehensive and accurate information on the user's topic. Use the `google_search` tool to find relevant information. Summarize your findings clearly. If you receive feedback that your research is insufficient, use the feedback to refine your next search. """, tools=[google_search], ) root_agent = researcher
Conceito principal: uso de ferramentas
Observe que transmitimos tools=[google_search]. O ADK lida com a complexidade de descrever essa ferramenta para o LLM. Quando o modelo decide que precisa de informações, ele gera uma chamada de ferramenta estruturada, o ADK executa a função Python google_search e envia o resultado de volta ao modelo.
5. ⚖️ O agente Judge

O pesquisador se esforça, mas os LLMs podem ser preguiçosos. Precisamos de um juiz para analisar o trabalho. O juiz aceita a pesquisa e retorna uma avaliação estruturada de aprovação/reprovação.
Resposta estruturada
Análise detalhada:para automatizar fluxos de trabalho, precisamos de resultados previsíveis. Uma avaliação de texto confusa é difícil de analisar de forma programática. Ao aplicar um esquema JSON (usando Pydantic), garantimos que o juiz retorne um booleano pass ou fail em que nosso código pode agir de maneira confiável.
- Abra
agents/judge/agent.py. - Analise o código a seguir, que define o esquema
JudgeFeedbacke o agentejudge.# 1. Define the Schema class JudgeFeedback(BaseModel): """Structured feedback from the Judge agent.""" status: Literal["pass", "fail"] = Field( description="Whether the research is sufficient ('pass') or needs more work ('fail')." ) feedback: str = Field( description="Detailed feedback on what is missing. If 'pass', a brief confirmation." ) # 2. Define the Agent judge = Agent( name="judge", model=MODEL, description="Evaluates research findings for completeness and accuracy.", instruction=""" You are a strict editor. Evaluate the 'research_findings' against the user's original request. If the findings are missing key info, return status='fail'. If they are comprehensive, return status='pass'. """, output_schema=JudgeFeedback, # Disallow delegation because it should only output the schema disallow_transfer_to_parent=True, disallow_transfer_to_peers=True, ) root_agent = judge
Conceito principal: restringir o comportamento do agente
Definimos disallow_transfer_to_parent=True e disallow_transfer_to_peers=True. Isso obriga o juiz a apenas retornar o JudgeFeedback estruturado. Ele não pode decidir "conversar" com o usuário ou delegar a outro agente. Isso o torna um componente determinista no nosso fluxo lógico.
6. ✍️ O agente do Criador de conteúdo

O Criador de conteúdo é o escritor criativo. Ela pega a pesquisa aprovada e a transforma em um curso. Ele usa um modelo Gemma disponibilizado pelo Cloud Run.
Primeiro, vamos analisar o serviço do Cloud Run que hospeda o modelo.
- Abrir
ollama_backend/Dockerfile - Aqui, você pode ver como o Dockerfile usa uma imagem do Ollama, detecta solicitações na porta 8080 e armazena o modelo solicitado em uma pasta /model.
FROM ollama/ollama:latest # Listen on all interfaces, port 8080 (Cloud Run default) ENV OLLAMA_HOST 0.0.0.0:8080 # Store model weight files in /models ENV OLLAMA_MODELS /models
⚙️ Ao implantar, você vai definir as seguintes configurações:
- GPU: NVIDIA L4 escolhida pela excelente relação preço-performance para cargas de trabalho de inferência. A L4 oferece 24 GB de memória de GPU e operações de tensor otimizadas, o que a torna ideal para modelos de 270 milhões de parâmetros, como o Gemma.
- Memória: 16 GB de memória do sistema para lidar com o carregamento de modelos, operações CUDA e gerenciamento de memória do Ollama
- CPU: 8 núcleos para processamento ideal de E/S e tarefas de pré-processamento
- Simultaneidade: quatro solicitações por instância equilibram a capacidade de processamento com o uso da memória da GPU.
- Tempo limite: 600 segundos para acomodar o carregamento inicial do modelo e a inicialização do contêiner
Agora vamos analisar o agente de criação do conteúdo que usa o modelo Gemma.
- Abra
agents/content_builder/agent.py. - Analise o código a seguir, que define o agente
content_builder.
# the `ollama-gemma-gpu` Cloud Run service URL which hosts the Gemma model
target_url = os.environ.get("OLLAMA_API_BASE")
# ... existing code ...
# (Note: We use 'ollama/gemma3:270m' to align with ADK's expected prefix)
gemma_model_name = os.environ.get("GEMMA_MODEL_NAME", "gemma3:270m")
model = LiteLlm(
model=f"ollama_chat/{gemma_model_name}",
api_base=target_url
)
# 5. Define the Agent
content_builder = Agent(
name="content_builder",
model=model,
description="Transforms research findings into a structured course.",
instruction="""
You are an expert course creator.
Take the approved 'research_findings' and transform them into a well-structured, engaging course module.
**Formatting Rules:**
1. Start with a main title using a single `#` (H1).
2. Use `##` (H2) for main section headings. These will be used for the Table of Contents.
3. Use `###` (H3) for sub-sections within main sections.
4. Use bullet points and clear paragraphs.
5. Maintain a professional but engaging tone.
**Structure Requirements:**
- Begin with a brief Introduction section explaining what the learner will gain.
- Organize content into 3-5 main sections with clear headings.
- Include Key Takeaways at the end as a bulleted summary.
- Keep each section focused and concise.
Ensure the content directly addresses the user's original request.
Do not include any preamble or explanation outside the course content itself.
""",
)
root_agent = content_builder
Conceito principal: propagação de contexto
Você pode se perguntar: "Como o Criador de conteúdo sabe o que o Pesquisador encontrou?" No ADK, os agentes em um pipeline compartilham um session.state. Mais tarde, no Orchestrator, vamos configurar o pesquisador e o avaliador para salvar as saídas nesse estado compartilhado. O comando do Content Builder tem acesso a esse histórico.
7. 🎻 O Orchestrator

O Orchestrator é o gerente da nossa equipe multiagente. Ao contrário dos agentes especializados (Pesquisador, Avaliador, Criador de conteúdo) que realizam tarefas específicas, o trabalho do Orquestrador é coordenar o fluxo de trabalho e garantir que as informações fluam corretamente entre eles.
🌐 A arquitetura: Agent-to-Agent (A2A)

Neste laboratório, vamos criar um sistema distribuído. Em vez de executar todos os agentes em um único processo Python, implantamos como microsserviços independentes. Isso permite que cada agente seja escalonado de forma independente e falhe sem falhar em todo o sistema.
Para isso, usamos o protocolo Agent-to-Agent (A2A).
O protocolo A2A
Análise detalhada:em um sistema de produção, os agentes são executados em servidores diferentes (ou até mesmo em nuvens diferentes). O protocolo A2A cria uma maneira padrão para que eles se descubram e conversem entre si por HTTP. RemoteA2aAgent é o cliente do ADK para esse protocolo.
- Abra
agents/orchestrator/agent.py. - Analise como o código a seguir define as conexões.
# ... existing code ... # Connect to the Researcher (Localhost port 8001) researcher_url = os.environ.get("RESEARCHER_AGENT_CARD_URL", "http://localhost:8001/a2a/agent/.well-known/agent-card.json") researcher = RemoteA2aAgent( name="researcher", agent_card=researcher_url, description="Gathers information using Google Search.", # IMPORTANT: Save the output to state for the Judge to see after_agent_callback=create_save_output_callback("research_findings"), # IMPORTANT: Use authenticated client for communication httpx_client=create_authenticated_client(researcher_url) ) # Connect to the Judge (Localhost port 8002) judge_url = os.environ.get("JUDGE_AGENT_CARD_URL", "http://localhost:8002/a2a/agent/.well-known/agent-card.json") judge = RemoteA2aAgent( name="judge", agent_card=judge_url, description="Evaluates research.", after_agent_callback=create_save_output_callback("judge_feedback"), httpx_client=create_authenticated_client(judge_url) ) # Content Builder (Localhost port 8003) content_builder_url = os.environ.get("CONTENT_BUILDER_AGENT_CARD_URL", "http://localhost:8003/a2a/agent/.well-known/agent-card.json") content_builder = RemoteA2aAgent( name="content_builder", agent_card=content_builder_url, description="Builds the course.", httpx_client=create_authenticated_client(content_builder_url) )
8. 🛑 O verificador de encaminhamento
Um loop precisa de uma maneira de parar. Se o juiz disser "Aprovado", queremos sair do loop imediatamente e passar para o Content Builder.
Lógica personalizada com BaseAgent
Análise detalhada:nem todos os agentes usam LLMs. Às vezes, você precisa de uma lógica simples do Python. BaseAgent permite definir um agente que apenas executa código. Nesse caso, verificamos o estado da sessão e usamos EventActions(escalate=True) para sinalizar a interrupção de LoopAgent.
- Ainda em
agents/orchestrator/agent.py. - Analise o feedback do juiz e siga para a próxima etapa quando estiver pronto.
class EscalationChecker(BaseAgent): """Checks the judge's feedback and escalates (breaks the loop) if it passed.""" async def _run_async_impl( self, ctx: InvocationContext ) -> AsyncGenerator[Event, None]: # Retrieve the feedback saved by the Judge feedback = ctx.session.state.get("judge_feedback") print(f"[EscalationChecker] Feedback: {feedback}") # Check for 'pass' status is_pass = False if isinstance(feedback, dict) and feedback.get("status") == "pass": is_pass = True # Handle string fallback if JSON parsing failed elif isinstance(feedback, str) and '"status": "pass"' in feedback: is_pass = True if is_pass: # 'escalate=True' tells the parent LoopAgent to stop looping yield Event(author=self.name, actions=EventActions(escalate=True)) else: # Continue the loop yield Event(author=self.name) escalation_checker = EscalationChecker(name="escalation_checker")
Conceito principal: fluxo de controle via eventos
Os agentes se comunicam não apenas com texto, mas também com eventos. Ao gerar um evento com escalate=True, esse agente envia um sinal para o pai dele (o LoopAgent), que é programado para capturar esse sinal e encerrar o loop.LoopAgent
9. 🔁 O ciclo de pesquisa

Precisamos de um ciclo de feedback: Pesquisa -> Avaliação -> (Falha) -> Pesquisa -> ...
- No arquivo
agents/orchestrator/agent.py. - Confira como o código a seguir define a definição de
research_loop.research_loop = LoopAgent( name="research_loop", description="Iteratively researches and judges until quality standards are met.", sub_agents=[researcher, judge, escalation_checker], max_iterations=3, )
Conceito principal: LoopAgent
O LoopAgent passa pelos sub_agents em ordem.
researcher: encontra dados.judge: avalia dados.escalation_checker: decide se é necessárioyield Event(escalate=True). Seescalate=Trueacontecer, o loop será interrompido antes. Caso contrário, ele será reiniciado no pesquisador (atémax_iterations).
10. 🔗 O pipeline final

Resumindo...
- No arquivo
agents/orchestrator/agent.py. - Revise como o
root_agenté definido na parte de baixo do arquivo.root_agent = SequentialAgent( name="course_creation_pipeline", description="A pipeline that researches a topic and then builds a course from it.", sub_agents=[research_loop, content_builder], )
Conceito principal: composição hierárquica
Observe que research_loop é um agente (um LoopAgent). Ele é tratado como qualquer outro subagente no SequentialAgent. Essa capacidade permite criar lógicas complexas aninhando padrões simples (loops dentro de sequências, sequências dentro de roteadores etc.).
11. 🚀 Implantar no Cloud Run
Vamos implantar cada agente como um serviço separado no Cloud Run, incluindo um serviço do Cloud Run para a interface do criador de cursos e um serviço do Cloud Run usando GPUs para o modelo Gemma.
Como entender a configuração da implantação
Ao implantar agentes no Cloud Run, transmitimos várias variáveis de ambiente para configurar o comportamento e a conectividade deles:
GOOGLE_CLOUD_PROJECT: garante que o agente use o projeto correto do Google Cloud para geração de registros e chamadas da Vertex AI.GOOGLE_GENAI_USE_VERTEXAI: informa à estrutura do agente (ADK) para usar a Vertex AI na inferência de modelos em vez de chamar as APIs Gemini diretamente.[AGENT]_AGENT_CARD_URL: é crucial para o Orchestrator. Ele informa ao orquestrador onde encontrar os agentes remotos. Ao definir isso como o URL implantado do Cloud Run (especificamente o caminho do card do agente), permitimos que o orquestrador descubra e se comunique com o pesquisador, o avaliador e o criador de conteúdo pela Internet.
Para implantar todos os agentes nos serviços do Cloud Run, execute o script a seguir.
Primeiro, verifique se o script é executável.
chmod u+x ~/multi-agent-system/deploy.sh
Observação: isso vai levar vários minutos para ser executado, já que cada serviço é implantado sequencialmente.
~/multi-agent-system/deploy.sh
12. Crie um curso!
Abra o site do Course Creator. O serviço do Cloud Run do Course Creator é o último serviço implantado pelo script. Você pode identificar o URL do criador do curso como https://course-creator-, que deve ser a linha de saída final do script de implantação.
e digite uma ideia de curso, por exemplo, "álgebra linear".
Seus agentes vão começar a trabalhar no curso.

13. Limpeza
Para evitar cobranças na sua conta do Google Cloud pelos recursos usados neste codelab, siga estas etapas para excluir seus serviços e imagens de contêiner.
1. Excluir serviços do Cloud Run
A maneira mais eficiente de limpar é excluir os serviços implantados no Cloud Run.
# Delete the main agent and app services
gcloud run services delete researcher content-builder judge orchestrator course-creator \
--region $REGION --quiet
# Delete the GPU backend (Ollama)
gcloud run services delete ollama-gemma-gpu \
--region $OLLAMA_REGION --quiet
2. Excluir imagens do Artifact Registry
Quando você usou a flag --source para fazer a implantação, o Google Cloud criou um repositório no Artifact Registry para armazenar as imagens de contêiner. Para remover esses arquivos e economizar nos custos de armazenamento, exclua o repositório:
gcloud artifacts repositories delete cloud-run-source-deploy --location us-east4 --quiet
3. Remover arquivos locais e ambiente
Para manter o ambiente shell do Cloud Shell limpo, remova a pasta do projeto e qualquer configuração local:
cd ~
rm -rf multi-agent-system
4. (Opcional) Excluir o projeto
Se você criou um projeto apenas para este codelab, encerre o projeto na página "Gerenciar recursos" para evitar mais cobranças.
14. Parabéns!
Você criou e implantou um sistema multiagente distribuído pronto para produção.
O que você realizou
- Decomposição de uma tarefa complexa: em vez de um comando gigante, dividimos o trabalho em funções especializadas (pesquisador, avaliador e criador de conteúdo).
- Controle de qualidade implementado: usamos um
LoopAgente umJudgeestruturado para garantir que apenas informações de alta qualidade cheguem à etapa final. - Criado para produção: usando o protocolo Agent-to-Agent (A2A) e o Cloud Run, criamos um sistema em que cada agente é um microsserviço independente e escalonável. Isso é muito mais robusto do que executar tudo em um único script Python.
- Orquestração: usamos
SequentialAgenteLoopAgentpara definir padrões claros de fluxo de controle. *. GPUs do Cloud Run: implantação de um modelo do Gemma em uma GPU do Cloud Run