Como usar o Jev para decidir quando o agente deve parar de iterar?

Diagrama mostrando o Jev recebendo um estado e devolvendo uma decisão tipada para controle de loop de agente
Resposta rápida

O Jev é o primeiro System One Model da TypeSafe AI, anunciado em 15/09/2026: ele não gera texto, recebe um estado e devolve decisões tipadas com probabilidade. Pra controle de loop isso muda tudo: em vez de pedir pro próprio LLM julgar se "já terminou?" e depois parsear a string, você declara as saídas válidas no schema e recebe um Noul (probabilidade de 0 a 1), um Choice ou um Score. A cada iteração você monta o state, faz as perguntas numa única chamada e usa a probabilidade como condição de saída do loop.

Agente que itera pra sempre e agente que para cedo demais têm a mesma causa raiz: quem responde "já terminou?" é o mesmo LLM que acabou de escrever a resposta

E ele quase sempre acha que fez um ótimo trabalho, né? 😅

A TypeSafe AI anunciou em 15/09/2026 o Jev, o primeiro System One Model deles: uma classe de modelo feita pra tomar decisão rápida e estruturada que o software consome direto. Ele não é autorregressivo, não prevê o próximo token e não te devolve uma stringzinha simpática

Tu manda um estado, ele devolve decisão tipada com probabilidade

É exatamente a peça que faltava pra tirar o "parar ou continuar" das mãos de quem tem conflito de interesse

Por que deixar o LLM julgar o próprio "já terminou?" falha

O desenho clássico é esse: o agente executa, produz um resultado, e aí você manda de volta pro mesmo modelo uma pergunta tipo "a tarefa está completa? responda SIM ou NÃO"

Dois problemas nascem juntos aí

O primeiro é o conflito: o gerador é o avaliador. O segundo é mecânico e dói mais no dia a dia: a saída é texto livre. Hoje vem SIM, amanhã vem Sim, a tarefa parece estar completa, embora... e o teu if quebra

E aí entra o gambiarrão de sempre: regex, .lower().startswith("sim"), retry quando não parseia, um JSON mode que às vezes volta com campo a mais

O Jev resolve isso por construção: as saídas válidas são declaradas no schema antes da chamada. Ele só responde dentro desse espaço declarado, sempre com probabilidade associada

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

Não tem resposta fora do espaço definido, não tem erro de tipo

Que "espaço definido"? É você quem escreve: se a pergunta é sim/não, o retorno é uma probabilidade entre 0 e 1. Se é escolha, o retorno é uma das opções da tua lista. Não existe terceira via inventada no meio do caminho

E não é ideia de maluco isolado: a LangChain publicou o material Building a harness with Jev descrevendo nós de decisão dentro do loop do agente, como roteamento de modelo e gate de tool call avaliado antes da execução

Ou seja: o padrão de "decisão de controle sai do LLM e vira chamada tipada" já tá documentado por terceiro, não é só o fornecedor falando bem de si mesmo

O que você precisa antes de começar

Lista curta, beleza?

  • Conta e chave de API criadas no console da TypeSafe (console.typesafe.ai)
  • A chave exportada na variável de ambiente TYPESAFE_API_KEY
  • SDK oficial, se você for usar: npm install @typesafe-ai/sdk ou pip install typesafe_sdk. Os dois leem a TYPESAFE_API_KEY e usam jev-latest por padrão
  • Um agente com loop já existente, porque o Jev não substitui o LLM que executa a tarefa

Esse último ponto é o que mais confunde gente chegando agora: o Jev não escreve teu código, não redige teu email, não chama tua tool. Ele decide

Sobre acesso: não tem mais waitlist, a TypeSafe abriu pra todo mundo. Conta nova recebe US$ 5,00 de crédito inicial (algo em torno de 120 milhões de tokens)

O preço é US$ 0,042 por milhão de tokens de entrada, e os tokens de saída são gratuitos

Sim, tu consegue prototipar um gate de loop inteiro dentro do crédito de boas-vindas 🙂

export TYPESAFE_API_KEY="sua_chave_aqui"

Tome cuidado: chave em variável de ambiente, não hardcoded no arquivo que você vai commitar. Já viu esse filme antes

Passo a passo: transformando o "parar ou continuar" em decisão tipada

1. Desenhe o state da iteração:

O campo state aceita string, objeto JSON, array ou null. Use isso a teu favor e mande estado estruturado, não prosa

O que costuma entrar: o objetivo original, a última ação executada, o resultado da tool, quantas tentativas já rolaram e o que ainda está pendente

{
  "objetivo": "Corrigir o teste que falha em auth/login_spec.ts",
  "tentativas": 3,
  "ultima_acao": "run_tests",
  "resultado_ultima_acao": "1 failing: expected 200, got 401",
  "arquivos_alterados": ["src/auth/session.ts"],
  "pendencias": ["teste ainda falhando"]
}

O erro comum deste passo: jogar o histórico bruto da conversa inteira dentro do state

Funciona? Provavelmente. Mas você acabou de transformar uma decisão barata numa chamada gorda, e enterrou o sinal relevante (tentativas, resultado da última ação) embaixo de dez mil tokens de "claro! vou analisar isso pra você"

Estado é estado. Transcrição é transcrição

2. Escolha o tipo de pergunta certo:

O Jev aceita exatamente três tipos, e é aqui que a maioria erra o desenho

Tipo O que você pergunta O que volta
Choice Uma opção entre até 255 alternativas A opção de maior probabilidade + a probabilidade de cada uma (somam 1) + confiança
Score Uma rubrica ordenada de 2 a 10 níveis Um valor fracionário no espectro + a distribuição completa + confiança
Noul Uma afirmação sim/não Probabilidade de 0 (não) a 1 (sim)

Noul é o nome que a TypeSafe dá pra pergunta sim/não, e é o tipo natural pro "já terminou?"

O erro comum deste passo: usar Choice com as opções ["parar", "continuar"] quando a pergunta é binária. Dá certo, mas você joga fora a graduação: com Noul você recebe o quanto o modelo acha que terminou, não só o lado vencedor

3. Monte a requisição:

O endpoint do Jev é próprio, não é /chat/completions. É POST https://api.typesafe.ai/v1/systemone

O corpo exige três campos: model, state e questions. O questions é um mapa do nome da pergunta pra um objeto com type e instructions

curl -X POST https://api.typesafe.ai/v1/systemone \
  -H "Authorization: Bearer $TYPESAFE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "jev-latest",
    "state": {
      "objetivo": "Corrigir o teste que falha em auth/login_spec.ts",
      "tentativas": 3,
      "ultima_acao": "run_tests",
      "resultado_ultima_acao": "1 failing: expected 200, got 401",
      "pendencias": ["teste ainda falhando"]
    },
    "questions": {
      "esta_completo": {
        "type": "Noul",
        "instructions": "O objetivo foi totalmente atingido e não há pendência aberta no estado?"
      }
    }
  }'

A resposta traz model, answers e usage

O erro comum deste passo: escrever instructions vago tipo "está bom?". Afirmação vaga gera distribuição espalhada, e distribuição espalhada é confiança baixa. Escreva a afirmação como uma frase que dá pra julgar olhando só o state

4. Faça várias perguntas de uma vez só:

As perguntas são avaliadas numa única ida e volta. Então não faz sentido chamar três vezes pra saber completude, qualidade e próxima ação

{
  "model": "jev-latest",
  "state": { "...": "..." },
  "questions": {
    "esta_completo": {
      "type": "Noul",
      "instructions": "O objetivo foi totalmente atingido e não há pendência aberta?"
    },
    "qualidade": {
      "type": "Score",
      "instructions": "Qualidade do resultado atual: 1 inutilizável, 5 pronto pra entregar"
    },
    "proxima_acao": {
      "type": "Choice",
      "instructions": "Qual a próxima ação mais útil dado o estado?",
      "options": ["rodar_testes", "editar_codigo", "ler_arquivo", "encerrar"]
    }
  }
}

O erro comum deste passo: adicionar uma pergunta pedindo pro Jev "explicar por que decidiu isso"

Ele não gera texto. Ponto. Se você precisa de justificativa legível pra humano, isso é trabalho de outro modelo, ou do teu log mostrando o state que entrou e a distribuição que saiu

5. Ligue a resposta ao controle do loop:

Agora a parte que importa: a condição de saída deixa de ser um parse de string e vira comparação numérica

const TYPESAFE_URL = "https://api.typesafe.ai/v1/systemone"

// valores arbitrários deste projeto: calibre com os seus próprios dados,
// não existe limiar oficial recomendado pela TypeSafe
const PARAR_ACIMA_DE = 0.9
const DESISTIR_ABAIXO_DE = 0.2
const MAX_ITERACOES = 12

async function decidir(state) {
  const res = await fetch(TYPESAFE_URL, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${process.env.TYPESAFE_API_KEY}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      model: "jev-latest",
      state,
      questions: {
        esta_completo: {
          type: "Noul",
          instructions: "O objetivo foi totalmente atingido e não há pendência aberta?"
        }
      }
    })
  })
  return res.json()
}

async function rodarAgente(objetivo) {
  let state = { objetivo, tentativas: 0, pendencias: ["concluir o objetivo"] }

  for (let i = 0; i < MAX_ITERACOES; i++) {
    state = await executarUmaIteracao(state) // aqui roda o teu LLM de sempre

    const { answers, usage } = await decidir(state)
    const p = answers.esta_completo

    console.log({ iteracao: i, completude: p, usage })

    if (p >= PARAR_ACIMA_DE) return { status: "concluido", state }
    if (p <= DESISTIR_ABAIXO_DE && state.tentativas >= 3) {
      return { status: "escalar_humano", state }
    }
  }

  return { status: "limite_de_iteracoes", state }
}

O erro comum deste passo: remover o MAX_ITERACOES porque "agora o Jev decide". Não. O gate é semântico, o contador é mecânico, e os dois protegem coisas diferentes

6. Pine a versão do modelo quando precisar de estabilidade:

jev-latest é ótimo pra prototipar e péssimo pra reprodutibilidade, porque o que está por trás dele pode mudar

O jev-latest já foi observado resolvendo para jev-1.13.0, e o identificador typesafe/jev-1.13 aparece listado em provedores

{ "model": "jev-1.13.0" }

O erro comum deste passo: pinar e esquecer. Se tu pinou, anota no README por que pinou e quando revisar, senão daqui a seis meses ninguém lembra

Usando o score de confiança como trava de segurança

Aqui mora a parte mais bonita do desenho, e a mais ignorada

Respostas de Choice e Score carregam um campo de confiança separado, de 0 a 1, derivado do formato da distribuição de probabilidades

Probabilidade concentrada numa opção significa confiança alta. Distribuição espalhada entre as opções significa confiança baixa

A regra prática que a própria documentação resume é linda de simples: a resposta diz o quê, a confiança diz se você deve agir

1. Separe três faixas de tratamento:

  • Confiança alta e decisão "completo": para o loop e entrega
  • Confiança alta e decisão "incompleto": continua iterando, com a próxima ação que o Choice apontou
  • Confiança baixa: não é pra parar nem pra insistir cegamente. É pra escalar, seja pra um humano, seja pra um modelo maior fazer uma passada de revisão

Distribuição espalhada quase sempre quer dizer que o state que você mandou não tem informação suficiente pra decidir. O modelo tá te avisando que a pergunta tá mal servida, não que a tarefa tá mais ou menos

Essa faixa do meio é a mesma discussão de autonomia do agente no Claude Code: o ponto não é dar autonomia total nem zero, é ter um sinal confiável pra saber em qual dos dois modos você está agora

2. Trate o Noul diferente:

Noul não tem campo de confiança separado. A própria probabilidade é o sinal que a aplicação usa

Ou seja: ali você não tem uma trava, você tem duas fronteiras

Perto de 1 é sim com força. Perto de 0 é não com força. E a região do meio, aquele território morno onde o modelo não se compromete, é justamente o teu gatilho de escalação

function faixaNoul(p) {
  if (p >= PARAR_ACIMA_DE) return "parar"
  if (p <= DESISTIR_ABAIXO_DE) return "continuar_iterando"
  return "escalar" // zona morna: ninguém decide por palpite
}

3. Entenda por que dá pra confiar nesse número:

O Jev é treinado com um método de calibração próprio da TypeSafe, o RLCD (Reinforcement Learning for Calibrated Decisions)

A propriedade buscada é essa: grupos de previsões com probabilidade mais alta devem acertar com mais frequência que grupos de probabilidade mais baixa

Parece óbvio, mas não é o comportamento padrão de um LLM cuspindo "tenho certeza absoluta" no meio de um parágrafo. Ali o número é texto. Aqui ele é a saída do modelo

Importante ser honesto: não existe limiar oficial recomendado pela TypeSafe do tipo "abaixo de tanto, continue". Os valores de corte são decisão sua, e a forma certa de achar é logar as probabilidades junto com o desfecho real de cada rodada e olhar os dados depois

Outras decisões de loop que valem tirar do LLM

Uma vez que o padrão entra na cabeça, você começa a ver decisão tipada em todo canto do harness

  • Gate de tool call: antes de executar a ferramenta, uma pergunta avalia se aquela chamada faz sentido no estado atual. A LangChain descreve exatamente esse nó avaliado antes da execução. Noul resolve, e é o seu escudo contra os rm -rf da vida
  • Roteamento de modelo: Choice entre o modelo rápido e o modelo caro, decidido pela dificuldade que aparece no state, não por um if com contagem de caracteres do prompt
  • Próxima ação: Choice dentro de um conjunto fechado de ferramentas. Como as opções são declaradas no schema, é impossível o agente inventar uma tool que não existe
  • Qualidade do rascunho antes de entregar: Score com rubrica ordenada, de 2 a 10 níveis. Muito melhor que "o texto está bom? sim/não"
  • Detecção de loop improdutivo: Noul perguntando se o agente está repetindo a mesma tentativa com o mesmo resultado. É o gate que salva você da conta de API surpresa no domingo de manhã 😅

Se você quer ver o modelo aplicado fora do contexto de agente, os casos de uso do Jev dentro do software seguem exatamente a mesma lógica: decisão que o código consome direto, sem parse no meio

Custo e latência: por que essa camada extra compensa

O argumento contra é previsível: "você adicionou mais uma chamada de modelo por iteração"

Verdade. Então vamos olhar os dois eixos

No custo, o preço é US$ 0,042 por milhão de tokens de entrada e os tokens de saída são gratuitos. Como o state estruturado que você manda é pequeno (lembra do passo 1?), o gate custa uma fração do que custa a própria iteração do agente

Na velocidade, a TypeSafe afirma que o Jev é de 40x a 200x mais rápido que LLMs de fronteira em tarefas System One

E aqui eu preciso ser chato: isso é claim do fornecedor, não benchmark independente. Não vou vender esse número como verdade medida por terceiro, porque não é

A boa notícia é que você não depende de acreditar: a resposta traz o campo usage. Loga ele a cada gate, soma no fim do dia e compara com o custo das iterações que o gate evitou

Um agente que parava na iteração 12 por timeout e agora para na 4 porque alguém perguntou direito "já terminou?" se paga sozinho

Conclusão

A ideia central cabe em uma frase: quem decide parar não deve ser quem escreveu a resposta

O Jev encaixa exatamente aí, porque ele não compete com o teu LLM executor. Ele ocupa o espaço que hoje é preenchido por regex, retry e torcida

Próximo passo concreto, sem firula: cria a chave no console, exporta a TYPESAFE_API_KEY e coloca um único Noul de completude no loop que mais te dá dor de cabeça hoje

Roda uma semana logando probabilidade e desfecho

Só depois disso você adiciona o Score de qualidade e o Choice de próxima ação, já com número na mão pra calibrar as faixas em vez de chutar

Começa pequeno, mede, expande

Até o próximo post! 🙂

Perguntas frequentes

Quanto custa usar o Jev pra decidir quando um agente deve parar de iterar?

O Jev cobra US$ 0,042 por milhão de tokens de entrada, e os tokens de saída são gratuitos. Conta nova ganha US$ 5,00 de crédito inicial, o que dá pra rodar bastante gate de decisão antes de gastar nada do bolso.

Qual a diferença entre Noul e Score pra saber se o agente já terminou?

Noul é a pergunta sim/não: devolve só uma probabilidade de 0 a 1, sem campo separado de confiança, porque a própria probabilidade já carrega esse sinal. Score é pra quando ‘terminou’ não é binário: retorna um valor fracionário numa rubrica de 2 a 10 níveis, mais a distribuição completa e um campo de confiança à parte.

Ainda existe lista de espera pra acessar o Jev?

Não. A TypeSafe removeu a waitlist e anunciou que o Jev está disponível pra qualquer pessoa, sem espera. O blog de lançamento de 15/09/2026 ainda menciona ‘early access’, mas esse trecho ficou desatualizado.

O Jev substitui o LLM que executa as tarefas do meu agente?

Não. O Jev só decide, ele não gera texto nem chama tool. Você precisa de um loop de agente já existente, com o LLM de execução separado, e usa o Jev como a camada que julga se continua ou para.

Dá pra fixar uma versão específica do Jev em vez de usar jev-latest?

Dá sim. O identificador jev-latest resolvia para jev-1.13.0 no momento deste post, e o id typesafe/jev-1.13 aparece listado em provedores pra quem quer pinar a versão manualmente.

O endpoint do Jev funciona igual ao /chat/completions de outros LLMs?

Não, o Jev tem endpoint próprio: POST https://api.typesafe.ai/v1/systemone. O corpo da requisição pede model, state e questions, e a resposta vem com model, answers e usage, num formato bem diferente do padrão de chat.



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