Caderno de campo: provar valor antes de automatizar

Este laboratório transforma “queremos IA na triagem de ordens” em uma decisão reproduzível. Você construirá um pacote mínimo de evidência, executará um baseline não-IA, inspecionará a amostra e provocará três falhas: vazamento temporal, rótulo contaminado e amostragem enviesada.

O melhor resultado possível não é “usar IA”. É escolher corretamente entre:

  1. manter a regra porque ela resolve o problema;
  2. corrigir processo ou dados antes de experimentar;
  3. testar um candidato em modo sombra;
  4. encerrar a iniciativa por falta de ganho ou risco incompatível.

Cartão do laboratório

Campo Definição
objetivo decidir se a triagem de OS precisa de IA
hipótese uma regra simples já atende ao gate; um candidato não deve avançar sem ganho material
público iniciante com noções de terminal e Python
pré-requisitos problema, baseline, matriz de confusão e leitura básica de código
duração estimada 60–90 minutos, incluindo análise e mutações
ambiente Python 3.11 ou superior; somente biblioteca padrão
segredo necessário nenhum
arquivos triagem_baseline.py e DECISAO.md
saída observável JSON por cenário, tabela comparativa e decisão assinada
limpeza apagar apenas a pasta criada para o laboratório

Os dados e limiares são didáticos. Eles não representam um benchmark de produção nem autorizam decisão operacional.

1. Escreva o contrato antes de executar

Copie e complete:

# Contrato da decisão

- Usuário: supervisor de manutenção.
- Decisão apoiada: ordenar quais OS abertas serão inspecionadas primeiro.
- Instante: imediatamente após a validação da abertura no ERP.
- Entradas permitidas: criticidade, equipamento parado, temperatura inicial,
  tipo de ativo, unidade e descrição registrada naquele instante.
- Saída permitida: faixa de prioridade para revisão humana.
- Efeitos proibidos: parar ativo, reservar peça, aprovar, encerrar ou mudar OS.
- Baseline: regra versionada neste laboratório.
- População-alvo: OS das unidades Norte e Sul dentro do escopo definido.
- Resultado de valor: reduzir atraso em OS críticas.
- Métrica principal offline: recall da classe crítica.
- Guardrails: precisão, falsos positivos, cobertura por unidade e ausência de campos futuros.
- Condição de parada: manter a regra se ela cumprir todos os gates e o candidato
  não produzir ganho material com custo e risco aceitáveis.

Não prossiga se “crítica” ainda não possui definição operacional. Neste laboratório, o rótulo significa: a revisão posterior confirmou necessidade de intervenção crítica em até quatro horas. Em projeto real, documente quem confirma, com quais evidências e como divergências são resolvidas.

2. Fronteiras do sistema

Fluxo: Técnico<br/>abre OS, API valida<br/>schema e identidade, ERP<br/>fonte de verdade, Baseline<br/>regra versionada, Candidato<br/>sem efeito, Painel do supervisor, Armazém de avaliação<br/>acesso restrito, API de autorizaçãoTécnico<br/>abre OSAPI valida<br/>schema eidentidadeERP<br/>fonte de verdadeBaseline<br/>regraversionadaCandidato<br/>sem efeitoPainel do supervisorArmazém deavaliação<br/>acessorestritoAPI de autorização
Ler o fluxo em texto
  1. 1. Técnico<br/>abre OS
  2. 2. API valida<br/>schema e identidade
  3. 3. ERP<br/>fonte de verdade
  4. 4. Baseline<br/>regra versionada
  5. 5. Candidato<br/>sem efeito
  6. 6. Painel do supervisor
  7. 7. Armazém de avaliação<br/>acesso restrito
  8. 8. API de autorização

Marque quatro limites:

  • o ERP conserva o estado oficial;
  • baseline e candidato só produzem recomendação;
  • a API de autorização aplica papel, unidade, estado e auditoria;
  • o armazenamento de avaliação recebe somente campos necessários e possui retenção.

Se um prompt diz “apenas supervisores podem aprovar”, mas a API aceita aprovação de qualquer perfil, não existe controle. Política de acesso fica fora do modelo.

3. Crie o simulador executável

Crie uma pasta vazia e salve o código abaixo como triagem_baseline.py. Ele usa dados sintéticos embutidos e somente a biblioteca padrão do Python.

#!/usr/bin/env python3
"""Laboratório didático: baseline, qualidade, leakage e decisão de não usar IA."""

from __future__ import annotations

import argparse
import json
from collections import Counter
from dataclasses import dataclass, replace
from datetime import date
from typing import Callable, Iterable


@dataclass(frozen=True)
class Ordem:
    os_id: str
    aberta_em: date
    unidade: str
    ativo: str
    criticidade: int
    parado: bool
    temperatura_c: float | None
    descricao: str
    critica_confirmada: bool
    # Campo FUTURO: só existe depois do período de observação.
    horas_parada_final: float


RAW = [
    ("OS-001", "2026-01-03", "Norte", "chiller", 5, True, 101, "compressor desligou", True, 9.0),
    ("OS-002", "2026-01-09", "Sul", "bomba", 2, False, 62, "ruído leve", False, 0.0),
    ("OS-003", "2026-01-17", "Norte", "quadro", 4, False, 70, "odor de queimado", True, 5.0),
    ("OS-004", "2026-01-28", "Sul", "elevador", 1, False, None, "lâmpada queimada", False, 0.0),
    ("OS-005", "2026-02-02", "Norte", "gerador", 3, False, 74, "teste mensal", False, 0.0),
    ("OS-006", "2026-02-15", "Sul", "chiller", 5, False, 96, "pressão anormal", True, 7.0),
    ("OS-007", "2026-02-23", "Norte", "bomba", 2, False, 60, "inspeção preventiva", False, 0.0),
    ("OS-008", "2026-03-04", "Sul", "quadro", 4, True, 78, "setor sem energia", True, 6.0),
    ("OS-009", "2026-03-12", "Norte", "elevador", 1, False, None, "porta rangendo", False, 0.0),
    ("OS-010", "2026-03-25", "Sul", "gerador", 3, False, 73, "vibração moderada", False, 0.0),
    ("OS-011", "2026-04-01", "Norte", "chiller", 5, True, 99, "parada total", True, 12.0),
    ("OS-012", "2026-04-16", "Sul", "bomba", 2, False, 61, "gotejamento pequeno", False, 0.0),
    ("OS-013", "2026-05-03", "Norte", "quadro", 4, False, 76, "aquecimento no barramento", True, 4.5),
    ("OS-014", "2026-05-11", "Sul", "elevador", 2, False, None, "botão intermitente", False, 0.0),
    ("OS-015", "2026-05-22", "Norte", "gerador", 3, False, 72, "manutenção prevista", False, 0.0),
    ("OS-016", "2026-06-02", "Sul", "chiller", 5, False, 98, "alta pressão", True, 8.0),
    # Holdout temporal: o baseline simples continua suficiente.
    ("OS-017", "2026-07-01", "Norte", "bomba", 2, False, 64, "ruído leve", False, 0.0),
    ("OS-018", "2026-07-04", "Sul", "quadro", 5, False, 80, "fumaceou ao ligar", True, 6.0),
    ("OS-019", "2026-07-08", "Norte", "elevador", 1, False, None, "limpeza de trilho", False, 0.0),
    ("OS-020", "2026-07-12", "Sul", "chiller", 3, True, 83, "unidade parada", True, 5.0),
    ("OS-021", "2026-07-16", "Norte", "gerador", 3, False, 75, "vibração moderada", False, 0.0),
    ("OS-022", "2026-07-20", "Sul", "bomba", 4, False, 68, "selo rompeu", True, 4.0),
    ("OS-023", "2026-07-25", "Norte", "quadro", 2, False, 71, "ruído no contator", False, 0.0),
    ("OS-024", "2026-07-29", "Sul", "elevador", 5, False, None, "travou com passageiro", True, 3.0),
]


def carregar() -> list[Ordem]:
    return [Ordem(os_id, date.fromisoformat(dia), unidade, ativo, criticidade,
                  parado, temperatura, descricao, rotulo, horas)
            for os_id, dia, unidade, ativo, criticidade, parado, temperatura,
            descricao, rotulo, horas in RAW]


def baseline(ordem: Ordem) -> bool:
    """Prediz crítica usando somente valores disponíveis na abertura."""
    return ordem.parado or ordem.criticidade >= 4 or (
        ordem.temperatura_c is not None and ordem.temperatura_c >= 95
    )


def candidato_textual(ordem: Ordem) -> bool:
    """Regra candidata deliberadamente simples; não é um modelo treinado."""
    sinais = ("fumac", "travou", "rompeu", "parada total", "sem energia")
    return baseline(ordem) or any(sinal in ordem.descricao.lower() for sinal in sinais)


def candidato_com_vazamento(ordem: Ordem) -> bool:
    """ERRADO: usa resultado futuro e, por isso, parece perfeito offline."""
    return ordem.horas_parada_final >= 3


def dividir_no_tempo(ordens: Iterable[Ordem]):
    treino, validacao, teste = [], [], []
    for ordem in sorted(ordens, key=lambda item: item.aberta_em):
        if ordem.aberta_em < date(2026, 5, 1):
            treino.append(ordem)
        elif ordem.aberta_em < date(2026, 7, 1):
            validacao.append(ordem)
        else:
            teste.append(ordem)
    return treino, validacao, teste


def matriz(ordens: Iterable[Ordem], prever: Callable[[Ordem], bool]) -> dict[str, int]:
    resultado = Counter(tp=0, fp=0, tn=0, fn=0)
    for ordem in ordens:
        previsto, real = prever(ordem), ordem.critica_confirmada
        chave = "tp" if previsto and real else "fp" if previsto else "fn" if real else "tn"
        resultado[chave] += 1
    return dict(resultado)


def metricas(m: dict[str, int]) -> dict[str, float]:
    precisao = m["tp"] / max(1, m["tp"] + m["fp"])
    recall = m["tp"] / max(1, m["tp"] + m["fn"])
    fpr = m["fp"] / max(1, m["fp"] + m["tn"])
    return {"precisao": round(precisao, 3), "recall": round(recall, 3),
            "taxa_falso_positivo": round(fpr, 3)}


def cobertura(ordens: Iterable[Ordem]) -> dict[str, int]:
    return dict(sorted(Counter(ordem.unidade for ordem in ordens).items()))


def executar(mutacao: str) -> dict[str, object]:
    ordens = carregar()
    treino, validacao, teste = dividir_no_tempo(ordens)
    aviso = None
    prever_candidato = candidato_textual

    if mutacao == "label-noise":
        # Simula erro de rotulagem no holdout, sem alterar as entradas.
        ids = {"OS-018", "OS-021"}
        teste = [replace(o, critica_confirmada=not o.critica_confirmada) if o.os_id in ids else o
                 for o in teste]
        aviso = "dois rótulos do teste foram invertidos"
    elif mutacao == "sampling-bias":
        # Simula uma coleta que excluiu completamente a unidade Sul.
        teste = [o for o in teste if o.unidade == "Norte"]
        aviso = "holdout contém apenas a unidade Norte"
    elif mutacao == "leakage":
        prever_candidato = candidato_com_vazamento
        aviso = "candidato recebeu horas_parada_final, indisponível na abertura"

    base = metricas(matriz(teste, baseline))
    cand = metricas(matriz(teste, prever_candidato))
    segmentos = cobertura(teste)

    qualidade_ok = len(teste) >= 8 and set(segmentos) == {"Norte", "Sul"}
    disponibilidade_ok = mutacao != "leakage"
    baseline_atende = base["recall"] >= 0.90 and base["precisao"] >= 0.70
    ganho_recall = cand["recall"] - base["recall"]
    candidato_material = ganho_recall >= 0.10 and cand["taxa_falso_positivo"] <= 0.25

    if not qualidade_ok:
        decisao = "PARAR: corrigir amostragem/qualidade antes de comparar"
    elif not disponibilidade_ok:
        decisao = "PARAR: resultado inválido por vazamento temporal"
    elif baseline_atende and not candidato_material:
        decisao = "NÃO USAR IA: baseline atende e candidato não traz ganho material"
    elif candidato_material:
        decisao = "TESTAR EM SHADOW MODE: ganho candidato precisa de validação operacional"
    else:
        decisao = "INVESTIGAR: objetivo não atendido; não automatizar"

    return {
        "mutacao": mutacao,
        "tamanhos": {"treino": len(treino), "validacao": len(validacao), "teste": len(teste)},
        "cobertura_teste": segmentos,
        "baseline": base,
        "candidato": cand,
        "guardrails": {"qualidade_e_representatividade": qualidade_ok,
                       "atributos_disponiveis_na_decisao": disponibilidade_ok},
        "aviso": aviso,
        "decisao": decisao,
    }


def main() -> None:
    parser = argparse.ArgumentParser()
    parser.add_argument("--mutation", choices=("none", "leakage", "label-noise", "sampling-bias"),
                        default="none")
    args = parser.parse_args()
    print(json.dumps(executar(args.mutation), ensure_ascii=False, indent=2))


if __name__ == "__main__":
    main()

4. Execute o caminho nominal

No terminal, dentro da pasta do laboratório:

python triagem_baseline.py

Resultado essencial esperado:

"tamanhos": {"treino": 12, "validacao": 4, "teste": 8}
"cobertura_teste": {"Norte": 4, "Sul": 4}
"baseline": {"precisao": 1.0, "recall": 1.0, "taxa_falso_positivo": 0.0}
"decisao": "NÃO USAR IA: baseline atende e candidato não traz ganho material"

Não celebre o número perfeito. O dataset é sintético e pequeno. A conclusão correta é apenas: neste pacote didático, com esta definição e estes casos, a regra cumpre o gate; não há justificativa para acrescentar IA. Em produção, estimar incerteza, ampliar cobertura e acompanhar mudança temporal seriam obrigatórios.

O que cada partição faz

Fluxo: jan–abr<br/>12 casos, treino, mai–jun<br/>4 casos, validação, jul<br/>8 casos preservados, teste/holdout, baseline e candidato congelados, decisão registradajan–abr<br/>12 casostreinomai–jun<br/>4 casosvalidaçãojul<br/>8 casospreservadosteste/holdoutbaseline e candidatocongeladosdecisão registrada
Ler o fluxo em texto
  1. 1. jan–abr<br/>12 casos
  2. 2. treino
  3. 3. mai–jun<br/>4 casos
  4. 4. validação
  5. 5. jul<br/>8 casos preservados
  6. 6. teste/holdout
  7. 7. baseline e candidato congelados
  8. 8. decisão registrada

O código não treina um modelo; as três partições existem para ensinar seus contratos. Se a equipe alterasse candidato_textual após olhar julho, o holdout deixaria de ser prova independente.

5. Inspecione o dataset antes da métrica

Preencha uma ficha:

Pergunta Resposta deste laboratório Evidência real exigida
unidade de análise uma OS no instante de abertura contrato de eventos do ERP
população-alvo unidades Norte e Sul inventário de unidades/ativos
origem do rótulo campo sintético protocolo e revisão de especialistas
atributos futuros horas_parada_final timestamp e linhagem de cada campo
cauda importante falhas críticas amostragem deliberada e métricas por segmento
dados pessoais nenhum no exemplo inventário, finalidade, base, acesso e retenção
retenção arquivo descartável política aprovada e exclusão verificável

Agora responda: se a unidade Sul usa outro ERP, ela poderia desaparecer silenciosamente? Se os ativos sem sensor têm temperatura nula, o nulo representa ausência de risco ou ausência de observação? Se apenas ordens encerradas entram no dataset, o que acontece com casos longos ainda abertos?

6. Mutação 1 — vazamento temporal

Execute:

python triagem_baseline.py --mutation leakage

O candidato usa horas_parada_final. Esse campo é fortemente relacionado ao rótulo, mas só existe depois da decisão. A métrica pode permanecer perfeita e ainda assim ser inválida.

Resultado de controle:

"atributos_disponiveis_na_decisao": false
"decisao": "PARAR: resultado inválido por vazamento temporal"

Diagnóstico

  1. reconstrua a linha do tempo da OS;
  2. liste timestamp de evento, ingestão e correção de cada atributo;
  3. confirme a disponibilidade no serviço que fará a previsão;
  4. remova atributos futuros antes de qualquer split ou ajuste;
  5. invalide relatórios e modelos derivados do campo;
  6. crie teste de schema que proíba o atributo na interface online.

Evidência esperada

Uma tabela de disponibilidade:

campo existe na abertura? sistema de origem permitido?
criticidade sim ERP sim
temperatura inicial às vezes telemetria sim, com indicador de ausência
horas de parada final não relatório posterior não
peça substituída não encerramento não

7. Mutação 2 — rótulo contaminado

Execute:

python triagem_baseline.py --mutation label-noise

Duas respostas do teste são invertidas. Observe que baseline e candidato parecem piores, embora suas regras não tenham mudado.

Rótulo ruim pode nascer de erro de digitação, proxy inadequado, definição ambígua, mudança de política ou feedback influenciado pela própria recomendação. A correção não é aumentar o modelo.

Protocolo mínimo de rótulos

  1. escreva definição positiva, negativa e casos limítrofes;
  2. oculte a previsão durante a revisão independente;
  3. duplique uma amostra entre avaliadores;
  4. registre divergência, adjudicação e versão da política;
  5. audite segmentos raros e de alto impacto;
  6. preserve o rótulo original e a correção com proveniência;
  7. não trate clique ou aceite do usuário como verdade automática.

Caso de discussão

Uma OS foi encerrada rapidamente porque não havia peça em estoque e o técnico aplicou contenção temporária. “Encerrada em quatro horas” significaria sucesso, baixa criticidade ou apenas pressão administrativa? O rótulo deve representar a decisão que se deseja apoiar, não o campo mais conveniente.

8. Mutação 3 — amostragem enviesada

Execute:

python triagem_baseline.py --mutation sampling-bias

A mutação remove toda a unidade Sul. Mesmo que as métricas restantes pareçam boas, o guardrail de representatividade bloqueia a comparação:

"cobertura_teste": {"Norte": 4}
"qualidade_e_representatividade": false
"decisao": "PARAR: corrigir amostragem/qualidade antes de comparar"

O exemplo usa presença de unidades como controle simples. Em projeto real, presença não basta. Compare distribuição de tipos de ativo, turnos, gravidade, idioma, versão do formulário, disponibilidade de sensores e mudanças sazonais. Defina antes quais diferenças são aceitáveis.

Fluxo: Métrica agregada boa, todos os segmentos críticos estão cobertos?, parar: ampliar ou redefinir população, desempenho atende por segmento?, investigar coleta, rótulo e processo, prosseguir para validação operacionalMétrica agregada boatodos os segmentoscríticos estão cobertos?parar: ampliar ouredefinir populaçãodesempenho atende porsegmento?investigar coleta,rótulo e processoprosseguir paravalidação operacional
Ler o fluxo em texto
  1. 1. Métrica agregada boa
  2. 2. todos os segmentos críticos estão cobertos?
  3. 3. parar: ampliar ou redefinir população
  4. 4. desempenho atende por segmento?
  5. 5. investigar coleta, rótulo e processo
  6. 6. prosseguir para validação operacional

9. Matriz de decisão preenchida

Dimensão Gate Baseline nominal Candidato nominal Decisão
recall crítico ≥ 0,90 1,00 1,00 empate
precisão ≥ 0,70 1,00 1,00 empate
cobertura Norte e Sul atende atende prossegue
disponibilidade nenhum campo futuro atende atende no nominal prossegue
complexidade menor é melhor no empate regra curta regra adicional baseline vence
ganho mínimo +0,10 de recall referência +0,00 não material

O candidato não precisa ser literalmente IA para que o raciocínio funcione. Ele representa qualquer camada nova. Se nem uma regra textual adicional cria ganho, ainda não existe evidência para comprar, treinar ou integrar um modelo.

10. Do offline ao mundo real

Se um candidato legítimo superar o baseline, não o conecte diretamente ao ERP. Avance por degraus:

offline reproduzível
  → shadow mode sem efeito
  → revisão interna dos piores erros
  → piloto com usuários treinados
  → canário por unidade/turno
  → ampliação gradual
  → reavaliação e retirada quando necessário

Cada degrau precisa de gate, responsável e rollback. Em shadow mode, compare as saídas com resultados posteriores, mas controle o feedback loop: depois que usuários veem a sugestão, suas decisões podem passar a refletir o sistema. Separe períodos ou coortes e preserve avaliações independentes.

Sinais mínimos de operação

  • versão da regra, modelo, prompt e dataset;
  • volume por unidade e tipo de ativo;
  • recall e precisão com atraso compatível com o rótulo;
  • taxa de abstenção e correção humana;
  • latência de ponta a ponta e indisponibilidade;
  • custo por OS corretamente auxiliada;
  • distribuição de entradas e ausências;
  • incidentes, override e motivo de rollback.

Logs não devem copiar descrições completas por padrão. Aplique minimização e redação antes de exportar telemetria.

11. Pré-mortem do cenário

Antes do piloto, imagine que o projeto falhou em seis meses:

Falha Detecção Contenção Teste do controle
OS crítica perdida recall por unidade e alerta de cauda regra de segurança + revisão humana replay de casos críticos
atributo futuro reaparece contrato de schema e linhagem rejeitar payload teste negativo na CI
unidade some da coleta cobertura diária por origem bloquear relatório comparativo remover uma unidade no teste
rótulo muda de significado versão da política congelar promoção conjunto de casos de fronteira
dado pessoal aparece no texto scanner e amostra restrita redação e quarentena injetar CPF fictício
candidato indisponível timeout e circuit breaker retornar baseline simular timeout

Uma defesa como “o modelo saberá recusar” não é controle verificável. Schema, autorização, limites e fallback são aplicados pela aplicação.

12. Produza DECISAO.md

Use o modelo:

# Decisão sobre IA na triagem de OS

## Contexto
[usuário, decisão, população, instante e consequência]

## Hipótese e critérios definidos antes do teste
[métrica, alvo, guardrails e condição de parada]

## Dados
[origem, período, unidade, rótulo, amostra, split, campos proibidos,
privacidade, limitações e versão]

## Alternativas comparadas
[processo atual, baseline executável e candidato]

## Resultados
[matriz de confusão, métricas globais e por segmento, custo, latência,
piores erros e intervalo de incerteza quando aplicável]

## Mutações
[leakage, label-noise e sampling-bias; controle que detectou cada uma]

## Decisão
[manter baseline | corrigir dados/processo | shadow mode | encerrar]

## Motivo e validade
[evidência, responsável, data, escopo e data de revisão]

## Retirada
[como voltar à regra e invalidar artefatos derivados]

No cenário nominal deste laboratório, a decisão correta é manter o baseline e não usar IA. Registre isso sem vergonha: o experimento poupou complexidade e criou uma fundação mensurável para reabrir a questão se a população ou o processo mudar.

13. Testes automatizados do laboratório

Salve o bloco abaixo no fim de um arquivo temporário ou execute em um REPL depois de importar triagem_baseline:

from triagem_baseline import executar

nominal = executar("none")
assert nominal["tamanhos"] == {"treino": 12, "validacao": 4, "teste": 8}
assert nominal["baseline"]["recall"] == 1.0
assert nominal["decisao"].startswith("NÃO USAR IA")

leakage = executar("leakage")
assert leakage["guardrails"]["atributos_disponiveis_na_decisao"] is False
assert "vazamento" in leakage["decisao"]

rotulo = executar("label-noise")
assert rotulo["baseline"] != nominal["baseline"]

amostra = executar("sampling-bias")
assert amostra["cobertura_teste"] == {"Norte": 4}
assert amostra["guardrails"]["qualidade_e_representatividade"] is False

print("4 cenários validados")

Esse teste demonstra detecção, não qualidade estatística. Um projeto real adicionaria testes de schema, duplicação, distribuição, estabilidade do rótulo, intervalos de incerteza e replay de incidentes.

14. Casos negativos obrigatórios

Além das três mutações, discuta como o sistema deveria agir quando:

  • temperatura está ausente porque o ativo não possui sensor;
  • o ERP está indisponível e não confirma criticidade;
  • uma OS pertence a outra unidade/tenant;
  • a descrição contém instrução maliciosa para o componente de IA;
  • o mesmo evento chega duas vezes;
  • o candidato demora além do timeout;
  • o supervisor contesta a sugestão;
  • a taxonomia de criticidade muda.

Resposta segura: validar, abster quando necessário, preservar a regra, não executar efeito sem autorização, registrar motivo e tornar a limitação visível.

15. Rubrica de competência

Pontue 0, 1 ou 2 em cada linha:

Critério 0 1 2
problema “usar IA” tarefa descrita usuário, decisão, instante, efeito e risco
baseline ausente conceitual executável, versionado e medido
hipótese vaga métrica sem limite valor, alvo, guardrails e prazo
dados arquivo sem contexto origem parcial população, amostra, rótulo, proveniência e privacidade
split aleatório por hábito divisão descrita divisão justificada pela generalização
leakage ignorado citado mutação detectada e bloqueada
representatividade média apenas um corte segmentos, ausência e cauda crítica
decisão preferência resultado isolado gate prévio e alternativa “não usar IA”
reprodutibilidade relato oral comando parcial ambiente limpo, comandos, saída e limitações
transferência copia o caso muda nomes aplica o método a outro domínio e justifica escolhas

Aceite mínimo: 16/20, sem zero em baseline, dados, leakage ou decisão. A pontuação não substitui revisão por outra pessoa.

16. Evidência a entregar

Entregue um pacote contendo:

  1. triagem_baseline.py exatamente executável;
  2. as quatro saídas JSON (none, leakage, label-noise, sampling-bias);
  3. contrato da decisão;
  4. ficha do dataset;
  5. tabela de disponibilidade dos atributos;
  6. matriz de decisão;
  7. DECISAO.md com conclusão e validade;
  8. uma revisão independente reproduzindo os comandos;
  9. um exemplo de transferência para outro problema.

“Li o capítulo” ou “cliquei em concluído” não é evidência de competência.

17. Troubleshooting

python não é reconhecido

Confirme a instalação com python --version ou tente py --version no Windows. Registre a versão usada. Não instale pacotes: o laboratório usa apenas biblioteca padrão.

A saída não coincide

Confirme que o arquivo foi copiado integralmente e que nenhum caso foi alterado. Execute primeiro sem mutação. Compare tamanhos das partições antes das métricas.

Acentos aparecem incorretos

Salve o arquivo em UTF-8 e use terminal com suporte a Unicode. O cálculo não depende dos acentos, mas a evidência precisa ser legível.

A métrica perfeita parece suspeita

Correto. Investigue dataset pequeno, regra de geração, duplicatas, leakage e facilidade do cenário. O laboratório foi desenhado para que a regra resolva o holdout; ele ensina que resultado perfeito não autoriza generalização.

O candidato com leakage parece bom

Esse é o objetivo da mutação. Métrica não supera invalidade causal. Bloqueie o campo futuro e invalide o experimento.

18. Exercícios de transferência

Exercício A — mude o futuro que o split representa

O objetivo agora é avaliar uma unidade nova, não um mês futuro. Redesenhe a divisão para manter a unidade Sul inteira fora de treino e validação. Antes de executar, escreva o que espera observar e por que um corte temporal já não responde à pergunta. Entregue a função de split, contagem por partição e uma verificação que impeça a mesma unidade de aparecer nos dois lados.

Exercício B — baseline de busca para suporte

Transfira o método para um assistente que sugere respostas a chamados. Use busca por palavras-chave e templates como baseline. Defina usuário, decisão, rótulo, amostra, holdout, um vazamento possível, dois guardrails e a condição de não usar geração por modelo. A evidência é um DECISAO.md preenchido e pelo menos 20 casos reproduzíveis.

Exercício C — projete um caso em que IA merece shadow mode

Altere somente quatro casos sintéticos de modo que a regra perca um padrão textual legítimo, disponível na abertura, e o candidato o recupere sem ultrapassar o limite de falsos positivos. Não use horas_parada_final nem consulte o teste durante o ajuste. Entregue a mutação, as métricas antes/depois e explique por que o resultado autoriza apenas shadow mode, não automação.

Exercício D — privacidade por minimização

Imagine que descrições reais contenham nome, telefone e localização precisa. Crie um inventário de campos com finalidade, necessidade, acesso, retenção e descarte. Remova um campo que parecia útil e demonstre se a métrica muda. A evidência é a comparação e uma decisão explícita sobre o custo de privacidade, não apenas texto de política.

19. Recuperação ativa

Sem olhar o código:

  1. Qual decisão o laboratório apoia e qual efeito permanece proibido?
  2. Por que julho é teste e não treino?
  3. O que torna horas_parada_final um vazamento?
  4. Por que inverter dois rótulos muda a avaliação sem mudar o sistema?
  5. Por que quatro casos da unidade Norte não representam Norte e Sul?
  6. Qual gate faz o baseline vencer?
  7. Quando seria justificável iniciar shadow mode?
  8. Como provar que um campo existia no instante da decisão?
  9. Quais artefatos devem ser invalidados após descobrir leakage?
  10. Por que “não usar IA” é um resultado positivo deste trabalho?

Conclusão

Engenharia de IA começa com uma prova capaz de dizer “não”. Neste caderno, o baseline curto atende ao gate e o candidato não acrescenta ganho material; por isso, a decisão é manter a regra. As mutações mostram por que um número alto pode mentir: um campo futuro cria leakage, um rótulo ruim muda a prova e uma amostra incompleta esconde a população.

O pacote final — contrato, dataset documentado, split justificado, execução, mutações e decisão — é mais valioso que uma demonstração. Ele preserva conhecimento para a próxima equipe, torna a recusa auditável e permite acrescentar complexidade somente quando a evidência exigir.

Fontes primárias e oficiais

Relações

Use este caderno antes dos livros de modelos, RAG e agentes. Conecte-o depois a avaliação estatística, segurança, observabilidade, MLOps e UX de supervisão. A mesma disciplina vale para um assistente generativo: busca simples e templates formam o baseline; o conjunto de casos e guardrails substitui “pareceu bom”; e ausência de ganho continua sendo razão suficiente para não adicionar IA.

Teste de fixação

Comprove o que você aprendeu

Responda todas as questões. O gabarito comentado só aparece depois do envio.

1. Como testar o candidato de triagem antes de permitir que ele altere a fila real de ordens?
2. Qual resultado deve bloquear a adoção do classificador mesmo que sua média global melhore?
3. Após o canário, surgem erros críticos concentrados. Qual retirada foi prevista no caderno?

Consulta universal

O que você quer encontrar?

Títulos, capítulos, conceitos, termos, laboratórios e ferramentas em uma única busca.

Digite pelo menos dois caracteres.