1. Introdução
Neste codelab, você vai aprender a ter os melhores resultados usando a API QueryData. Você vai descobrir como gerar resultados precisos e repetíveis ao fazer solicitações em linguagem natural para seu banco de dados. Para ajudar você a fazer isso, o guia mostra seis receitas em vários capítulos, explorando diferentes aspectos da linguagem natural para SQL (NL2SQL) e suas aplicações práticas.
Pré-requisitos
- Conhecimentos básicos sobre o Google Cloud e o console do Google Cloud
- Habilidades básicas com a interface de linha de comando e o Cloud Shell
O que você vai aprender
- Como implantar um cluster do AlloyDB e uma instância principal
- Como ativar o QueryData, as funções de IA e as visualizações seguras parametrizadas
- Como criar um conjunto de contextos do QueryData
- Como usar diferentes modelos e contextos na API QueryData
- Como tornar os modelos QueryData mais flexíveis usando atributos
- Como resolver a ambiguidade de dados com a pesquisa de valores e a indexação de trigramas
- Como usar funções de IA para pesquisa semântica com modelos
- Como usar visualizações seguras parametrizadas com a API QueryData
O que é necessário
- Uma conta do Google Cloud e um projeto na nuvem do Google Cloud
- Um navegador da Web, como o Chrome, que seja compatível com o console do Google Cloud e o Cloud Shell
2. Configuração e requisitos
Configuração do projeto
- Faça login no Console do Google Cloud. Crie uma conta do Gmail ou do Google Workspace, se ainda não tiver uma.
Use uma conta pessoal em vez de uma conta escolar ou de trabalho.
- Crie um projeto ou reutilize um existente. Para criar um projeto no console do Google Cloud, clique no botão "Selecionar um projeto" no cabeçalho, que vai abrir uma janela pop-up.

Na janela "Selecionar um projeto", clique em "Novo projeto", que vai abrir uma caixa de diálogo para o novo projeto.

Na caixa de diálogo, insira um nome de projeto e escolha o local.

- O Nome do projeto é o nome de exibição para os participantes do projeto. O nome do projeto não é usado pelas APIs do Google e pode ser alterado a qualquer momento.
- O ID do projeto é exclusivo em todos os projetos do Google Cloud e não pode ser mudado após a definição. O console do Google Cloud gera automaticamente um ID exclusivo, mas você pode personalizá-lo. Se você não gostar do ID gerado, crie outro aleatório ou forneça o seu para verificar a disponibilidade. Na maioria dos codelabs, é necessário fazer referência ao ID do projeto, que normalmente é identificado com o marcador de posição PROJECT_ID.
- Para sua informação, há um terceiro valor, um Número do projeto, que algumas APIs usam. Saiba mais sobre esses três valores na documentação.
Ativar faturamento
Configurar uma conta de faturamento pessoal
Se você configurou o faturamento usando créditos do Google Cloud, pule esta etapa.
Para configurar uma conta de faturamento pessoal, acesse este link para ativar o faturamento no console do Cloud.
Algumas observações:
- A conclusão deste laboratório custa menos de US $5 em recursos do Cloud.
- Siga as etapas no final deste laboratório para excluir recursos e evitar mais cobranças.
- Novos usuários podem aproveitar o teste sem custos financeiros de US$300.
Iniciar o Cloud Shell
Embora o Google Cloud e o Spanner possam ser operados remotamente do seu laptop, neste codelab usaremos o Google Cloud Shell, um ambiente de linha de comando executado no Cloud.
No Console do Google Cloud, clique no ícone do Cloud Shell na barra de ferramentas superior à direita:

Ou pressione G e S. Essa sequência vai ativar o Cloud Shell se você estiver no console do Google Cloud ou usar este link.
O provisionamento e a conexão com o ambiente levarão apenas alguns instantes para serem concluídos: Quando o processamento for concluído, você verá algo como:

Essa máquina virtual contém todas as ferramentas de desenvolvimento necessárias. Ela oferece um diretório principal persistente de 5 GB, além de ser executada no Google Cloud. Isso aprimora o desempenho e a autenticação da rede. Neste codelab, todo o trabalho pode ser feito com um navegador. Você não precisa instalar nada.
3. Antes de começar
Ativar API
Para usar o AlloyDB, o Compute Engine, os serviços de rede e a Agent Platform, ative as respectivas APIs no seu projeto na nuvem do Google Cloud.
No terminal do Cloud Shell, verifique se o ID do projeto está configurado:
gcloud config get-value project
O comando vai retornar o ID do projeto do Google Cloud.
Defina a variável de ambiente PROJECT_ID:
PROJECT_ID=$(gcloud config get-value project)
Ative as APIs necessárias:
gcloud services enable alloydb.googleapis.com \
compute.googleapis.com \
cloudresourcemanager.googleapis.com \
servicenetworking.googleapis.com \
geminidataanalytics.googleapis.com \
cloudaicompanion.googleapis.com \
aiplatform.googleapis.com \
dataplex.googleapis.com
Saída esperada:
student@cloudshell:~ (test-project-001-402417)$ gcloud config set project test-project-001-402417
Updated property [core/project].
student@cloudshell:~ (test-project-001-402417)$ PROJECT_ID=$(gcloud config get-value project)
Your active configuration is: [cloudshell-14650]
student@cloudshell:~ (test-project-001-402417)$
student@cloudshell:~ (test-project-001-402417)$ gcloud services enable alloydb.googleapis.com \
compute.googleapis.com \
cloudresourcemanager.googleapis.com \
servicenetworking.googleapis.com \
geminidataanalytics.googleapis.com \
cloudaicompanion.googleapis.com \
aiplatform.googleapis.com \
dataplex.googleapis.com
Operation "operations/acat.p2-4470404856-1f44ebd8-894e-4356-bea7-b84165a57442" finished successfully.
Leia sobre cada API ativada na documentação.
4. Implantar o AlloyDB
Crie um cluster e uma instância principal do AlloyDB. É possível fazer a implantação usando um script preparado que vai implantar todos os recursos necessários ou seguir as etapas da documentação do AlloyDB.
Implantar o AlloyDB usando um script automatizado
Essa abordagem usa um script automatizado para implantar o cluster do AlloyDB e fornece os detalhes de configuração necessários para começar a trabalhar com os recursos implantados.
No terminal do Cloud Shell, execute o comando para clonar o script de implantação do repositório:
REPO_NAME="codelabs"
REPO_URL="https://github.com/GoogleCloudPlatform/$REPO_NAME"
SOURCE_DIR="alloydb-ai-nla"
git clone --no-checkout --filter=blob:none --depth=1 $REPO_URL
cd $REPO_NAME
git sparse-checkout set $SOURCE_DIR
git checkout
cd $SOURCE_DIR
Execute o script de implantação:
./deploy_alloydb.sh
O script leva de cinco a sete minutos para ser concluído. A saída mostra os detalhes da implantação do cluster. Sua senha será diferente. Anote-a para uso futuro.
... <redacted> ... Creating primary instance: alloydb-aip-01-pr (8 vCPUs for TRIAL cluster) Operation ID: operation-1765988049916-646282264938a-bddce198-9f248715 Creating instance...done. ---------------------------------------- Deployment Process Completed Cluster: alloydb-aip-01 (TRIAL) Instance: alloydb-aip-01-pr Region: us-central1 Initial Password: JBBoDTgixzYwYpkF (if new cluster) ----------------------------------------
Confira o novo cluster e a instância na página de clusters do AlloyDB no console do Google Cloud.

5. Preparar banco de dados
Crie um banco de dados, ative a integração da Gemini Enterprise Agent Platform, crie objetos de banco de dados e adicione dados de amostra.
Conceder as permissões necessárias ao AlloyDB
Conceda os papéis do IAM necessários ao agente de serviço do AlloyDB:
Abra uma nova guia do Cloud Shell clicando em Adicionar (+).

Na nova guia, execute:
PROJECT_ID=$(gcloud config get-value project)
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:service-$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")@gcp-sa-alloydb.iam.gserviceaccount.com" \
--role="roles/aiplatform.user"
Saída esperada do console:
student@cloudshell:~ (test-project-001-402417)$ PROJECT_ID=$(gcloud config get-value project) Your active configuration is: [cloudshell-11039] student@cloudshell:~ (test-project-001-402417)$ gcloud projects add-iam-policy-binding $PROJECT_ID \ --member="serviceAccount:service-$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")@gcp-sa-alloydb.iam.gserviceaccount.com" \ --role="roles/aiplatform.user" Updated IAM policy for project [test-project-001-402417]. bindings: - members: - serviceAccount:service-4470404856@gcp-sa-alloydb.iam.gserviceaccount.com role: roles/aiplatform.user - members: ... etag: BwYIEbe_Z3U= version: 1
Ativar a API Data Access
Ative a API Data Access no cluster do AlloyDB.
Na mesma guia do terminal, execute o seguinte comando:
PROJECT_ID=$(gcloud config get-value project)
REGION=us-central1
ADBCLUSTER=alloydb-aip-01
curl -X PATCH \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json" \
https://alloydb.googleapis.com/v1alpha/projects/$PROJECT_ID/locations/$REGION/clusters/$ADBCLUSTER/instances/$ADBCLUSTER-pr?updateMask=dataApiAccess \
-d '{
"dataApiAccess": "ENABLED",
}'
Atualizar flags do banco de dados
Antes de ativar flags no nível da instância, aguarde a conclusão da etapa da API Data Access. Confira se o status da instância mostra uma marca de seleção verde, conforme ilustrado na imagem a seguir.

Para usar extensões de IA e autenticação do IAM em ferramentas de agente, é necessário ativar flags de banco de dados específicas na instância e se adicionar como um usuário do banco de dados. Ative as seguintes flags:
- alloydb.iam_authentication
- password.enforce_complexity
- google_ml_integration.enable_ai_query_engine
- parameterized_views
Na mesma guia do terminal, execute os seguintes comandos:
PROJECT_ID=$(gcloud config get-value project)
REGION=us-central1
ADBCLUSTER=alloydb-aip-01
gcloud beta alloydb instances update $ADBCLUSTER-pr \
--database-flags password.enforce_complexity=on,alloydb.iam_authentication=on,google_ml_integration.enable_ai_query_engine=on,parameterized_views.enabled=on \
--region=$REGION \
--cluster=$ADBCLUSTER \
--project=$PROJECT_ID \
--update-mode=FORCE_APPLY
Crie um usuário do IAM no AlloyDB para sua conta:
REGION=us-central1
ADBCLUSTER=alloydb-aip-01
gcloud alloydb users create $(gcloud config get-value account) \
--cluster=$ADBCLUSTER \
--superuser=true \
--region=$REGION \
--type=IAM_BASED
Feche a guia executando o comando de saída no terminal:
exit
Conectar-se ao AlloyDB Studio
Nos capítulos a seguir, você pode executar todos os comandos SQL que exigem uma conexão de banco de dados no AlloyDB Studio.
Para abrir o AlloyDB Studio, siga estas etapas:
- No console do Google Cloud, acesse a página "Clusters" do AlloyDB para PostgreSQL.
- Selecione a instância principal para abrir a interface da Web.

- Em seguida, clique em AlloyDB Studio à esquerda:

- Selecione o banco de dados
postgres, escolha "Autenticação do IAM" e clique em "Autenticar".

Essa ação abre a interface do AlloyDB Studio.
- Selecione a guia "Consulta sem título" para abrir o editor de SQL.

Isso abre um editor em que é possível executar comandos SQL, conforme mostrado na imagem a seguir:

Criar banco de dados
Criar o banco de dados de início rápido
No editor do AlloyDB Studio, execute o seguinte comando para criar o banco de dados:
CREATE DATABASE quickstart_db
Saída esperada:
Statement executed successfully
Conectar-se a quickstart_db
Clique em "Mudar banco de dados/usuário" no AlloyDB Studio.

Selecione quickstart_db na lista de bancos de dados, escolha "Autenticação do IAM" e faça a autenticação.

Isso vai abrir uma nova conexão em que você pode trabalhar com objetos do banco de dados quickstart_db.
Ativar extensões
Verifique se todas as extensões necessárias estão ativadas no banco de dados e têm as versões mínimas corretas.
Verifique se todas as extensões necessárias estão no seu banco de dados:
SELECT extname, extversion FROM pg_extension WHERE extname IN ('vector', 'google_ml_integration', 'parameterized_views');
Saída esperada:
extname | extversion -----------------------+---------------- google_ml_integration | 1.5.9 parameterized_views | 1.0 vector | 0.8.2.google-1
Se não retornar todas as linhas acima, significa que algumas das extensões não estão ativadas.
Antes de ativar as extensões, precisamos garantir que todas as flags do banco de dados "google_ml_integration.enable_ai_query_engine" e "parameterized_views.enabled" estejam ativadas na instância.
No AlloyDB Studio, enquanto conectado ao quickstart_db, execute:
show google_ml_integration.enable_ai_query_engine;
show parameterized_views.enabled;
Se algum deles estiver mostrando "desativado", repita a etapa "Atualizar flags de banco de dados" e verifique o status usando os comandos "show..." novamente.
Ative as extensões necessárias.
No AlloyDB Studio, enquanto conectado ao quickstart_db, execute:
CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS parameterized_views;
Verifique as versões das extensões parameterized_views e google_ml.
No AlloyDB Studio, enquanto conectado ao quickstart_db, execute:
SELECT extname, extversion FROM pg_extension WHERE extname IN ('vector', 'google_ml_integration', 'parameterized_views');
Saída esperada:
extname | extversion -----------------------+---------------- google_ml_integration | 1.5.9 parameterized_views | 1.0 vector | 0.8.2.google-1
Se a versão for anterior à necessária, tente atualizar a extensão parameterized_views.
Para parameterized_views, tente:
ALTER EXTENSION parameterized_views UPDATE;
Verifique a versão novamente.
No AlloyDB Studio, enquanto conectado ao quickstart_db, execute:
SELECT extname, extversion FROM pg_extension WHERE extname IN ('vector', 'google_ml_integration', 'parameterized_views');
Saída esperada:
extname | extversion -----------------------+---------------- google_ml_integration | 1.5.9 parameterized_views | 1.0 vector | 0.8.2.google-1
6. Dados de amostra
Agora você precisa criar objetos no banco de dados e carregar dados. Você vai usar um conjunto de dados fictício de uma imobiliária. Ele tem dados fictícios sobre vendas de imóveis e agentes. Os dados foram fornecidos no script SQL real_estate_data.sql no repositório clonado.
Crie um bucket do Cloud Storage
Use o SDK do Google (gcloud) para importar dados do repositório clonado para o banco de dados do AlloyDB. Para isso, crie um bucket do Cloud Storage e conceda acesso à conta de serviço do AlloyDB. Como alternativa, você pode tentar fazer isso usando o console da Web, conforme descrito na documentação.
No terminal do Google Cloud Shell, execute:
PROJECT_ID=$(gcloud config get-value project)
REGION=us-central1
gcloud storage buckets create gs://$PROJECT_ID-import --project=$PROJECT_ID --location=$REGION
gcloud storage buckets add-iam-policy-binding gs://$PROJECT_ID-import --member="serviceAccount:service-$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")@gcp-sa-alloydb.iam.gserviceaccount.com" --role=roles/storage.objectViewer
Carregar dados
O dump SQL do banco de dados está localizado na pasta do repositório clonado. O comando a seguir pressupõe que você usou seu diretório principal como ponto de partida ao clonar o repositório na etapa anterior durante a criação do cluster do AlloyDB.
Copie o arquivo dump do banco de dados para o bucket do Cloud Storage:
REPO_NAME="codelabs"
SOURCE_DIR="alloydb-ai-nla"
cd ~/$REPO_NAME/$SOURCE_DIR
gcloud storage cp ~/$REPO_NAME/$SOURCE_DIR/real_estate_data.sql gs://$PROJECT_ID-import
Importe o conjunto de dados para quickstart_db:
PROJECT_ID=$(gcloud config get-value project)
CLUSTER_NAME=alloydb-aip-01
REGION=us-central1
IAM_USER=$(gcloud config get-value account)
gcloud alloydb clusters import $CLUSTER_NAME --region=us-central1 --database=quickstart_db --gcs-uri=gs://$PROJECT_ID-import/real_estate_data.sql --project=$PROJECT_ID --sql --user=$IAM_USER
O comando vai carregar o conjunto de dados de amostra no banco de dados quickstart_db.
Verifique a importação contando os registros na tabela "real_estate.agents" usando o AlloyDB Studio:
SELECT COUNT(*) FROM real_estate.agents;
7. Preparar a ontologia de esquema
Configure o conjunto de contexto QueryData, forneça metadados de esquema e execute o agente do ADK.
Criar metadados
Os metadados consistem em comentários SQL aplicados a tabelas e colunas de banco de dados. Esses comentários orientam o mecanismo QueryData ao selecionar objetos de banco de dados.
Se você importou seu esquema de dados usando o dump SQL fornecido, todos os metadados já foram criados no seu esquema.
Confira um exemplo de snippet de metadados aplicado ao esquema real_estate:
COMMENT ON TABLE real_estate.agents IS 'Stores profile, contact, brokerage affiliation, and active status for individual real estate agents.'; COMMENT ON COLUMN real_estate.agents.agent_id IS 'Primary key uniquely identifying each real estate agent in the database.'; ...
Se você estiver trabalhando com seu próprio conjunto de dados, siga o guia documentado sobre como adicionar os metadados do seu esquema.
Criar contexto de ontologia de esquema
Um conjunto de contexto contém modelos de consulta, atributos e pesquisas de valor que ajudam o modelo de IA a gerar consultas. Sem o contexto definido, um agente de IA vai tentar gerar uma consulta usando apenas as informações disponíveis do esquema public, principalmente com base nos nomes de tabelas, colunas e metadados, tentando deduzir os objetos certos para responder a uma solicitação de consulta natural.
O conjunto de contexto QueryData é um arquivo JSON com modelos de consulta, facetas e pesquisas de valor. Confira diferentes exemplos na documentação.
Carregar o conjunto de contexto QueryData no console da Web
Para carregar um conjunto de contexto, abra o AlloyDB Studio e, no painel esquerdo na parte de baixo, você vai encontrar Context sets e três pontos.

Clique nos três pontos e escolha Create context set.
Na caixa de diálogo aberta, insira os seguintes valores:
- Nome:
sixrecipes - Descrição:
Real Estate Query Data - Fazer upload do arquivo de contexto: deixe-o vazio
Ao pressionar o botão Create, pode levar algum tempo para inicializar o armazenamento de contexto se você fizer isso pela primeira vez.
Verifique o ID do conjunto de contexto QueryData clicando novamente nos três pontos à direita do nome do conjunto de contexto e escolha Edit context set.

O ID do conjunto de contexto aparece na parte de cima da guia aberta à direita.

Salve esse ID para as próximas etapas.
Iniciar o agente de IA
Para interagir com o back-end QueryData e gerar e executar consultas, use a interface do AlloyDB Studio, conforme descrito na documentação. Mas, neste laboratório, você vai usar um agente de IA como a principal ferramenta de comunicação com o banco de dados. Os agentes de IA são um cenário mais realista para cargas de trabalho futuras, e a estrutura ADK do Google oferece uma ótima interface da Web em que é possível conferir todas as etapas e interações entre modelos, APIs e aplicativos.
Revise a configuração da origem do agente no Cloud Shell:
REPO_NAME="codelabs"
SOURCE_DIR="alloydb-ai-nla"
cd ~/$REPO_NAME/$SOURCE_DIR/data_agent
edit agent.py
No arquivo, você pode ver onde definimos a lista de tabelas no nosso esquema. Vamos voltar a isso em uma das próximas etapas.
# List of database tables included in QueryData API requests
TABLE_IDS = [
"real_estate.municipalities",
"real_estate.cities",
"real_estate.agents",
"real_estate.properties",
"real_estate.schools",
"real_estate.school_to_property",
"real_estate.property_transactions",
"real_estate.secure_offers",
]
Além disso, há um procedimento call_querydata_api para trabalhar com a API QueryData e um conjunto de ferramentas para usar as habilidades da API QueryData.
def call_querydata_api(
prompt: str,
target_project_id: str = project_id,
target_location: str = location,
target_cluster_id: str = cluster_name,
target_instance_id: str = instance_name,
target_database_id: str = database_name,
target_context_set_id: str = context_set_id,
target_table_ids: list[str] = TABLE_IDS,
) -> dict:
"""Calls the Gemini Data Analytics QueryData API to translate natural ...
<Redacted>
...
# ADK File-Based Skill
database_query_skill = load_skill_from_dir(
pathlib.Path(__file__).parent / "skills" / "database-query-skill"
)
skill_toolset = SkillToolset(
skills=[database_query_skill]
)
Este é o agente raiz com um comando e as ferramentas disponíveis.
# Agent configuration
root_agent = Agent(
model=MODEL_ID,
name='root_agent',
description='A helpful assistant for analyst requests.',
instruction=f"""
Answer user questions to the best of your knowledge using provided tools.
Do not try to generate non-existent data but use the grounded data from the database.
When you answer questions about database contents, real estate properties, or sales activity:
1. Refer to database-query-skill for instructions on querying data using QueryData API.
2. Use `call_querydata_api` to submit the natural language prompt to the QueryData API.
CRITICAL: Call `call_querydata_api` EXACTLY ONCE per user request. Do NOT make retries, follow-up calls, or rephrased calls to `call_querydata_api`, even if the result contains zero rows or empty data.
3. Immediately parse the JSON response from that first `call_querydata_api` call.
4. Format your final response to the user containing:
- The generated SQL query (formatted in a Markdown SQL code block).
- The query results formatted as a Markdown table (constructed from `queryResult.columns` and `queryResult.rows`).
- The natural language answer (`naturalLanguageAnswer`).
""",
tools=[call_querydata_api, skill_toolset],
)
Analise data_agent/SKILL.md para entender as instruções do sistema do agente:
REPO_NAME="codelabs"
SOURCE_DIR="alloydb-ai-nla"
cd ~/$REPO_NAME/$SOURCE_DIR/data_agent
edit SKILL.md
Antes de iniciar o agente, prepare um arquivo .env com parâmetros para solicitações de API Agent e QueryData.
Exporte o ID do conjunto de contexto para uma variável de ambiente:
export QUERYDATA_CONTEXTSET=<context set id from the Create Context Set chapter>
Crie o arquivo de configuração do ambiente de execução (.env) no diretório data_agent:
PROJECT_ID=$(gcloud config get-value project)
REGION=us-central1
REPO_NAME="codelabs"
SOURCE_DIR="alloydb-ai-nla"
cd ~/$REPO_NAME/$SOURCE_DIR/data_agent
echo "GOOGLE_GENAI_USE_ENTERPRISE=true" > .env
echo "GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project -q)" >> .env
echo "GOOGLE_CLOUD_LOCATION=global" >> .env
echo "QUERYDATA_CONTEXTSET=$QUERYDATA_CONTEXTSET" >> .env
echo "ALLOYDB_CLUSTER=alloydb-aip-01" >> .env
echo "ALLOYDB_INSTANCE=alloydb-aip-01-pr" >> .env
echo "ALLOYDB_DATABASE=quickstart_db" >> .env
echo "ALLOYDB_LOCATION=$REGION" >> .env
Instale as dependências e inicie o serviço da Web do agente:
cd ~/$REPO_NAME/$SOURCE_DIR/
uv sync
Inicie o agente:
uv run adk web --allow_origins 'regex:https://.*\.cloudshell\.dev'
Você vai ver uma saída como esta, com o endpoint http://127.0.0.1:8000 .
INFO: Started server process [83608] INFO: Waiting for application startup. +-----------------------------------------------------------------------------+ | ADK Web Server started | | | | For local testing, access at http://127.0.0.1:8000. | +-----------------------------------------------------------------------------+ INFO: Application startup complete. INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)

Clique no URL do servidor da Web gerado (por exemplo, http://127.0.0.1:8000) no Cloud Shell para iniciar a interface do agente. Se não funcionar, no Cloud Shell, clique em "Visualização na Web" -> "Visualizar na porta 8000" para abrir a interface do agente.
Verifique se data_agent está selecionado no menu suspenso no canto superior esquerdo.

Gerar e executar consultas
Vamos executar a consulta Q1
Execute este comando de linguagem natural na interface de chat do agente para avaliar a performance básica do QueryData sem modelos ou facetas personalizados:
How many properties are currently for sale in San Diego?
e pressione o botão de seta.

Ele vai iniciar o fluxo de trabalho do agente quando escolher a habilidade adequada e usá-la, além da função, para enviar a solicitação ao endpoint de API e receber de volta a consulta gerada e os resultados.

E se você passar o cursor do mouse sobre as etapas, poderá ver exatamente o que elas estavam fazendo. Você também pode conferir isso e muito mais no painel à esquerda ao escolher uma ou outra etapa. Ele pode ajudar a entender como os agentes trabalham com habilidades e APIs.

Envie uma consulta complementar (Q2):
List agents who sold a property for over $1000000.
Você vai notar que o agente vai direto para a habilidade da API QueryData, já que ele já gravou na memória as habilidades disponíveis e não precisa passar pela fase de descoberta novamente.
O SQL gerado é semelhante a esta instrução:
SELECT DISTINCT "a"."agent_id", "a"."firstname", "a"."lastname", "a"."email", "a"."brokerage" FROM "real_estate"."agents" AS "a" INNER JOIN "real_estate"."property_transactions" AS "t" ON "a"."agent_id" = "t"."seller_agent_id" WHERE "t"."sale_price" > 1000000 AND "a"."agent_id" IS NOT NULL ORDER BY "a"."lastname" ASC NULLS LAST;
Tente outra consulta (Q3):
What is the average price of a single-family home with a garage in San Diego?
O QueryData gera consultas padrão com um conjunto de contexto vazio, mas as tarefas comerciais geralmente exigem uma lógica de negócios específica e um comportamento determinista.
8. Alcance alta precisão e relevância comercial injetando interpretação
Ao injetar interpretação nos comandos, você garante que as consultas geradas correspondam a uma lógica de negócios específica.
Você vai testar um exemplo em que um cliente pede casas de um único nível em Del Mar. A pergunta tem duas métricas importantes e representa um padrão frequente para uma seleção.
Teste o seguinte comando de linguagem natural (Q4) no agente.
Single level Del Mar houses
O mecanismo retorna uma consulta geral, mas pode incluir algumas condições adicionais, como is_single_family = TRUE:
SELECT p."property_id", p."address_street", p."price", p."bedrooms", p."bathrooms", p."listing_status", p."is_single_family", p."num_stories", c."city_name" FROM "real_estate"."properties" AS p JOIN "real_estate"."cities" AS c ON p."city_id" = c."city_id" WHERE c."city_name" ILIKE 'Del Mar' AND p."num_stories" = 1 AND p."is_single_family" = TRUE ORDER BY p."property_id" ASC NULLS LAST;
Recebemos uma linha retornada como resultado:
Natural Language Answer The database contains one single-level, single-family house in Del Mar: Address: 999 Main Ave (Postal Code: 90024) Price: $3,800,000.00 Bedrooms: 4 Bathrooms: 3.5 Listing Status: Active Features: Single-family home (1 story), has a garage, and no condo fees.
Teste outro comando (Q5):
Del Mar houses close to good schools
Ele é inteligente o suficiente para usar as colunas proximity_miles e school_ranking para classificar as propriedades, mas não avalia o peso e a importância de cada métrica.
SELECT "p"."property_id", "p"."address_street", "p"."price", "p"."bedrooms", "p"."bathrooms", "s"."school_name", "s"."school_ranking", "sp"."proximity_miles" FROM "real_estate"."properties" AS "p" INNER JOIN "real_estate"."cities" AS "c" ON "p"."city_id" = "c"."city_id" INNER JOIN "real_estate"."school_to_property" AS "sp" ON "p"."property_id" = "sp"."property_id" INNER JOIN "real_estate"."schools" AS "s" ON "sp"."school_id" = "s"."school_id" WHERE "c"."city_name" = 'Del Mar' AND "sp"."proximity_miles" IS NOT NULL AND "s"."school_ranking" IS NOT NULL ORDER BY "sp"."proximity_miles" ASC NULLS LAST, "s"."school_ranking" ASC NULLS LAST;
Generalizar o exemplo de consulta em um modelo
A lógica de negócios exige:
- Proximidade em um raio de 3 km
- Classificação da escola de 5 ou menos
- Ordenação ponderada: 80% de classificação da escola + 20% de proximidade (pontuação = 0,8 * classificação_da_escola + 0,2 * milhas_de_proximidade)
Esta é a fórmula do ranking ponderado:
Score = 0.8 * school_ranking + 0.2 * proximity_miles
Faça o download do arquivo de contexto sixrecipe_context1_1.json do Cloud Shell usando a interface de linha de comando no Cloud Shell:
cloudshell download ~/codelabs/alloydb-ai-nla/sixrecipe_context1_1.json
Ou usando o item de menu Download no menu do Cloud Shell:

Faça upload do sixrecipe_context1_1.json no conjunto de contexto sixrecipe usando o AlloyDB Studio para definir essa estrutura padrão. Clique nos três pontos à direita do contexto sixrecipes e use "Editar conjunto de contexto" para fazer upload do novo arquivo. Isso vai substituir o contexto vazio antigo pelo novo.
O modelo define regras explícitas de modelo SQL para boas regras de proximidade escolar:
{
"facets": [],
"templates": [
{
"nl_query": "Riverside houses close to good schools.",
"sql": "SELECT \"p\".\"address_street\", \"p\".\"address_postal_code\", \"s\".\"school_name\", \"stp\".\"proximity_miles\" FROM \"real_estate\".\"properties\" AS \"p\" JOIN \"real_estate\".\"cities\" AS \"c\" ON \"p\".\"city_id\" = \"c\".\"city_id\" JOIN \"real_estate\".\"school_to_property\" AS \"stp\" ON \"p\".\"property_id\" = \"stp\".\"property_id\" JOIN \"real_estate\".\"schools\" AS \"s\" ON \"stp\".\"school_id\" = \"s\".\"school_id\" WHERE \"c\".\"city_name\" = 'Riverside' AND \"s\".\"school_ranking\" <= 5 AND \"stp\".\"proximity_miles\" <= 2 ORDER BY 0.8 * \"s\".\"school_ranking\" + 0.2 * \"stp\".\"proximity_miles\"",
"intent": "Houses in Riverside close to good schools (within 2 miles of schools with a rank of at least 5).",
"manifest": "A given city houses close to good schools.",
"parameterized": {
"parameterized_intent": "Houses in $1 close to good schools (within 2 miles of schools with a rank of at least 5).",
"parameterized_sql": "SELECT \"p\".\"address_street\", \"p\".\"address_postal_code\", \"s\".\"school_name\", \"stp\".\"proximity_miles\" FROM \"real_estate\".\"properties\" AS \"p\" JOIN \"real_estate\".\"cities\" AS \"c\" ON \"p\".\"city_id\" = \"c\".\"city_id\" JOIN \"real_estate\".\"school_to_property\" AS \"stp\" ON \"p\".\"property_id\" = \"stp\".\"property_id\" JOIN \"real_estate\".\"schools\" AS \"s\" ON \"stp\".\"school_id\" = \"s\".\"school_id\" WHERE \"c\".\"city_name\" = $1 AND \"s\".\"school_ranking\" <= 5 AND \"stp\".\"proximity_miles\" <= 2 ORDER BY 0.8 * \"s\".\"school_ranking\" + 0.2 * \"stp\".\"proximity_miles\""
}
}
]
}
Execute o comando novamente:
Del Mar houses close to good schools
A consulta resultante agora corresponde à lógica de negócios definida no modelo:
SELECT "p"."address_street", "p"."address_postal_code", "s"."school_name", "stp"."proximity_miles" FROM "real_estate"."properties" AS "p" JOIN "real_estate"."cities" AS "c" ON "p"."city_id" = "c"."city_id" JOIN "real_estate"."school_to_property" AS "stp" ON "p"."property_id" = "stp"."property_id" JOIN "real_estate"."schools" AS "s" ON "stp"."school_id" = "s"."school_id" WHERE "c"."city_name" = 'Del Mar' AND "s"."school_ranking" <= 5 AND "stp"."proximity_miles" <= 2 ORDER BY 0.8 * "s"."school_ranking" + 0.2 * "stp"."proximity_miles"
Além da instrução SQL gerada, a seguinte intenção é produzida:
intentExplanation: "Houses in Del Mar close to good schools (within 2 miles of schools with a rank of at least 5)."
Você pode ver a intent no painel esquerdo da interface da web do ADK, como mostrado aqui:

Os resultados mostram duas propriedades classificadas pela nossa pontuação:
Query Results address_street address_postal_code school_name proximity_miles 200 Coast Blvd 92014 Del Mar Heights Elementary 0.50 100 Del Mar Heights Rd 92014 Del Mar Heights Elementary 1.00 Answer Based on the data, here are the properties in Del Mar located within 2 miles of a top-rated school (ranking of 5 or better): 200 Coast Blvd (92014) School: Del Mar Heights Elementary Proximity: 0.50 miles 100 Del Mar Heights Rd (92014) School: Del Mar Heights Elementary Proximity: 1.00 miles
No próximo capítulo, você vai ampliar o escopo do modelo.
Injetar interpretação capturando e interpretando várias perguntas
Você pode ampliar o escopo do nosso modelo para que ele seja usado não apenas para "perto de boas escolas", mas também adicionando outras condições ao manifesto para ser usado, por exemplo, para "casas para famílias com crianças".
Baixe o arquivo de contexto atualizado:
cloudshell download ~/codelabs/alloydb-ai-nla/sixrecipe_context1_2.json
Faça upload do arquivo sixrecipe_context1_2.json atualizado para seu conjunto de contexto.
No novo arquivo de conjunto de contexto, estamos substituindo o manifesto de "manifest": "A given city houses close to good schools." para o manifesto "manifest": "A given city houses close to good schools, or are great for families with kids.". Ele expande as aplicações desse modelo para ser usado em mais de um caso.
Envie esta consulta (Q6):
Houses in Waterloo great for families with kids.
O agente usa o manifesto de modelo atualizado para aplicar sua lógica de consulta padronizada, retornando a mesma consulta acima, com o objetivo de:
intentExplanation : "Houses in Waterloo close to good schools (within 2 miles of schools with a rank of at least 5)."
9. Use modelos facetados para alcançar alta precisão e manter a flexibilidade
Os refinamentos são condições SQL modulares combinadas dinamicamente com modelos para processar qualificadores (por exemplo, "família iniciante", "vista para o mar") sem criar modelos separados para cada permutação.
Em vez de criar um modelo para cada consulta ou condição, podemos preparar fragmentos que podem ser aplicados a modelos atuais, adicionando mais dimensões à consulta.
Defina uma faceta para propriedades com os seguintes atributos:
- Uma casa unifamiliar
- Um status de informações do produto ativo
- Três a quatro quartos e pelo menos dois banheiros
- Localização em um município com uma taxa de criminalidade inferior a 500 por 100 mil habitantes
Baixe o arquivo de contexto facetado:
cloudshell download ~/codelabs/alloydb-ai-nla/sixrecipe_context2_1.json
Faça upload de sixrecipe_context2_1.json para o conjunto de contexto sixrecipes no AlloyDB Studio para configurar as facetas.
"facets": [
{
"sql_snippet": "real_estate.properties.is_single_family = TRUE AND real_estate.properties.listing_status = 'Active' AND real_estate.properties.bedrooms BETWEEN 3 AND 4 AND real_estate.properties.bathrooms >= 2.0 AND 500 > (SELECT m.crime_rate_per_100k FROM real_estate.cities c JOIN real_estate.municipalities m ON c.municipality_id = m.municipality_id AND c.city_id = real_estate.properties.city_id)",
"intent": "for a starter family (active single-family home listings with 3 to 4 bedrooms, 2+ bathrooms, and a crime rate under 500 per 100,000 residents)",
"manifest": "for a starter family",
"parameterized": {
"parameterized_intent": "for a starter family (active single-family home listings with 3 to 4 bedrooms, 2+ bathrooms, and a crime rate under 500 per 100,000 residents)",
"parameterized_sql_snippet": "real_estate.properties.is_single_family = TRUE AND real_estate.properties.listing_status = 'Active' AND real_estate.properties.bedrooms BETWEEN 3 AND 4 AND real_estate.properties.bathrooms >= 2.0 AND 500 > (SELECT m.crime_rate_per_100k FROM real_estate.cities c JOIN real_estate.municipalities m ON c.municipality_id = m.municipality_id AND c.city_id = real_estate.properties.city_id)"
}
}
]
Consulta usando a pesquisa facetada
Execute esta consulta em linguagem natural (Q7):
Del Mar houses close to good schools for a starter family.
O mecanismo anexa suas condições de faceta diretamente à consulta básica:
SELECT "p"."address_street", "p"."address_postal_code", "s"."school_name", "stp"."proximity_miles"
FROM "real_estate"."properties" AS "p"
JOIN "real_estate"."cities" AS "c" ON "p"."city_id" = "c"."city_id"
JOIN "real_estate"."school_to_property" AS "stp" ON "p"."property_id" = "stp"."property_id"
JOIN "real_estate"."schools" AS "s" ON "stp"."school_id" = "s"."school_id"
WHERE "c"."city_name" = 'Del Mar'
AND "s"."school_ranking" <= 5
AND "stp"."proximity_miles" <= 2
AND "p"."is_single_family" = TRUE
AND "p"."listing_status" = 'Active'
AND "p"."bedrooms" BETWEEN 3 AND 4
AND "p"."bathrooms" >= 2.0
AND 500 > (
SELECT m.crime_rate_per_100k
FROM real_estate.cities c
JOIN real_estate.municipalities m ON c.municipality_id = m.municipality_id
AND c.city_id = p.city_id
)
ORDER BY 0.8 * "s"."school_ranking" + 0.2 * "stp"."proximity_miles"
Confira os resultados:
Query Results address_street address_postal_code school_name proximity_miles 200 Coast Blvd 92014 Del Mar Heights Elementary 0.50 Natural Language Answer Based on your criteria, there is an active listing for a single-family house in Del Mar that fits your needs: Address: 200 Coast Blvd, Del Mar, 92014 Nearby School: Del Mar Heights Elementary (ranked within the top 5) Proximity to School: 0.50 miles
Adicionar mais atributos
E se quisermos adicionar mais uma dimensão com base no novo padrão emergente, como uma visualização de janela para a propriedade?
Adicione a correspondência semântica de vista para o mar em uma definição de faceta.
{
"sql_snippet": "((real_estate.properties.description_embedding <=> google_ml.embedding('gemini-embedding-001', 'unobstructed, panoramic, ocean vista, vast Pacific, breathtaking, commanding view, deep blue horizon, massive, sweeping view')::vector) < 0.4)",
"intent": "with ocean view",
"manifest": "with ocean view",
"parameterized": {
"parameterized_intent": "with ocean view",
"parameterized_sql_snippet": "((real_estate.properties.description_embedding <=> google_ml.embedding('gemini-embedding-001', 'unobstructed, panoramic, ocean vista, vast Pacific, breathtaking, commanding view, deep blue horizon, massive, sweeping view')::vector) < 0.4)"
}
O valor 0,4 na definição de faceta acima é um limite calibrado experimentalmente. Baixe o arquivo de contexto multifacetado:
cloudshell download ~/codelabs/alloydb-ai-nla/sixrecipe_context2_2.json
Faça upload de sixrecipe_context2_2.json para seu conjunto de contexto e execute este comando (Q8):
Ocean view Del Mar homes near good schools.
A saída contém condições padrão combinadas com correspondência de similaridade de vetor via google_ml.embedding:
SELECT "p"."address_street", "p"."address_postal_code", "s"."school_name", "stp"."proximity_miles"
FROM "real_estate"."properties" AS "p"
JOIN "real_estate"."cities" AS "c" ON "p"."city_id" = "c"."city_id"
JOIN "real_estate"."school_to_property" AS "stp" ON "p"."property_id" = "stp"."property_id"
JOIN "real_estate"."schools" AS "s" ON "stp"."school_id" = "s"."school_id"
WHERE "c"."city_name" = 'Del Mar' AND "s"."school_ranking" <= 5 AND "stp"."proximity_miles" <= 2
AND (((p.description_embedding <=> google_ml.embedding('gemini-embedding-001', 'unobstructed, panoramic, ocean vista, vast Pacific, breathtaking, commanding view, deep blue horizon, massive, sweeping view')::vector) <= 0.4))
ORDER BY 0.8 * "s"."school_ranking" + 0.2 * "stp"."proximity_miles";
E a consulta retorna uma propriedade:
Query Results address_street address_postal_code school_name proximity_miles 100 Del Mar Heights Rd 92014 Del Mar Heights Elementary 1.00 Answer The ocean-view home in Del Mar near a top-ranked school is located at 100 Del Mar Heights Rd (92014). It is situated just 1.00 mile away from Del Mar Heights Elementary, which is one of the area's highly-ranked schools (ranking of 5 or better).
Verifique os resultados conferindo a descrição da propriedade no AlloyDB Studio e executando a seguinte consulta:
select description from real_estate.properties where address_postal_code='92014' and description is not null;
A descrição vai aparecer com "magnificent marine spectacle".
Well-located 2-bedroom condo with excellent proximity to coastal shopping and dining. The balcony provides a magnificent marine spectacle against an azure backdrop. Under contract, high monthly HOA fee.
10. Desambiguação dos seus dados particulares usando pesquisas de valor
Solicitações ambíguas podem corresponder a várias entidades, como confundir o nome de um local com o de uma empresa. As pesquisas de valor mapeiam termos para conceitos de banco de dados e ajudam a resolver essas referências.
A pesquisa de valores fornece associações entre o nome da coluna mais os valores na coluna e um tipo de conceito, que pode ser, por exemplo, uma cidade, um país ou um nome. Como ele indexou não apenas metadados, mas também amostras representativas dos dados em uma coluna, é possível associar um valor usado na solicitação em linguagem natural a um tipo de conceito potencial e a qual tabela e coluna podem ser usadas no SQL resultante.
Ambiguidade em uma consulta
Na vida real, isso pode ser ainda mais difícil devido a erros de ortografia de diferentes nomes e locais. Execute este comando (Q9) com um erro de digitação e um termo ambíguo:
Westwod's sold properties in the last 1 month.
Há dois problemas aqui: o nome está escrito incorretamente e não está claro se estamos falando de propriedades vendidas no local com nomes semelhantes ou de uma imobiliária. Quando executamos a consulta, ela retorna uma consulta como esta:
SELECT "p"."property_id", "p"."address_street", "p"."address_postal_code", "p"."price" AS "listing_price", "p"."bedrooms", "p"."bathrooms", "p"."listing_status", "pt"."sale_date", "pt"."sale_price", "c"."city_name" FROM "real_estate"."properties" AS "p" INNER JOIN "real_estate"."property_transactions" AS "pt" ON "p"."property_id" = "pt"."property_id" INNER JOIN "real_estate"."cities" AS "c" ON "p"."city_id" = "c"."city_id" WHERE ("c"."city_name" ILIKE '%Westwood%' OR "c"."city_name" ILIKE '%Westwod%') AND "pt"."sale_date" >= '2025-09-01'::date AND "pt"."sale_date" <= '2025-09-30'::date ORDER BY "pt"."sale_date" DESC NULLS LAST, "pt"."sale_price" DESC NULLS LAST
Ele corrigiu o nome e assumiu que a pergunta era sobre a localização das propriedades, tentando corresponder a propriedades na cidade de Westwood.
Ative a extensão pg_trgm no AlloyDB Studio para oferecer suporte a comparações de strings aproximadas:
CREATE EXTENSION IF NOT EXISTS pg_trgm;
Depois disso, podemos usar a extensão para adicionar pesquisas de valor ao nosso conjunto de contexto QueryData.
Confira a lista de pesquisas de valor que queremos usar:
"value_searches": [
{
"conceptType": "Municipality name",
"query": "/* Requires extension: pg_trgm */ WITH TrigramMetrics AS (SELECT T.municipality_name AS original_value, (T.municipality_name % $value::text) AS normalized_dist FROM real_estate.municipalities T WHERE T.municipality_name % $value::text) SELECT original_value AS value, 'real_estate.municipalities.municipality_name' AS columns, 'Name of the municipality' AS concept_type, normalized_dist AS distance, ''::text AS context FROM TrigramMetrics",
"description": "Trigram match for municipality name"
},
{
"conceptType": "City name",
"query": "/* Requires extension: pg_trgm */ WITH TrigramMetrics AS (SELECT T.city_name AS original_value, (T.city_name % $value::text) AS normalized_dist FROM real_estate.cities T WHERE T.city_name % $value::text) SELECT original_value AS value, 'real_estate.cities.city_name' AS columns, 'Name of the city' AS concept_type, normalized_dist AS distance, ''::text AS context FROM TrigramMetrics",
"description": "Trigram match for city name"
},
{
"conceptType": "Brokerage name",
"query": "/* Requires extension: pg_trgm */ WITH TrigramMetrics AS (SELECT T.brokerage AS original_value, (T.brokerage % $value::text) AS normalized_dist FROM real_estate.agents T WHERE T.brokerage % $value::text) SELECT original_value AS value, 'real_estate.agents.brokerage' AS columns, 'Name of the brokerage' AS concept_type, normalized_dist AS distance, ''::text AS context FROM TrigramMetrics",
"description": "Trigram match for brokerage name"
}
]
Baixe o arquivo de contexto de pesquisa de valor:
cloudshell download ~/codelabs/alloydb-ai-nla/sixrecipe_context3_1.json
Faça upload de sixrecipe_context3_1.json para o conjunto de contextos sixrecipes do QueryData e salve.
Execute o comando novamente (Q9):
Westwod's sold properties in the last 1 month.
Ela retornou uma resposta de esclarecimento porque, na pesquisa de valores, encontrou três entidades diferentes com valores semelhantes:
The database requires some clarification to provide the exact information you need: The search term 'Westwod' (Westwood) is ambiguous because it can refer to: A municipality name (e.g., the municipality of Westwood) A city name (e.g., the city of Westwood) A brokerage name (e.g., properties sold by agents affiliated with the Westwood brokerage) Could you please clarify which of these you are referring to?
O rastreamento nos dá uma pista de por que ele escolheu esse caminho específico.

Confira o texto completo:
"[NOT_ENOUGH_INFO] The search term 'Westwod' is ambiguous because it can refer to a municipality name, a city name, or a brokerage name. Could you please clarify if you are referring to properties sold within the municipality of Westwood, the city of Westwood, or properties sold by agents affiliated with the Westwood brokerage?"
Remover a ambiguidade da consulta
Refine o comando de entrada (Q10):
Westwood city location properties sold in September 2025.
Agora temos a consulta e os resultados:
Generated SQL SELECT "p"."property_id", "p"."address_street", "p"."address_postal_code", "p"."price", "pt"."sale_date", "pt"."sale_price" FROM "real_estate"."properties" AS "p" INNER JOIN "real_estate"."cities" AS "c" ON "p"."city_id" = "c"."city_id" INNER JOIN "real_estate"."property_transactions" AS "pt" ON "p"."property_id" = "pt"."property_id" WHERE "c"."city_name" = 'Westwood' AND "pt"."sale_date" >= '2025-09-01'::date AND "pt"."sale_date" <= '2025-09-30'::date ORDER BY "pt"."sale_date" ASC NULLS LAST Query Results property_id address_street address_postal_code price sale_date sale_price 32 999 Main St 99999 3800000.00 2025-09-12 1000000.00
11. Pesquisa semântica e funções de IA
As funções de IA do AlloyDB permitem a filtragem semântica em dados não estruturados. Use funções como ai.if e google_ml.embedding diretamente em consultas SQL com operadores de banco de dados padrão.
Modelo com operadores ILIKE
Como primeira etapa, faça upload do novo arquivo de contexto com operadores ILIKE.
Faça o download do arquivo de contexto do modelo ILIKE:
cloudshell download ~/codelabs/alloydb-ai-nla/sixrecipe_context4_1.json
Faça upload de sixrecipe_context4_1.json no seu conjunto de contexto para avaliar a correspondência de padrões ILIKE padrão para casas "prontas para morar".
{
"nl_query": "Move-in ready houses",
"sql": "SELECT \"p\".\"address_street\", \"p\".\"address_postal_code\" FROM \"real_estate\".\"properties\" AS \"p\" WHERE \"p\".listing_status = 'Active' AND \"p\".\"description\" IS NOT NULL AND (\"p\".description ILIKE '%turnkey%' OR \"p\".description ILIKE '%move-in%')",
"intent": "Move-in ready houses",
"manifest": "Move-in ready houses",
"parameterized": {
"parameterized_intent": "Move-in ready houses",
"parameterized_sql": "SELECT \"p\".\"address_street\", \"p\".\"address_postal_code\" FROM \"real_estate\".\"properties\" AS \"p\" WHERE \"p\".listing_status = 'Active' AND \"p\".\"description\" IS NOT NULL AND (\"p\".description ILIKE '%turnkey%' OR \"p\".description ILIKE '%move-in%')"
}
}
Envie esta consulta (Q11):
List move-in ready houses.
Consulta resultante:
SELECT "p"."address_street", "p"."address_postal_code"
FROM "real_estate"."properties" AS "p"
WHERE "p".listing_status = 'Active'
AND "p"."description" IS NOT NULL
AND ("p".description ILIKE '%turnkey%' OR "p".description ILIKE '%move-in%')
Ele retorna um registro correspondente.
Query Results address_street address_postal_code 40 Main St, Unit 8 N2H 2G8
Modelo com a função AI.IF
Baixe o arquivo de contexto do modelo AI.IF:
cloudshell download ~/codelabs/alloydb-ai-nla/sixrecipe_context4_2.json
Faça upload de sixrecipe_context4_2.json para seu conjunto de contexto e avalie a função de filtragem semântica ai.if.
{
"nl_query": "List Move-in ready houses",
"sql": "SELECT \"p\".\"address_street\", \"p\".\"address_postal_code\" FROM \"real_estate\".\"properties\" AS \"p\" WHERE \"p\".listing_status = 'Active' AND \"p\".\"description\" IS NOT NULL AND ai.if('Does this description represent a move-in ready house? Description: ' || \"p\".\"description\")",
"intent": "List Move-in ready houses",
"manifest": "List Move-in ready houses",
"parameterized": {
"parameterized_intent": "List Move-in ready houses",
"parameterized_sql": "SELECT \"p\".\"address_street\", \"p\".\"address_postal_code\" FROM \"real_estate\".\"properties\" AS \"p\" WHERE \"p\".listing_status = 'Active' AND \"p\".\"description\" IS NOT NULL AND ai.if('Does this description represent a move-in ready house? Description: ' || \"p\".\"description\")"
}
}
Repita o comando (Q12):
List move-in ready houses.
SQL gerado:
SELECT "p"."address_street", "p"."address_postal_code"
FROM "real_estate"."properties" AS "p"
WHERE "p".listing_status = 'Active'
AND "p"."description" IS NOT NULL
AND ai.if('Does this description represent a move-in ready house? Description: ' || "p"."description")
Isso nos dá a mesma propriedade no resultado:
Query Results Address Street Address Postal Code 40 Main St, Unit 8 N2H 2G8 Natural Language Answer The move-in ready home currently available is located at: Address: 40 Main St, Unit 8 Postal Code: N2H 2G8
Atributo com pesquisa vetorial
Baixe o arquivo de contexto da pesquisa de incorporação:
cloudshell download ~/codelabs/alloydb-ai-nla/sixrecipe_context4_3.json
Faça upload de sixrecipe_context4_3.json para seu conjunto de contexto e avalie a pesquisa vetorial semântica usando google_ml.embedding e pesquise casas com eletrodomésticos de cozinha novos.
Atualize o conjunto de contexto usando o arquivo sixrecipe_context4_3.json com mais uma faceta usando a pesquisa vetorial do AlloyDB.
{
"sql_snippet": "((real_estate.properties.description_embedding <=> google_ml.embedding('gemini-embedding-001', 'Upgraded kitchen appliances')::vector) < 0.4)",
"intent": "with upgraded kitchen appliances",
"manifest": "with upgraded kitchen appliances",
"parameterized": {
"parameterized_intent": "with upgraded kitchen appliances",
"parameterized_sql_snippet": "((real_estate.properties.description_embedding <=> google_ml.embedding('gemini-embedding-001', 'Upgraded kitchen appliances')::vector) < 0.4)"
}
}
O valor 0,4 na definição de faceta acima é um limite calibrado experimentalmente.
Execute esta consulta (Q13):
List move-in ready houses with upgraded kitchen appliances.
SQL gerado:
SELECT "p"."address_street", "p"."address_postal_code" FROM "real_estate"."properties" AS "p" WHERE "p"."listing_status" = 'Active' AND "p"."description" IS NOT NULL AND ai.if('Does this description represent a Move-in ready house? Description: ' || "p"."description") AND ((("p"."description_embedding" <=> google_ml.embedding('gemini-embedding-001', 'Upgraded kitchen appliances')::vector) < 0.4))
Aqui estão os resultados da consulta e a recomendação em linguagem natural:
Query Results Address Postal Code 40 Main St, Unit 8 N2H 2G8 Natural Language Answer The move-in ready house with upgraded kitchen appliances is located at: Address: 40 Main St, Unit 8 Postal Code: N2H 2G8
12. Segurança e privacidade
Sempre que a API QueryData gera consultas, há um risco de privacidade de que as consultas geradas exponham dados de outros usuários. As visualizações seguras parametrizadas (PSVs, na sigla em inglês) aplicam limites de segurança no nível da linha durante a geração de NL2SQL.
Criar visualização segura parametrizada
Temos uma tabela real_estate.offers com informações sobre ofertas de todos os nossos negócios imobiliários. Queremos que nossos agentes vejam apenas os próprios negócios, e não os de outros agentes. Criamos uma PSV com a capacidade de filtrar linhas com base no agent_id.
Crie uma visualização segura parametrizada para a tabela de ofertas no AlloyDB Studio:
CREATE VIEW real_estate.secure_offers
WITH (security_barrier) AS
SELECT offer_id, property_id, buyer_agent_id,
seller_agent_id, offer_amount, offer_date,
offer_status, offer_expiration_date,
contingencies
FROM real_estate.offers
WHERE buyer_agent_id = $@agent_id;
Verifique a definição da visualização de segurança parametrizada:
SELECT definition
FROM parameterized_views.all_parameterized_views
WHERE schemaname = 'real_estate' AND viewname = 'secure_offers';
E a tabela "real_estate.offers"?
Limitar o acesso aos dados do QueryData usando visualizações seguras parametrizadas do AlloyDB
No agent.py, a visualização de segurança parametrizada real_estate.secure_offers é registrada em TABLE_IDS em vez de real_estate.offers:
O código-fonte de agent.py:
List of database tables included in QueryData API requests
TABLE_IDS = [
"real_estate.municipalities",
"real_estate.cities",
"real_estate.agents",
"real_estate.properties",
"real_estate.schools",
"real_estate.school_to_property",
"real_estate.property_transactions",
"real_estate.secure_offers",
]
E transmite o contexto de tempo de execução da sessão para um agente com agent_id=1:
"parameterized_secure_view_parameters": {
"parameters": {
"key": "agent_id",
"value": "1"
}
}
},
Como resultado, todas as solicitações de API QueryData vão transmitir esse parâmetro. Quando a visualização segura for incluída na solicitação, ela vai aplicar a filtragem, retornando apenas resultados para esse agente específico.
Execute esta consulta (Q14):
List the offer id and listing price in 2025 where the offer was within 5% of the final selling price.
SQL gerado:
SELECT "o"."offer_id", "p"."price" AS "listing_price"
FROM "real_estate"."secure_offers" AS "o"
INNER JOIN "real_estate"."properties" AS "p" ON "o"."property_id" = "p"."property_id"
INNER JOIN "real_estate"."property_transactions" AS "t" ON "o"."property_id" = "t"."property_id"
WHERE "o"."offer_date" >= '2025-01-01'
AND "o"."offer_date" <= '2025-12-31'
AND "o"."offer_amount" IS NOT NULL
AND "t"."sale_price" IS NOT NULL
AND "p"."price" IS NOT NULL
AND ABS("o"."offer_amount" - "t"."sale_price") <= (0.05 * "t"."sale_price")
ORDER BY "o"."offer_id" ASC NULLS LAST
A consulta da visualização filtra os resultados pelo parâmetro de sessão do agente ativo, protegendo dados de registros não autorizados e retornando apenas dois registros.
Query Results Offer ID Listing Price 7 $750,000.00 8 $510,000.00 Natural Language Answer Here are the offers from 2025 where the offer amount was within 5% of the final selling price: Offer ID 7: Listing Price of $750,000.00 Offer ID 8: Listing Price of $510,000.00
Se você executar a seguinte consulta na tabela base real_estate.offers no AlloyDB Studio:
SELECT "o"."offer_id", "p"."price" AS "listing_price"
FROM "real_estate"."offers" AS "o"
INNER JOIN "real_estate"."properties" AS "p" ON "o"."property_id" = "p"."property_id"
INNER JOIN "real_estate"."property_transactions" AS "t" ON "o"."property_id" = "t"."property_id"
WHERE "o"."offer_date" >= '2025-01-01'
AND "o"."offer_date" <= '2025-12-31'
AND "o"."offer_amount" IS NOT NULL
AND "t"."sale_price" IS NOT NULL
AND "p"."price" IS NOT NULL
AND ABS("o"."offer_amount" - "t"."sale_price") <= (0.05 * "t"."sale_price")
ORDER BY "o"."offer_id" ASC NULLS LAST
Ele retorna mais de dois registros, mostrando dados de todos os agentes.
Chegamos ao fim do laboratório. Você aprendeu a usar a API QueryData, as funções de IA e as visualizações seguras parametrizadas do AlloyDB.
13. Limpar o ambiente
Destrua as instâncias e o cluster do AlloyDB quando terminar o laboratório.
Excluir o cluster do AlloyDB e todas as instâncias
O cluster é destruído com a opção force, que também exclui todas as instâncias pertencentes a ele.
Se o terminal foi desconectado, conecte-se novamente e defina as variáveis de projeto e ambiente no Cloud Shell:
gcloud config set project <YOUR_PROJECT_ID>
export REGION=us-central1
export ADBCLUSTER=alloydb-aip-01
export PROJECT_ID=$(gcloud config get-value project)
Exclua o cluster:
gcloud alloydb clusters delete $ADBCLUSTER --region=$REGION --force
Saída esperada do console:
student@cloudshell:~ (test-project-001-402417)$ gcloud alloydb clusters delete $ADBCLUSTER --region=$REGION --force All of the cluster data will be lost when the cluster is deleted. Do you want to continue (Y/n)? Y Operation ID: operation-1697820178429-6082890a0b570-4a72f7e4-4c5df36f Deleting cluster...done.
Excluir backups do AlloyDB
Exclua todos os backups do AlloyDB do cluster:
for i in $(gcloud alloydb backups list \
--filter="CLUSTER_NAME: projects/$PROJECT_ID/locations/$REGION/clusters/$ADBCLUSTER" \
--format="value(name)" \
--sort-by=~createTime) ; do \
gcloud alloydb backups delete $(basename $i) --region $REGION --quiet; done
Saída esperada do console:
student@cloudshell:~ (test-project-001-402417)$ for i in $(gcloud alloydb backups list --filter="CLUSTER_NAME: projects/$PROJECT_ID/locations/$REGION/clusters/$ADBCLUSTER" --format="value(name)" --sort-by=~createTime) ; do gcloud alloydb backups delete $(basename $i) --region $REGION --quiet; done Operation ID: operation-1697826266108-60829fb7b5258-7f99dc0b-99f3c35f Deleting backup...done.
Excluir o bucket do Cloud Storage
Exclua o bucket de importação do Cloud Storage para evitar cobranças contínuas de armazenamento:
gcloud storage rm -r gs://${PROJECT_ID}-import
14. Parabéns
Parabéns por concluir o codelab!
O que aprendemos
- Como implantar um cluster do AlloyDB e uma instância principal
- Como ativar QueryData, funções de IA e visualizações seguras parametrizadas para o AlloyDB
- Como criar um conjunto de contextos do QueryData
- Como usar diferentes modelos e contextos na API QueryData
- Como tornar os modelos QueryData mais flexíveis usando atributos
- Como resolver a ambiguidade de dados com a pesquisa de valores e a indexação de trigramas
- Como usar funções de IA para pesquisa semântica com modelos
- Como usar visualizações seguras parametrizadas com a API QueryData
Pesquisa
Saída: