Como usar o Jev para escolher qual ação de remediação rodar quando um serviço cai?

diagrama mostrando o Jev escolhendo uma ação de remediação quando um serviço cai
Resposta rápida

O Jev é o modelo System One da TypeSafe AI: você manda um state e perguntas tipadas, ele devolve resposta tipada com probabilidades e confiança, sem gerar texto livre. Para remediação, cada runbook conhecido vira uma opção de um Choice (até 255 opções, mais uma de escape), e métricas, logs e estado do deploy entram como state em JSON. A resposta traz a opção escolhida, a distribuição de probabilidades e um confidence de 0 a 1. É esse confidence que separa o que roda sozinho do que para na aprovação humana, com piso sugerido de 0.6.

Fala aí, beleza? Três da manhã, o alerta dispara, o serviço tá fora e existem cinco runbooks possíveis na sua wiki

Restart do pod, rollback do último deploy, escalar réplicas, drenar a fila, ou simplesmente esperar porque é o provedor que tá com problema

Quem decide isso hoje é o plantonista, no olho, com sono, lendo três dashboards ao mesmo tempo 😅

O Jev entra exatamente aí, e ele NÃO é um chatbot que escreve um textão dizendo o que você deveria fazer

Ele é o modelo System One da TypeSafe AI: recebe um state mais perguntas tipadas e devolve respostas tipadas, com probabilidade de cada opção e um número de confiança

Ou seja: modelo de decisão tipada, não de geração de texto

Isso muda tudo pra automação de incidente, porque uma decisão tipada você consegue colocar dentro de um if sem parser, sem regex, sem rezar pro JSON vir bem formado

Bora montar isso na prática?

O que você precisa antes de começar

Antes do código, o de sempre: acesso, chave e ambiente

  • Conta com chave de API da TypeSafe. Aqui tem um detalhe importante de estado atual: a TypeSafe abriu cadastro direto pra todo mundo em 20/09/2026, com US$ 5 de crédito, e pausou novos cadastros no console.typesafe.ai em 22/09/2026. Quem já tem conta segue funcionando normal, e eles disseram que trabalham pra reabrir. Até hoje (24/09/2026) não saiu anúncio de reabertura, então se você não pegou a janela, fica de olho
  • Node 20 ou mais novo, se for pelo SDK JavaScript: npm install @typesafe-ai/sdk. Ele lê a chave da variável de ambiente TYPESAFE_API_KEY e chama jev-latest por padrão
  • Ou nada disso, e você bate direto no endpoint: POST https://api.typesafe.ai/v1/systemone, com header Authorization: Bearer e Content-Type: application/json. É isso, é uma requisição HTTP comum
Curso de Jev: Sistemas Mais Inteligentes, Rápidos e Robustos
Curso Recomendado

Curso de Jev: Sistemas Mais Inteligentes, Rápidos e Robustos

Desenvolva sistemas mais inteligentes, rápidos e robustos com Jev

Tem ainda a agent skill oficial, que empacota o contexto da API (as três primitivas, padrões e boas práticas) pro seu agente não chutar a forma do payload

No Claude Code:

claude plugin marketplace add typesafe-ai/skills
claude plugin install typesafe@typesafe-ai

Em outros agentes:

npx skills add typesafe-ai/skills --skill typesafe-ai

Repara que o identificador muda de um comando pro outro, e isso confunde geral: no Claude Code você instala o plugin typesafe vindo do marketplace typesafe-ai, nos outros agentes você pede a skill typesafe-ai de dentro do repo typesafe-ai/skills

É o mesmo conteúdo, só muda o nome que cada produto usa pra se referir a ele, então copie o comando do SEU produto e não tente adaptar o do outro

E se você precisa de rota alternativa: o typesafe/jev-1.13 e o jev-latest estão listados na OpenRouter, e lá dentro tem um provedor só servindo esses modelos, a própria TypeSafe

Fora da OpenRouter, o Jev também aparece no catálogo de modelos da Cloudflare AI, que é outra porta de entrada

Sobre custo, é curioso: o Jev cobra só por token de entrada, US$ 0,042 por 1 milhão de tokens de input, e output custa US$ 0,00

Faz sentido quando você lembra que a saída dele é uma opção e alguns floats, não um textão 🙂

Passo a passo: da lista de runbooks à decisão de remediação

A ideia central é simples: o seu runbook vira opção, o seu monitoring vira state

1. Transforme cada runbook conhecido em uma opção

A primitiva aqui é o Choice: escolhe uma opção de um conjunto

Um Choice aceita até 255 opções, o que é MUITO mais do que qualquer wiki de runbook saudável tem, então espaço não é o seu problema

O que importa é a descrição de cada opção ser específica e não pisar na descrição da vizinha

{
  "restart_service": "Reiniciar as instâncias do serviço. Use quando o processo está vivo mas travado, sem relação com deploy recente",
  "rollback_deploy": "Voltar para a versão anterior. Use quando a falha começou depois de um deploy nas últimas horas",
  "scale_replicas": "Aumentar o número de réplicas. Use quando há saturação de CPU ou memória com tráfego acima do normal",
  "drain_queue": "Drenar a fila de mensagens acumuladas. Use quando o backlog da fila é a causa da lentidão",
  "upstream_wait": "Nenhuma ação local. Use quando a falha vem de dependência externa fora do seu controle",
  "none_of_the_above": "Nenhuma das opções acima descreve a situação"
}

Repara nessa última: a doc recomenda incluir uma opção de escape tipo other ou none of the above sempre que a lista pode não cobrir todo input

Incidente é o exemplo perfeito de lista que não cobre tudo, porque sempre aparece um jeito novo de quebrar

O erro comum deste passo: descrições sobrepostas. Se "restart" e "rollback" ambos dizem "use quando o serviço não responde", você não deu ao modelo o que diferencia uma da outra, e a probabilidade vai se espalhar entre as duas. Se quiser ver a dinâmica de escolha entre opções em um cenário mais visual, tem esse post sobre a demo de navegação do Jev

2. Monte o state com métrica, log e estado do deploy

O state pode ser texto simples ou dado estruturado (objeto ou array), tipo o estado atual da sua aplicação

Pra incidente, estruturado é bem melhor, porque você consegue apontar a pergunta pra um pedaço específico depois

{
  "service": "checkout-api",
  "alert": {
    "name": "HighErrorRate",
    "fired_at": "2026-09-24T03:12:00Z"
  },
  "metrics": {
    "error_rate_pct": 47.2,
    "p99_latency_ms": 8300,
    "cpu_pct": 31,
    "memory_pct": 62,
    "queue_backlog": 12
  },
  "deploy": {
    "last_deploy_minutes_ago": 18,
    "version": "2026.09.24-a1",
    "changed_services": ["checkout-api"]
  },
  "logs": [
    "ERROR payment_gateway: connection reset by peer",
    "ERROR payment_gateway: connection reset by peer",
    "WARN retry budget exhausted for payment_gateway"
  ]
}

Repara que eu já mandei error_rate_pct e queue_backlog calculados

Isso não é preguiça de formatar, é regra: a doc do jev-1.13 diz explicitamente que o modelo não conta de forma confiável e que o erro cresce com o tamanho do que se conta

Então a conta fica no seu código, e pro modelo vai o resultado

O erro comum deste passo: despejar 4 mil linhas de log cru achando que "mais contexto é melhor". A acurácia do jev-1.13 cai quando o state cresce com conteúdo irrelevante pra decisão, e ainda tem o orçamento de contexto: a doc fala em 64k cobrindo o state mais todas as perguntas somadas, e 32k pro state mais a pergunta mais longa. Mande a amostra que decide, não o arquivo inteiro

3. Escreva instructions e criteria sem contradição

Cada pergunta é um objeto com type, instructions e criteria

E aqui tem uma limitação documentada que muda a forma de escrever: o Jev lê a pergunta ao pé da letra. Escopo, negação e condição implícita são lidos literalmente

Então nada de "escolha a ação, exceto se não for o caso de não reiniciar" kkk

Frase direta, afirmativa, um objetivo só

A doc também orienta apontar a pergunta pra um valor específico do state usando caminho com pontos e índices entre crases, tipo metrics.error_rate_pct ou logs[0]

O erro comum deste passo: instruction dizendo uma coisa e criteria dizendo outra. Se a instruction fala "priorize a ação menos arriscada" e a descrição do rollback fala "use sempre que houver deploy recente", você criou um conflito, e critérios contraditórios confundem o modelo

4. Monte o body e dispare

O corpo tem três campos no topo: state, model e questions

curl -X POST https://api.typesafe.ai/v1/systemone \
  -H "Authorization: Bearer $TYPESAFE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "state": { "service": "checkout-api", "metrics": { "error_rate_pct": 47.2 } },
    "model": "jev-latest",
    "questions": {
      "runbook": {
        "type": "choice",
        "instructions": "Escolha a ação de remediação mais adequada para o incidente descrito em `state`, considerando `metrics`, `deploy` e `logs`",
        "criteria": {
          "restart_service": "Reiniciar as instâncias do serviço. Use quando o processo está vivo mas travado, sem relação com deploy recente",
          "rollback_deploy": "Voltar para a versão anterior. Use quando a falha começou depois de um deploy nas últimas horas",
          "scale_replicas": "Aumentar o número de réplicas. Use quando há saturação de CPU ou memória com tráfego acima do normal",
          "drain_queue": "Drenar a fila de mensagens acumuladas. Use quando o backlog da fila é a causa da lentidão",
          "upstream_wait": "Nenhuma ação local. Use quando a falha vem de dependência externa fora do seu controle",
          "none_of_the_above": "Nenhuma das opções acima descreve a situação"
        }
      }
    }
  }'

O model aceita jev-latest (o padrão do SDK e dos exemplos da doc) ou IDs versionados tipo jev-1.13.0

Se você quer previsibilidade em produção, versionado é o caminho, porque aí o comportamento não muda debaixo de você numa madrugada de plantão

5. Leia a opção, a distribuição e o confidence

A resposta de um Choice traz três coisas: a opção escolhida, a probabilidade de cada opção (floats que somam 1) e um confidence entre 0 e 1 derivado dessa distribuição

E a resposta vem uma por pergunta, na mesma chave que você definiu lá no mapa questions

const res = await fetch("https://api.typesafe.ai/v1/systemone", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.TYPESAFE_API_KEY}`,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({ state, model: "jev-1.13.0", questions })
})

const resultado = await res.json()
const decisao = resultado["runbook"] // confira o formato exato da resposta na doc da API

console.log(decisao.confidence)

O detalhe que muita gente ignora: a distribuição é tão útil quanto a opção vencedora

Um caso em que rollback_deploy ganhou com margem folgada é muito diferente de um caso em que rollback e restart ficaram empatados tecnicamente

No segundo, a decisão é "o modelo não sabe", e é isso que o confidence vai te dizer

Como combinar várias perguntas numa requisição só

O campo questions é um mapa, e a doc mostra que dá pra fazer perguntas diferentes (inclusive de primitivas diferentes) numa única requisição

Pra remediação isso é ouro, porque "qual ação" sozinha não basta

1. Pergunte qual runbook (Choice)

É a pergunta que você já montou ali em cima, com as opções e a de escape

2. Pergunte a gravidade (Score)

O Score dá uma nota numa rubrica de níveis ordenados, com mínimo de 2 e máximo de 10 níveis

Quatro níveis costumam resolver bem a vida de um pipeline de incidente:

"severidade": {
  "type": "score",
  "instructions": "Classifique a gravidade do impacto no usuário final com base em `metrics` e `alert`",
  "criteria": {
    "baixa": "Degradação sem impacto perceptível para o usuário",
    "media": "Parte das requisições falha, existe caminho alternativo",
    "alta": "Funcionalidade principal indisponível para boa parte dos usuários",
    "critica": "Serviço totalmente indisponível ou com risco de perda de dados"
  }
}

3. Pergunte se a evidência basta (Noul)

O Noul é sim/não numa escala de 0 a 1

Perfeito pra uma pergunta de porteiro:

"evidencia_suficiente": {
  "type": "noul",
  "instructions": "A evidência em `logs` e `metrics` é suficiente para identificar a causa da falha?",
  "criteria": {
    "sim": "Os dados apontam uma causa provável de forma consistente",
    "nao": "Os dados são insuficientes ou contraditórios"
  }
}

4. Cruze as três antes de encostar em qualquer botão

A lógica de cruzamento fica no SEU código, não no prompt:

const acao = resultado["runbook"]
const sev = resultado["severidade"]
const evidencia = resultado["evidencia_suficiente"]

const podeAgirSozinho =
  acao.confidence >= 0.8 &&
  evidencia.confidence >= 0.8 &&
  acoesAutomaticas.includes(acao.answer)

O erro comum deste bloco: empurrar o state inteiro pra todas as perguntas. A doc orienta dar a cada pergunta só o contexto de que ela precisa e manter junto o que precisa ser comparado. A pergunta de gravidade não precisa do histórico de deploy, por exemplo

Roteamento por confiança: quais ações rodam sozinhas e quais param na aprovação humana

Agora o ponto sensível, e é aqui que a maioria das automações de remediação se estrepa

A TypeSafe documenta esse padrão de forma bem seca: a resposta diz o quê, a confiança diz se pode agir sozinho

Caso incerto vai pra uma pessoa ou pra um modelo de raciocínio mais caro

O exemplo da própria doc é literalmente isso:

if (answer.confidence < 0.8) {
  await enviarParaPlantonista(answer)
} else {
  await handlerAutomatico(answer)
}

E tem duas orientações que valem mais que o snippet

A primeira é o piso: a doc sugere 0.6 como piso pra pegar o que o modelo está genuinamente incerto

Abaixo disso, nem discute, é humano

A segunda é que acima do piso, cada tipo de ação tem seu próprio limiar, conforme a consequência de errar

E é MUITO diferente errar um restart e errar um rollback de banco, né?

Ação Reversível? Custo de errar Quem decide
Restart do serviço sim, em segundos baixo pode ser automática
Escalar réplicas sim baixo, custa dinheiro pode ser automática
Drenar fila parcialmente médio automática com limiar alto
Rollback de deploy sim, mas mexe em tráfego real médio a alto confirmação humana
Rollback de banco não altíssimo sempre humano, sem exceção

Repara na última linha: ação destrutiva e irreversível não entra na régua de confiança

Não existe confidence alto o bastante pra restaurar um banco sozinho às 3 da manhã, e isso não é medo da IA, é a mesma regra que você já aplica pros rm -rf da vida

A sua lista de ações automáticas é uma allowlist explícita no código, nunca "tudo que o modelo escolher"

O erro comum aqui: usar um único limiar global pra tudo. Se você põe 0.8 e aplica pra restart e pra rollback, ou você está frouxo demais no rollback ou rígido demais no restart

O segundo erro comum: nunca validar o limiar. A doc recomenda testar plotando confiança contra acurácia nos seus próprios dados, e é isso que transforma o número de chute em decisão de engenharia

Cenários de incidente em que esse padrão se encaixa bem

A TypeSafe lista, como caso de uso do modelo, priorizar alertas por risco, relevância e qualidade da evidência, e mandar caso ambíguo pra revisão humana

Traduzindo pro seu dia a dia:

  • Rajada de alerta: caem 40 alertas em dois minutos e metade é consequência do outro. Um Score de risco por alerta ordena a fila antes do humano abrir o dashboard
  • Qual serviço olhar primeiro: Choice entre os serviços envolvidos, com a descrição de cada um explicando quando ele é causa e quando é vítima
  • Rollback ou escalar réplicas: a clássica. Saturação com tráfego acima do normal puxa pra réplica, falha começando 18 minutos depois do deploy puxa pra rollback
  • Roteamento do caso ambíguo: quando a distribuição fica espalhada, o caso vai direto pro plantonista com a distribuição anexada, que já é um resumo do que o modelo considerou

E a latência ajuda: a TypeSafe reporta 70 ms a 500 ms ponta a ponta

Isso cabe dentro de um pipeline de alerta sem ninguém notar, o que não aconteceria se você mandasse tudo pra um modelo de raciocínio gerar um relatório

Se você ainda tá avaliando onde esse tipo de modelo encaixa melhor no seu produto, dá uma olhada nos casos de uso de automação com o Jev

Erros que derrubam a qualidade da decisão (e como prevenir)

A TypeSafe publica uma página de limitações conhecidas do jev-1.13, e quase todas mordem justamente em contexto de incidente

Contagem: o sintoma é a resposta que muda sozinha

Sintoma: você pergunta "quantos erros apareceram nos últimos 5 minutos" e o número vem errado, e o erro piora quanto mais linha tem

Causa: o modelo não conta de forma confiável, e o erro cresce com o tamanho do que se conta

Ajuste: aritmética no código. Conta você, e manda o resultado pronto no state, como error_count_5m: 143

Data: o sintoma é a ordem cronológica bagunçada

Sintoma: ele não percebe que o deploy veio ANTES do alerta

Causa: o Jev lê data como texto, não como quantidade ordenada

Ajuste: pré-calcule a relação no seu código e mande explícito, tipo last_deploy_minutes_ago: 18 em vez de dois timestamps pro modelo comparar

State inflado: o sintoma é a acurácia caindo conforme você "melhora" o contexto

Sintoma: você adiciona mais log pra ajudar e a decisão piora

Causa: a acurácia cai quando o state cresce com conteúdo irrelevante pra decisão

Ajuste: state enxuto e filtrado. Só o que participa da decisão entra, o resto fica no seu sistema de log mesmo

Negação e condição: o sintoma é o modelo fazendo o oposto do combinado

Sintoma: você escreveu uma regra com "exceto" e ele ignorou o exceto

Causa: escopo, negação e condição implícita são lidos literalmente

Ajuste: perguntas estreitas e afirmativas. Se precisa de condição, quebre em duas perguntas na mesma requisição, que é de graça em termos de round trip

Log hostil: o sintoma é a decisão estranha vinda de um input específico

Sintoma: um log com texto esquisito empurra a escolha pra um lado inesperado

Causa: o state é tratado como dado, não como hostil, então conteúdo adversarial pode mover a resposta

Ajuste: sanitize o que você coloca no state, principalmente log que carrega input de usuário. Trate log como entrada não confiável, do mesmo jeito que você trataria num parser

Critérios em conflito: o sintoma é a distribuição sempre espalhada

Sintoma: nenhuma opção ganha com folga, em nenhum incidente

Causa: instruções e critérios contraditórios confundem o modelo

Ajuste: releia a instruction junto de cada criteria, em voz alta. Se duas descrições servem pro mesmo cenário, funde ou diferencia

Próximo passo: comece com uma decisão só, em modo sombra

O caminho que eu sugeriria pra quem quer levar isso pra produção não é ligar automação no dia um

É rodar em modo sombra: a cada incidente, o Jev responde em paralelo, ninguém age em cima disso, e você guarda a opção escolhida, a distribuição e o confidence junto do que o plantonista realmente fez

Depois de um punhado de incidentes, você tem o dado pra fazer exatamente o que a doc recomenda: plotar confiança contra acurácia e descobrir onde fica o seu limiar de verdade

Aí sim você libera um runbook automático, o mais reversível da lista, geralmente o restart

Depois o segundo, e por aí vai

Rollback destrutivo continua com humano no meio, sempre, mesmo com confidence de 0.99

Sobre acesso: lembrando que os novos cadastros no console da TypeSafe estão pausados desde 22/09/2026, e as contas existentes seguem ativas

Se você já tem chave, a doc da API e a agent skill oficial são a melhor continuação, porque elas carregam os padrões atualizados direto pro seu agente

E se você montar esse fluxo aí no seu on-call, me conta como foi… tenho curiosidade de saber qual runbook você liberaria primeiro 😀

até o próximo post!

Perguntas frequentes

Qual limiar de confiança usar antes de rodar a remediação automática?

São dois números com papéis diferentes, e vale não misturar. O 0.6 é o piso que a doc sugere pra pegar o que o modelo está genuinamente incerto: abaixo disso, vai pra humano sem discussão. Acima do piso, cada tipo de ação tem seu próprio limiar conforme a consequência de errar, e o exemplo da própria doc usa 0.8 como corte (se answer.confidence < 0.8, manda pra revisão humana, senão chama o handler automático). Na prática: use 0.8 como ponto de partida do limiar da sua remediação automática, nunca desça abaixo do piso de 0.6, e valide o número plotando confiança contra acurácia nos seus próprios dados de incidente.

O Jev consegue contar quantos erros aconteceram no log pra decidir a ação?

Não é recomendado. A doc de limitações do jev-1.13 é clara: ele não conta de forma confiável e o erro cresce com o tamanho do que se conta. Por isso o certo é calcular error_rate_pct, queue_backlog e afins no seu código, e mandar só o resultado pronto no state.

Dá pra misturar Choice com Score na mesma chamada de remediação?

Dá sim. O campo questions é um mapa de ids pra objetos de pergunta, e as três primitivas (Choice, Score e Noul) podem dividir a mesma request. Então você pode pedir o Choice da ação de remediação e um Score de severidade no mesmo POST pro endpoint.

Quanto custa rodar o Jev em cada disparo de alerta?

O Jev cobra só por token de entrada, US$ 0,042 por 1 milhão de tokens de input, e o output sai a US$ 0,00. Como um payload de incidente típico (métricas, alguns logs e as opções do Choice) é pequeno perto de 1 milhão de tokens, o custo por decisão fica bem baixo.

O que fazer se eu não peguei a janela de cadastro aberto da TypeSafe?

A TypeSafe abriu cadastro direto no console.typesafe.ai em 20/09/2026 com US$ 5 de crédito e pausou novos cadastros em 22/09/2026. Contas já criadas continuam funcionando normalmente, mas não há anúncio de reabertura até 24/09/2026. Uma alternativa nesse meio tempo é acessar o modelo pela OpenRouter, onde o typesafe/jev-1.13 e o jev-latest estão listados.

Quantos runbooks (opções) eu posso colocar num Choice de remediação?

Uma pergunta Choice aceita até 255 opções, o que cobre folgado qualquer lista de runbooks real. O ponto de atenção não é quantidade, é a doc recomendando sempre incluir uma opção de escape tipo other ou none of the above pra quando o incidente não bater com nenhum runbook conhecido.



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 45min

Blog | Mais populares