Pular para conteúdo

Runbook — Troubleshooting de agentes IA

Checklist de diagnóstico para os 10 problemas mais comuns. Ordem de leitura: identificar o sintoma → seguir o bloco correspondente.


Começando sempre por aqui

Antes de qualquer diagnóstico, 3 comandos básicos:

# 1. Engine online?
curl https://gita-engine-gita-agents.ewzc9p.easypanel.host/health
# Esperado: {"status":"ok","uptime":<N>}

# 2. Agentes ativos no banco?
# Via SQL:
SELECT slug, is_active, client_name FROM ai_agents WHERE client_name = '<Cliente>';

# 3. Webhook Uazapi apontando certo?
curl -s "https://grupogita.uazapi.com/webhook" -H "token: <instance_token>"

Depois, filtrar logs do lead específico em agent_logs:

SELECT created_at, event, level, data 
FROM agent_logs 
WHERE remote_jid = '<numero>@s.whatsapp.net'
ORDER BY created_at DESC 
LIMIT 50;

Problema 1 — Agente não responde

Sintoma: Lead mandou mensagem, nada volta no WhatsApp.

Diagnóstico

  1. Engine vivo? curl /health
  2. Webhook chegou? Ver logs do Easypanel do engine, procurar webhook.received
  3. Agente ativo? SELECT is_active FROM ai_agents WHERE slug = '<slug>'
  4. Filter blocked? SELECT * FROM agent_logs WHERE event='filter.blocked' — pode ser own_message, block_ia_human, whitelist
  5. Dry-run header? Se veio X-Gita-Dry-Run: 1 sem querer, envio é bypassado (logs send.dry_run)

Causas prováveis

  • Engine offline → Easypanel, restart
  • Agent não encontrado (webhook.agent_not_found) → slug errado no webhook Uazapi
  • Block IA ativo → lead com label pausar-ia no Chatwoot ou TTL no Redis ainda não expirou
  • Whitelist (se business_hours_enabled=true) → fora do horário
  • Uazapi desconectadocurl /instance/status com token da instância, ver status: "connected"

Problema 2 — Agente responde mas com delay enorme (>30s)

Sintoma: A mensagem demora 1-3 minutos pra voltar.

Causas prováveis

  1. Debounce muito altodelay_debounce padrão é 8s, alguns agentes estão em 15-20s
  2. Gemini lento ou fallback pra OpenAI — ver logs gemini.fallback_triggered + openai.fallback_success
  3. Tool pesada demorando — ex: agendar_reuniao esperando resposta do Google Calendar
  4. Histórico muito grandegetContents pega últimas 40 msgs, se o lead tem histórico denso o prompt fica pesado

Fix

  • Reduzir delay_debounce no admin (mas cuidado: se muito baixo, mensagens vêm em pedaços separados)
  • Se Gemini cai recorrente, trocar model pra gemini-2.5-pro (mais estável que flash)
  • Se tool é o gargalo, investigar o handler em tools.ts

Problema 3 — Agente responde coisa aleatória / alucina

Sintoma: Agente menciona features que não existem, promete prazos não combinados, confunde cliente A com cliente B.

Causas prováveis

  1. Histórico contaminado — lead já conversou com OUTRO agente do mesmo tenant, o prompt cross-agent funciona por design (ver history.ts:getContents com clientName)
  2. Temperature alta — flash 2.5 com temp=0.7 improvisa demais
  3. Prompt não prescritivo — lista contexto sem proibir explicitamente
  4. Nome do lead confuso (buildLeadContext) — se lead.name é algo estranho, agente pode usar em lugar errado

Fix

  • Limpar histórico do lead: DELETE FROM messages WHERE remote_jid = '<jid>' (só se for aceitável perder contexto)
  • Reduzir temperature pra 0.3-0.5 em agentes de venda
  • Adicionar bloco "Restrições duras" no topo do prompt: "NUNCA mencione X, Y, Z"
  • Ver histórico de conversa inteiro: SELECT role, parts FROM messages WHERE remote_jid = '<jid>' ORDER BY id

Problema 4 — Tool não é chamada quando deveria

Sintoma: Lead pede explicitamente algo (ex: "quero falar com humano") e o agente ignora, segue o script normal.

Causas

  1. Tool não está registrada no bancoSELECT * FROM tools WHERE agent_id = '<id>'
  2. is_active=false na tool
  3. function_declaration malformada — parâmetros ambíguos, description vaga
  4. Regra no prompt não é prescritiva o suficiente — "use reportar quando ..." no final do prompt é facilmente ignorado

Fix

  • Mover regra pra topo do prompt em bloco "PRIORIDADE MÁXIMA"
  • Refinar description da tool: explicar exatamente quando chamar, com exemplos
  • Testar isolado em dry-run com mensagem-gatilho óbvia

Padrão validado (bug real #3 de 2026-04-20)

## PRIORIDADE MÁXIMA: escalação imediata

Se o lead fizer QUALQUER uma das coisas abaixo, PARE tudo, ignore o fluxo normal e chame a tool `reportar` IMEDIATAMENTE:

1. Mencionar nome de pessoa conhecida do time
2. Pedir humano explicitamente
3. ...

Problema 5 — Tool é chamada mas retorna erro

Sintoma: Log function.error ou function.executed com result.output: "Erro ao ...".

Exemplos comuns

Tool Erro Causa
agendar_reuniao "Google Calendar: precisa de service_account ou oauth2 configurado" Falta credencial no agente
agendar_reuniao "Horário já ocupado" Conflito real no calendar, agente reagenda
oferecer_empresa_no_digital Sem erro visível, mas lead não recebe link Tool retornou info mas Gemini não usou no próximo turno
reportar ClickUp não notificou notification_clickup_channel_id null ou token expirado
qualificar_lead Campos perdidos após merge Fix aplicado em leads.ts:updateLeadQualification (merge com GET→merge→UPDATE)

Fix

  • Verificar provider_config e tool-specific config via SELECT handler_config FROM tools WHERE id='<id>'
  • Se é credencial, corrigir via admin ou SQL direto
  • Ver log completo da chamada: agent_logs WHERE event='function.executed' AND data->>'name'='<tool>'

Problema 6 — FIT_ROUTING não redireciona

Sintoma: Lead qualificado continua recebendo respostas do captacao em vez do conversao/downsell.

Causas

  1. qualified_data.fit não foi salvo — ver leads.qualified_data no banco
  2. fit tem valor não mapeadoFIT_ROUTING só conhece gita_agents e empresa_digital
  3. Router não tem FIT_ROUTING pro tenant — ver router-classifier.ts:FIT_ROUTING — só Gita Agentes hoje
  4. Sticky routing prevalece — ordem de resolução no router: FIT_ROUTING → regex → sticky → default

Fix

-- Ver o que está salvo
SELECT qualified_data FROM leads WHERE remote_jid = '<jid>';

-- Corrigir fit manualmente se necessário (raro)
UPDATE leads SET qualified_data = jsonb_set(qualified_data, '{fit}', '"gita_agents"'::jsonb)
WHERE remote_jid = '<jid>';

Problema 7 — Leads duplicados no dashboard

Sintoma: Mesmo contato aparece múltiplas vezes, cada um associado a um agent_id diferente.

Causa

Quando FIT_ROUTING redireciona pra outro agente, o orchestrator chamava getOrCreateLead(novo_agent_id, jid) e criava lead novo. O qualified_data ficava no lead antigo.

Fix aplicado (2026-04-20)

router-classifier.ts:FIT_ROUTING agora copia qualified_data + name pro lead do agente alvo antes de retornar o slug. Se já existe, faz merge.

Se aparecer mesmo com fix

  • Verificar se o engine foi redeployado após o fix
  • Uptime do engine deve ser menor que o timestamp do commit 9ee41e6

Problema 8 — Follow-up não dispara (ou dispara errado)

Sintoma: Lead ficou silencioso, passou o intervalo, não recebeu reengajamento. Ou o contrário: lead converso, follow-up insistiu.

Diagnóstico

-- Ver estado do follow-up no lead
SELECT 
  remote_jid, 
  follow_up_stage, 
  follow_up_last_at,
  status,
  qualified_data
FROM leads WHERE remote_jid = '<jid>';

Causas comuns

  1. follow_up_enabled=false no agente — ver SELECT follow_up_enabled FROM ai_agents
  2. Status já é converted ou downsell_offered — follow-up ignora
  3. Block IA ativo (Redis) — follow-up respeita o block
  4. Intervalo não passou aindafollow_up_last_at + intervals[stage] > NOW()
  5. Distributed lock falhando — raro, ver logs followup.lock_failed

Forçar follow-up manual (teste)

UPDATE leads 
SET follow_up_stage = 0, follow_up_last_at = NOW() - INTERVAL '1 hour'
WHERE remote_jid = '<jid>';

Próximo ciclo (até 60s) pega o lead e dispara stage 1.


Problema 9 — ClickUp não recebe notificação (reportar)

Sintoma: Tool reportar foi chamada (aparece em agent_logs), mas ninguém viu no canal.

Diagnóstico

  1. Dry-run? Log reportar.dry_run em vez de reportar.posted → header X-Gita-Dry-Run: 1 veio sem querer
  2. Channel ID errado? SELECT notification_clickup_channel_id FROM ai_agents WHERE slug='<slug>'
  3. Token ClickUp expirou? Ver env CLICKUP_TOKEN no engine
  4. Post falhou? Log clickup.post_failed com status e body

Fix

  • Corrigir channel ID no agente (ver lista de canais: mcp__claude_ai_ClickUp__clickup_get_chat_channels)
  • Renovar token se expirou
  • Fallback: reativar notification_number (WhatsApp) temporariamente

Problema 10 — Histórico contaminado entre clientes

Sintoma: Lead testa agente da Gita, depois manda mensagem pra Janaina e Janaina menciona algo da Gita.

Causa

history.ts:getContents aceita um parâmetro clientName opcional — quando passado, retorna mensagens de todos os agentes do mesmo tenant. Cross-tenant (Janaina vs Gita) não vaza.

Mas intra-tenant (captacao + conversao + downsell do mesmo cliente) é intencional — pra handoff funcionar.

Se suspeitar de vazamento cross-tenant

-- Listar leads do mesmo JID em múltiplos tenants
SELECT l.remote_jid, a.slug, a.client_name
FROM leads l
JOIN ai_agents a ON a.id = l.agent_id
WHERE l.remote_jid = '<jid>'
ORDER BY a.client_name;

Se aparecer mais de um client_name → legítimo (contato real em múltiplos clientes). Ver auditCrossTenantLeads em router-classifier.ts.

Se o prompt responde coisas do cliente errado mesmo assim → bug no filtro do history.ts ou no client_name do agente. Abrir issue.


Quando abrir issue / chamar dev

Sintoma Você resolve Dev precisa
Typo em prompt ✅ admin panel
Trocar variável (link, horário, valor) ✅ admin panel
Pausar lead específico ✅ label pausar-ia no Chatwoot
Pausar agente is_active=false via admin
Nova tool / nova integração
Bug do pipeline (ex: tool não chamada)
Mudança no router (regex, FIT_ROUTING)
Migration de cliente novo

Comandos de emergência

Parar um agente AGORA

UPDATE ai_agents SET is_active = false WHERE slug = '<slug>';
-- Aguarde 60s (cache)

Limpar histórico de um lead

DELETE FROM messages WHERE remote_jid = '<jid>';
DELETE FROM leads WHERE remote_jid = '<jid>';
-- Cuidado: próxima mensagem vira "novo lead"

Reset de Redis (block_ia + debounce)

  • Acesso ao Redis via Easypanel
  • DEL block:* e DEL debounce:* (só em emergência absoluta)