Como usar o Jev para classificar a severidade de um alerta e decidir se acorda o on-call?

Fluxograma mostrando o Jev TypeSafe classificando severidade de um alerta antes de acionar o on-call
Resposta rápida

O Jev TypeSafe é um modelo System One da TypeSafe AI: em vez de texto, ele devolve decisão tipada com probabilidade e confidence. Para triagem de alerta isso muda tudo, porque você monta um state com log, métrica e serviço afetado e recebe severidade (Score), rota de notificação (Choice) e um sim/não de degradação real (Noul) num único request. A latência reportada fica entre 70 e 500 ms e o preço é US$ 0,042 por 1 milhão de tokens de entrada, com US$ 0,00 na saída. O confidence vira limiar explícito no código: caso incerto escala para humano, nunca vira silêncio

3h47 da manhã, o alerta dispara

E existe só uma pergunta que importa nesse momento: isso acorda alguém ou espera o horário comercial?

Essa decisão é binária, acontece centenas de vezes por semana e quase nunca merece um parágrafo de reflexão de um LLM. O que ela merece é um veredito tipado, rápido, com um número de confiança do lado pra tu decidir se confia ou se escala

É exatamente aí que entra o Jev, o primeiro modelo da classe "System One" da TypeSafe AI. Ele não gera texto, ele devolve decisão estruturada que teu código consome direto 🙂

Por que a decisão de severidade precisa ser rápida (e tipada)

Triagem de alerta é o caso clássico de decisão System One: volume alto, deliberação baixa, resposta em milissegundos

Se você conhece a diferença entre "pensar rápido" e "pensar devagar", é mais ou menos isso. Escrever o post mortem do incidente é System Two, precisa de raciocínio longo. Decidir se o alerta é P1 ou P3 é reflexo, e reflexo com 4 segundos de latência e JSON quebrado não serve pra caminho crítico

O Jev abre mão da geração de string justamente por isso. A saída é estruturada por construção, ou seja, ele não consegue devolver um valor fora do schema que você definiu. A TypeSafe reporta 0% de taxa de erro de structured output e 0% de erro de tool call

E o que significa isso na prática? Significa que tu pode tirar do pipeline aquele bloco de try/except que existe só pra tratar o dia em que o modelo resolveu responder "Claro! Aqui está a classificação:" antes do JSON 😛

Tem também referência de fora da casa. Um benchmark de classificação publicado pela LiteLLM comparou Jev e Claude Haiku na mesma tarefa: o Jev classificou 5,43x mais rápido (mediana de 126,81 ms contra 688,40 ms), acertou o tier esperado em 95,00% das chamadas contra 73,75% do Haiku, com custo 96,12% menor

Número de benchmark não é promessa pro teu dado, mas dá a ordem de grandeza do que dá pra colocar no meio de um pipeline de alerta sem culpa

O que você precisa antes de começar

Pouca coisa, e essa é a graça

  • Conta na TypeSafe: o cadastro é em console.typesafe.ai. A waitlist do lançamento foi removida, o acesso está aberto pra qualquer pessoa e conta nova recebe US$ 5 de crédito gratuito
  • Um jeito de chamar o modelo: existem SDKs oficiais de Python e JavaScript, e existe a API HTTP pura. Todos os modelos System One são servidos pelo mesmo endpoint, POST /v1/systemone
  • O identificador do modelo: o default dos exemplos e do SDK é o alias jev-latest, e a versão corrente é a 1.13. Se você quer pinar a versão, o campo model aceita IDs versionados como jev-1.13.0

Duas notas que salvam tempo depois

O Jev tem dois limites de contexto rodando ao mesmo tempo: 64k tokens pro estado somado a TODAS as perguntas, e 32k tokens pro estado somado à pergunta mais longa. Guarda esse 32k, ele vai voltar no passo 1

E o inglês é a língua principal de treino dos modelos Jev, onde a acurácia é melhor atualmente. O teu log já é em inglês de qualquer jeito, então escreve as instruções e os níveis em inglês também, mesmo que o resto do sistema seja em português

Passo a passo: do alerta bruto à decisão de acordar o on-call

O desenho é simples: um state (o alerta), três perguntas de tipos diferentes, um request só

  1. Montar o state com log, métrica e serviço afetado

O estado aceito pelo Jev não precisa ser texto puro: pode ser uma string, um objeto JSON ou um array de texto. Pra alerta, JSON é o formato natural, porque tu já tem os campos separados

state = {
    "service": "checkout-api",
    "environment": "production",
    "alert": "HTTP 5xx rate above threshold",
    "metrics": {
        "error_rate": taxa_de_erro_atual,
        "baseline_error_rate": taxa_de_erro_normal,
        "p95_latency_ms": 2380,
        "window": "last 5 minutes",
    },
    "recent_logs": [
        "upstream connect error: connection timeout to payments-gateway",
        "circuit breaker open for payments-gateway",
        "retry budget exhausted",
    ],
    "recent_deploys": ["checkout-api v2.31.0 deployed 9 minutes ago"],
}

O erro comum deste passo: jogar dez mil linhas de log cruas dentro do state. Além de estourar o teto de 32k de state mais a pergunta mais longa, tu afoga o sinal no ruído. Manda amostra deduplicada, a métrica com o baseline do lado e o deploy recente. Baseline importa: taxa de erro alta só diz alguma coisa quando o modelo sabe qual é o normal daquele serviço

  1. Instanciar o cliente

O cliente Python é instanciado sem parâmetros obrigatórios

from typesafe_sdk import Choice, Noul, Score, TypeSafeClient

client = TypeSafeClient()
  1. Escrever a pergunta de severidade com Score

Severidade é escala ordenada, então a primitiva é o Score. O mínimo é 2 níveis e a API aceita até 10

severity = Score(
    instructions="How severe is this production alert for end users right now?",
    criteria={
        "1": "Informational. No user impact, no action needed.",
        "2": "Low. Internal noise or single-instance blip, self-healing.",
        "3": "Medium. Degraded experience for a subset of users, can wait for business hours.",
        "4": "High. Core user flow broken or error budget burning fast.",
        "5": "Critical. Full outage or revenue-blocking failure in production.",
    },
)

O erro comum deste passo: usar níveis genéricos, tipo "baixo, médio, alto", sem descrever o que cada um significa no TEU sistema. A escala é descritiva de propósito. Quanto mais específico o nível, mais calibrada fica a probabilidade

  1. Adicionar o Choice da rota de notificação

Rota não é escala, é conjunto. Logo, Choice, que aceita até 255 opções

route = Choice(
    instructions="Which notification route should this alert take?",
    criteria={
        "page_oncall_now": "Wake up the on-call engineer immediately.",
        "slack_urgent": "Post to the incident channel with an urgent tag.",
        "slack_backlog": "Post to the team channel for business hours triage.",
        "suppress": "Known noise, no notification.",
    },
)

O erro comum deste passo: misturar severidade e rota numa pergunta só, criando aquele monstro "P1 e acorda o on-call". Separa. Severidade é sobre o mundo, rota é sobre a tua política de plantão, e as duas mudam por motivos diferentes

  1. Adicionar um Noul pra pergunta de sim ou não

Noul devolve um único número entre 0 e 1 com a probabilidade de "sim". Não existe campo de confidence separado aqui, porque a distribuição tem só dois resultados: o próprio número já é a distribuição inteira

real_impact = Noul(
    instructions="Does this alert indicate real, user-visible degradation "
                 "(as opposed to a synthetic probe, a test deploy or a known flaky check)?",
)
  1. Disparar tudo num único request

Cada requisição é um state mais uma ou mais perguntas, e elas podem misturar os três tipos. Todas veem o mesmo state e são avaliadas de forma independente, em paralelo, num único passe

questions = {
    "severity": severity,
    "route": route,
    "real_impact": real_impact,
}

O state e esse dicionário de perguntas vão juntos na mesma chamada do cliente, como no quickstart da TypeSafe, e a resposta volta indexada pelo nome que tu deu pra cada pergunta

O erro comum deste passo: quebrar em três requests "pra ficar organizado". Além de triplicar o token de entrada (o state vai junto toda vez), tu perde a garantia de que as três respostas olharam exatamente o mesmo estado do mundo

  1. Ler o resultado

O retorno vem indexado pelo nome que você deu na pergunta

rota = response.choices["route"].choice
conf_rota = response.choices["route"].confidence

No Choice tu tem a opção de maior probabilidade, a probabilidade de cada opção (floats que somam 1) e o confidence. No Score, o score, a probabilidade de cada nível e o confidence. No Noul, o número de 0 a 1 e pronto

Aqui vale um conselho: loga a distribuição inteira, não só a opção vencedora. Quando o classificador errar feio às 4h da manhã, a distribuição é o que vai te contar se ele estava em dúvida entre P1 e P2 ou se ele decidiu convicto na opção errada

Como usar o confidence para escalar em vez de silenciar

Essa é a parte que separa um classificador de alerta bom de um gerador de ruído automatizado

O confidence é um valor de 0 a 1 presente no Choice e no Score, e ele não é o modelo se auto avaliando. É estatística derivada da própria distribuição de probabilidade da resposta: probabilidade concentrada numa opção significa confidence alta, probabilidade espalhada entre várias significa baixa

A documentação recomenda três faixas como ponto de partida:

  • Alta: agir automaticamente
  • Média: agir com cautela, pedindo confirmação, marcando pra revisão ou buscando mais informação
  • Baixa: não agir sozinho, e sim rotear pra humano, pedir esclarecimento ou cair em outro sistema

E tem o padrão de confidence-gated routing, que usa limiar DIFERENTE por ação, conforme o risco. O exemplo da doc é de atendimento: piso de 0,6 pra qualquer ação, ação de baixo risco (consultar saldo) passa com 0,6, ação de alto risco (aprovar transferência) exige acima de 0,85, e abaixo do piso vai pra humano

Traduzindo pro on-call:

PISO = 0.6
ALTO_RISCO = 0.85

if conf_rota < PISO:
    escalar_para_humano(alerta, motivo="baixa confianca na rota")
elif rota == "suppress":
    # silenciar e alto risco: so com confianca alta
    if conf_rota > ALTO_RISCO and conf_sev > ALTO_RISCO and severidade <= 2:
        suprimir(alerta)
    else:
        notificar_canal_urgente(alerta)
elif rota == "page_oncall_now":
    if conf_rota > ALTO_RISCO:
        acordar_oncall(alerta)
    else:
        notificar_canal_urgente(alerta)
else:
    executar_rota(rota, alerta)

Repara no ponto central: suprimir é ação de alto risco, igual acordar alguém

Parece contraintuitivo, né? A intuição diz que silenciar é o "seguro", porque ninguém acorda à toa. Só que silenciar errado é o único erro que ninguém descobre até o cliente reclamar. Por isso a dúvida sempre sobe um degrau: da supressão pro canal urgente, do canal urgente pro humano de plantão decidir. Incerteza escala pra cima, nunca vira silêncio

A orientação da doc vai na mesma linha: o código deve tomar ações diferentes pra respostas confiantes e não confiantes, escalando o caso incerto pra uma pessoa ou pra um modelo de raciocínio mais caro

E os limiares? Não copia os meus, não copia os da doc. A recomendação é testar plotando confidence contra acurácia nos teus próprios dados, e é isso que define se o teu piso é 0,6 ou 0,72. O mesmo raciocínio de limiar aparece quando tu usa o modelo pra moderar conteúdo enviado por usuários, só que lá o caso duvidoso vai pra fila de revisão em vez de ir pro pager

Outros usos do Jev no seu pipeline de observabilidade

Uma vez que o state do alerta já está montado, dá pra reaproveitar ele pra um monte de decisão

  • Deduplicar alerta repetido: Noul, com o state trazendo o alerta novo e o incidente aberto. A pergunta é "esse alerta é a mesma falha do incidente em andamento?" e a saída de 0 a 1 vira o teu limiar de agrupamento
  • Decidir se o log pede rollback ou investigação: Choice, com opções tipo rollback imediato, feature flag off, escalar pro time dono e investigar sem agir. Conjunto fechado, cada opção com descrição clara
  • Priorizar fila de incidente: Score, pela mesma razão que severidade é Score. Ordenar é escala, e é a mesma mecânica de priorizar leads no funil, trocando lead por incidente aberto
  • Decidir se o erro vira ticket ou é ruído conhecido: Noul pro corte binário, ou Choice se tu quer separar em ticket, backlog e ruído conhecido

A regra pra escolher é a mesma sempre: conjunto fechado é Choice, escala ordenada é Score, sim ou não é Noul

Choice, Score e Noul: qual primitiva usar em cada decisão de alerta

Primitiva O que retorna Limites Tem confidence? Pergunta típica de triagem
Choice Opção de maior probabilidade, probabilidade de cada opção (somam 1) e confidence Máximo de 255 opções Sim "Qual rota de notificação esse alerta deve seguir?"
Score O score, a probabilidade de cada nível e confidence Mínimo de 2 níveis, a API aceita até 10 Sim "Qual a severidade desse alerta pro usuário final?"
Noul Um único número entre 0 e 1 com a probabilidade de "sim" Saída binária Não, porque a distribuição tem só dois resultados "Isso é degradação real e visível pro usuário?"

Custo, latência e onde rodar o Jev

O modelo de cobrança do Jev é curioso e cai bem pra esse caso de uso: paga só o token de ENTRADA

São US$ 0,042 por 1 milhão de tokens de entrada e US$ 0,00 por 1 milhão de tokens de saída. Faz sentido, já que não existe geração de string pra cobrar

Pra um pipeline de observabilidade isso muda a conta de cabeça. O teu custo passa a ser função de quanto contexto tu manda por alerta, e não de quantas perguntas tu faz sobre ele. Como as perguntas do mesmo request compartilham o mesmo state, adicionar uma quarta ou quinta pergunta sai muito mais barato que abrir um request novo

Na latência, o reportado de ponta a ponta fica entre 70 e 500 ms por chamada. Isso é o que permite colocar o classificador no caminho crítico do alerta, antes do roteamento, em vez de rodar depois como enriquecimento

E dá pra chamar o Jev fora da API da TypeSafe também. Ele está disponível no Cloudflare Workers AI com o model typesafe/jev, e no Vercel AI Gateway com o id typesafe-ai/jev. Se o teu receiver de webhook já vive num Worker ou numa function da Vercel, tu economiza um hop de rede

Conclusão

O ponto todo aqui não é "a IA decide se acorda o on-call"

O ponto é que a decisão vira um valor tipado, com probabilidade e confidence, e o LIMIAR fica explícito no teu código, versionado, revisável em pull request. A política de plantão para de morar na cabeça de quem configurou o alerta em 2023 e passa a ser código que dá pra discutir

O próximo passo eu sugeriria assim: roda o classificador em modo sombra primeiro

Pega os alertas dos últimos meses, passa todos pelo Jev sem notificar ninguém, e compara a saída com o que o time realmente decidiu na época. Onde o modelo teria acordado alguém à toa? Onde ele teria suprimido algo que virou incidente? Plota o confidence contra o acerto e só então escolhe o piso e o teto de verdade

Depois disso tu liga o paging automático, e aí sim dá pra dormir tranquilo 😀

Tome cuidado com a tentação de ligar direto em produção porque o benchmark é bonito. Alerta é o tipo de sistema em que a confiança do time vale mais que a acurácia do modelo, e confiança se constrói com sombra e calibração

Até o próximo post!

Perguntas frequentes

Quanto custa classificar um alerta com o Jev em produção?

O Jev cobra só pela entrada: US$ 0,042 por 1 milhão de tokens. A saída sai a US$ 0,00 por 1 milhão de tokens, já que o modelo não gera texto solto, só a decisão estruturada. Pra um state de alerta com poucas linhas de log e três perguntas, o custo por chamada fica bem próximo de zero.

O Jev entende alerta escrito em português ou preciso mandar tudo em inglês?

O inglês é a língua principal de treino dos modelos Jev, e é onde a acurácia é melhor hoje. Por isso vale escrever as instructions e os criteria do Score e do Choice em inglês, mesmo que o resto do teu sistema esteja em português. Como logs de produção normalmente já saem em inglês, isso na prática não muda muita coisa no pipeline.

Qual confidence é seguro pra deixar o Jev acordar o on-call sem revisão humana?

A documentação recomenda pensar em três faixas: confidence alta age automático, média age com cautela (confirmação ou revisão) e baixa não age sozinha. O exemplo oficial usa um piso de 0,6 pra qualquer ação e exige acima de 0,85 pra ação de alto risco, caindo pra confirmação abaixo disso. Como acordar alguém às 3h é ação de alto risco, faz sentido usar um piso parecido e testar o limiar plotando confidence contra acurácia nos teus próprios dados antes de confiar cego.

Qual a diferença entre usar Score e Noul pra decidir se o alerta acorda o on-call?

Score serve pra escala ordenada e descritiva, por isso é a primitiva certa pra nível de severidade (de 1 a 5, por exemplo). Noul devolve um único número entre 0 e 1 representando a probabilidade de sim, sem campo de confidence separado, porque só tem dois resultados possíveis. Dá pra usar as duas juntas no mesmo request: Score classifica a severidade e Noul responde direto a pergunta binária ‘isso acorda alguém agora’.

Dá pra rodar o Jev fora da API da TypeSafe, tipo direto na Vercel?

Sim. O Jev também está disponível no Cloudflare Workers AI com o identificador ‘typesafe/jev’ e no Vercel AI Gateway com o id ‘typesafe-ai/jev’. A Vercel inclusive anunciou oficialmente a disponibilidade do Jev no AI Gateway, então quem já usa esse gateway não precisa trocar de infraestrutura pra testar.

Ainda existe lista de espera pra usar o Jev?

Não. O Jev foi lançado em early access com waitlist em 15/09/2026, mas essa lista foi removida e o acesso está aberto pra qualquer pessoa. Basta se cadastrar em console.typesafe.ai, e conta nova já recebe US$ 5 de crédito gratuito pra começar a testar.



Escrito por | Matheus Battisti

Matheus Battisti
Fundador da Hora de Codar

Programador apaixonado pelo mundo das tecnologias, sempre buscando em aprender e se aprofundar em linguagens, frameworks e o que mais for necessário para executar um bom trabalho. Agora tem uma nova missão que é de passar seu conhecimento adiante para formar novos programadores e especializar mais os que já são.

Subscribe
Notify of
guest

0 Comentários
Oldest
Newest Most Voted

Formações

Formação Claude Code

Formação Claude Code

Domine Claude Code do absoluto zero até o avançado

  • 120 aulas
  • 4 projetos
  • 9h 48min

Blog | Mais populares