1. Introdução
Nesta sessão prática, você vai além dos chatbots básicos e sem estado para criar um concierge de um café inteligente, um agente de IA desenvolvido pelo Gemini que atua como um barista simpático. Ele recebe pedidos de café rastreados no estado da sessão, lembra preferências alimentares de longo prazo no estado do escopo do usuário e persiste tudo em um banco de dados PostgreSQL do Cloud SQL. No final, o agente se lembra de que você tem intolerância à lactose, mesmo depois de reiniciar o aplicativo e iniciar uma conversa totalmente nova.
Confira a arquitetura do sistema que vamos criar

Pré-requisitos
- Uma conta do Google Cloud com uma conta de faturamento de teste
- Noções básicas sobre o Python.
- Não é necessário ter experiência com ADK, agentes de IA ou Cloud SQL
O que você vai aprender
- Criar um agente de IA usando o Kit de Desenvolvimento de Agente (ADK) do Google com ferramentas personalizadas
- Definir ferramentas que leem e gravam o estado da sessão via
ToolContext - Distinguir entre estado no escopo da sessão e estado no escopo do usuário (prefixo
user:) - Provisionar uma instância do Cloud SQL PostgreSQL e se conectar a ela pelo Cloud Shell
- Migrar do armazenamento local (que é o padrão ao usar o comando
adk web) paraDatabaseSessionServicepara armazenamento permanente com banco de dados dedicado - Verifique se a memória do agente persiste entre reinicializações do aplicativo e sessões de conversa separadas.
O que é necessário
- Um computador em funcionamento e uma conexão de Internet confiável.
- Um navegador, como o Chrome, para acessar o console do Google Cloud
- Uma mente curiosa e vontade de aprender.
2. Configuração de seu ambiente
Esta etapa prepara o ambiente do Cloud Shell e configura seu projeto do Google Cloud
Abra o Cloud Shell
Abra o Cloud Shell no navegador. O Cloud Shell oferece um ambiente pré-configurado com todas as ferramentas necessárias para este codelab. Clique em Autorizar quando solicitado a
Sua interface deve ser parecida com esta

Essa será nossa interface principal, com o IDE na parte de cima e o terminal na parte de baixo.
Configurar seu diretório de trabalho
Crie o diretório de trabalho. Todo o código que você escrever neste codelab vai ficar aqui, separado do repositório de referência:
# Create your working directory
mkdir -p ~/build-agent-adk-cloudsql
# Change cloudshell workspace and working directory into previously created dir
cloudshell workspace ~/build-agent-adk-cloudsql && cd ~/build-agent-adk-cloudsql
Para gerar o terminal, encontre Visualizar -> Terminal.

Configurar o projeto do Google Cloud e as variáveis de ambiente iniciais
Faça o download do script de configuração do projeto para o diretório de trabalho:
curl -sL https://raw.githubusercontent.com/alphinside/cloud-trial-project-setup/main/setup_verify_trial_project.sh -o setup_verify_trial_project.sh
Execute o script. Ele verifica sua conta de faturamento de teste, cria um projeto (ou valida um existente), salva o ID do projeto em um arquivo .env no diretório atual e define o projeto ativo no terminal.
bash setup_verify_trial_project.sh && source .env
Ao executar esse comando, você vai receber uma sugestão de nome para o ID do projeto. Pressione Enter para continuar.

Depois de esperar um pouco, se você vir esta saída no console, poderá passar para a próxima etapa 
O script executado faz as seguintes etapas:
- Verifique se você tem uma conta de faturamento de teste ativa
- Verifique se há um projeto em
.env(se houver). - Crie um novo projeto ou reutilize o atual
- Vincular a conta de faturamento de teste ao projeto
- Salve o ID do projeto em .env
- Definir o projeto como o projeto ativo do gcloud
Verifique se o projeto está definido corretamente conferindo o texto amarelo ao lado do diretório de trabalho no prompt do terminal do Cloud Shell. Ele vai mostrar o ID do projeto.

Ativar as APIs necessárias
Ative as APIs do Google Cloud necessárias para este codelab:
gcloud services enable \
aiplatform.googleapis.com \
sqladmin.googleapis.com \
compute.googleapis.com
- API Vertex AI (
aiplatform.googleapis.com): seu agente usa modelos do Gemini pela Vertex AI. - API Cloud SQL Admin (
sqladmin.googleapis.com): você provisiona e gerencia uma instância do PostgreSQL para armazenamento permanente. - API Compute Engine (
compute.googleapis.com): necessária para criar instâncias do Cloud SQL.
Configurar a região dos produtos do Gemini e do Cloud
Antes de continuar, vamos configurar a localização/região necessária para o produto com que interagimos. Adicione a seguinte configuração ao arquivo .env:
# This is for our Gemini endpoint
echo "GOOGLE_CLOUD_LOCATION=global" >> .env
# This is for our other Cloud products
echo "REGION=us-central1" >> .env
source .env
Vamos para a próxima etapa
3. Configurar o Cloud SQL
Esta etapa provisiona uma instância do Cloud SQL PostgreSQL e muda seu agente do armazenamento na memória para o armazenamento com suporte de banco de dados. A criação da instância leva alguns minutos. Por isso, vamos começar esse processo primeiro e continuar nossa discussão sobre o próximo tópico enquanto esperamos a conclusão.
Iniciar a criação da instância
Adicione a senha do banco de dados ao arquivo .env e recarregue-o. Vamos usar cafe-agent-pwd-2025 como senha.
echo "DB_PASSWORD=cafe-agent-pwd-2025" >> .env
source .env
Execute este comando para criar uma instância do Cloud SQL PostgreSQL. A conclusão leva alguns minutos. Deixe o processo em execução e continue para a próxima seção.
gcloud sql instances create cafe-concierge-db \
--database-version=POSTGRES_17 \
--edition=ENTERPRISE \
--region=${REGION} \
--availability-type=ZONAL \
--project=${GOOGLE_CLOUD_PROJECT} \
--tier=db-f1-micro \
--root-password=${DB_PASSWORD} \
--quiet &
Algumas observações sobre o comando acima:
db-f1-microé o menor (e mais barato) nível do Cloud SQL, suficiente para este codelab.--root-passworddefine a senha do usuário postgres padrão.- O sufixo
&no comando executa o comando em segundo plano para que você possa continuar trabalhando.
O processo será executado em segundo plano, mas a saída do console será mostrada ocasionalmente no terminal atual. Abra uma nova guia do terminal no Cloud Shell (clique no ícone +) para ficar mais focado.

Navegue até o diretório de trabalho novamente e ative o projeto usando o script de configuração anterior.
cd ~/build-agent-adk-cloudsql
bash setup_verify_trial_project.sh && source .env
Em seguida, vamos para a próxima seção
4. Criar o agente de concierge do café
Esta etapa cria a estrutura do projeto para o agente do ADK e define um Cafe Concierge básico com uma ferramenta de menu.
Inicializar o projeto Python
Este codelab usa o uv, um gerenciador de pacotes Python rápido que lida com ambientes virtuais e dependências em uma única ferramenta. Ele vem pré-instalado no Cloud Shell.
Inicialize um projeto Python e adicione o ADK como uma dependência:
uv init
uv add google-adk==1.25.0 asyncpg
O uv init cria um pyproject.toml e um ambiente virtual. O comando uv add instala a dependência e a registra em pyproject.toml.
Inicializar a estrutura do projeto do agente
O ADK espera um layout de pasta específico: um diretório com o nome do seu agente que contenha __init__.py, agent.py e também .env dentro do diretório do agente.
O ADK tem um comando integrado para ajudar você a estabelecer isso rapidamente. Execute o comando a seguir:
uv run adk create cafe_concierge \
--model gemini-2.5-flash \
--project ${GOOGLE_CLOUD_PROJECT} \
--region ${GOOGLE_CLOUD_LOCATION}
Esse comando vai criar uma estrutura de agente com gemini-2.5-flash como o cérebro. Seu diretório vai ficar assim:
build-agent-adk-cloudsql/ ├── cafe_concierge/ │ ├── __init__.py │ ├── agent.py │ └── .env ├── pyproject.toml ├── .env ├── .venv/ └── ...
Escrever o agente
Abra cafe_concierge/agent.py no editor do Cloud Shell
cloudshell edit cafe_concierge/agent.py
e substitua o arquivo com o seguinte código:
# cafe_concierge/agent.py
from google.adk.agents import LlmAgent
from google.adk.tools import ToolContext
CAFE_MENU = {
"espresso": {
"price": 3.50,
"description": "Rich and bold single shot",
"tags": ["vegan", "dairy-free", "gluten-free"],
},
"latte": {
"price": 5.00,
"description": "Espresso with steamed milk",
"tags": ["gluten-free"],
},
"oat milk latte": {
"price": 5.50,
"description": "Espresso with steamed oat milk",
"tags": ["vegan", "dairy-free", "gluten-free"],
},
"cappuccino": {
"price": 4.50,
"description": "Espresso with equal parts steamed milk and foam",
"tags": ["gluten-free"],
},
"cold brew": {
"price": 4.00,
"description": "Slow-steeped for 12 hours, served over ice",
"tags": ["vegan", "dairy-free", "gluten-free"],
},
"matcha latte": {
"price": 5.50,
"description": "Ceremonial grade matcha with steamed milk",
"tags": ["gluten-free"],
},
"croissant": {
"price": 3.00,
"description": "Buttery, flaky French pastry",
"tags": [],
},
"banana bread": {
"price": 3.50,
"description": "Homemade with walnuts",
"tags": ["vegan"],
},
}
def get_menu() -> dict:
"""Returns the full cafe menu with prices, descriptions, and dietary tags.
Use this tool when the customer asks what's available, wants to see
the menu, or asks about specific items.
"""
return CAFE_MENU
root_agent = LlmAgent(
name="cafe_concierge",
model="gemini-2.5-flash",
instruction="""You are a friendly and knowledgeable barista at "The Cloud Cafe".
Your job:
- Help customers browse the menu and answer questions about items.
- Take coffee and food orders.
- Remember and respect dietary preferences.
Be conversational, warm, and concise. If a customer mentions a dietary
restriction, acknowledge it and suggest suitable options from the menu.
""",
tools=[get_menu],
)
Isso define um agente básico com uma ferramenta: get_menu(). O agente pode responder a perguntas sobre o cardápio, mas ainda não consegue rastrear pedidos ou lembrar preferências.
Verificar se o agente está em execução
Inicie a interface do desenvolvedor do ADK no seu diretório de trabalho:
cd ~/build-agent-adk-cloudsql
uv run adk web
Abra o URL mostrado no terminal (normalmente http://localhost:8000) usando o recurso de visualização na Web do Cloud Shell. Selecione cafe_concierge no menu suspenso do agente no canto superior esquerdo.
Digite o texto a seguir na barra de chat e verifique se o agente responde com itens de menu e preços.
What's on the menu?

Interrompa a interface de desenvolvimento com Ctrl+C antes de continuar.
5. Adicionar gerenciamento de pedidos com estado
O agente pode mostrar o menu, mas não pode receber pedidos nem lembrar preferências. Esta etapa adiciona quatro ferramentas que usam o sistema de estado do ADK para rastrear pedidos em uma conversa e armazenar preferências alimentares em várias conversas.
Entender eventos e estado da sessão
Cada conversa do ADK fica dentro de um objeto Session. Uma sessão rastreia duas coisas distintas: eventos e estado. Entender a diferença é fundamental para criar agentes que se lembrem das coisas certas da maneira certa.
Eventos são o registro cronológico de tudo o que acontece em uma conversa. Cada mensagem do usuário, cada resposta do agente, cada chamada de ferramenta e seu valor de retorno são registrados como um Event e anexados à lista events da sessão. Os eventos são imutáveis: depois de registrados, eles nunca mudam. Pense nos eventos como a transcrição completa de uma conversa.
O estado é um bloco de notas de chave-valor que o agente lê e grava durante uma conversa. Ao contrário dos eventos, o estado é mutável: os valores mudam à medida que a conversa evolui. O estado é onde o agente armazena os dados estruturados necessários para agir: o pedido atual, as preferências do cliente, um total em andamento. Pense no estado como post-its que o agente mantém ao lado da transcrição.
Veja como eles se relacionam:

As ferramentas leem e gravam o estado usando ToolContext, um objeto que o ADK injeta automaticamente em qualquer função de ferramenta que o declare como um parâmetro. Você não cria esse arquivo. Com o tool_context.state, uma ferramenta pode ler e gravar o bloco de notas de estado da sessão. O ADK inspeciona a assinatura da função: parâmetros com o tipo ToolContext são injetados, e todos os outros parâmetros são preenchidos pelo LLM com base na conversa.
Quando uma ferramenta grava em tool_context.state, o ADK registra essa mudança como um state_delta dentro do evento. Em seguida, o SessionService aplica o delta ao estado atual da sessão. Isso significa que as mudanças de estado são sempre rastreáveis até o evento que as causou. Isso também é válido para outras formas de contexto, como callback_context.
Entender os prefixos de estado
As chaves de estado usam prefixos para controlar o escopo:
Prefixo | Escopo | Sobrevive à reinicialização? (com DB) |
(nenhum) | Apenas a sessão atual | Sim |
| Todas as sessões deste usuário | Sim |
| Todas as sessões, todos os usuários | Sim |
| Somente a invocação atual | Não |
Neste codelab, você vai usar dois desses prefixos: chaves sem prefixo para dados no escopo da sessão (o pedido atual, relevante apenas para esta conversa) e chaves user: para dados no escopo do usuário (preferências alimentares, relevantes em todas as conversas desse usuário).
Adicionar as ferramentas com estado
Abra cafe_concierge/agent.py no editor do Cloud Shell.
cloudshell edit cafe_concierge/agent.py
Em seguida, adicione as quatro funções acima da definição de root_agent:
# cafe_concierge/agent.py (add below get_menu, above root_agent)
def place_order(tool_context: ToolContext, items: list[str]) -> dict:
"""Places an order for the specified menu items.
Use this tool when the customer confirms they want to order something.
Args:
tool_context: Provided automatically by ADK.
items: A list of menu item names the customer wants to order.
"""
valid_items = []
invalid_items = []
total = 0.0
for item in items:
item_lower = item.lower()
if item_lower in CAFE_MENU:
valid_items.append(item_lower)
total += CAFE_MENU[item_lower]["price"]
else:
invalid_items.append(item)
if not valid_items:
return {"error": f"None of these items are on our menu: {invalid_items}"}
order = {"items": valid_items, "total": round(total, 2)}
tool_context.state["current_order"] = order
result = {"order": order}
if invalid_items:
result["warning"] = f"These items are not on our menu: {invalid_items}"
return result
def get_order_summary(tool_context: ToolContext) -> dict:
"""Returns the current order summary for this session.
Use this tool when the customer asks about their current order,
wants to review what they ordered, or asks for the total.
Args:
tool_context: Provided automatically by ADK.
"""
order = tool_context.state.get("current_order")
if order:
return {"order": order}
return {"message": "No order has been placed yet in this session."}
def set_dietary_preference(tool_context: ToolContext, preference: str) -> dict:
"""Saves a dietary preference that persists across all conversations.
Use this tool when the customer mentions a dietary restriction or
preference (e.g., "I'm vegan", "I'm lactose intolerant",
"I have a nut allergy").
Args:
tool_context: Provided automatically by ADK.
preference: The dietary preference to save (e.g., "vegan",
"lactose intolerant", "nut allergy").
"""
existing = tool_context.state.get("user:dietary_preferences", [])
if not isinstance(existing, list):
existing = []
preference_lower = preference.lower().strip()
if preference_lower not in existing:
existing.append(preference_lower)
tool_context.state["user:dietary_preferences"] = existing
return {
"saved": preference_lower,
"all_preferences": existing,
}
def get_dietary_preferences(tool_context: ToolContext) -> dict:
"""Retrieves the customer's saved dietary preferences.
Use this tool when you need to check the customer's dietary
restrictions before making recommendations.
Args:
tool_context: Provided automatically by ADK.
"""
preferences = tool_context.state.get("user:dietary_preferences", [])
if preferences:
return {"preferences": preferences}
return {"message": "No dietary preferences saved yet."}
Duas observações importantes:
place_ordereget_order_summaryusam chaves sem prefixo (current_order). Esse estado está vinculado à sessão atual. Uma nova conversa começa com um pedido vazio.set_dietary_preferenceeget_dietary_preferencesusam o prefixouser:(user:dietary_preferences). Esse estado é compartilhado em todas as sessões do mesmo usuário.
Atualizar o agente com novas ferramentas e instruções
Substitua a definição root_agent atual na parte de baixo do arquivo por:
# cafe_concierge/agent.py (replace the existing root_agent)
root_agent = LlmAgent(
name="cafe_concierge",
model="gemini-2.5-flash",
instruction="""You are a friendly and knowledgeable barista at "The Cloud Cafe".
Your job:
- Help customers browse the menu and answer questions about items.
- Take coffee and food orders.
- Remember and respect dietary preferences.
The customer's saved dietary preferences are: {user:dietary_preferences?}
IMPORTANT RULES:
- When a customer mentions a dietary restriction, ALWAYS save it using the
set_dietary_preference tool before doing anything else.
- Before recommending items, check the customer's dietary preferences. If they
have preferences saved, only recommend items compatible with those
restrictions. Check the menu item tags to determine compatibility.
- When placing an order, confirm the items and total with the customer.
Be conversational, warm, and concise.
""",
tools=[
get_menu,
place_order,
get_order_summary,
set_dietary_preference,
get_dietary_preferences,
],
)
A instrução usa o modelo de injeção de estado {user:dietary_preferences?} para injetar as preferências salvas do cliente diretamente no comando.
Verificar o arquivo completo
Seu cafe_concierge/agent.py agora deve conter:
- O dicionário
CAFE_MENU - Cinco funções de ferramenta:
get_menu,place_order,get_order_summary,set_dietary_preference,get_dietary_preferences - A definição de
root_agentcom todas as cinco ferramentas
6. Testar o agente com a interface de desenvolvimento do ADK
Esta etapa executa o agente e exercita todos os recursos com estado: ordenação, rastreamento de preferências e memória entre sessões (no mesmo processo). Você também vai inspecionar os painéis "Eventos" e "Estado" para ver como o ADK rastreia a conversa internamente.
Iniciar a interface de desenvolvimento
cd ~/build-agent-adk-cloudsql
uv run adk web
Abra a visualização da Web na porta 8000 e selecione cafe_concierge no menu suspenso.
Conversa 1: fazer um pedido e definir preferências
Tente estes comandos em sequência:
What's on the menu?
I'm lactose intolerant
What would you recommend?
I'll have an oat milk latte and a banana bread
What's my order?
Inspecionar eventos de sessão
Todos os Eventos serão capturados e exibidos na interface da Web. Na caixa de chat, você vai notar que não há apenas seu comando e resposta, mas também tool_call e tool_response.

Uma lista de eventos vai aparecer em ordem. Cada evento tem um autor (quem o produziu) e um tipo (que tipo de interação ele representa):
Author | Tipo | O que ele representa |
|
| Uma mensagem que você digitou no chat |
|
| A resposta de texto do agente |
|
| O agente decidiu chamar uma ferramenta (mostra o nome da função + argumentos) |
|
| O valor de retorno de uma chamada de função |
Clique em um dos eventos tool_call, por exemplo, a chamada set_dietary_preference. Você verá:
- Nome da função:
set_dietary_preference - Arguments:
{"preference": "lactose intolerant"}
Agora clique no evento tool_response correspondente logo abaixo. Você vai ver o valor de retorno:
- Resposta:
{"saved": "lactose intolerant", "all_preferences": ["lactose intolerant"]}

Procure o campo state_delta no evento tool_response. Isso mostra exatamente qual estado mudou como resultado da chamada de função:
state_delta: {"user:dietary_preferences": ["lactose intolerant"]}
Cada mudança de estado pode ser rastreada até um evento específico. É assim que o ADK garante que o bloco de notas de estado permaneça sincronizado com o histórico de conversas.
Inspecionar o estado da sessão
Clique na guia Estado. Ao contrário do registro de eventos (que mostra o histórico completo), a guia "Estado" mostra um snapshot do que o agente sabe agora: o valor atual de cada chave de estado.

Você vai encontrar duas entradas:
current_order—{"items": ["oat milk latte", "banana bread"], "total": 9.0}user:dietary_preferences—["lactose intolerant"]
Observe a diferença nos nomes das chaves:
current_ordernão tem prefixo. Ele é do escopo da sessão. Ele existe apenas nessa conversa e desaparece quando a sessão termina.user:dietary_preferencestem o prefixouser:e é no escopo do usuário. Ele é compartilhado em todas as sessões desse usuário.
Essa distinção é invisível no código (ambos usam tool_context.state), mas controla o alcance dos dados. Você vai ver isso no próximo teste.
Conversa 2: verificar o estado do usuário em várias sessões
Clique no botão Nova sessão na interface do desenvolvedor para iniciar uma nova conversa. Isso cria uma nova sessão para o mesmo usuário.

Teste este comando:
What do you recommend for me?
Verifique a guia Estado na nova sessão. A tecla user:dietary_preferences é transferida, mas current_order desaparece, porque esse estado estava vinculado à sessão anterior.

7. Observar a limitação do armazenamento local
O agente se lembra das preferências entre as sessões, mas apenas enquanto o armazenamento local existir. Esta etapa demonstra a limitação fundamental do armazenamento local.
Inicie o agente novamente
Você parou a interface de desenvolvimento no final da etapa anterior. Agora vamos remover o armazenamento local e iniciá-lo novamente para simular um ambiente sem servidor, que não tem estado:
cd ~/build-agent-adk-cloudsql
rm -f cafe_concierge/.adk/session.db
uv run adk web
Agora, abra a Visualização da Web na porta 8000 e selecione cafe_concierge.
Teste de recordação de preferências
Tipo:
Do you remember my dietary preferences?
O agente não se lembra. As preferências alimentares, o histórico de pedidos — tudo sumiu.

Tudo foi apagado quando excluímos o armazenamento local, o que geralmente acontecia quando usávamos um ambiente sem servidor. O session.db armazena todo o estado na memória do processo. A remoção apaga tudo.
A solução: especifique DatabaseSessionService, que neste tutorial vai armazenar todos os dados da sessão em um banco de dados PostgreSQL no Cloud SQL. O código e as ferramentas do agente permanecem exatamente os mesmos. A única coisa que muda é o back-end de armazenamento.
Interrompa a interface de desenvolvimento com Ctrl+C antes de continuar.
8. Revisar a configuração do banco de dados
Neste momento, a criação da instância de banco de dados já deve ter sido concluída. Para verificar, execute o seguinte comando:
gcloud sql instances describe cafe-concierge-db --format="value(state)"
Você vai ver a seguinte saída. Marque como concluído.
RUNNABLE
Criar o banco de dados
Crie um banco de dados dedicado para os dados da sessão do agente:
gcloud sql databases create agent_db --instance=cafe-concierge-db
Iniciar o proxy de autenticação do Cloud SQL
O proxy de autenticação do Cloud SQL fornece uma conexão segura e autenticada do Cloud Shell à sua instância do Cloud SQL sem precisar colocar endereços IP na lista de permissões. Ele já vem pré-instalado no Cloud Shell.
cloud-sql-proxy ${GOOGLE_CLOUD_PROJECT}:${REGION}:cafe-concierge-db --port 5432 &
O sufixo & no comando faz com que o proxy seja executado em segundo plano. Você vai ver uma saída confirmando que o proxy está pronto, como mostrado abaixo.
[your-project-id:your-region:cafe-concierge-db] Listening on 127.0.0.1:5432 The proxy has started successfully and is ready for new connections!
Verificar a conexão
Teste se é possível se conectar ao banco de dados pelo proxy:
psql "host=127.0.0.1 port=5432 dbname=agent_db user=postgres password=$DB_PASSWORD" -c "SELECT 'Connection ok' AS status;"
Você verá:
status --------------------- Connection ok (1 row)
9. Verificar a memória persistente em várias sessões
Esta etapa prova que a memória do seu agente sobrevive à redefinição quando garantimos que cafe_concierge/.adk/session_db (o banco de dados local) seja removido e abranja sessões de conversa.
Iniciar o agente
Verifique se o proxy de autenticação do Cloud SQL ainda está em execução (confira com os jobs). Se não estiver, reinicie:
if ss -tlnp | grep -q ':5432 '; then
echo "Cloud SQL Auth Proxy is already running."
else
cloud-sql-proxy ${GOOGLE_CLOUD_PROJECT}:${REGION}:cafe-concierge-db --port 5432 &
fi
Em seguida, vamos iniciar a interface do desenvolvedor do ADK especificando o banco de dados como o serviço de sessão.
uv run adk web --session_service_uri postgresql+asyncpg://postgres:${DB_PASSWORD}@127.0.0.1:5432/agent_db
Abra a Visualização da Web na porta 8000 e selecione cafe_concierge.
Teste 1: fazer um pedido e definir preferências
Na primeira sessão, siga estas instruções:
Show me the menu
I'm vegan
What can I eat?
I'll have a cold brew and banana bread
Teste 2: sobreviver a uma reinicialização
Pare a interface do usuário de desenvolvimento com Ctrl+C e verifique se o session.db local foi removido.
rm -f cafe_concierge/.adk/session.db
Em seguida, execute novamente o servidor da interface de desenvolvimento.
uv run adk web --session_service_uri postgresql+asyncpg://postgres:${DB_PASSWORD}@127.0.0.1:5432/agent_db
Abra a visualização da Web na porta 8000, selecione cafe_concierge e inicie uma nova sessão. Em seguida, pergunte
What are my dietary preferences?
O agente responde com suas preferências salvas: vegana. Os dados sobreviveram à reinicialização porque agora estão armazenados no PostgreSQL, não no armazenamento local. O mesmo acontece se criarmos uma nova sessão, já que o estado user: é transferido para cada nova sessão desse usuário.

Inspecionar o banco de dados diretamente
Abra uma nova guia do terminal no Cloud Shell e consulte o banco de dados para ver os dados armazenados:
psql "host=127.0.0.1 port=5432 dbname=agent_db user=postgres password=$DB_PASSWORD" -c "\dt"
Você vai encontrar tabelas que o ADK criou automaticamente para armazenar sessões, eventos e estados, como neste exemplo:
List of relations Schema | Name | Type | Owner --------+-----------------------+-------+---------- public | adk_internal_metadata | table | postgres public | app_states | table | postgres public | events | table | postgres public | sessions | table | postgres public | user_states | table | postgres (5 rows)
Resumo do comportamento do estado
Chave de estado | Prefixo | Escopo | Compartilhados entre sessões? |
| (nenhum) | Sessão | Não |
|
| Usuário | Sim |
10. Parabéns / Limpeza
Parabéns! Você criou um agente de IA persistente e com estado usando o ADK e o Cloud SQL.
O que você aprendeu
- Como criar um agente do ADK com ferramentas personalizadas que leem e gravam o estado da sessão
- A diferença entre o estado no escopo da sessão (sem prefixo) e o estado no escopo do usuário (prefixo
user:) - Por que o adk local
session.dbpadrão é adequado apenas para desenvolvimento: todos os dados são perdidos na remoção (e são fáceis de remover, sem backup), não sendo adequados para implantação sem servidor, que é sem estado. - Como provisionar uma instância do Cloud SQL PostgreSQL e se conectar a ela com o proxy de autenticação do Cloud SQL
- Como se conectar ao DatabaseSessionService com PostgreSQL no CloudSQL com uma mudança mínima de código: mesmas ferramentas, mesmo agente, back-end diferente
- Como o estado no escopo do usuário persiste em sessões de conversa separadas
Limpeza
Para evitar cobranças na sua conta do Google Cloud, limpe os recursos criados neste codelab.
Opção 1: excluir o projeto (recomendado)
A maneira mais fácil de fazer a limpeza é excluir o projeto. Isso remove todos os recursos associados ao projeto.
gcloud projects delete ${GOOGLE_CLOUD_PROJECT}
Opção 2: excluir recursos individuais
Se você quiser manter o projeto, mas remover apenas os recursos criados neste codelab:
gcloud sql instances delete cafe-concierge-db --quiet