Como criar agentes de IA com o ADK: como orquestrar fluxos de trabalho de gráficos

1. Visão geral

Para atender a uma solicitação de viagem com várias restrições (como planejar um dia em Kyoto com US $100, incluindo templos históricos, ramen local e nenhum museu de arte moderna), é necessário extrair preferências estruturadas, pesquisar locais simultaneamente, sintetizar um rascunho detalhado e auditar o custo total antes de responder. No ADK 1.x, a orquestração dessas etapas exigia o aninhamento de wrappers SequentialAgent, ParallelAgent e LoopAgent, salvando cada saída intermediária no estado da sessão e invocando uma chamada de ferramenta de LLM extra apenas para sair de um loop de refinamento.

Neste codelab, você vai criar um planejador de viagens multiagente na Plataforma de Agentes usando os fluxos de trabalho de gráfico (Workflow) do Kit de Desenvolvimento de Agente (ADK) 2. Em três etapas progressivas, você vai conectar nós especialistas Agent (com tecnologia do gemini-3.8-flash) em uma cadeia de borda sequencial (node_input), distribuir pesquisadores google_search simultâneos sincronizados com JoinNode e aplicar regras de orçamento e exclusão com um roteador Python determinista (Event(route=...)) que ignora o refinamento sempre que o rascunho inicial passa na auditoria.

Pré-requisitos

Conteúdo do laboratório

  • Como declarar um pipeline multiagente no ADK 2 usando tuplas de borda Workflow
  • Como o ADK 2 transmite saídas diretamente pelas arestas como node_input e vincula chaves de estado de sessão como parâmetros de função
  • Como distribuir ramificações de pesquisa simultâneas e mesclar as saídas com o JoinNode
  • Como rotear ciclos de criador-verificador limitados de forma determinística em Python com Event(route=...)
  • Como inspecionar gráficos de fluxo de trabalho compilados, linhas do tempo de execução paralela e deltas de estado na interface da Web do ADK

O que é necessário

  • Uma Conta do Google (use uma conta pessoal do @gmail.com se estiver resgatando créditos do workshop)
  • Um link de crédito do workshop do seu instrutor (além de uma câmera de smartphone para ler o QR code) ou uma conta do Cloud Billing ativa.
  • Google Chrome (recomendamos usar uma janela anônima para evitar misturar contas pessoais e de trabalho)

2. Resgatar créditos do Google Cloud (opcional)

Se você estiver participando de um workshop com um link de crédito de evento, resgate seu crédito do Google Developer Program para provisionar uma conta de faturamento sem cartão de crédito.

Resgatar seu crédito do evento

  1. Abra o link de crédito do workshop em uma janela anônima e faça login com sua conta do @gmail.com.
  2. Em Resgatar seu benefício, clique em Resgatar crédito:

Card "Resgatar seu benefício" do Google Builders Hub mostrando o botão "Resgatar crédito"

  1. Se for solicitado que você crie um perfil do Google Developer Program, preencha o formulário.
  2. Quando a mensagem Leia o QR code para confirmar que você é uma pessoa aparecer, leia o QR code com seu smartphone e conclua a verificação. Se o QR code não aparecer, atualize a página e clique em Resgatar crédito novamente:

Caixa de diálogo do QR code "Leia o código para confirmar que você é uma pessoa" do Google Developer Program

  1. Confirme se a mensagem Seu crédito do evento foi solicitado! aparece e clique em Abrir conta de faturamento:

Google Builders Hub mostrando que o crédito do evento foi solicitado e o botão "Abrir conta de faturamento"

🔍 Verifique seu trabalho

A configuração da conta de faturamento leva até 3 minutos:

  1. Abra o Google Cloud Billing (ou copie o URL na janela anônima) e selecione Suas contas de faturamento:
https://console.cloud.google.com/billing
  1. Atualize até que sua conta do GDP Credit mostre o status Ativo:

Gerenciamento de contas do Cloud Billing do Google mostrando uma conta de faturamento ativa com crédito do GDP

3. Criar um projeto do Google Cloud (opcional)

Crie um projeto dedicado do Google Cloud para que todos os recursos deste codelab fiquem isolados e sejam fáceis de limpar.

  1. Abra Criar um projeto (ou copie o URL na janela anônima):
https://console.cloud.google.com/projectcreate
  1. Insira os detalhes do projeto:
    • Nome do projeto: por exemplo, google-cloud-workshop
    • Conta de faturamento (se exibida): selecione GDP Credit (ou sua conta de faturamento ativa).
    • Recurso pai: Nenhuma organização (ou selecione sua organização, se necessário)
  2. Anote o ID do projeto gerado abaixo do nome do projeto e clique em Criar:

Tela "Criar um projeto do Google Cloud" mostrando o nome do projeto, o ID do projeto, o recurso pai e o botão "Criar"

🔍 Verifique seu trabalho

Clique em Notificações na barra de ferramentas no canto superior direito e em Selecionar projeto quando a criação do projeto for concluída:

Menu "Notificações" do console do Google Cloud mostrando "Criar projeto" e o link "Selecionar projeto"

4. Configurar o ambiente

Configurar o Google Cloud Shell, ativar a API Agent Platform e criar um ambiente virtual isolado do Python 3.12 com uv.

Configure o Cloud Shell

  1. Clique em Ativar o Cloud Shell (>_) na barra de ferramentas do console do Google Cloud ou abra o Google Cloud Shell diretamente (ou copie o URL na janela anônima):
https://shell.cloud.google.com/?show=ide,terminal

Botão "Ativar o Cloud Shell" na barra de ferramentas do console do Google Cloud

  1. Clique em Autorizar se solicitado:

Caixa de diálogo "Autorizar o Cloud Shell"

  1. Selecione o ID do projeto ativo do Google Cloud no menu numerado do terminal:
unset CLOUDSDK_CORE_PROJECT
PS3="Select your project (e.g. 1): "
select PROJECT_ID in $(gcloud projects list --format="value(projectId)"); do
  [ -n "$PROJECT_ID" ] && gcloud config set project "$PROJECT_ID" && break
done

Você verá uma saída semelhante a esta (os projetos sem tags também mostram uma linha informativa [environment: untagged]):

1) google-cloud-workshop-4210
2) my-cloud-project-8812
Select your project (e.g. 1): 1
Updated property [core/project].

Verifique se o ID do projeto selecionado aparece destacado em amarelo no prompt do Cloud Shell:

Terminal do Cloud Shell mostrando o ID do projeto selecionado em destaque em amarelo

Ativar APIs obrigatórias

Ative a API Agent Platform para que seus agentes do ADK possam invocar modelos do Gemini:

gcloud services enable aiplatform.googleapis.com

Você verá uma saída como:

Operation "operations/acat.p2-..." finished successfully.

Criar um ambiente virtual do Python e instalar o ADK

Crie o espaço de trabalho ~/adk-graph-agents e ative um ambiente virtual do Python 3.12:

cd ~
mkdir -p adk-graph-agents && cd ~/adk-graph-agents

which uv >/dev/null 2>&1 || curl -LsSf https://astral.sh/uv/install.sh | sh
export PATH="$HOME/.local/bin:$PATH"

uv venv .venv --python 3.12
source .venv/bin/activate

Confirme se o prefixo (.venv) aparece no início do prompt do terminal:

Terminal do Cloud Shell mostrando o prefixo .venv em um ambiente virtual ativo do Python

Instale o ADK 2 no ambiente virtual ativo:

uv pip install --no-cache "google-adk==2.14.0"

🔍 Verifique seu trabalho

Verifique a versão instalada da CLI adk:

adk --version

Você verá uma saída como:

adk, version 2.14.0

5. Criar o esqueleto do planejador de viagens

Gere o pacote inicial travel_planner com adk create e teste o valor de referência padrão de agente único em adk web.

Gerar o pacote inicial

Execute adk create de ~/adk-graph-agents:

cd ~/adk-graph-agents
adk create travel_planner

Selecione as seguintes opções quando solicitado (se Enable telemetry? [Y/n]: aparecer na primeira execução, pressione Enter ou digite n e pressione Enter):

  1. Escolha um modelo para o agente raiz: digite 2 para selecionar gemini-3.8-flash (a opção 1 seleciona gemini-3.5-flash) e pressione Enter.
  2. Escolha um back-end: digite 2 para selecionar o back-end da Plataforma de Agentes do Google Cloud (opção 2 no menu da CLI abaixo) e pressione Enter.
  3. Insira o ID do projeto do Google Cloud: pressione Enter para aceitar o ID do projeto detectado entre colchetes.
  4. Insira a região do Google Cloud: digite global (para usar o endpoint global do Gemini) e pressione Enter.

adk create grava GOOGLE_GENAI_USE_ENTERPRISE=1, o ID do projeto e GOOGLE_CLOUD_LOCATION=global em travel_planner/.env para que suas credenciais permaneçam intactas quando você substituir agent.py mais tarde.

Você verá uma saída como:

Choose a model for the root agent:
1. gemini-3.5-flash
2. gemini-3.8-flash
3. Other models (fill later)
Choose model (1, 2, 3): 2
1. Google AI
2. Vertex AI
3. Login with Google
Choose a backend (1, 2, 3): 2

You need an existing Google Cloud account and project, check out this link for details:
https://google.github.io/adk-docs/get-started/quickstart/#gemini---google-cloud-vertex-ai

Enter Google Cloud project ID [google-cloud-workshop-4210]:
Enter Google Cloud region [us-central1]: global

Agent created in /home/your_username/adk-graph-agents/travel_planner:
- .env
- .gitignore
- __init__.py
- agent.py

⚠️  WARNING: Secrets (like GOOGLE_API_KEY) are stored in .env.

Next steps:
- Chat with your agent in the terminal: adk run travel_planner
- Or in the browser: adk web .
- Have your coding agent evaluate and deploy it: uvx google-agents-cli setup
  (other install options: https://adk.dev/get-started/agents-cli/)

Abra ~/adk-graph-agents no editor de código do Cloud Shell:

which cloudshell >/dev/null 2>&1 && cloudshell workspace ~/adk-graph-agents || true

Reative o ambiente virtual no terminal recarregado:

cd ~/adk-graph-agents
source .venv/bin/activate

Testar o agente único inicial

Inicie a interface da Web do ADK para observar como um único agente inicial não orquestrado responde a um comando de viagem:

cd ~/adk-graph-agents
adk web --allow_origins "*"

Clique no ícone Visualização da Web na barra de ferramentas do Cloud Shell no canto superior direito, selecione Alterar porta, insira 8000 e clique em Alterar e visualizar:

Caixa de diálogo de configuração da porta de visualização da Web do Cloud Shell definida como 8000

🔍 Verifique seu trabalho

Selecione travel_planner no menu suspenso no canto superior esquerdo de adk web e envie "Help me plan a trip to Japan":

Interface da Web de desenvolvimento do ADK mostrando uma conversa básica com um único agente

Você vai receber uma resposta de conversa de passagem única no painel de chat (com uma única invocação de root_agent em Eventos):

root_agent -> responds in one pass without structured preference extraction, live search, or budget verification

Pressione Ctrl + C no terminal do Cloud Shell para interromper o adk web antes de editar os arquivos na próxima etapa.

6. Criar um fluxo de trabalho de gráfico linear

Crie seu primeiro ADK 2 Workflow: uma cadeia sequencial que conecta o ponto de entrada reservado "START" a user_profiler_agent e itinerary_synthesizer_agent (qualquer nó sem arestas de saída atua como um nó terminal). Cada borda (a, b) executa automaticamente os nós Agent (um alias para LlmAgent) no modo isolado single_turn e entrega a saída do nó a como node_input (a mensagem do usuário recebida) para o nó b, enquanto {user_preferences} em uma string de instrução interpola a chave de estado da sessão correspondente salva via output_key.

Diagrama de arquitetura mostrando travel_workflow (fluxo de trabalho) conectando START a user_profiler_agent e itinerary_synthesizer_agent

Criar os especialistas iniciais

Verifique se adk web está parado (Ctrl + C) e abra um novo arquivo chamado travel_planner/specialists.py:

cloudshell edit ~/adk-graph-agents/travel_planner/specialists.py

Cole o código a seguir em travel_planner/specialists.py para definir user_profiler_agent e itinerary_synthesizer_agent (importando google_search com antecedência para a próxima etapa):

from google.adk import Agent
from google.adk.tools import google_search

MODEL = "gemini-3.8-flash"

# --- Specialist 1: The User Profiler ---
user_profiler_agent = Agent(
    model=MODEL,
    name="user_profiler_agent",
    description="Extracts travel preferences and constraints from user input.",
    instruction="""
        Extract destination, duration (default 1 day), budget, interests, and exclusions.
        Return a single JSON object with keys: "destination", "duration", "budget", "interests", "exclusions".
    """,
    output_key="user_preferences",  # Saved for multi-hop constraints downstream
)

# --- Specialist 2: The Synthesizer ---
itinerary_synthesizer_agent = Agent(
    model=MODEL,
    name="itinerary_synthesizer_agent",
    description="Compiles preferences and research into a final Markdown itinerary.",
    instruction="""
        You are an elite Travel Concierge. Using the incoming input and
        User Preferences ({user_preferences}), write a Markdown itinerary
        with an itemized USD and local currency cost breakdown.
    """,
    output_key="final_itinerary",
)

Definir a cadeia de bordas sequenciais

Abra um novo arquivo chamado travel_planner/workflows.py:

cloudshell edit ~/adk-graph-agents/travel_planner/workflows.py

Cole a seguinte definição de Workflow (em que uma tupla de três ou mais nós é compilada em uma cadeia sequencial de "START"):

from google.adk import Workflow
from .specialists import (
    itinerary_synthesizer_agent,
    user_profiler_agent,
)

# 1. SEQUENTIAL GRAPH: START -> user_profiler_agent -> itinerary_synthesizer_agent
travel_workflow = Workflow(
    name="travel_workflow",
    description="Orchestrates the end-to-end travel planning process as a graph workflow.",
    edges=[
        ("START", user_profiler_agent, itinerary_synthesizer_agent),
    ],
)

Expor o fluxo de trabalho como root_agent

Abra travel_planner/agent.py:

cloudshell edit ~/adk-graph-agents/travel_planner/agent.py

Substitua todo o conteúdo de travel_planner/agent.py por estas duas linhas:

from .workflows import travel_workflow

root_agent = travel_workflow

🔍 Verifique seu trabalho

Inicie o adk web em ~/adk-graph-agents:

cd ~/adk-graph-agents
adk web --allow_origins "*"

Abra a Visualização da Web na porta 8000, clique em + Nova sessão e envie:

Help me plan a trip to Kyoto

Na visualização Eventos, você verá uma sequência de eventos semelhante a:

1. user_profiler_agent -> outputs JSON {"destination": "Kyoto", "duration": "1 day", ...} and writes state["user_preferences"]
2. itinerary_synthesizer_agent -> receives preferences via node_input and outputs the Markdown itinerary

Interface da Web do ADK 2.14.0 mostrando a execução de grafo de START para user_profiler_agent e itinerary_synthesizer_agent e o itinerário gerado para Kyoto

Clique em qualquer evento em Eventos e no ícone Gráfico (account_tree na barra de ferramentas de detalhes do evento) para inspecionar a topologia START -> user_profiler_agent -> itinerary_synthesizer_agent compilada. Em seguida, verifique a guia Estado para conferir se user_preferences e final_itinerary estão preenchidos.

Pressione Ctrl + C no terminal para interromper adk web antes de continuar.

7. Distribuir e mesclar com JoinNode

Embase o itinerário em dados da Web em tempo real adicionando dois especialistas em google_search simultâneos (activity_finder_agent e restaurant_finder_agent) e sincronizando-os com JoinNode:

  • Tupla de fan-out: colocar (activity_finder_agent, restaurant_finder_agent) dentro da tupla de borda entrega a saída de user_profiler_agent como node_input para os dois pesquisadores ao mesmo tempo.
  • Barreira de fan-in (JoinNode): colocar JoinNode(name="research_join") logo após a tupla aguarda até que todas as ramificações de entrada sejam concluídas e transmite um dict ({"activity_finder_agent": ..., "restaurant_finder_agent": ...}) mesclado como node_input para itinerary_synthesizer_agent em vez de acionar a síntese duas vezes.

Diagrama de arquitetura mostrando travel_workflow se dividindo de user_profiler_agent por node_input para activity_finder_agent e restaurant_finder_agent em paralelo, se unindo em research_join (JoinNode) e transmitindo node_input (dict) para itinerary_synthesizer_agent

Adicionar os especialistas em pesquisa

Confirme se adk web está parado (Ctrl + C) e abra travel_planner/specialists.py:

cloudshell edit ~/adk-graph-agents/travel_planner/specialists.py

Anexe activity_finder_agent e restaurant_finder_agent à parte de baixo de travel_planner/specialists.py (nenhum deles precisa de output_key porque research_join encaminha as duas saídas diretamente por node_input):

# --- Specialist 3: The Activity Finder ---
activity_finder_agent = Agent(
    model=MODEL,
    name="activity_finder_agent",
    description="Finds 3 attractions matching the user's destination and interests.",
    instruction="""
        Using the travel preferences in the input, call google_search to find 3 specific attractions
        (including budget-friendly options).
        Return a JSON list with keys: "attraction_name", "estimated_cost_local", "estimated_cost_usd", "notes".
    """,
    tools=[google_search],
)

# --- Specialist 4: The Restaurant Finder ---
restaurant_finder_agent = Agent(
    model=MODEL,
    name="restaurant_finder_agent",
    description="Finds 3 restaurants matching the destination and budget.",
    instruction="""
        Using the travel preferences in the input, call google_search to find 3 highly-rated restaurants
        across price points.
        Return a JSON list with keys: "restaurant_name", "cuisine", "estimated_cost_local", "estimated_cost_usd".
    """,
    tools=[google_search],
)

Adicionar fan-out e JoinNode a workflows.py

Abra travel_planner/workflows.py:

cloudshell edit ~/adk-graph-agents/travel_planner/workflows.py

Substitua todo o conteúdo de travel_planner/workflows.py pelo gráfico de fan-out e JoinNode:

from google.adk import Workflow
from google.adk.workflow import JoinNode
from .specialists import (
    activity_finder_agent,
    itinerary_synthesizer_agent,
    restaurant_finder_agent,
    user_profiler_agent,
)

research_join = JoinNode(name="research_join")

# 2. FAN-OUT / FAN-IN GRAPH: Profile -> (Activities || Restaurants) -> Join -> Synthesize
travel_workflow = Workflow(
    name="travel_workflow",
    description="Orchestrates the end-to-end travel planning process as a graph workflow.",
    edges=[
        (
            "START",
            user_profiler_agent,
            (activity_finder_agent, restaurant_finder_agent),
            research_join,
            itinerary_synthesizer_agent,
        ),
    ],
)

🔍 Verifique seu trabalho

Inicie o adk web para testar a pesquisa simultânea e a sincronização do JoinNode:

cd ~/adk-graph-agents
adk web --allow_origins "*"

Abra a Visualização da Web na porta 8000, clique em + Nova sessão e envie:

Help me plan a trip to Kyoto focused on historic temples and ramen

Na visualização Eventos, você verá uma sequência de eventos semelhante a:

1. user_profiler_agent -> emits JSON preferences via node_input
2. activity_finder_agent & restaurant_finder_agent -> invoke google_search concurrently
3. research_join -> merges both researcher outputs into one dict node_input
4. itinerary_synthesizer_agent -> drafts final_itinerary from the merged dict + {user_preferences}

Pressione Ctrl + C no terminal para interromper adk web antes de continuar.

8. Ciclos de revisão de rotas

Aplique restrições de orçamento e negativas adicionando um itinerary_critic_agent, um itinerary_refiner_agent e dois nós de função determinística do Python (route_critique e finalize_itinerary) que retornam objetos Event do ADK:

  • route: seleciona qual chave de ramificação nomeada em uma borda de dicionário ({"revise": ..., "approved": ...}) será executada em seguida.
  • output: transmite um valor ou uma string do Python tipado ao longo da borda como node_input para o próximo nó sem renderizar uma mensagem de chat.
  • message e state: message emite texto visível ao usuário na transcrição da conversa, enquanto state confirma atualizações de chave-valor (stateDelta) no estado da sessão.

Diagrama de arquitetura mostrando travel_workflow com itinerary_critic_agent alimentando route_critique, que encaminha "revise" para itinerary_refiner_agent (retornando para itinerary_critic_agent) ou "approved" para finalize_itinerary

Adicionar os especialistas em crítica e refinamento

Confirme se adk web está parado (Ctrl + C) e abra travel_planner/specialists.py:

cloudshell edit ~/adk-graph-agents/travel_planner/specialists.py

Adicione itinerary_critic_agent e itinerary_refiner_agent ao final de travel_planner/specialists.py (o refinador não precisa de ferramentas google_search ou exit_loop porque troca itens já coletados em {final_itinerary} e só é executado quando route_critique seleciona "revise"):

# --- Specialist 5: The Budget & Constraint Critic ---
itinerary_critic_agent = Agent(
    model=MODEL,
    name="itinerary_critic_agent",
    description="Audits the itinerary draft against budget and negative constraints.",
    instruction="""
        Audit the itinerary in the input against User Preferences ({user_preferences}).
        Verify that the USD total stays within the user's budget and no excluded venue types appear.
        If all checks pass, respond EXACTLY with the single word "APPROVED".
        Otherwise, output 1-2 concise revision instructions explaining what to swap or adjust.
    """,
)

# --- Specialist 6: The Itinerary Refiner ---
itinerary_refiner_agent = Agent(
    model=MODEL,
    name="itinerary_refiner_agent",
    description="Revises the itinerary draft using the critic's feedback.",
    instruction="""
        Revise Current Itinerary ({final_itinerary}) using the auditor critique in the input
        so all USD budget and exclusion rules in {user_preferences} pass.
        Output ONLY the updated Markdown itinerary.
    """,
    output_key="final_itinerary",
)

Adicione route_critique e o ciclo

Abra travel_planner/workflows.py:

cloudshell edit ~/adk-graph-agents/travel_planner/workflows.py

Substitua todo o conteúdo de travel_planner/workflows.py pelo fluxo de trabalho de gráfico completo:

from google.adk import Event, Workflow
from google.adk.workflow import JoinNode
from .specialists import (
    activity_finder_agent, itinerary_critic_agent, itinerary_refiner_agent,
    itinerary_synthesizer_agent, restaurant_finder_agent, user_profiler_agent,
)

MAX_REVISIONS = 2
research_join = JoinNode(name="research_join")


def route_critique(node_input: str, revision_count: int = 0):
    """Routes to 'approved' when constraints pass, or 'revise' up to MAX_REVISIONS."""
    approved = node_input.strip().rstrip(".").upper() == "APPROVED"
    if approved or revision_count >= MAX_REVISIONS:
        return Event(route="approved", output=approved)
    return Event(
        route="revise", output=node_input, state={"revision_count": revision_count + 1}
    )


def finalize_itinerary(node_input: bool, final_itinerary: str, revision_count: int = 0):
    """Emits the verified itinerary and resets revision_count for the next turn."""
    status = (
        f"Itinerary approved after {revision_count} revision(s)."
        if node_input
        else f"Max revisions ({revision_count}) reached; returning best-effort draft."
    )
    return Event(
        message=f"{status}\n\n{final_itinerary}",
        output=final_itinerary,
        state={"revision_count": 0},
    )


travel_workflow = Workflow(
    name="travel_workflow",
    description="Orchestrates the end-to-end travel planning process as a graph workflow.",
    edges=[
        (
            "START",
            user_profiler_agent,
            (activity_finder_agent, restaurant_finder_agent),
            research_join,
            itinerary_synthesizer_agent,
            itinerary_critic_agent,
            route_critique,
        ),
        (route_critique, {"revise": itinerary_refiner_agent, "approved": finalize_itinerary}),
        (itinerary_refiner_agent, itinerary_critic_agent),
    ],
)

🔍 Verifique seu trabalho

Verifique se travel_planner/workflows.py é compilado sem erros e mostra as arestas do gráfico direcionado:

cd ~/adk-graph-agents && source .venv/bin/activate
python3 -c "from travel_planner.agent import root_agent; print('\n'.join(f'{e.from_node.name} -> {e.to_node.name} (route={e.route})' for e in root_agent.graph.edges))"

Você verá uma saída como:

__START__ -> user_profiler_agent (route=None)
user_profiler_agent -> activity_finder_agent (route=None)
user_profiler_agent -> restaurant_finder_agent (route=None)
activity_finder_agent -> research_join (route=None)
restaurant_finder_agent -> research_join (route=None)
research_join -> itinerary_synthesizer_agent (route=None)
itinerary_synthesizer_agent -> itinerary_critic_agent (route=None)
itinerary_critic_agent -> route_critique (route=None)
route_critique -> itinerary_refiner_agent (route=revise)
route_critique -> finalize_itinerary (route=approved)
itinerary_refiner_agent -> itinerary_critic_agent (route=None)

Em seguida, inicie adk web para testar a aprovação imediata e as revisões acionadas pelo orçamento:

adk web --allow_origins "*"

Abra a Visualização da Web na porta 8000, clique em + Nova sessão e envie o comando de Kyoto com várias restrições:

Design a full-day itinerary for Kyoto with a total budget of $100. My main interests are historical landmarks, temples, and authentic local cuisine. Please do not include any modern art museums or galleries.

Para ver o loop route="revise" em ação, envie um comando complementar com um orçamento apertado de US$ 15:

Now design a full-day Kyoto itinerary with paid temple admissions, lunch, and dinner on a strict total budget of $15 USD.

Na visualização Eventos, você verá uma sequência de execução semelhante a:

1. user_profiler_agent -> writes JSON constraints to state["user_preferences"]
2. (activity_finder_agent, restaurant_finder_agent) -> run google_search concurrently -> research_join
3. itinerary_synthesizer_agent -> writes initial draft to state["final_itinerary"]
4. itinerary_critic_agent -> outputs "APPROVED" (or revision instructions when over budget)
5. route_critique -> emits route="approved" (skipping refiner) or route="revise" -> itinerary_refiner_agent -> itinerary_critic_agent
6. finalize_itinerary -> emits "Itinerary approved after N revision(s)." (or max-revisions notice) and resets revision_count=0

Pressione Ctrl + C no terminal para interromper adk web.

9. Solução de problemas

O menu suspenso do agente está vazio em adk web

  • Causa: adk web foi iniciado dentro de travel_planner/ em vez do diretório pai ~/adk-graph-agents, ou a sessão do Cloud Shell foi reiniciada.
  • Correção: pressione Ctrl + C, volte ao diretório pai e reinicie com cd ~/adk-graph-agents && source .venv/bin/activate && adk web --allow_origins "*".

404 NOT_FOUND erro de modelo

  • Causa: você pressionou Enter para aceitar a região padrão us-central1 durante adk create em vez de digitar global.
  • Correção: abra ~/adk-graph-agents/travel_planner/.env e verifique se GOOGLE_CLOUD_LOCATION=global está definido.

ERROR: [Errno 98] address already in use na porta 8000

  • Causa: um servidor adk web anterior ainda está em execução no Cloud Shell.
  • Correção: pressione Ctrl + C no terminal ativo ou interrompa o processo atual com pkill -f "adk web" antes de iniciar adk web novamente.

10. Limpar

Remova o espaço de trabalho local e, se quiser, desative a API ou exclua um projeto de workshop dedicado.

Excluir os arquivos do projeto local

Remova o diretório ~/adk-graph-agents e o ambiente virtual:

cd ~
rm -rf ~/adk-graph-agents

Desativar a API Agent Platform (opcional)

Desative a API Agent Platform se ela não for mais necessária neste projeto:

gcloud services disable aiplatform.googleapis.com --quiet

🔍 Verifique seu trabalho

Confirme se ~/adk-graph-agents foi removido:

test ! -d ~/adk-graph-agents && echo "Workspace ~/adk-graph-agents removed"

Você verá uma saída como:

Workspace ~/adk-graph-agents removed

11. Parabéns

Você criou um planejador de viagens multiagente usando o ADK 2 Workflow, unificando cadeias sequenciais, fan-out simultâneo de google_search com JoinNode e ciclos condicionais de criador-verificador em um único gráfico de borda declarativo.

O que você fez até aqui

  • Declarou um pipeline multiagente usando o ADK 2 Workflow(edges=[...])
  • Transmitiu dados diretamente entre os nós de função Agent, JoinNode e Python usando node_input e parâmetros vinculados ao estado, mantendo o estado da sessão mínimo.
  • Ramificações simultâneas de google_search distribuídas e sincronizadas com JoinNode
  • Substituição de LoopAgent e do escalonamento de loop baseado em ferramentas por um roteador determinista Event(route=...) que ignora chamadas de LLM desnecessárias em rascunhos aprovados

Próximas etapas