Intelligence (Cérebro/Observatório)
Status: 🟢 Estável (Sprints 1.A → 2.A deployadas) Code: backend/app/modules/intelligence UI: frontend/src/app/(admin)/[slug]/admin/intelligence Última revisão deste doc: 2026-05-13 por Felipe + Claude Dependências fortes: whatsapp + crm + email + business + diary (lê dados crus L0); council + agents (consomem L1/L3/L5); tenant_router (multi-tenant)
1. Identidade
O que faz (uma frase)
Observatório do negócio: agrega dados crus dos módulos (whatsapp, crm, email, business, diary), calcula atributos por contato (L1), descobre padrões persistentes (L3), registra observações de IA (L5), e expõe tudo via tools que Conselho e Agentes consomem para tomar decisões com evidência.
Por que existe (negócio)
Sem Intelligence, cada decisão de IA seria stateless e estatisticamente cega:
- Conselheiro responderia "como vai a saúde do cliente?" sem ter um score calculado.
- Agente Hari não saberia que o lead já desistiu 3x antes de responder a 4ª.
- Felipe não veria padrões tipo "no-show de yoga sempre na segunda manhã" sem ter alguém olhando.
A camada Intelligence resolve isso operando como observatório passivo + analítico ativo:
- Atributos por contato (L1): churn_risk_score, engagement_score, ltv, tags comportamentais — tudo calculado e cacheado.
- Padrões (L3): "campanhas com vídeo convertem 3x mais que com imagem" — discovered via causality sub-agent.
- Insights pontuais (L2): anomalias, sumários, crisis detection.
- Observações de IA (L5): log do que o Conselho/Agente viu antes de cada decisão (auditabilidade).
Por que existe (técnico)
Intelligence é o agregador-único entre módulos. Sem ele:
- CRM teria que importar
whatsapp.message,email.send,billing.invoice(acoplamento). - Conselho/Agentes refariam queries pesadas em cada turn (sem cache).
- Sem padrão pra "explicabilidade" — cada módulo inventaria seu jeito.
Como módulo dedicado:
- Refresh determinístico com
formula_version+inputs_hash(skip se nada mudou). - Provenance nativo —
confidence,churn_explanation,health_explanation,at_risk_reasonem cada atributo. - Catálogo de behavior tags universal:
dormant,new_lead,objection_open,no_show_chronic,at_risk_customer,repeat_buyer, etc. - Append-only history (
contact_attribute_history) pra reconstruir trajetória. - Tools cross-módulo que Conselho usa direto sem precisar entender 7 schemas diferentes.
Status atual
- Sprint 1.A deployada (2026-05-13) — atribuição (campaign + touchpoint + crm_contact.attribution_*, mig 0094).
emit_eventem council/diary/whatsapp delivered/read/reaction. - Sprint 1.B + 1.C deployadas (2026-05-13) — alembic 0095+0096. L1
contact_attribute(3758 rows mais-consciente), L3intelligence_pattern, L5brain_observation, sub-agent causality, 13 tools novas no Council. Telas/admin/intelligence/{contact-attributes,patterns,observations}. - Sprint 2.A "Contact OS" deployada (2026-05-13) — alembic 0101 + commit
c8ca39e2. L1 ganhou provenance (formula_version, inputs_hash, confidence), explainability nativa, 4 tags novas, refresh v2 cruzando objections+price_inquiry+appointment, skip-on-no-change, contact_attribute_history append-only, tool Councilread_contact_attribute_history, endpoint /health do catálogo, UI estendida. Validado em 3758 contatos mais_consciente.
Próxima mudança planejada: L4 (truth) implementação completa (regras derivadas em runtime); embeddings para knowledge_entry busca semântica.
2. Cases de uso reais
Case 1: Conselho responde "como está minha taxa de churn?"
Situação: Felipe pergunta no Conselho.
Fluxo:
- CEO chama tool
read_intelligence_insights(severity=warning, sub_agent=churn_detection). - Tool roda
cross_module.list_intelligence_insights→ retorna últimos N insights de churn. - Brain monta resposta narrativa: "X contatos em risco crítico, top 3 razões: dormant, objection_open, low_engagement..."
- Mostra contatos específicos via
read_contact_attributes(behavior_tag='at_risk_customer', limit=10).
Impacto: Felipe entende health do negócio sem abrir 5 telas de CRM.
Case 2: Agente Hari evita oferecer produto a contato com objection_open
Situação: Lead tem objeção registrada ("preço alto") em product X, agora pergunta sobre product Y.
Fluxo:
- Brain de Hari chama
read_contact_objections(contact_id, unresolved_only=True). - Detecta objeção aberta.
- Brain ajusta resposta: cita product Y mas aborda objeção de preço primeiro ("entendo que valor era preocupação...").
Impacto: Conversão não morre por agente "robô" ignorando histórico.
Case 3: Padrão descoberto pelo causality sub-agent
Situação: Causality roda diariamente, snapshot de cohorts × outcomes.
Fluxo:
causality.discover_patterns(tenant_id)coleta:- Campaign cohorts → conversão
- Channel analysis → engagement
- Product affinity → cross-sell
- Objection distribution
- Appointment patterns (no-show por weekday/hour)
- Churn signals
- Manda JSONs estruturados (não dados crus de pessoa) pro Claude.
- Claude retorna padrões com evidência:
{kind, scope_kind, title, evidence: {metric, comparison, base}, confidence, sample_size, severity}. - Persiste em
intelligence_patterncomstatus=provisional,discovered_by=causality. - Felipe revê em
/admin/intelligence/patterns, marcaconfirmedouinvalidated.
Exemplo real: "Yoga no-show 60% segunda 9h vs 12% terça 19h" (n=42, confidence=0.85).
Impacto: Felipe descobre padrões que jamais identificaria manualmente; ajusta horários, comunicação, oferta.
Case 4: Refresh L1 hora a hora — provenance + skip-on-no-change
Situação: Beat refresh_contact_attributes (30min).
Fluxo:
- Pega N contatos do tenant (limit 5000 default).
- Pra cada contato: ~16 queries determinísticas (engagement_30d, ltv, quote_count, purchase_count, objections, price_inquiries, appointments, last_touch).
- Calcula scores:
churn_risk_score,relationship_health_score,engagement_score_*. - Calcula
inputs_hash = sha256(snapshot_estável). - Compara com
inputs_hashanterior:- Igual → atualiza só
refreshed_at(skip materializar). - Diferente → recalcula tudo + grava novos atributos + insere em
contact_attribute_history(mudanças materiais).
- Igual → atualiza só
confidenceproporcional a volume de sinais.churn_explanation+health_explanation: lista de fatores ponderados.
Impacto: 3758 contatos refreshados em 2-5s; ~70% skip materializar; histórico append-only permite reconstruir trajetória.
3. Oportunidades de negócio
- Vender Intelligence como camada standalone: "Mandir Insights" (subset com L1+L3+L5) para empresas que já têm CRM/WhatsApp próprios mas querem atribuição + patterns + churn risk como API.
- Causality como produto premium: descoberta automática de padrões via Claude — "pague por padrão confirmado". Diferencial sobre BIs tradicionais (Looker, Metabase) que só mostram, não descobrem.
- Compliance LGPD: explainability nativa (churn_explanation, etc.) é argumento legal. "Por que você está em risco?" → resposta auditável.
- Marketplace de patterns por vertical: padrões descobertos em e-commerce funcionam pra outros e-commerces. Anonimização + share + adapt.
- Predição como serviço: ChurnAttribute → predição de churn em 90d com confidence. API pricing por inferência.
- Brain Observatory cross-tenant (L5): insights agregados (anonimizados) ajudam o Mandir a melhorar produto. Telemetria opt-in.
Riscos comerciais:
- Custo LLM em escala (causality + crisis_detection rodam por tenant).
- Privacy: refresh de L1 lê dados sensíveis — LGPD exige consentimento + auditoria.
- Padrões "óbvios" que Claude vai inventar sem cuidado (mitigação:
confidence ≤ 0.3 se sample_size < 10).
4. Arquitetura interna
Camadas L0-L5 (Brain Observatory)
L0 — Cru (vive em outros módulos)
whatsapp_message, crm_deal, email_send, contact_touchpoint,
product_objection, price_inquiry, appointment, campaign
↓ refresh_contact_attributes (Beat 30min)
L1 — Atributos por contato (contact_attribute)
scores, tags, provenance, recência, explanations
↓ scoring/threshold rules
L2 — Insights pontuais (intelligence_insight)
summary, anomaly, crisis_detection, churn_detection
↓ causality sub-agent (LLM)
L3 — Padrões persistentes (intelligence_pattern)
cohort_behavior, cross_channel_correlation, no_show_pattern, ...
↓ regras derivadas em runtime
L4 — Verdade (não persistida — TBD)
"se churn_risk ≥ 70 then contato em risco"
↓ logged when consulted
L5 — Observações de IA (brain_observation)
"advisor X consultou Y antes de decidir Z"
Arquivos do módulo
| Arquivo | Propósito |
|---|---|
models.py | 7 tabelas |
routes.py | 29+ endpoints |
contact_attributes.py | L1 refresh engine (provenance, skip-on-no-change, hash) |
segments.py | Query builder (criteria JSONB → contact list) |
segment_evaluation.py | Materialization de intelligence_segment_member |
sub_agents.py | Determinísticos: summary, engagement_score, anomaly, churn, cohort |
llm_agents.py | LLM-based: chat_query, crisis_detection, thread_sales_analysis, relationship_health_batch |
llm_tools.py | 8 tools: count_contacts, list_contacts, count_emails, count_whatsapp_messages, list_segments, count_segment_members, deals_summary, members_summary |
causality.py | Pattern discovery (snapshots → Claude → IntelligencePattern) |
tasks.py | Beat tasks |
Tasks Celery (Beat schedule)
| Task | Cron | Multi-tenant? | Notas |
|---|---|---|---|
intelligence.refresh_contact_attributes | */30 * * * * | Sim — loop tenants ativos | Crítico, ~5000 contatos / 2-5s |
intelligence.refresh_segment_members | 5 * * * * | Sim | Materializa segments |
intelligence.run_summary | 0 8 * * * | Sim | Agregado diário |
intelligence.run_engagement_score | 0 9 * * * | Sim | Top contatos |
intelligence.run_churn_detection | 0 6 * * * | Sim | Threshold 50 default |
intelligence.run_cohort_analytics | 0 10 * * 0 | Sim | Semanal (domingo) |
intelligence.analyze_thread | On-demand (whatsapp callback) | Sim | Thread sales analysis |
Todas usam tenant_router.worker_session(tenant_id) (NullPool por task).
5. Tabelas + relacionamentos (7)
intelligence_insight (L2)
Descobertas pontuais por sub-agent.
| Coluna chave | Tipo | Notas |
|---|---|---|
tenant_id | UUID | idx |
sub_agent | VARCHAR | summary / engagement_score / anomaly / crisis_detection / churn_detection / chat_query / dynamic_segment / event_trigger / causality |
subject_type | VARCHAR | contact / deal / tenant / global (ou NULL) |
subject_id | UUID | ID do objeto referenciado |
severity | VARCHAR | info / warning / critical |
title / body_md | ||
payload | JSONB | Estruturado por sub-agent |
acknowledged_at / acknowledged_by_user_id |
Índices: (tenant, severity), (tenant, sub_agent), (tenant, subject_type, subject_id).
intelligence_segment + intelligence_segment_member
Segmentos dinâmicos.
intelligence_segment: slug (UQ), name, criteria JSONB, member_count, is_active, refreshed_at.
intelligence_segment_member: segment_id, contact_id, added_at — materializado por beat 05:00 UTC.
contact_attribute (L1) ⭐
Atributos agregados por contato.
| Coluna chave | Tipo | Notas |
|---|---|---|
tenant_id | UUID | idx |
contact_id | UUID | UNIQUE (1 row por contato) |
engagement_score_30d / engagement_score_90d | INT | wa_in×3 + wa_out×2 + email_open×1 + email_click×4, capped 100 |
churn_risk_score | INT | 0-100 (factors weighted) |
relationship_health_score | INT | 0-100 (baseline 40) |
lifetime_value_brl | DECIMAL | Soma de purchases |
quote_count / purchase_count / quote_to_purchase_ratio | INT/FLOAT | |
last_interaction_at / last_purchase_at / days_since_last_interaction | Recência | |
no_show_rate / no_show_pattern | FLOAT/JSONB | Por weekday/hour |
top_objections | JSONB array | |
channels_used / preferred_channel / best_time_to_contact | ||
attribution_kind / attribution_channel | Sprint 1.A | |
| Provenance (Sprint 2.A): | ||
formula_version | VARCHAR | v2 (atual). Bump força reprocessamento. |
inputs_hash | VARCHAR(64) | sha256 de snapshot estável. Igual = skip materializar. |
confidence | FLOAT | 0..1 baseado em volume de sinais |
churn_explanation | JSONB | {factors: [{factor, weight, value}], score} |
health_explanation | JSONB | idem |
at_risk_reason | VARCHAR | Label curto do fator dominante |
behavior_tags | JSONB array | high_engagement, low_engagement, price_sensitive, repeat_buyer, at_risk_customer, dormant, new_lead, objection_open, no_show_chronic |
refreshed_at | TIMESTAMP(tz) |
Índices: (tenant, churn_risk_score DESC), (tenant, relationship_health_score DESC), (tenant, engagement_score_30d DESC), (tenant, last_interaction_at DESC).
contact_attribute_history (append-only)
Mudanças materiais ao longo do tempo.
| Coluna chave | Tipo | Notas |
|---|---|---|
tenant_id / contact_id | UUID | |
attribute_name | VARCHAR | engagement_score_30d, churn_risk_score, behavior_tags, etc. |
value_text / previous_value_text | TEXT | |
delta_kind | VARCHAR | first_value / score_jump_up / score_jump_down / tag_added / tag_removed |
changed_at | TIMESTAMP(tz) |
Quando escreve: Δ ≥ 10 em scores trackeados; tag add/remove; primeira vez (first_value).
Índices: (tenant, contact, time), (tenant, attribute, time).
intelligence_pattern (L3)
Padrões persistentes descobertos.
| Coluna chave | Tipo | Notas |
|---|---|---|
tenant_id | UUID | idx |
kind | VARCHAR | cohort_behavior / contact_behavior / cross_channel_correlation / temporal / product_affinity / churn_predictor / conversion_path / objection_pattern / no_show_pattern |
scope_kind | VARCHAR | global / cohort / contact / campaign / product / segment / channel |
scope_id | UUID | Quando aplicável |
title | VARCHAR(80) | |
description_md | TEXT | 2-4 linhas pt-BR com números |
evidence | JSONB | {metric, comparison: "62% vs 8%", base: "n=42"} |
confidence | FLOAT | 0..1 |
sample_size | INT | |
severity | VARCHAR | info / warning / critical / opportunity |
status | VARCHAR | provisional / confirmed / invalidated / stale |
discovered_by | VARCHAR | causality (futuro: outros) |
discovered_at / last_seen_at / invalidated_at | TIMESTAMP | Lifecycle |
acknowledged_by_user_id / notes_md | Felipe revisa |
Índices: (tenant, kind), (tenant, status), (tenant, scope_kind, scope_id).
brain_observation (L5)
Log do que IA observou antes de cada decisão.
| Coluna chave | Tipo | Notas |
|---|---|---|
advisor_slug | VARCHAR | ceo, commercial, low_ticket_sales, etc. |
conversation_id | UUID | Contexto |
message_id / contact_id | UUID | |
trigger_kind | VARCHAR | contact_pre_interaction / campaign_launch_eligibility / diary_engagement |
observed_facts | JSONB | {contact_engagement: 75, churn_risk: 42, ...} |
patterns_used | JSONB array | IDs dos intelligence_pattern consultados |
decision_md | TEXT | Raciocínio em markdown |
Relacionamentos cross-módulo
| Direção | Outro módulo | Como | Por quê |
|---|---|---|---|
| ↗ Lê | whatsapp | Queries em whatsapp_message, whatsapp_thread | engagement, sentimento |
| ↗ Lê | crm | crm_contact, crm_deal, crm_contact_tag | lifecycle, deals, tags |
| ↗ Lê | email | email_send | opens, clicks |
| ↗ Lê | business | product_objection, price_inquiry, appointment | sinais de churn |
| ↗ Lê | diary | diary_entry (apenas counts agregados — sem conteúdo cru) | crisis detection |
| ↘ Escreve | crm_contact | sentiment_trend, conversation_health_score (Sprint 2.A) | Coloca scores no CRM |
| ↗ Lê | attribution | crm_contact.attribution_*, contact_touchpoint, campaign | atribuição de conversão |
| ↘ Escreve via tools | council | cross_module.read_intelligence_insights, etc. | Conselho consulta |
| ↘ Escreve via tools | agents | read_contact_attributes, read_patterns | Agentes ajustam respostas |
6. API / Endpoints (29+)
Prefixo /api/intelligence.
Insights (L2)
| Método | Rota | O que faz |
|---|---|---|
| GET | /insights | Lista (filtros: severity, sub_agent, limit) |
| POST | /run/summary | Sync com window_days |
| POST | /run/engagement-score | Top N contatos |
| POST | /run/crisis-detection | LLM batch (diary + WA inbound) |
| POST | /run/anomaly | Queda de engajamento |
| POST | /run/churn-detection | Threshold-based |
| POST | /run/cohort-analytics | Programa × conclusão |
| POST | /insights/{id}/ack | Marca acknowledge |
Segments (Dinâmicos)
| Método | Rota | O que faz |
|---|---|---|
| GET / POST / PATCH / DELETE | /segments | CRUD |
| POST | /segments/{id}/refresh | Recalc count |
| GET | /segments/{id}/members | Lista contatos |
| POST | /segments/preview | Preview sem persist |
Contact Attributes (L1)
| Método | Rota | O que faz |
|---|---|---|
| GET | /contact-attributes | Lista (filtros: min_engagement, max_churn_risk, behavior_tag, q_text) |
| GET | /contact-attributes/health | Cobertura por atributo (sentinela) |
| GET | /contact-attributes/{id} | Detail completo (explanations) |
| GET | /contact-attributes/{id}/history | Timeline append-only |
| POST | /contact-attributes/refresh | Sync batch (force ignora hash) |
Patterns (L3)
| Método | Rota | O que faz |
|---|---|---|
| GET | /patterns | Lista (kind, status, severity, min_confidence) |
| PATCH | /patterns/{id} | Update status, severity, notes, acknowledge |
| POST | /run/causality | Sync LLM discovery |
Observations (L5)
| Método | Rota | O que faz |
|---|---|---|
| GET | /observations | Lista (contact_id, conversation_id, advisor_slug filters) |
Chat Query (LLM Tool Use)
| Método | Rota | O que faz |
|---|---|---|
| POST | /chat-query | Pergunta natural → resposta via tools (loop até 8 iter) |
WhatsApp Intelligence
| Método | Rota | O que faz |
|---|---|---|
| POST | /analyze/thread/{id} | On-demand: sentiment + purchase intent + summary |
| GET | /whatsapp/sentiment-trends | Distribuição últimos N dias |
| GET | /whatsapp/purchase-intent-signals | Threads por sinal |
| GET | /whatsapp/relationship-health | Contatos com trend + upsell |
| POST | /run/relationship-health | Batch LLM (90d default) |
7. Sub-agentes
| Sub-Agent | Tipo | O que faz |
|---|---|---|
summary | Determinístico | Agregado: contatos, deals, email opens, WA messages, diary entries (counts) |
engagement_score | Determinístico | Top N contatos por wa_in×3 + wa_out×2 + email_open×1 + email_click×4 |
chat_query | LLM (Claude) | Pergunta natural → tool use (8 tools) → resposta narrativa |
dynamic_segment | Determinístico | Avalia criteria JSONB → IntelligenceSegmentMember |
crisis_detection | LLM | Diary + WA inbound → tom de crise (warning/critical) |
event_trigger | TBD | Não implementado |
anomaly | Determinístico | Queda eng prev_window > 0 e curr = 0 |
causality | LLM | Snapshots cohort + Claude → IntelligencePattern (L3) |
thread_sales_analysis | LLM | Thread WA → sentimento + purchase intent + care score |
relationship_health_batch | LLM | Histórico contato → sentiment trend + health score |
cohort_analytics | Determinístico | Programa × turma → taxa conclusão |
churn_detection | Determinístico | ContactAttribute.churn_risk_score ≥ threshold |
refresh_contact_attributes | Determinístico | Crítico — recalcula L1 em batch |
refresh_all_segments | Determinístico | Recompila segments ativos |
8. Contact Attribute (L1) — Refresh Pipeline
Princípios cravados (Sprint 2.A):
formula_version: cada linha carrega versão (v2atual). Bump força reprocessamento comforce=true.inputs_hash: sha256 de snapshot estável (eng, ltv, quote_count, purchase_count, appt_count, ns_count, churn_risk, health_score, tags, at_risk_reason, last_int_at, last_pur_at). Idêntico → skip materializar (atualiza apenasrefreshed_at).confidence: 0..1 baseado em volume de sinais (wa_in, wa_out, purchases, touches).- Explicabilidade:
churn_explanation+health_explanationsão dicts com fatores ponderados — UI mostra "por que risco?"
Catálogo de behavior tags
| Tag | Critério |
|---|---|
high_engagement | engagement_score_30d ≥ 60 |
low_engagement | engagement_score_30d ≤ 10 |
repeat_buyer | purchase_count ≥ 3 |
price_sensitive | quote_to_purchase_ratio < 0.34 com ≥ 3 quotes |
at_risk_customer | customer + engagement_30 ≤ 5 |
dormant | sem interação > 60 dias |
objection_open | ≥ 1 objeção sem resolução |
no_show_chronic | no_show_rate ≥ 0.3 com ≥ 3 appointments |
new_lead | criado < 14 dias |
Heurísticas de scoring (determinísticas, sem LLM)
- engagement_score =
wa_in×3 + wa_out×2 + email_open×1 + email_click×4, capped 100 - churn_risk_score (0-100):
- eng_30 crítico (+30)
- eng_90 queda (-20)
-
60d sem interação (+20)
- customer sem compra 180d (+15)
- objeção aberta (+10)
- no_show_rate ≥ 0.3 (+12)
- relationship_health_score (0-100):
- Baseline 40
- eng_30 ≥ 40 (+25)
- comprou (+15)
- 3+ compras (+10)
- objeção aberta (-15)
- no_show_rate ≥ 0.3 (-10)
-
30d sem interação (-10)
History (append-only)
- TRACKED_SCORES: engagement_score_30d, churn_risk_score, relationship_health_score → entry quando Δ ≥ 10.
- Tags: entry em cada add/remove.
- delta_kind:
first_value,score_jump_up,score_jump_down,tag_added,tag_removed.
Performance (3758 contatos)
- ~16 queries totais por refresh (paralelo-friendly).
- Batch upsert via
pg_insert.on_conflict_do_update. - Skip-on-no-change: ~70% das linhas pulam materialização.
- ~2-5s por 5000 contatos.
9. Patterns (L3) — Causality Sub-Agent
Snapshots coletados:
campaign_cohorts— por campanha → n contatos, deals_won, deals_lost, ltv, avg eng/churn/health.channel_analysis— por canal (YouTube, IG, Email, Ads) → similar.product_affinity— produtos comprados juntos.objection_distribution— categorias em deals won vs lost.appointment_patterns— no-show por weekday/hour.churn_signals— contatos com churn_risk alto + engagement queda.
Prompt do Claude (causality.py):
Recebe JSONs estruturados (nunca dados crus de pessoa). Pede "padrões com evidência estatística". Retorna array:
{
"kind": "cohort_behavior|cross_channel_correlation|temporal|...",
"scope_kind": "global|cohort|contact|campaign|product|segment|channel",
"scope_id": "uuid-if-applicable",
"title": "≤80 chars",
"description_md": "2-4 linhas pt-BR com números",
"severity": "info|warning|critical|opportunity",
"confidence": 0..1,
"sample_size": int,
"evidence": {"metric": "...", "comparison": "62% vs 8%", "base": "n=42"}
}
Regras firmes:
confidence ≤ 0.3sesample_size < 10.- Nunca inventar números.
- Citar na descrição: base (n=X) e efeito (Y% vs Z%).
10. Brain Observation (L5)
Estrutura (planejado para cross-tenant via mandir-events, hoje só log estruturado):
advisor_slug— qual agente/conselheiro consultou intelligence.conversation_id,message_id,contact_id— contexto.trigger_kind—contact_pre_interaction,campaign_launch_eligibility,diary_engagement.observed_facts(JSONB) —{contact_engagement: 75, churn_risk: 42, last_interaction_days: 3}.patterns_used— IDs de patterns consultados.decision_md— raciocínio em markdown.
Exemplos:
- "Luciano cota 7 no vídeo Yoga" —
contact_id=luciano,observed_facts={sentiment: "positive", engagement_topic: "yoga"},trigger_kind="diary_engagement". - "Yoga no-show segunda-manhã 60%" — padrão global,
scope_kind="global",observed_facts={no_show_bucket: "weekday_0_hour_09", rate: 0.60}.
11. Configuração
Env vars
| Var | Propósito |
|---|---|
ANTHROPIC_API_KEY | Claude (compartilhado com council/agents) |
Settings flags (planejados — TODO)
INTELLIGENCE_LLM_ENABLED(master switch para sub-agentes LLM)INTELLIGENCE_REFRESH_ENABLED(pause refresh em deploy)INTELLIGENCE_CONTACT_ATTRIBUTE_FORCE_VERSION(bump formula)
12. Operações
Como rodar refresh ad-hoc
# Forçar refresh de tudo (ignora hash)
curl -X POST '/api/intelligence/contact-attributes/refresh?force=true'
# Refresh limit 100
curl -X POST '/api/intelligence/contact-attributes/refresh?limit=100'
Como descobrir patterns
curl -X POST '/api/intelligence/run/causality'
# Verifica /admin/intelligence/patterns
# Marca confirmed/invalidated
Troubleshooting
Sintoma: ContactAttribute desatualizado
Diagnóstico:
SELECT MAX(refreshed_at), COUNT(*) FROM contact_attribute;
Fix: verificar Beat refresh_contact_attributes rodando (docker logs mandir-suite-beat).
Sintoma: Padrão "óbvio" / inventado
Causa: Claude inventando sem evidence forte.
Fix: verificar confidence e sample_size. Se baixo, marcar invalidated na UI.
Sintoma: Custo LLM crescendo
Causa: crisis_detection ou causality rodando muito.
Fix: ajustar Beat schedule; usar model_tier=fast (Haiku) onde possível.
13. Métricas e observabilidade
Logs estruturados-chave
| Logger key | Quando emite | Campos |
|---|---|---|
intelligence.refresh.start | Beat refresh começou | tenant_id, limit, force |
intelligence.refresh.done | Refresh terminou | updated, skipped_no_change, history_rows, duration_ms |
intelligence.causality.discovered | Pattern novo | tenant_id, kind, confidence, sample_size |
intelligence.crisis.detected | Crisis insight | severity, contact_id |
intelligence.churn.flagged | Churn alto | contact_id, score, factors |
14. Limitações e débitos técnicos conhecidos
| # | Item | Impacto | Plano |
|---|---|---|---|
| 1 | L4 (truth) não persistido | Mid — regras derivadas só em runtime | Fase futura |
| 2 | event_trigger sub-agent não implementado | Low | Backlog |
| 3 | Embeddings em knowledge_entry | Mid — busca só ILIKE | pgvector planejado |
| 4 | Crisis detection sem fallback heurístico | Mid — se LLM falha, sem alert | Adicionar regex fallback |
| 5 | Patterns sem expiry automático | Low — stale precisa marcar manual | Job futuro |
| 6 | brain_observation cross-tenant não publica | Mid — analytics agregada perdida | Implementar mandir-events |
| 7 | causality cost | Mid — 1 call Claude por discovery cycle | Cache snapshots; reduce frequency |
| 8 | History sem TTL | Low — contact_attribute_history cresce | Archive > 90d futuro |
| 9 | Segments materialization full-refresh | Mid — sem diff incremental | Fase 2 |
| 10 | chat_query tool use sem cache de results | Low — cada chamada repete tools | Cache LRU futuro |
15. Histórico relevante
- 2026-05-13 (alembic 0101, commit
c8ca39e2) — Sprint 2.A "Contact OS": provenance (formula_version, inputs_hash, confidence), explainability nativa (churn/health/at_risk), 4 tags novas (dormant, new_lead, objection_open, no_show_chronic), refresh v2 cruzando objections+price_inquiries+appointments, skip-on-no-change, history append-only, tool Councilread_contact_attribute_history, endpoint /health, UI estendida. Validado em 3758 contatos. - 2026-05-13 (alembic 0095+0096) — Sprint 1.B+1.C: L1 contact_attribute, L3 intelligence_pattern, L5 brain_observation, sub-agent causality, módulo business (knowledge+products+quotes+objections+appointments+brain_config), 13 tools novas no Council. Telas
/admin/intelligence/{contact-attributes,patterns,observations}. - 2026-05-13 (alembic 0094, commits
09aada4+a3729da) — Sprint 1.A: móduloattribution(campaign + touchpoint + crm_contact.attribution_*). Áudio inbound vira contexto do Council.emit_eventem council.intervention, diary, whatsapp delivered/read/reaction. UTM resolution on-create.
Apêndices
A. Catálogo completo de behavior tags
| Tag | Quando aplica |
|---|---|
high_engagement | eng_30d ≥ 60 |
low_engagement | eng_30d ≤ 10 |
at_risk_customer | é cliente + eng_30d ≤ 5 |
dormant | > 60d sem interação |
new_lead | < 14d desde criação |
repeat_buyer | ≥ 3 compras |
price_sensitive | quote_to_purchase_ratio < 0.34 com ≥ 3 quotes |
objection_open | ≥ 1 objeção sem resolução |
no_show_chronic | no_show_rate ≥ 0.3 com ≥ 3 appointments |
B. Glossário
- L0-L5: camadas do Brain Observatory (cru → atributo → insight → padrão → verdade → observação).
- Provenance: rastreabilidade da computação (formula_version + inputs_hash + confidence).
- Skip-on-no-change: se inputs_hash igual ao anterior, atualiza só
refreshed_at(não escreve atributos novamente). - Sub-agent: unidade de processamento dentro de Intelligence (summary, anomaly, causality, etc.).
- Pattern: descoberta persistente (vs Insight, que é pontual).
- Behavior tag: marcador comportamental aplicado ao contact_attribute (universalmente reconhecido por agentes/conselheiros).