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¶
- Engine vivo?
curl /health - Webhook chegou? Ver logs do Easypanel do engine, procurar
webhook.received - Agente ativo?
SELECT is_active FROM ai_agents WHERE slug = '<slug>' - Filter blocked?
SELECT * FROM agent_logs WHERE event='filter.blocked'— pode serown_message,block_ia_human,whitelist - Dry-run header? Se veio
X-Gita-Dry-Run: 1sem querer, envio é bypassado (logssend.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-iano Chatwoot ou TTL no Redis ainda não expirou - Whitelist (se
business_hours_enabled=true) → fora do horário - Uazapi desconectado →
curl /instance/statuscom token da instância, verstatus: "connected"
Problema 2 — Agente responde mas com delay enorme (>30s)¶
Sintoma: A mensagem demora 1-3 minutos pra voltar.
Causas prováveis¶
- Debounce muito alto —
delay_debouncepadrão é 8s, alguns agentes estão em 15-20s - Gemini lento ou fallback pra OpenAI — ver logs
gemini.fallback_triggered+openai.fallback_success - Tool pesada demorando — ex:
agendar_reuniaoesperando resposta do Google Calendar - Histórico muito grande —
getContentspega últimas 40 msgs, se o lead tem histórico denso o prompt fica pesado
Fix¶
- Reduzir
delay_debounceno admin (mas cuidado: se muito baixo, mensagens vêm em pedaços separados) - Se Gemini cai recorrente, trocar
modelpragemini-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¶
- Histórico contaminado — lead já conversou com OUTRO agente do mesmo tenant, o prompt cross-agent funciona por design (ver
history.ts:getContentscomclientName) - Temperature alta — flash 2.5 com
temp=0.7improvisa demais - Prompt não prescritivo — lista contexto sem proibir explicitamente
- Nome do lead confuso (
buildLeadContext) — selead.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
temperaturepra 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¶
- Tool não está registrada no banco —
SELECT * FROM tools WHERE agent_id = '<id>' is_active=falsena toolfunction_declarationmalformada — parâmetros ambíguos, description vaga- 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
descriptionda 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_confige tool-specific config viaSELECT 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¶
qualified_data.fitnão foi salvo — verleads.qualified_datano bancofittem valor não mapeado —FIT_ROUTINGsó conhecegita_agentseempresa_digital- Router não tem FIT_ROUTING pro tenant — ver
router-classifier.ts:FIT_ROUTING— sóGita Agenteshoje - 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¶
follow_up_enabled=falseno agente — verSELECT follow_up_enabled FROM ai_agents- Status já é
convertedoudownsell_offered— follow-up ignora - Block IA ativo (Redis) — follow-up respeita o block
- Intervalo não passou ainda —
follow_up_last_at + intervals[stage] > NOW() - 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¶
- Dry-run? Log
reportar.dry_runem vez dereportar.posted→ headerX-Gita-Dry-Run: 1veio sem querer - Channel ID errado?
SELECT notification_clickup_channel_id FROM ai_agents WHERE slug='<slug>' - Token ClickUp expirou? Ver env
CLICKUP_TOKENno engine - Post falhou? Log
clickup.post_failedcomstatusebody
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:*eDEL debounce:*(só em emergência absoluta)