Nas contas observadas nos benchmarks públicos do Google Ads, a análise manual de um search query report perde 60 a 80% dos negativos ocultos após 30 minutos de análise visual por um PPC manager experiente. E o custo dessa falha é mensurável: 14 a 28% do spend mensal acaba em queries não-pertinentes que ninguém verá no top 50 dos SQR (documentação oficial do Google Ads sobre negativos). É tipicamente a alavanca negligenciada que prejudica o ratio CPA / Quality Score de uma conta madura.
Aqui está o diagnóstico: um humano que analisa um SQR faz pattern matching visual nas 200-500 primeiras linhas ordenadas por custo. Ele perde (1) as queries da cauda longa que pesam apenas 3 a 8 EUR cada mas que acumuladas representam 18 a 26% do spend, (2) as variações semânticas agrupáveis ('avaliação', 'review', 'opinião', 'depoimento' = mesmo intent), e (3) os clusters de queries fora do intent comercial (emprego, formação gratuita, definição, preço baixo low-end) que o algoritmo Smart Bidding não identifica se o tracking de conversão é por valor fixo.
Este guia fornece o pipeline IA reprodutível: extração GAQL do SQR, embeddings (OpenAI ou sentence-transformers), clustering DBSCAN, scoring intent + cost wasted, export CSV para Google Ads Editor. Todo o código é em Python, funciona localmente, e o repo público github.com/steerads/google-ads-negatives-ai contém um Dockerfile e um workflow n8n de exemplo. Para a base de match types que condiciona este pipeline, veja nosso guia match types 2026. Nosso calculador de gasto desperdiçado estima o € queimado/mês por broad sem negativos ou bounce de LP excessivo.
O problema: 60 a 80% dos negativos ocultos na análise manual
A análise manual de um search query report (SQR) é uma das tarefas mais demoradas do PPC manager. Em uma conta média (5.000 a 15.000 queries / 30 dias), são necessários 45 minutos a 2 horas para fazer uma passagem limpa. E mesmo com esse tempo investido, a taxa de detecção dos negativos pertinentes permanece estruturalmente limitada pela fadiga cognitiva e pela ordenação por custo decrescente.
Três pontos cegos sistemáticos na análise manual:
- A cauda longa é invisível. As 50 primeiras queries ordenadas por custo concentram 35 a 50% do spend. O PPC manager as vê. Mas as 4.950 queries restantes — cada uma a 1 a 8 EUR — concentram 50 a 65% do spend total e permanecem inexploradas. É nessa cauda que se escondem os padrões recorrentes não-pertinentes.
- O pattern matching visual perde as variações semânticas. Um humano identifica 'avaliação' como candidato a negativo. Mas 'review', 'opinião', 'depoimento', 'feedback' compartilham o mesmo intent e aparecem em queries diferentes. Sem embedding, impossível agrupar.
- Sem scoring de cost wasted. Uma query a 25 EUR cost / 0 conversão em 30 dias é mais impactante que uma query a 4 EUR cost / 0 conversão — mesmo que a segunda apareça 6 vezes mais frequentemente. O humano ordena por alfabeto ou custo bruto, raramente por cost wasted (cost / conversions).
Nas contas observadas nos benchmarks públicos do Google Ads, o ratio de spend recuperável via clustering IA dos negativos converge para um limiar muito reprodutível: 12 a 22% do spend mensal após 60 dias de pipeline ativo. Em um orçamento de 30.000 EUR/mês, são entre 3.600 e 6.600 EUR de spend recuperado todo mês — não para os concorrentes, mas reinjetado nas queries que convertem. O ROI vs tempo de PPC manager economizado é superior a 25x para a maioria das contas tratadas.
O pipeline IA descrito aqui substitui a passagem manual por um workflow reprodutível. A primeira execução leva 30 a 45 minutos (setup + run + review). As execuções seguintes levam 5 a 15 minutos (review da amostra apenas). Para a base de auditoria que deve preceder esta automação, leia nossa checklist de auditoria Google Ads.
Pipeline IA em 5 etapas: query report para lista de negativos
O pipeline completo encadeia 5 etapas determinísticas, cada uma testável isoladamente. Arquitetura voluntariamente simples, sem dependência ML pesada além de scikit-learn e sentence-transformers / openai. O output final é um CSV diretamente importável no Google Ads Editor.
Pré-processamento das search queries: a etapa que se pula com muita frequência
Antes de fazer embedding de qualquer coisa, o pré-processamento do SQR condiciona 30 a 50% da qualidade final do clustering. Quatro transformações a aplicar sistematicamente. Primeira etapa: normalização Unicode e caixa. Os SQR do Google Ads frequentemente contêm duplicatas fantasmas: 'Orçamento Seguro', 'orçamento seguro', 'orçamento seguro' (espaço duplo), 'orçamento-seguro' aparecem como 4 queries distintas quando representam a mesma coisa. Aplicar unicodedata.normalize('NFKC', s).strip().lower() mais uma regex \s+ -> ' ' junta essas duplicatas em uma linha única com cost e clicks agregados. Em uma conta média, essa etapa reduz o volume de queries em 8 a 14% sem perda de informação.
Segunda etapa: deduplicação inteligente. Além da normalização simples, a deduplicação deve tratar as variantes morfológicas (singular/plural, masculino/feminino, acentos) conforme necessário. Para o clustering, manter as variantes brutas é geralmente mais útil (o embedding as agrupará mecanicamente), mas para o export de negativos final, deduplicar no representative_query do cluster evita propor 5 vezes o mesmo negativo. Terceira etapa: filtragem de queries one-shot com baixo custo. Uma query que aparece uma única vez em 30 dias com 1,20 EUR de custo não merece embedding (é ruído puro). Filtrar previamente com clicks >= 1 AND cost >= 1 evita poluir o clustering com 25-40% de ruído irredutível.
Quarta etapa: detecção de PII e termos sensíveis. Algumas queries contêm números de telefone, emails ou nomes próprios de usuários (digitados por engano na barra de busca ao invés da URL). Essas queries não têm nenhum interesse de análise e seu tratamento pela OpenAI levantaria problemas de LGPD. Filtrar previamente via regex e NUNCA enviar a uma API externa. Nos dados agregados do Google Ads 2025-2026, este tipo de queries representa 0,3 a 1,2% do SQR — baixo em volume mas crítico em compliance.
[Google Ads API / CSV export]
|
v Etapa 1 — extração SQR (GAQL ou CSV)
[search_terms.csv : query, clicks, cost, conv]
|
v Etapa 2 — embeddings (OpenAI ou ST)
[embeddings.npy : matriz 384/1536 dim]
|
v Etapa 3 — clustering DBSCAN ou HDBSCAN
[queries_clustered.csv : query, cluster_id]
|
v Etapa 4 — scoring intent + cost wasted
[clusters_scored.csv : cluster, waste_score, intent_score]
|
v Etapa 5 — filtragem + match type + export
[negatives_export.csv : pronto para Google Ads Editor]
Aqui está o esqueleto Python do runner principal. O código completo (com gestão de erros, logs, parâmetros CLI) está no repo público.
# main.py — pipeline completo em 5 etapas
import pandas as pd
import numpy as np
from embeddings import embed_queries
from clustering import cluster_dbscan
from scoring import score_clusters
from export import export_negatives_csv
def main(sqr_path: str, output_path: str, backend: str = "sentence-transformers"):
# Etapa 1 — carregamento SQR
df = pd.read_csv(sqr_path)
df = df[df["clicks"] >= 1] # filtrar queries sem clique
print(f"Loaded {len(df)} queries")
# Etapa 2 — embeddings
embeddings = embed_queries(df["search_term"].tolist(), backend=backend)
print(f"Embeddings shape: {embeddings.shape}")
# Etapa 3 — clustering
df["cluster_id"] = cluster_dbscan(embeddings, eps=0.15, min_samples=5)
n_clusters = df["cluster_id"].nunique() - (1 if -1 in df["cluster_id"].values else 0)
print(f"Found {n_clusters} clusters")
# Etapa 4 — scoring
clusters_scored = score_clusters(df, whitelist_path="whitelist.txt")
# Etapa 5 — export
export_negatives_csv(clusters_scored, output_path,
min_cluster_size=3, min_waste_score=30)
print(f"Exported negatives to {output_path}")
if __name__ == "__main__":
main(
sqr_path="data/search_terms.csv",
output_path="output/negatives_export.csv",
backend="sentence-transformers", # ou "openai"
)
Cada etapa produz um artefato persistido (CSV ou .npy). Isso facilita o debug: se o clustering produz muito ruído, pode-se iterar na etapa 3 sem relançar os embeddings (caro em API call). Cf. nosso guia automação Google Ads API Python para o setup OAuth e a extração GAQL detalhada.
Embeddings: OpenAI text-embedding-3 vs sentence-transformers
O embedding é a etapa crítica. Uma query vetorizada permite medir a similaridade semântica entre 'orçamento seguro auto' e 'preço seguro veículo' — mesmo se zero palavras em comum. Sem embedding, o clustering recai em matching de tokens e perde 70% dos agrupamentos pertinentes.
Dois backends pertinentes em 2026: OpenAI text-embedding-3-small (hospedado, 1536 dim, pago por uso) e sentence-transformers all-MiniLM-L6-v2 ou multilingual-e5-base (local, 384 ou 768 dim, gratuito). A escolha depende do volume e da sensibilidade dos dados.
Variante OpenAI — production-ready, batch otimizado:
# embeddings.py — backend OpenAI
from openai import OpenAI
import numpy as np
import os
def embed_queries_openai(queries: list[str], batch_size: int = 100) -> np.ndarray:
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
all_embeddings = []
for i in range(0, len(queries), batch_size):
batch = queries[i : i + batch_size]
response = client.embeddings.create(
model="text-embedding-3-small",
input=batch,
encoding_format="float",
)
embeddings = [item.embedding for item in response.data]
all_embeddings.extend(embeddings)
return np.array(all_embeddings, dtype=np.float32)
Variante sentence-transformers — local, custo zero:
# embeddings.py — backend local sentence-transformers
from sentence_transformers import SentenceTransformer
import numpy as np
def embed_queries_st(queries: list[str], model_name: str = "all-MiniLM-L6-v2") -> np.ndarray:
model = SentenceTransformer(model_name)
embeddings = model.encode(
queries,
batch_size=64,
show_progress_bar=True,
normalize_embeddings=True, # importante para cosseno
)
return embeddings.astype(np.float32)
def embed_queries(queries: list[str], backend: str = "sentence-transformers") -> np.ndarray:
if backend == "openai":
return embed_queries_openai(queries)
elif backend == "sentence-transformers":
return embed_queries_st(queries, model_name="paraphrase-multilingual-MiniLM-L12-v2")
else:
raise ValueError(f"Unknown backend: {backend}")
Referência de campo: em uma conta e-commerce de 8.000 queries, o delta de qualidade de cluster entre OpenAI e e5-base fica em torno de 6 a 9% em precisão (medida: nb negativos válidos / nb propostas). Em MiniLM v1 anglófono, o delta sobe para 12 a 18% — daí a escolha paraphrase-multilingual-MiniLM-L12-v2 para o PT. Para uma conta 100% lusófona, é o melhor compromisso custo / qualidade. Documentação oficial OpenAI embeddings.
text-embedding-3-large vs text-embedding-3-small: quando o large vale o custo extra? Três casos concretos onde text-embedding-3-large (3072 dim, 0,13 USD / 1M tokens, ou seja 6,5x mais caro que small) justifica o investimento. Caso 1: intent fino em setores técnicos especializados (médico, jurídico, engenharia) onde a nuance entre 'advogado tributarista' e 'advogado tributário' muda o scoring de intent. O large captura 4 a 7% de precisão suplementar mensurável na coorte de validação. Caso 2: multilíngue misto (PT + EN + ES na mesma conta) onde a robustez cross-língua do large evita dividir o pipeline em três passagens distintas. Caso 3: volume muito elevado (50.000+ queries por mês) onde o custo marginal adicional fica abaixo de 1 EUR por execução e sem impacto significativo no P&L. Fora desses três casos, text-embedding-3-small permanece o bom padrão para uma conta mid-market.
Análise de custo de API OpenAI em um caso real. Para uma conta que processa 8.000 queries de 4 a 8 palavras toda semana (em média 32 tokens por query, portanto 256.000 tokens por execução), o custo da execução em small é de 256.000 / 1.000.000 x 0,02 USD = 0,005 USD. Em 52 execuções anuais, ou seja aproximadamente 0,27 USD por conta por ano. Em large, o custo se torna 256.000 / 1.000.000 x 0,13 USD = 0,033 USD por execução, ou seja aproximadamente 1,72 USD anual. Nos dois casos, o custo de API OpenAI é marginal comparado ao tempo de PPC manager economizado. A armadilha clássica: deixar rodar sem batching (1 query por chamada ao invés de 100 por batch), o que multiplica o custo por 8 a 12 por causa da repetição dos custos fixos por requisição. Sempre fazer batch com mínimo de 50-100 queries por chamada.
Clustering DBSCAN: por que não K-means
K-means é o algoritmo de clustering mais conhecido, mas é a escolha errada para search queries do Google Ads. Três razões técnicas:
- K-means exige fixar K antecipadamente. Quantos clusters de queries não-pertinentes existem na sua conta? Ninguém sabe antes da análise. K-means obriga a adivinhar — e um K errado produz clusters muito amplos (mesmos intents misturados) ou muito finos (sobre-fragmentação).
- K-means atribui todos os pontos a um cluster. Porém 30 a 50% das queries são ruído (queries únicas sem equivalente). DBSCAN as identifica como ruído (cluster -1) ao invés de forçá-las em um cluster fictício. Resultado: clusters mais limpos.
- K-means assume clusters esféricos de mesma densidade. Os clusters de queries não-pertinentes têm densidades muito variáveis (um cluster 'gratuito' muito denso + um cluster 'comparação concorrente' difuso). DBSCAN lida com essa variância, K-means não.
DBSCAN (Density-Based Spatial Clustering of Applications with Noise) recebe dois parâmetros: eps (raio de vizinhança) e min_samples (nb mín de pontos para formar um cluster). Ele identifica zonas densas no espaço dos embeddings e agrupa os pontos próximos.
# clustering.py — DBSCAN
from sklearn.cluster import DBSCAN
import numpy as np
def cluster_dbscan(embeddings: np.ndarray, eps: float = 0.15, min_samples: int = 5) -> np.ndarray:
# Distância cosseno para embeddings normalizados
clustering = DBSCAN(
eps=eps,
min_samples=min_samples,
metric="cosine",
n_jobs=-1,
)
labels = clustering.fit_predict(embeddings)
return labels
def cluster_hdbscan(embeddings: np.ndarray, min_cluster_size: int = 5) -> np.ndarray:
import hdbscan
clustering = hdbscan.HDBSCAN(
min_cluster_size=min_cluster_size,
metric="euclidean", # HDBSCAN não suporta cosseno direto
cluster_selection_method="eom",
)
labels = clustering.fit_predict(embeddings)
return labels
Calibração do parâmetro eps: é o limiar de similaridade cosseno abaixo do qual duas queries são consideradas como vizinhas. Quanto menor o eps, mais finos os clusters. Referência de campo: começar com eps=0.15. Se mais de 70% das queries saem como ruído (cluster -1), subir para 0.20. Se os clusters são muito amplos (cluster 'serviço' que mistura B2B e B2C), descer para 0.12.
HDBSCAN como alternativa, se DBSCAN produz clusters mal calibrados. HDBSCAN autodetecta a densidade local e não precisa de eps. Mais robusto em datasets heterogêneos mas mais lento e mais complexo de debugar.
Antes de passar ao scoring, visualize os clusters obtidos com UMAP em 2D. umap-learn reduz os embeddings de 384 dim para 2 dim para um scatter plot legível. Você vê instantaneamente se o clustering está limpo (clusters nítidos e separados) ou ruidoso (clusters que se sobrepõem). Se ruidoso, ajustar eps antes de continuar. 5 minutos investidos evitam 30 minutos de scoring inútil.
Validação dos clusters: três métricas além do visual UMAP
A visualização UMAP é útil mas subjetiva. Para validar quantitativamente a qualidade do clustering, três métricas objetivas a calcular sistematicamente antes de passar ao scoring. Métrica 1: silhouette score. Implementado em sklearn.metrics.silhouette_score, essa métrica mede o quanto cada ponto está mais próximo do seu próprio cluster do que dos outros clusters. Score entre -1 (catastrófico) e +1 (perfeito). Um silhouette superior a 0,3 no dataset completo indica um clustering explorável; abaixo de 0,15, é preciso re-tunar eps. Nas contas observadas nos benchmarks públicos do Google Ads, uma conta e-commerce mid-size atinge tipicamente 0,32 a 0,48 de silhouette em sentence-transformers e 0,38 a 0,55 em OpenAI text-embedding-3-small.
Métrica 2: porcentagem de ruído. Contar o ratio (labels == -1).mean(). Um bom clustering DBSCAN em SQR do Google Ads deveria ter entre 25 e 45% de ruído (queries não atribuídas a um cluster). Abaixo de 25%, eps está muito amplo e os clusters estão sobre-fundidos. Acima de 60%, eps está muito estrito e a maioria das queries são rejeitadas. Essa métrica é gratuita para calcular e serve como guarda-chuva para evitar configurações degenerativas.
Métrica 3: tamanho mediano dos clusters. Calcular np.median([size for _, size in clusters_size]). Um clustering explorável produz clusters de tamanho mediano entre 4 e 12 queries. Acima de 20, os clusters são muito amplos e misturam intents diferentes. Abaixo de 4, são muito finos e o scoring se torna instável. Se o tamanho mediano estiver fora dessa janela, ajustar min_samples (DBSCAN) ou min_cluster_size (HDBSCAN) antes de continuar o pipeline. Nas iterações de produção, monitorar essas três métricas e registrar sua deriva permite detectar regressões silenciosas do pipeline (uma mudança de API de embedding, um drift nas queries fonte) antes que os negativos propostos sejam impactados.
Scoring: pertinência de intent + cost wasted
Uma vez as queries clusterizadas, é preciso pontuar cada cluster para decidir quais são candidatos a negativos. O scoring combina duas dimensões: (1) o cost wasted (quanto de spend foi queimado sem conversão) e (2) o intent score (o quanto o cluster está distante do seu intent comercial alvo).
Cost wasted é trivial de calcular: soma do cost / max(soma conversions, 0.1) por cluster. Quanto mais alto o ratio, mais o cluster é candidato a negativo.
Intent score é mais sutil. Compara-se a similaridade cosseno média do cluster com uma whitelist de keywords alvo (seus keywords de marca + produtos principais + intenções de compra fortes). Se a similaridade média do cluster com a whitelist é superior a 0.65, provavelmente é um cluster pertinente (a NÃO excluir). Se inferior a 0.30, é um cluster distante do intent comercial = candidato a negativo forte.
# scoring.py — scoring intent + cost wasted
import pandas as pd
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
def score_clusters(df: pd.DataFrame, whitelist_path: str) -> pd.DataFrame:
# Carregar whitelist (1 keyword por linha)
with open(whitelist_path) as f:
whitelist_keywords = [line.strip() for line in f if line.strip()]
# Fazer embedding da whitelist
from embeddings import embed_queries
whitelist_emb = embed_queries(whitelist_keywords, backend="sentence-transformers")
# Agregar por cluster
cluster_stats = []
for cluster_id, group in df.groupby("cluster_id"):
if cluster_id == -1:
continue # ignorar ruído
cost = group["cost"].sum()
conv = group["conversions"].sum()
clicks = group["clicks"].sum()
size = len(group)
# waste_score : custo por conversão (0.1 floor para evitar divisão por 0)
waste_score = cost / max(conv, 0.1)
# intent_score : similaridade cosseno média com whitelist
cluster_emb = np.stack(group["embedding"].values)
sim_matrix = cosine_similarity(cluster_emb, whitelist_emb)
intent_score = float(sim_matrix.max(axis=1).mean())
# exemplo representativo (query mais central do cluster)
centroid = cluster_emb.mean(axis=0)
distances = np.linalg.norm(cluster_emb - centroid, axis=1)
representative_idx = distances.argmin()
representative_query = group.iloc[representative_idx]["search_term"]
cluster_stats.append({
"cluster_id": cluster_id,
"size": size,
"cost": round(cost, 2),
"conversions": round(conv, 2),
"clicks": clicks,
"waste_score": round(waste_score, 2),
"intent_score": round(intent_score, 3),
"representative_query": representative_query,
"negative_candidate": waste_score > 30 and intent_score < 0.30,
})
result = pd.DataFrame(cluster_stats)
return result.sort_values("waste_score", ascending=False)
Leitura da tabela de saída: ordena-se por waste_score decrescente, depois filtra-se em intent_score < 0.30 E size >= 3. Esse trio identifica os clusters que (1) queimam spend, (2) estão distantes do intent comercial, e (3) têm queries suficientes para valer um negativo (não um one-shot).
Referência de limiares:
waste_score >= 30(pelo menos 30 EUR de custo sem conversão) — corresponde ao limiar de pertinência na maioria das contas.intent_score < 0.30(similaridade cosseno com whitelist abaixo de 30%) — acima, risco de falso negativo.size >= 3(pelo menos 3 queries no cluster) — abaixo de 3, é ruído ou cauda longa, tratar caso a caso.
Esses limiares são pontos de partida. Ajuste conforme seus retornos de amostra manual após 2-3 iterações.
Export CSV pronto para Google Ads Editor
O output final deve ser diretamente importável no Google Ads Editor — caso contrário você perde 30 minutos reformatando manualmente. Formato esperado: CSV UTF-8, colunas específicas, match type claro, ação explícita ("Add" para adição).
# export.py — geração CSV Google Ads Editor
import pandas as pd
def export_negatives_csv(
clusters_scored: pd.DataFrame,
output_path: str,
min_cluster_size: int = 3,
min_waste_score: float = 30,
max_intent_score: float = 0.30,
) -> None:
# Filtrar clusters candidatos
candidates = clusters_scored[
(clusters_scored["size"] >= min_cluster_size)
& (clusters_scored["waste_score"] >= min_waste_score)
& (clusters_scored["intent_score"] < max_intent_score)
]
rows = []
for _, cluster in candidates.iterrows():
# Determinar match type segundo dispersão do cluster
# (a parametrizar mais finamente em prod: aqui simplificação)
match_type = "Phrase match" if cluster["size"] <= 8 else "Broad match"
rows.append({
"Action": "Add",
"Campaign": "ALL", # ou cluster["campaign"] se disponível
"Ad group": "", # vazio = nível campanha
"Keyword": cluster["representative_query"],
"Match type": match_type,
"Status": "Enabled",
"Comment": f"AI cluster #{cluster['cluster_id']} | "
f"size={cluster['size']} | "
f"waste={cluster['waste_score']} EUR | "
f"intent={cluster['intent_score']}",
})
out_df = pd.DataFrame(rows)
out_df.to_csv(output_path, index=False, encoding="utf-8")
print(f"Wrote {len(out_df)} negative candidates to {output_path}")
Procedimento de import no Google Ads Editor: Google Ads Editor > File > Import > From CSV. A ferramenta detecta as colunas, valida o formato de match type, e propõe um diff visual antes do push. Revisar o diff (amostra 30-50 linhas), validar, depois Post Changes. Para a documentação oficial do Google Ads Editor, veja support.google.com/google-ads/answer/2475106.
Match type — heurística de campo:
- Phrase match para clusters muito homogêneos (size 3-8 queries, expressões curtas e similares). Match preciso, baixo risco de bloqueio acidental de uma query pertinente.
- Broad match para conceitos amplos (size superior a 15, queries variadas em torno de um mesmo intent). Mais amplo, mas não esquecer de monitorar após push para detectar bloqueios excessivos.
- Exact match raramente pertinente como negativo IA — trata-se mais de conceitos do que de queries exatas.
NUNCA faça upload do CSV diretamente sem review humana na primeira execução. Amostra 30-50 linhas aleatórias, verificar que nenhum termo de marca / produto principal / keyword alvo aparece, validar o match type. Se mais de 10% da amostra for falso positivo, ajustar os limiares (min_waste_score mais alto, max_intent_score mais baixo) e re-executar. Uma vez pipeline validado em 2-3 iterações (taxa de erro abaixo de 5%), automatizável em modo automático.
ROI típico: quanto se recupera de spend
Questão prática: quanto este pipeline IA rende vs a análise manual? Resposta em números de campo, medidos nas contas observadas nos benchmarks públicos do Google Ads.
Leitura: o pipeline IA não é mágico na precisão (um humano atento faz igualmente bem). Sua vantagem está no recall — ele identifica 75 a 88% dos negativos pertinentes vs 20 a 35% para um humano em 30 minutos. E o tempo do PPC manager passa de 30 min para 5-15 min por execução após setup inicial. O verdadeiro ganho é cumulativo: em 12 meses, são 4 a 6 horas de PPC manager economizadas E 12 a 22% de spend melhor utilizado.
Referência numérica: em uma conta de 30.000 EUR/mês, recuperar 15% do spend = 4.500 EUR/mês redirecionados para queries que convertem. A CPA igual, são 4.500 / CPA conversões suplementares em bottom-funnel todo mês. Em 12 meses, são tipicamente entre 230 e 380 conversões adicionais, sem aumento de orçamento. O ROI vs investimento inicial (45 min de setup + chave API embeddings) é superior a 50x.
O ratio chave: recall dividido por tempo investido. Para análise manual 2h, o ratio é aproximadamente 0,25 (50% de recall / 2h). Para o pipeline IA, o ratio é aproximadamente 6 (80% de recall / 0,2h após setup). É 24x mais eficiente na métrica que realmente conta — quanto de spend wasted se identifica por hora de PPC manager investida. E esse ratio melhora ainda mais ao longo das execuções: na 5a iteração, a amostra manual se reduz a 15-25 negativos a revisar (vs 60-80 na primeira execução), porque os padrões recorrentes são absorvidos pelos clusters anteriores.
Medição prática em 60 dias: as contas que ativam o pipeline em modo semanal convergem para um steady-state onde a maioria dos novos negativos vêm de padrões novos (concorrentes que sobem, queries sazonais, evoluções semânticas da audiência). O pipeline detecta essas novidades em menos de 7 dias após aparecimento, vs 30-60 dias em monitoramento manual — ou seja uma janela de 23-53 dias economizada de spend wasted em cada padrão emergente. É o verdadeiro moat da automação baseada em embedding: a velocidade de reação, não apenas o recall pontual.
Nosso motor de auto-otimização embarca esse pipeline em modo gerenciado: extração GAQL automática, embeddings hospedados, clustering DBSCAN, scoring + filtragem, e propostas semanais validáveis em 1 clique. Para as contas que querem industrializar sem programar. Veja também nosso guia 10 scripts Google Ads para automação do lado scripts nativos, e nosso guia n8n + Google Ads para agendar o pipeline em workflow self-hosted. As complementaridades entre esses três ângulos — pipeline IA, scripts nativos, n8n self-hosted — são detalhadas em nossa coleção de prompts ChatGPT Google Ads.
Erros comuns a evitar na industrialização
Cinco erros aparecem recorrentemente na colocação em produção de pipeline IA de negativos Google Ads. Cada um cria falso negativo (negativos mal direcionados que bloqueiam tráfego pertinente) ou falso positivo (negativos perdidos). Diagnóstico e correção direta.
1. Lançar o pipeline sem whitelist de marca e produtos alvo. Diagnóstico: o pipeline propõe negativos que contêm seus termos de marca ou nomes de produtos principais, porque estes são mal diferenciados semanticamente de queries não-pertinentes. Correção: manter uma whitelist whitelist.txt com no mínimo as variantes de marca (palavras simples + compostas), 10 a 20 nomes de produtos alvo, e os termos comerciais fortes. Essa whitelist serve ao scoring de intent (intent_score) e bloqueia o export de qualquer cluster cujo representative_query corresponda parcialmente à whitelist.
2. Confundir exact match e phrase match no export de negativos. Diagnóstico: exportar um cluster em exact match na representative_query bloqueia apenas a query exata (10-15% do cluster), deixando 85-90% do cost wasted continuar. Correção: usar phrase match como padrão para clusters coerentes, e broad match para conceitos amplos. Testar antes do push consultando o Keyword Planner sobre o negativo proposto: se o volume estimado é superior a 5x o volume do cluster de origem, o match type está muito amplo.
3. Lançar o pipeline com muita frequência e gerar ruído. Diagnóstico: um pipeline diário produz dezenas de propostas por dia, das quais 60-70% são reformulações de propostas anteriores. A fadiga de validação empurra a equipe a validar tudo sem review. Correção: lançar semanalmente (segunda-feira de manhã), não diariamente. A janela de 7 dias estabiliza os padrões e evita decisões prematuras sobre queries one-shot. Para contas com frequência de evolução muito alta (sazonalidade forte), passar para bisemanal no máximo, nunca diário.
4. Ignorar clusters de pequeno tamanho mas alto waste. Diagnóstico: o filtro min_cluster_size: 3 exclui sistematicamente os clusters de 1-2 queries que podem ter waste elevado (uma query a 80 EUR sem conversão, por exemplo). Esses padrões isolados passam sob o radar do pipeline. Correção: adicionar uma segunda passagem que proponha queries individuais acima de waste_score = 60 independentemente de sua pertença a um cluster. Essas propostas individuais são mais arriscadas para autovalidar, portanto revisar manualmente antes do export.
5. Não medir a performance pós-aplicação. Diagnóstico: os negativos são carregados, o pipeline roda em autopilot, mas ninguém verifica se o CPA e o ROAS melhoram realmente. Correção: rastrear um indicador de saúde do pipeline: delta_cpa_30j_post_negativos (variação do CPA nos 30 dias após push de N negativos). Se a variação é nula ou negativa, significa que os negativos propostos eram marginais. Ajustar os limiares min_waste_score e max_intent_score para mirar clusters de impacto mais claro. Nas contas observadas nos benchmarks públicos do Google Ads, a melhoria mensurável aparece tipicamente nas 3 a 5 primeiras iterações depois se estabiliza.
Para as contas que querem industrializar sem rodar o pipeline elas mesmas, nosso módulo Auto-otimização roda o pipeline embeddings + clustering toda semana na sua conta, propõe os negativos candidatos validados via UI, e aplica após review. Conexão OAuth em 2 minutos, primeira análise em 5 minutos. Repo público github.com/steerads/google-ads-negatives-ai disponível para quem prefere self-hospedar, com Dockerfile e workflow n8n de exemplo.
Fontes
Fontes oficiais consultadas para este guia:
FAQ
É obrigatório usar OpenAI ou posso ficar 100% open-source?
Você pode ficar 100% open-source. sentence-transformers (modelo all-MiniLM-L6-v2 ou multilingual-e5-base) roda localmente em CPU, sem chave de API nem custo, com qualidade suficiente para clusterizar search queries. A diferença observável vs OpenAI text-embedding-3-small: -8 a -14% de precisão nos clusters finos (separar 'orçamento' comercial vs 'orçamento' jurídico), mas +zero euro de custo de API. Para contas que processam menos de 5.000 queries/mês, sentence-transformers é suficiente. Acima disso, ou se você processa multilíngue com acentos, text-embedding-3-small tem melhor relação qualidade/esforço. O pipeline suporta os dois backends via variável de ambiente.
Qual volume mínimo de search queries para que o clustering seja confiável?
Limiar prático: 500 queries mínimo na janela de análise (tipicamente 30 dias). Abaixo disso, DBSCAN não tem densidade suficiente para identificar clusters estáveis e a maioria das queries sai como ruído. Sweet spot: 2.000 a 10.000 queries em 30 dias. Acima de 10.000, divida por campanha para evitar misturar intents muito diferentes (B2B + B2C no mesmo clustering = ruído). Se sua conta faz menos de 500 queries/30 dias, estenda a janela para 60 ou 90 dias.
DBSCAN ou HDBSCAN: qual escolher na prática?
HDBSCAN é geralmente superior para search queries do Google Ads: ele lida com clusters de densidade variável, o que corresponde à realidade (um cluster 'gratuito' muito denso + um cluster 'concorrente' difuso). DBSCAN exige fixar um parâmetro eps único para todo o dataset, o que força compromissos. No entanto, DBSCAN continua mais simples de parametrizar e mais rápido em volumes pequenos (menos de 5.000 queries). Recomendação: começar com DBSCAN com eps em torno de 0,15 e min_samples de 5, depois passar para HDBSCAN se os clusters parecerem mal calibrados. O pipeline suporta os dois via variável de configuração.
Como avaliar a qualidade dos negativos propostos pelo pipeline antes de fazer upload?
Três verificações obrigatórias antes de qualquer upload no Google Ads Editor. (1) Amostra manual: revisar 30 a 50 negativos aleatórios, visar taxa de validação superior a 90%. (2) Whitelist: verificar que nenhum termo de marca, produto principal ou keyword alvo aparece na lista (o script deve ter uma whitelist como input). (3) Match type: verificar que o match type exportado corresponde à intenção (phrase match para expressões exatas, broad match para conceitos). Se menos de 90% de validação na amostra manual, ajustar os limiares do scoring (cost_min, cluster_size_min) em vez de fazer upload tal qual. Iterar 2 a 3 vezes antes de visar o modo automático.
É possível automatizar este pipeline em execução semanal no n8n ou Cloud Run?
Sim, e é o objetivo final para industrializar. O pipeline Python roda em menos de 3 minutos para 5.000 queries (CPU local) ou em menos de 60 segundos via OpenAI batch embeddings + DBSCAN GPU. Você pode agendá-lo em cron no Cloud Run, Lambda, ou em workflow n8n. Padrão recomendado: execução semanal (segunda-feira de manhã), output em um Google Sheet compartilhado, validação humana da amostra, upload via Google Ads Editor (ou via Google Ads API diretamente se confiança elevada no pipeline). O repo github.com/steerads/google-ads-negatives-ai inclui um Dockerfile e um exemplo de workflow n8n.