MÓDULO 5.6

💰 Camada 5b — Governança: Custo e Audit

Um agente em loop pode gastar $500 em uma hora. Isso já aconteceu em produção. Budget por execução, alertas multicamada, cost allocation e ROI de agentes — a governança financeira que protege a empresa.

6
Tópicos
50
Minutos
Avançado
Nível
Código
Tipo
1

⚠️ O Problema do Custo Não Monitorado

Este não é um cenário hipotético. Em 2024, múltiplas startups reportaram publicamente faturas de $5.000 a $50.000 em APIs de LLM causadas por bugs de loop em agentes sem controle de custo. Aqui está como isso acontece.

Anatomia de um loop de custo

1. Agente recebe tarefa: "monitore preços de 100 produtos e alerte quando mudarem"
2. Bug: condição de parada nunca é atingida (preços "mudam" a cada verificação por arredondamento)
3. Agente chama LLM 60 vezes por minuto durante 8 horas: 28.800 chamadas
4. A $0.015 por chamada: $432 em uma noite. Empresa descobre na manhã seguinte.
$432
Caso real: loop de monitoramento, 8 horas
$8.000
Startup B: agente de RAG em recursão, 72 horas
$0
Com budget cap de $5: encerra, salva resultado parcial
2

💵 Budget por Execução

Cada job do orquestrador tem um budget máximo. O orquestrador monitora custo acumulado em tempo real e para quando o limite é atingido — entregando o resultado parcial em vez de falhar silenciosamente.

Implementação: BudgetMonitor

class BudgetMonitor:
    """Monitora custo em tempo real e aplica limites por execução."""

    # Custo por 1k tokens por modelo (USD) — atualizar conforme preços vigentes
    MODEL_COSTS = {
        "claude-haiku-4-5":  {"input": 0.00025, "output": 0.00125},
        "claude-sonnet-4-6": {"input": 0.003,   "output": 0.015},
        "claude-opus-4-6":   {"input": 0.015,   "output": 0.075},
        "gpt-4o-mini":       {"input": 0.00015, "output": 0.0006},
        "gpt-4o":            {"input": 0.005,   "output": 0.015},
    }

    def __init__(self,
                 hard_limit_usd: float,
                 soft_limit_usd: float = None,
                 session_id: str = None):
        self.hard_limit = hard_limit_usd
        self.soft_limit = soft_limit_usd or (hard_limit_usd * 0.8)
        self.session_id = session_id
        self.accumulated_cost = 0.0
        self.cost_by_task: dict[str, float] = {}
        self.cost_by_model: dict[str, float] = {}
        self._soft_alert_sent = False

    def record_llm_call(self, task_id: str, model: str,
                        input_tokens: int, output_tokens: int) -> dict:
        """
        Registra custo de uma chamada LLM.
        Retorna {"cost": X, "status": "ok"|"warning"|"exceeded"}
        """
        costs = self.MODEL_COSTS.get(model, {"input": 0.005, "output": 0.015})
        call_cost = (input_tokens / 1000 * costs["input"] +
                     output_tokens / 1000 * costs["output"])

        self.accumulated_cost += call_cost
        self.cost_by_task[task_id] = self.cost_by_task.get(task_id, 0) + call_cost
        self.cost_by_model[model] = self.cost_by_model.get(model, 0) + call_cost

        status = "ok"
        if self.accumulated_cost >= self.hard_limit:
            status = "exceeded"
        elif self.accumulated_cost >= self.soft_limit and not self._soft_alert_sent:
            status = "warning"
            self._soft_alert_sent = True

        return {
            "call_cost": round(call_cost, 8),
            "accumulated": round(self.accumulated_cost, 6),
            "hard_limit": self.hard_limit,
            "utilization_pct": round(self.accumulated_cost / self.hard_limit * 100, 1),
            "status": status
        }

    def check_budget(self) -> bool:
        """Retorna True se ainda há budget disponível."""
        return self.accumulated_cost < self.hard_limit

    def raise_if_exceeded(self):
        """Lança exceção se budget foi excedido."""
        if not self.check_budget():
            raise BudgetExceededException(
                f"Budget de ${self.hard_limit:.2f} excedido. "
                f"Custo acumulado: ${self.accumulated_cost:.4f}"
            )

    def get_summary(self) -> dict:
        return {
            "session_id": self.session_id,
            "total_cost_usd": round(self.accumulated_cost, 6),
            "hard_limit_usd": self.hard_limit,
            "utilization_pct": round(self.accumulated_cost / self.hard_limit * 100, 1),
            "cost_by_task": {k: round(v, 6) for k, v in self.cost_by_task.items()},
            "cost_by_model": {k: round(v, 6) for k, v in self.cost_by_model.items()},
        }

class BudgetExceededException(Exception):
    """Lançada quando execução atinge o limite de custo configurado."""
    pass
3

🔔 Alertas de Custo

Alertas multicamada garantem que nenhum padrão anômalo de custo passe despercebido — sem criar alert fatigue com notificações excessivas.

Camada 1: Por execução

Imediato

Execução ultrapassa 80% do budget → alerta soft (warning). 100% → budget hard stop automático. Ação: notificar responsável + pausar execução se configurado.

Camada 2: Por hora/dia

Agregado

Custo horário ultrapassa threshold configurado → alerta. Custo diário acima do baseline histórico → alerta de anomalia. Identifica padrões antes da fatura chegar.

Camada 3: Por usuário/tenant

Mensal

Custo mensal de um departamento/cliente ultrapassa limite configurado → alerta para gestor responsável. Permite chargeback proativo.

class CostAlertSystem:
    """Sistema de alertas de custo multicamada."""

    def __init__(self, slack_webhook: str, email_recipients: list[str]):
        self.slack_webhook = slack_webhook
        self.emails = email_recipients

        # Thresholds configuráveis
        self.thresholds = {
            "per_execution_warning_usd": 4.0,    # 80% de budget $5
            "per_execution_critical_usd": 5.0,   # budget máximo
            "per_hour_usd": 20.0,                # custo/hora máximo
            "per_day_usd": 100.0,                # custo/dia máximo
            "anomaly_multiplier": 2.5,           # X vezes o baseline histórico
        }

        self._hourly_cost = 0.0
        self._daily_cost = 0.0
        self._baseline_hourly = None  # calculado do histórico

    async def check_and_alert(self, cost_event: dict):
        """Verifica todas as camadas e dispara alertas se necessário."""
        cost = cost_event["call_cost"]
        accumulated = cost_event["accumulated"]

        self._hourly_cost += cost
        self._daily_cost += cost

        alerts = []

        # Camada 1: por execução
        if accumulated >= self.thresholds["per_execution_critical_usd"]:
            alerts.append({
                "level": "CRITICAL",
                "message": f"Budget crítico: ${accumulated:.2f} atingido",
                "action": "Execução pausada automaticamente"
            })
        elif accumulated >= self.thresholds["per_execution_warning_usd"]:
            alerts.append({
                "level": "WARNING",
                "message": f"Execução em ${accumulated:.2f} (80% do budget)",
                "action": "Monitorar de perto"
            })

        # Camada 2: por hora
        if self._hourly_cost > self.thresholds["per_hour_usd"]:
            alerts.append({
                "level": "WARNING",
                "message": f"Custo horário: ${self._hourly_cost:.2f}/h (limite: ${self.thresholds['per_hour_usd']})"
            })

        # Anomaly detection simples
        if self._baseline_hourly and self._hourly_cost > self._baseline_hourly * self.thresholds["anomaly_multiplier"]:
            alerts.append({
                "level": "WARNING",
                "message": f"Anomalia: custo {self._hourly_cost/self._baseline_hourly:.1f}x acima do baseline"
            })

        for alert in alerts:
            await self._send_alert(alert, cost_event)

    async def _send_alert(self, alert: dict, context: dict):
        """Envia alerta para Slack."""
        emoji = "🚨" if alert["level"] == "CRITICAL" else "⚠️"
        message = {
            "text": f"{emoji} *Alerta de Custo de Agente*",
            "attachments": [{
                "color": "#FF0000" if alert["level"] == "CRITICAL" else "#FFA500",
                "fields": [
                    {"title": "Nível", "value": alert["level"], "short": True},
                    {"title": "Mensagem", "value": alert["message"], "short": False},
                    {"title": "Session", "value": context.get("session_id", "N/A"), "short": True},
                ]
            }]
        }
        async with aiohttp.ClientSession() as session:
            await session.post(self.slack_webhook, json=message)
4

🏢 Cost Allocation

Cada execução do orquestrador precisa ter um cost_center associado — departamento, projeto ou cliente. Isso cria accountability e permite chargeback interno.

Schema de cost allocation

-- Adição ao schema de sessões para cost allocation
ALTER TABLE orchestration_sessions ADD COLUMN IF NOT EXISTS
    cost_center VARCHAR(100),      -- "financeiro/q2-análise"
    department  VARCHAR(100),      -- "financeiro"
    project_id  VARCHAR(100),      -- "q2-analise-concorrencia"
    client_id   VARCHAR(100),      -- para SaaS multi-tenant
    requester   VARCHAR(100);      -- quem solicitou a execução

-- View para relatório mensal de cost center
CREATE VIEW monthly_cost_by_department AS
SELECT
    department,
    DATE_TRUNC('month', started_at) AS month,
    COUNT(*) AS total_sessions,
    SUM(cost_usd) AS total_cost_usd,
    AVG(cost_usd) AS avg_cost_per_session,
    COUNT(*) FILTER (WHERE status = 'completed') AS successful
FROM orchestration_sessions
WHERE started_at >= NOW() - INTERVAL '12 months'
GROUP BY department, DATE_TRUNC('month', started_at)
ORDER BY month DESC, total_cost_usd DESC;

Relatório de chargeback mensal

Departamento Sessões Custo Março Custo Fev
Financeiro47$234.50$198.20
Jurídico32$189.10$201.40
Produto83$412.80$356.90
TOTAL162$836.40$756.50
5

📈 Relatório de Custo e ROI

O argumento final para manter orçamento em agentes: mostrar o ROI real. Custo de IA vs. custo de trabalho humano equivalente para as mesmas tarefas.

Exemplo: Due Diligence de empresa

Custo com agentes:$2.40
Tempo com agentes:6.5 min
Custo humano equivalente:$800
Tempo humano equivalente:8h
ROI:333x

Onde o ROI é menor (mas ainda positivo)

Tarefas criativas de alto valor (copywriting especializado): ROI ~5x
Análises que exigem julgamento humano crítico: ROI ~3x (mais revisão)
Setup inicial e configuração: ROI negativo nas primeiras semanas
Tarefas repetitivas de pesquisa e análise: ROI 50-200x

Query SQL para cálculo de ROI

-- ROI por tipo de tarefa (baseado em custo humano configurado)
WITH human_cost_reference AS (
    SELECT
        task_type,
        human_hourly_rate_usd,
        estimated_human_hours
    FROM task_type_config  -- tabela de configuração com custo humano estimado
),
agent_cost AS (
    SELECT
        JSON_EXTRACT(input_data, '$.agente_tipo') AS task_type,
        AVG(cost_usd) AS avg_agent_cost,
        AVG(EXTRACT(EPOCH FROM (completed_at - started_at))) AS avg_duration_sec,
        COUNT(*) AS total_executions
    FROM task_executions
    WHERE status = 'done'
      AND started_at >= NOW() - INTERVAL '30 days'
    GROUP BY task_type
)
SELECT
    a.task_type,
    a.avg_agent_cost,
    a.avg_duration_sec / 60 AS avg_duration_min,
    (h.human_hourly_rate_usd * h.estimated_human_hours) AS human_cost_equivalent,
    (h.human_hourly_rate_usd * h.estimated_human_hours) / a.avg_agent_cost AS roi_multiplier,
    a.total_executions,
    a.total_executions * a.avg_agent_cost AS total_ai_cost,
    a.total_executions * (h.human_hourly_rate_usd * h.estimated_human_hours) AS total_human_equivalent
FROM agent_cost a
JOIN human_cost_reference h ON a.task_type = h.task_type
ORDER BY roi_multiplier DESC;
6

✂️ Otimização de Custo

Além dos controles de custo, há técnicas ativas para reduzir o custo por execução mantendo a qualidade. A combinação das 3 técnicas pode reduzir custo em 70-90%.

Técnica 1: Heterogeneous Routing (detalhado no módulo 5.10)

Usar o modelo mais barato capaz para cada tipo de tarefa. Classificador de complexidade direciona para Haiku ($0.00025/1k) quando possível, Sonnet para médio, Opus apenas para complexo.

Redução típica: 60-85% do custo de LLM

Técnica 2: Semantic Caching (detalhado no módulo 5.10)

Quando duas execuções fazem perguntas semanticamente similares, retornar resultado cacheado. Embedding similarity com threshold de 0.92+ detecta queries equivalentes.

Redução típica: 30-50% em workloads com queries repetidas

Técnica 3: Context Compression

Em vez de passar o resultado completo de uma tarefa para a próxima, passar um sumário comprimido. Compressão 10:1 nos resultados intermediários reduz tokens de contexto drasticamente.

Redução típica: 40-70% dos tokens de contexto

Resultado combinado das otimizações

# Exemplo: due diligence de empresa sem vs. com otimizações

baseline = {
    "modelo": "claude-opus-4-6 para tudo",
    "cache_hit_rate": "0%",
    "context_compressao": "sem compressão",
    "custo_estimado": "$24.80",
    "tempo_min": 8.5,
    "qualidade_score": 9.2  # de 10
}

otimizado = {
    "modelo": "heterogeneous: 40% Haiku, 45% Sonnet, 15% Opus",
    "cache_hit_rate": "35%",
    "context_compressao": "10:1 nos resultados intermediários",
    "custo_estimado": "$2.40",  # 90% de redução!
    "tempo_min": 6.5,           # mais rápido também
    "qualidade_score": 8.9  # quase idêntico
}

# A pergunta: você aceita 0.3 pontos de qualidade por 90% de redução de custo?
# Na maioria dos casos: SIM — essa é a fronteira de Pareto correta

Resumo do Módulo 5.6

Loops sem budget = risco de fatura de $500+ em horas — isso é documentado e real
BudgetMonitor com hard stop automático: 5 linhas de código que previnem $500 de fatura
Alertas multicamada: por execução, por hora e por anomalia — sem alert fatigue
Cost allocation: accountability por departamento, relatório automático de chargeback
ROI calculado: custo AI vs. custo humano — o argumento que mantém o orçamento
3 técnicas de otimização combinadas: redução de 90% de custo com 97% da qualidade